Change new meeting schedule editor to not layout the time slots on a
linear scale, instead lay them out horizontally per day in chronological order with a small amount of size hinting by interpolating the width depending on the duration of the timeslot/session. Solve the problem of labeling time slots that don't necessarily align by simply labeling each slot separately. Add scheduled time slot information to the session info in the bottom right corner. Add selector for hiding timeslots to make it possible to hide special morning sessions. Add requested duration to the sessions in the grid. Use a smaller font size for the grid and switch to a non-serif, more condensed font. Tweak the margins. The grid is now slightly smaller than the old editor. Fix a couple of bugs. - Legacy-Id: 18012
This commit is contained in:
parent
8bd9e5de6e
commit
b60939a26c
ietf
meeting
static/ietf
templates/meeting
|
@ -508,20 +508,22 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
assignments_by_session[a.session_id].append(a)
|
||||
|
||||
# Prepare timeslot layout, making a timeline per day scaled in
|
||||
# browser em units to ensure that everything lines up even if the
|
||||
# browser rem units to ensure that everything lines up even if the
|
||||
# timeslots are not the same in the different rooms
|
||||
|
||||
min_duration = min(t.duration for t in timeslots_qs)
|
||||
max_duration = max(t.duration for t in timeslots_qs)
|
||||
|
||||
def timedelta_to_css_ems(timedelta):
|
||||
css_ems_per_hour = 5
|
||||
return timedelta.seconds / 60.0 / 60.0 * css_ems_per_hour
|
||||
capped_min_d = max(min_duration, datetime.timedelta(minutes=30))
|
||||
capped_max_d = min(max_duration, datetime.timedelta(hours=4))
|
||||
capped_timedelta = min(max(capped_min_d, timedelta), capped_max_d)
|
||||
|
||||
timeslots_by_day = defaultdict(list)
|
||||
for t in timeslots_qs:
|
||||
timeslots_by_day[t.time.date()].append(t)
|
||||
|
||||
day_min_max = []
|
||||
for day, timeslots in sorted(timeslots_by_day.items()):
|
||||
day_min_max.append((day, min(t.time for t in timeslots), max(t.end_time() for t in timeslots)))
|
||||
min_d_css_rems = 8
|
||||
max_d_css_rems = 10
|
||||
# interpolate
|
||||
scale = (capped_timedelta - capped_min_d) / (capped_max_d - capped_min_d) if capped_min_d != capped_max_d else 1
|
||||
return min_d_css_rems + (max_d_css_rems - min_d_css_rems) * scale
|
||||
|
||||
timeslots_by_room_and_day = defaultdict(list)
|
||||
room_has_timeslots = set()
|
||||
|
@ -530,34 +532,7 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
timeslots_by_room_and_day[(t.location_id, t.time.date())].append(t)
|
||||
|
||||
days = []
|
||||
for day, day_min_time, day_max_time in day_min_max:
|
||||
day_labels = []
|
||||
day_width = timedelta_to_css_ems(day_max_time - day_min_time)
|
||||
|
||||
label_width = 4 # em
|
||||
|
||||
hourly_delta = 2
|
||||
|
||||
first_hour = int(math.ceil((day_min_time.hour + day_min_time.minute / 60.0) / hourly_delta) * hourly_delta)
|
||||
t = day_min_time.replace(hour=first_hour, minute=0, second=0, microsecond=0)
|
||||
|
||||
last_hour = int(math.floor((day_max_time.hour + day_max_time.minute / 60.0) / hourly_delta) * hourly_delta)
|
||||
end = day_max_time.replace(hour=last_hour, minute=0, second=0, microsecond=0)
|
||||
|
||||
while t <= end:
|
||||
left_offset = timedelta_to_css_ems(t - day_min_time)
|
||||
right_offset = day_width - left_offset
|
||||
if right_offset > label_width:
|
||||
# there's room for the label
|
||||
day_labels.append((t, 'left', left_offset))
|
||||
else:
|
||||
day_labels.append((t, 'right', right_offset))
|
||||
|
||||
t += datetime.timedelta(seconds=hourly_delta * 60 * 60)
|
||||
|
||||
if not day_labels:
|
||||
day_labels.append((day_min_time, 'left', 0))
|
||||
|
||||
for day in sorted(set(t.time.date() for t in timeslots_qs)):
|
||||
room_timeslots = []
|
||||
for r in rooms:
|
||||
if r.pk not in room_has_timeslots:
|
||||
|
@ -565,23 +540,24 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
|
||||
timeslots = []
|
||||
for t in timeslots_by_room_and_day.get((r.pk, day), []):
|
||||
timeslots.append({
|
||||
'timeslot': t,
|
||||
'offset': timedelta_to_css_ems(t.time - day_min_time),
|
||||
'width': timedelta_to_css_ems(t.end_time() - t.time),
|
||||
})
|
||||
t.layout_width = timedelta_to_css_ems(t.end_time() - t.time)
|
||||
timeslots.append(t)
|
||||
|
||||
room_timeslots.append((r, timeslots))
|
||||
|
||||
days.append({
|
||||
'day': day,
|
||||
'width': day_width,
|
||||
'time_labels': day_labels,
|
||||
'room_timeslots': room_timeslots,
|
||||
})
|
||||
|
||||
room_labels = [[r for r in rooms if r.pk in room_has_timeslots] for i in range(len(days))]
|
||||
|
||||
# possible timeslot start/ends
|
||||
timeslot_groups = defaultdict(set)
|
||||
for ts in timeslots_qs:
|
||||
ts.start_end_group = "ts-group-{}-{}".format(ts.time.strftime("%Y%m%d-%H%M"), int(ts.duration.total_seconds() / 60))
|
||||
timeslot_groups[ts.time.date()].add((ts.time, ts.end_time(), ts.start_end_group))
|
||||
|
||||
# prepare sessions
|
||||
for ts in timeslots_qs:
|
||||
ts.session_assignments = []
|
||||
|
@ -637,7 +613,7 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
elif s.name:
|
||||
s.scheduling_label = s.name
|
||||
|
||||
s.requested_duration_in_hours = s.requested_duration.seconds / 60.0 / 60.0
|
||||
s.requested_duration_in_hours = round(s.requested_duration.seconds / 60.0 / 60.0, 1)
|
||||
|
||||
session_layout_margin = 0.2
|
||||
s.layout_width = timedelta_to_css_ems(s.requested_duration) - 2 * session_layout_margin
|
||||
|
@ -688,6 +664,7 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
|||
'js_data': json.dumps(js_data, indent=2),
|
||||
'days': days,
|
||||
'room_labels': room_labels,
|
||||
'timeslot_groups': sorted((d, list(sorted(t_groups))) for d, t_groups in timeslot_groups.items()),
|
||||
'unassigned_sessions': unassigned_sessions,
|
||||
'session_parents': session_parents,
|
||||
'hide_menu': True,
|
||||
|
|
|
@ -1022,81 +1022,66 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day {
|
||||
margin-right: 2.5em;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .room-label-column .day {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-label {
|
||||
height: 3em;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-flow {
|
||||
margin-left: 8em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 120em) {
|
||||
/* if there's only room for two days, it looks a bit odd with space-between */
|
||||
.edit-meeting-schedule .edit-grid .day-flow {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .day-flow .day-label {
|
||||
border-bottom: 2px solid #eee;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeline {
|
||||
.edit-meeting-schedule .edit-grid .timeslots {
|
||||
position: relative;
|
||||
height: 1.6em;
|
||||
height: 4.5em;
|
||||
padding-bottom: 0.15em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeline > div {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeline.timeslots {
|
||||
height: 3.3em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeline .time-label {
|
||||
font-size: smaller;
|
||||
border-left: 2px solid #eee;
|
||||
border-right: 2px solid #eee;
|
||||
padding: 0 0.2em;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeline .time-label.text-left {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeline .time-label.text-right {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .timeslot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #eee;
|
||||
.edit-meeting-schedule .edit-grid .timeslot {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
background-color: #f4f4f4;
|
||||
height: 100%;
|
||||
border-bottom: 0.15em solid #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .timeslot.dropping {
|
||||
.edit-meeting-schedule .edit-grid .timeslot .time-label {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot .drop-target {
|
||||
position: relative; /* this is merely to make sure we are positioned above the time labels */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid .timeslot.dropping {
|
||||
background-color: #ccc;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .timeslot.overfull {
|
||||
.edit-meeting-schedule .edit-grid .timeslot.overfull {
|
||||
border-right: 2px dashed #fff; /* cut-off illusion */
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .timeslot.would-violate-hint {
|
||||
.edit-meeting-schedule .edit-grid .timeslot.would-violate-hint {
|
||||
background-color: #ffe0e0;
|
||||
}
|
||||
|
||||
|
@ -1111,7 +1096,6 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
|
||||
.edit-meeting-schedule .formatted-constraints .encircled {
|
||||
font-size: smaller;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* sessions */
|
||||
|
@ -1139,7 +1123,7 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
}
|
||||
|
||||
.edit-meeting-schedule .session.dragging {
|
||||
opacity: 0.3;
|
||||
opacity: 0.1;
|
||||
transition: opacity 0.4s;
|
||||
}
|
||||
|
||||
|
@ -1148,6 +1132,11 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
margin-right: 0;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .edit-grid, .edit-meeting-schedule .session {
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session .session-label {
|
||||
flex-grow: 1;
|
||||
margin-left: 0.1em;
|
||||
|
@ -1208,6 +1197,7 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
left: 0;
|
||||
width: 100%;
|
||||
border-top: 0.2em solid #ccc;
|
||||
margin-bottom: 2em;
|
||||
background-color: #fff;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
@ -1217,14 +1207,11 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
margin-top: 0.5em;
|
||||
min-height: 4em;
|
||||
max-height: 13em;
|
||||
overflow-y: auto;
|
||||
background-color: #eee;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions.dropping {
|
||||
|
@ -1232,6 +1219,12 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .unassigned-sessions .drop-target {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .scheduling-panel .preferences {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
@ -1245,6 +1238,21 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body {
|
||||
/*column-count: 3;*/
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body > * {
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body label {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.edit-meeting-schedule .session-parent-toggles {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
@ -1259,8 +1267,9 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
|||
|
||||
.edit-meeting-schedule .scheduling-panel .session-info-container {
|
||||
padding-left: 0.5em;
|
||||
flex: 0 0 20em;
|
||||
max-height: 15em;
|
||||
flex: 0 0 25em;
|
||||
max-height: 25em;
|
||||
font-size: 14px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ jQuery(document).ready(function () {
|
|||
|
||||
let sessions = content.find(".session");
|
||||
let timeslots = content.find(".timeslot");
|
||||
let days = content.find(".day-flow .day");
|
||||
|
||||
// hack to work around lack of position sticky support in old browsers, see https://caniuse.com/#feat=css-sticky
|
||||
if (content.find(".scheduling-panel").css("position") != "sticky") {
|
||||
|
@ -43,7 +44,11 @@ jQuery(document).ready(function () {
|
|||
sessions.not(element).removeClass("selected");
|
||||
jQuery(element).addClass("selected");
|
||||
showConstraintHints(element.id.slice("session".length));
|
||||
content.find(".scheduling-panel .session-info-container").html(jQuery(element).find(".session-info").html()).find('[data-original-title]').tooltip();
|
||||
let sessionInfoContainer = content.find(".scheduling-panel .session-info-container");
|
||||
sessionInfoContainer.html(jQuery(element).find(".session-info").html());
|
||||
sessionInfoContainer.find('[data-original-title]').tooltip();
|
||||
let time = jQuery(element).closest(".timeslot").find(".time-label").text() || "";
|
||||
sessionInfoContainer.find('.time').text(time.replace(new RegExp(" ", "g"), ""));
|
||||
}
|
||||
else {
|
||||
sessions.removeClass("selected");
|
||||
|
@ -107,13 +112,13 @@ jQuery(document).ready(function () {
|
|||
sessions.prop('draggable', true);
|
||||
|
||||
// dropping
|
||||
let dropElements = content.find(".timeslot,.unassigned-sessions");
|
||||
let dropElements = content.find(".timeslot .drop-target,.unassigned-sessions .drop-target");
|
||||
dropElements.on('dragenter', function (event) {
|
||||
if ((event.originalEvent.dataTransfer.getData("text/plain") || "").slice(0, "session".length) != "session")
|
||||
return;
|
||||
|
||||
event.preventDefault(); // default action is signalling that this is not a valid target
|
||||
jQuery(this).addClass("dropping");
|
||||
jQuery(this).parent().addClass("dropping");
|
||||
});
|
||||
|
||||
dropElements.on('dragover', function (event) {
|
||||
|
@ -128,11 +133,11 @@ jQuery(document).ready(function () {
|
|||
if (event.originalEvent.currentTarget.contains(event.originalEvent.relatedTarget))
|
||||
return;
|
||||
|
||||
jQuery(this).removeClass("dropping");
|
||||
jQuery(this).parent().removeClass("dropping");
|
||||
});
|
||||
|
||||
dropElements.on('drop', function (event) {
|
||||
jQuery(this).removeClass("dropping");
|
||||
jQuery(this).parent().removeClass("dropping");
|
||||
|
||||
let sessionId = event.originalEvent.dataTransfer.getData("text/plain");
|
||||
if ((event.originalEvent.dataTransfer.getData("text/plain") || "").slice(0, "session".length) != "session")
|
||||
|
@ -148,6 +153,7 @@ jQuery(document).ready(function () {
|
|||
return;
|
||||
|
||||
let dropElement = jQuery(this);
|
||||
let dropParent = dropElement.parent();
|
||||
|
||||
function done(response) {
|
||||
if (response != "OK") {
|
||||
|
@ -157,11 +163,11 @@ jQuery(document).ready(function () {
|
|||
|
||||
dropElement.append(sessionElement); // move element
|
||||
updateCurrentSchedulingHints();
|
||||
if (dropElement.hasClass("unassigned-sessions"))
|
||||
if (dropParent.hasClass("unassigned-sessions"))
|
||||
sortUnassigned();
|
||||
}
|
||||
|
||||
if (dropElement.hasClass("unassigned-sessions")) {
|
||||
if (dropParent.hasClass("unassigned-sessions")) {
|
||||
jQuery.ajax({
|
||||
url: ietfData.urls.assign,
|
||||
method: "post",
|
||||
|
@ -179,7 +185,7 @@ jQuery(document).ready(function () {
|
|||
data: {
|
||||
action: "assign",
|
||||
session: sessionId.slice("session".length),
|
||||
timeslot: dropElement.attr("id").slice("timeslot".length)
|
||||
timeslot: dropParent.attr("id").slice("timeslot".length)
|
||||
},
|
||||
timeout: 5 * 1000
|
||||
}).fail(failHandler).done(done);
|
||||
|
@ -348,7 +354,7 @@ jQuery(document).ready(function () {
|
|||
|
||||
sortUnassigned();
|
||||
|
||||
// toggling of sessions
|
||||
// toggling visible sessions by session parents
|
||||
let sessionParentInputs = content.find(".session-parent-toggles input");
|
||||
|
||||
function updateSessionParentToggling() {
|
||||
|
@ -362,7 +368,25 @@ jQuery(document).ready(function () {
|
|||
}
|
||||
|
||||
sessionParentInputs.on("click", updateSessionParentToggling);
|
||||
|
||||
updateSessionParentToggling();
|
||||
|
||||
// toggling visible timeslots
|
||||
let timeslotGroupInputs = content.find("#timeslot-group-toggles-modal .modal-body input");
|
||||
function updateTimeslotGroupToggling() {
|
||||
let checked = [];
|
||||
timeslotGroupInputs.filter(":checked").each(function () {
|
||||
checked.push("." + this.value);
|
||||
});
|
||||
|
||||
timeslots.filter(checked.join(",")).removeClass("hidden");
|
||||
timeslots.not(checked.join(",")).addClass("hidden");
|
||||
|
||||
days.each(function () {
|
||||
jQuery(this).toggle(jQuery(this).find(".timeslot:not(.hidden)").length > 0);
|
||||
});
|
||||
}
|
||||
|
||||
timeslotGroupInputs.on("click change", updateTimeslotGroupToggling);
|
||||
updateTimeslotGroupToggling();
|
||||
});
|
||||
|
||||
|
|
|
@ -58,10 +58,8 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="timeline"></div>
|
||||
|
||||
{% for room in labels %}
|
||||
<div class="timeline timeslots">
|
||||
<div class="timeslots">
|
||||
<div class="room-name">
|
||||
<strong>{{ room.name }}</strong><br>
|
||||
{% if room.capacity %}{{ room.capacity }} <i class="fa fa-user-o"></i>{% endif %}
|
||||
|
@ -74,26 +72,26 @@
|
|||
|
||||
<div class="day-flow">
|
||||
{% for day in days %}
|
||||
<div class="day" style="width: {{ day.width }}em;">
|
||||
<div class="day">
|
||||
<div class="day-label">
|
||||
<strong>{{ day.day|date:"l" }}</strong><br>
|
||||
{{ day.day|date:"N j, Y" }}
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
{% for t, left_or_right, offset in day.time_labels %}
|
||||
<div class="time-label text-{{ left_or_right }}" style="{{ left_or_right }}: {{ offset }}em;">{{ t|date:"H:i" }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for room, timeslots in day.room_timeslots %}
|
||||
<div class="timeline timeslots" data-roomcapacity="{{ room.capacity }}">
|
||||
<div class="timeslots" data-roomcapacity="{{ room.capacity }}">
|
||||
|
||||
{% for t in timeslots %}
|
||||
<div id="timeslot{{ t.timeslot.pk }}" class="timeslot" data-start="{{ t.timeslot.time.isoformat }}" data-end="{{ t.timeslot.end_time.isoformat }}" data-duration="{{ t.timeslot.duration.total_seconds }}" style="left: {{ t.offset }}em; width: {{ t.width }}em;">
|
||||
{% for assignment, session in t.timeslot.session_assignments %}
|
||||
<div id="timeslot{{ t.pk }}" class="timeslot {{ t.start_end_group }}" data-start="{{ t.time.isoformat }}" data-end="{{ t.end_time.isoformat }}" data-duration="{{ t.duration.total_seconds }}" style="width: {{ t.layout_width }}rem;">
|
||||
<div class="time-label">
|
||||
{{ t.time|date:"G:i" }} - {{ t.end_time|date:"G:i" }}
|
||||
</div>
|
||||
|
||||
<div class="drop-target">
|
||||
{% for assignment, session in t.session_assignments %}
|
||||
{% include "meeting/edit_meeting_schedule_session.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
@ -106,9 +104,11 @@
|
|||
<div class="scheduling-panel">
|
||||
<div class="unassigned-container">
|
||||
<div class="unassigned-sessions">
|
||||
{% for session in unassigned_sessions %}
|
||||
{% include "meeting/edit_meeting_schedule_session.html" %}
|
||||
{% endfor %}
|
||||
<div class="drop-target">
|
||||
{% for session in unassigned_sessions %}
|
||||
{% include "meeting/edit_meeting_schedule_session.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preferences">
|
||||
|
@ -128,11 +128,44 @@
|
|||
<label class="parent-{{ p.acronym }}"><input type="checkbox" checked value="{{ p.acronym }}"> {{ p.acronym }}</label>
|
||||
{% endfor %}
|
||||
</span>
|
||||
|
||||
<span class="timeslot-group-toggles">
|
||||
<button class="btn btn-default" data-toggle="modal" data-target="#timeslot-group-toggles-modal"><input type="checkbox" checked="checked" disabled> Timeslots</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="session-info-container"></div>
|
||||
</div>
|
||||
|
||||
<div id="timeslot-group-toggles-modal" class="modal" role="dialog" aria-labelledby="timeslot-group-toggles-modal-title">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title" id="timeslot-group-toggles-modal-title">Displayed timeslots</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
{% for day, t_groups in timeslot_groups %}
|
||||
<div>
|
||||
<div><strong>{{ day|date:"M. d" }}</strong></div>
|
||||
{% for start, end, key in t_groups %}
|
||||
<label><input type="checkbox" name="timeslot-group" value="{{ key }}" checked="checked"> {{ start|date:"H:i" }} - {{ end|date:"H:i" }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<span class="requested-duration">{{ session.requested_duration_in_hours|floatformat }}h</span>
|
||||
|
||||
{% if session.attendees != None %}
|
||||
<span class="attendees">{{ session.attendees }}</span>
|
||||
<span class="attendees">· {{ session.attendees }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if session.comments %}
|
||||
|
@ -23,12 +25,15 @@
|
|||
|
||||
{# the JS uses this to display session information in the bottom panel #}
|
||||
<div class="session-info">
|
||||
<label>
|
||||
{{ session.scheduling_label }}
|
||||
· {{ session.requested_duration_in_hours }} h
|
||||
{% if session.group %}· {% if session.group.is_bof %}BoF{% else %}{{ session.group.type.name }}{% endif %}{% endif %}
|
||||
{% if session.attendees != None %}· {{ session.attendees }} <i class="fa fa-user-o"></i>{% endif %}
|
||||
</label>
|
||||
<div>
|
||||
<strong>
|
||||
<span class="time pull-right"></span>
|
||||
{{ session.scheduling_label }}
|
||||
· {{ session.requested_duration_in_hours }}h
|
||||
{% if session.group %}· {% if session.group.is_bof %}BoF{% else %}{{ session.group.type.name }}{% endif %}{% endif %}
|
||||
{% if session.attendees != None %}· {{ session.attendees }} <i class="fa fa-user-o"></i>{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
{% if session.group %}
|
||||
<div>
|
||||
|
@ -42,7 +47,7 @@
|
|||
|
||||
{% if session.requested_by_person %}
|
||||
<div>
|
||||
<i class="fa fa-user-circle-o"></i> {{ session.requested_by_person.plain_name }} {% if session.requested_time %}({{ session.requested_time|date:"Y-m-d" }}){% endif %}
|
||||
<i title="Requested by" class="fa fa-user-circle-o"></i> {{ session.requested_by_person.plain_name }} {% if session.requested_time %}({{ session.requested_time|date:"Y-m-d" }}){% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
|
Loading…
Reference in a new issue