Swap the axes in the meeting schedule editor and rework it to allow
flowing the days. Add JS workaround for missing position sticky support, instead of the CSS workaround which added an annoying padding for everyone. - Legacy-Id: 17616
This commit is contained in:
parent
b8b1b67e6d
commit
6c48575042
|
@ -508,17 +508,14 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
||||||
for a in assignments:
|
for a in assignments:
|
||||||
assignments_by_session[a.session_id].append(a)
|
assignments_by_session[a.session_id].append(a)
|
||||||
|
|
||||||
# Prepare timeslot layout. We arrange time slots in columns per
|
# Prepare timeslot layout, making a timeline per day scaled in
|
||||||
# room where everything inside is grouped by day. Things inside
|
# browser em units to ensure that everything lines up even if the
|
||||||
# the days are then layouted proportionally to the actual time of
|
# timeslots are not the same in the different rooms
|
||||||
# day, to ensure that everything lines up, even if the time slots
|
|
||||||
# are not the same in the different rooms.
|
|
||||||
|
|
||||||
def timedelta_to_css_ems(timedelta):
|
def timedelta_to_css_ems(timedelta):
|
||||||
css_ems_per_hour = 1.8
|
css_ems_per_hour = 5
|
||||||
return timedelta.seconds / 60.0 / 60.0 * css_ems_per_hour
|
return timedelta.seconds / 60.0 / 60.0 * css_ems_per_hour
|
||||||
|
|
||||||
# time labels column
|
|
||||||
timeslots_by_day = defaultdict(list)
|
timeslots_by_day = defaultdict(list)
|
||||||
for t in timeslots_qs:
|
for t in timeslots_qs:
|
||||||
timeslots_by_day[t.time.date()].append(t)
|
timeslots_by_day[t.time.date()].append(t)
|
||||||
|
@ -526,10 +523,19 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
||||||
day_min_max = []
|
day_min_max = []
|
||||||
for day, timeslots in sorted(timeslots_by_day.iteritems()):
|
for day, timeslots in sorted(timeslots_by_day.iteritems()):
|
||||||
day_min_max.append((day, min(t.time for t in timeslots), max(t.end_time() for t in timeslots)))
|
day_min_max.append((day, min(t.time for t in timeslots), max(t.end_time() for t in timeslots)))
|
||||||
|
|
||||||
time_labels = []
|
timeslots_by_room_and_day = defaultdict(list)
|
||||||
|
room_has_timeslots = set()
|
||||||
|
for t in timeslots_qs:
|
||||||
|
room_has_timeslots.add(t.location_id)
|
||||||
|
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:
|
for day, day_min_time, day_max_time in day_min_max:
|
||||||
day_labels = []
|
day_labels = []
|
||||||
|
day_width = timedelta_to_css_ems(day_max_time - day_min_time)
|
||||||
|
|
||||||
|
label_width = 4 # em
|
||||||
|
|
||||||
hourly_delta = 2
|
hourly_delta = 2
|
||||||
|
|
||||||
|
@ -540,47 +546,42 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
||||||
end = day_max_time.replace(hour=last_hour, minute=0, second=0, microsecond=0)
|
end = day_max_time.replace(hour=last_hour, minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
while t <= end:
|
while t <= end:
|
||||||
day_labels.append((t, 'top', timedelta_to_css_ems(t - day_min_time), 'left'))
|
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)
|
t += datetime.timedelta(seconds=hourly_delta * 60 * 60)
|
||||||
|
|
||||||
if not day_labels:
|
if not day_labels:
|
||||||
day_labels.append((day_min_time, 'top', 0, 'left'))
|
day_labels.append((day_min_time, 'left', 0))
|
||||||
|
|
||||||
time_labels.append({
|
room_timeslots = []
|
||||||
'day': day,
|
for r in rooms:
|
||||||
'height': timedelta_to_css_ems(day_max_time - day_min_time),
|
if r.pk not in room_has_timeslots:
|
||||||
'labels': day_labels,
|
continue
|
||||||
})
|
|
||||||
|
|
||||||
# room columns
|
timeslots = []
|
||||||
timeslots_by_room_and_day = defaultdict(list)
|
|
||||||
for t in timeslots_qs:
|
|
||||||
timeslots_by_room_and_day[(t.location_id, t.time.date())].append(t)
|
|
||||||
|
|
||||||
room_columns = []
|
|
||||||
for r in rooms:
|
|
||||||
room_days = []
|
|
||||||
|
|
||||||
for day, day_min_time, day_max_time in day_min_max:
|
|
||||||
day_timeslots = []
|
|
||||||
for t in timeslots_by_room_and_day.get((r.pk, day), []):
|
for t in timeslots_by_room_and_day.get((r.pk, day), []):
|
||||||
day_timeslots.append({
|
timeslots.append({
|
||||||
'timeslot': t,
|
'timeslot': t,
|
||||||
'offset': timedelta_to_css_ems(t.time - day_min_time),
|
'offset': timedelta_to_css_ems(t.time - day_min_time),
|
||||||
'height': timedelta_to_css_ems(t.end_time() - t.time),
|
'width': timedelta_to_css_ems(t.end_time() - t.time),
|
||||||
})
|
})
|
||||||
|
|
||||||
room_days.append({
|
room_timeslots.append((r, timeslots))
|
||||||
'day': day,
|
|
||||||
'timeslots': day_timeslots,
|
|
||||||
'height': timedelta_to_css_ems(day_max_time - day_min_time),
|
|
||||||
})
|
|
||||||
|
|
||||||
if any(d['timeslots'] for d in room_days):
|
days.append({
|
||||||
room_columns.append({
|
'day': day,
|
||||||
'room': r,
|
'width': day_width,
|
||||||
'days': room_days,
|
'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))]
|
||||||
|
|
||||||
# prepare sessions
|
# prepare sessions
|
||||||
for ts in timeslots_qs:
|
for ts in timeslots_qs:
|
||||||
|
@ -701,7 +702,7 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
||||||
s.requested_duration_in_hours = s.requested_duration.seconds / 60.0 / 60.0
|
s.requested_duration_in_hours = s.requested_duration.seconds / 60.0 / 60.0
|
||||||
|
|
||||||
session_layout_margin = 0.2
|
session_layout_margin = 0.2
|
||||||
s.layout_height = timedelta_to_css_ems(s.requested_duration) - 2 * session_layout_margin
|
s.layout_width = timedelta_to_css_ems(s.requested_duration) - 2 * session_layout_margin
|
||||||
s.parent_acronym = s.group.parent.acronym if s.group and s.group.parent else ""
|
s.parent_acronym = s.group.parent.acronym if s.group and s.group.parent else ""
|
||||||
s.historic_group_ad_name = ad_names.get(s.group_id)
|
s.historic_group_ad_name = ad_names.get(s.group_id)
|
||||||
|
|
||||||
|
@ -744,9 +745,8 @@ def edit_meeting_schedule(request, num=None, owner=None, name=None):
|
||||||
'schedule': schedule,
|
'schedule': schedule,
|
||||||
'can_edit': can_edit,
|
'can_edit': can_edit,
|
||||||
'js_data': json.dumps(js_data, indent=2),
|
'js_data': json.dumps(js_data, indent=2),
|
||||||
'time_labels': time_labels,
|
'days': days,
|
||||||
'rooms': rooms,
|
'room_labels': room_labels,
|
||||||
'room_columns': room_columns,
|
|
||||||
'unassigned_sessions': unassigned_sessions,
|
'unassigned_sessions': unassigned_sessions,
|
||||||
'session_parents': session_parents,
|
'session_parents': session_parents,
|
||||||
'hide_menu': True,
|
'hide_menu': True,
|
||||||
|
|
|
@ -974,7 +974,7 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
||||||
|
|
||||||
.fc-button {
|
.fc-button {
|
||||||
/* same as button-primary */
|
/* same as button-primary */
|
||||||
background-image: linear-gradient(rgb(107, 91, 173) 0px, rgb(80, 68, 135) 100%)
|
background-image: linear-gradient(rgb(107, 91, 173) 0px, rgb(80, 68, 135) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Edit Milestones============================================= */
|
/* === Edit Milestones============================================= */
|
||||||
|
@ -987,62 +987,77 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
||||||
/* === Edit Meeting Schedule ====================================== */
|
/* === Edit Meeting Schedule ====================================== */
|
||||||
|
|
||||||
.edit-meeting-schedule .edit-grid {
|
.edit-meeting-schedule .edit-grid {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .schedule-column .room-name {
|
.edit-meeting-schedule .edit-grid .room-label-column {
|
||||||
height: 2em;
|
/* make sure we cut this column off - the time slots will determine
|
||||||
font-weight: bold;
|
how much of it is shown */
|
||||||
text-align: center;
|
position: absolute;
|
||||||
margin: 0;
|
top: 0;
|
||||||
white-space: nowrap;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .schedule-column .day-label {
|
.edit-meeting-schedule .edit-grid .day {
|
||||||
height: 2.5em;
|
margin-right: 2.5em;
|
||||||
max-width: 5em; /* let it stick out and overlap the other columns */
|
|
||||||
white-space: nowrap;
|
|
||||||
font-style: italic;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .schedule-column > .day {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .schedule-column > .day > div {
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .edit-grid .day-flow .day-label {
|
||||||
|
border-bottom: 2px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .edit-grid .timeline {
|
||||||
|
position: relative;
|
||||||
|
height: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .edit-grid .timeline > div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .time-labels-column > div {
|
.edit-meeting-schedule .edit-grid .timeline.timeslots {
|
||||||
min-width: 5em;
|
height: 3.3em;
|
||||||
padding-right: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .time-labels-column .time-label.top-aligned {
|
.edit-meeting-schedule .edit-grid .timeline .time-label {
|
||||||
border-top: 1px solid #ccc;
|
font-size: smaller;
|
||||||
|
border-left: 2px solid #eee;
|
||||||
|
border-right: 2px solid #eee;
|
||||||
|
padding: 0 0.2em;
|
||||||
|
height: 1.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .time-labels-column .time-label.text-left span {
|
.edit-meeting-schedule .edit-grid .timeline .time-label.text-left {
|
||||||
background-color: #fff;
|
border-right: none;
|
||||||
padding-right: 0.2em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .time-labels-column .time-label.bottom-aligned {
|
.edit-meeting-schedule .edit-grid .timeline .time-label.text-right {
|
||||||
border-bottom: 1px solid #ccc;
|
border-left: none;
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .room-column {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .timeslot {
|
.edit-meeting-schedule .timeslot {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
width: 100%;
|
height: 100%;
|
||||||
border-left: 0.15em solid #fff;
|
border-bottom: 0.15em solid #fff;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,99 +1067,23 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .timeslot.overfull {
|
.edit-meeting-schedule .timeslot.overfull {
|
||||||
border-bottom: 2px dashed #fff; /* cut-off illusion */
|
border-right: 2px dashed #fff; /* cut-off illusion */
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule {
|
|
||||||
/* this is backwards-compatible measure - if the browser doesn't
|
|
||||||
support position: sticky but only position: fixed, we ensure there's room for the scheduling
|
|
||||||
panel */
|
|
||||||
padding-bottom: 5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .scheduling-panel {
|
|
||||||
position: fixed; /* backwards compatibility */
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
position: sticky;
|
|
||||||
display: flex;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
border-top: 0.2em solid #ccc;
|
|
||||||
background-color: #fff;
|
|
||||||
opacity: 0.95;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .scheduling-panel .unassigned-container {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .unassigned-sessions {
|
|
||||||
min-height: 4em;
|
|
||||||
max-height: 13em;
|
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
background-color: #eee;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .unassigned-sessions.dropping {
|
|
||||||
background-color: #e5e5e5;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .scheduling-panel .preferences {
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .scheduling-panel .preferences > span {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .sort-unassigned select {
|
|
||||||
width: auto;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .session-parent-toggles {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .session-parent-toggles label {
|
|
||||||
font-weight: normal;
|
|
||||||
margin-right: 1em;
|
|
||||||
padding: 0 1em;
|
|
||||||
border: 0.1em solid #eee;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .scheduling-panel .session-info-container {
|
|
||||||
padding-left: 0.5em;
|
|
||||||
flex: 0 0 20em;
|
|
||||||
max-height: 15em;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .scheduling-panel .session-info-container .comments {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sessions */
|
/* sessions */
|
||||||
.edit-meeting-schedule .session {
|
.edit-meeting-schedule .session {
|
||||||
display: flex;
|
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 0 0.2em;
|
|
||||||
padding-left: 0.5em;
|
|
||||||
margin: 0.2em;
|
margin: 0.2em;
|
||||||
|
padding-right: 0.2em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
line-height: 1.3em;
|
||||||
border-radius: 0.4em;
|
border-radius: 0.4em;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .session.selected {
|
.edit-meeting-schedule .session.selected {
|
||||||
border: 1px solid #bbb;
|
background-color: #fcfcfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .session.dragging {
|
.edit-meeting-schedule .session.dragging {
|
||||||
|
@ -1153,13 +1092,8 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .timeslot.overfull .session {
|
.edit-meeting-schedule .timeslot.overfull .session {
|
||||||
border-radius: 0.4em 0.4em 0 0; /* remove bottom rounding to illude to being cut off */
|
border-radius: 0.4em 0 0 0.4em; /* remove bottom rounding to illude to being cut off */
|
||||||
margin-bottom: 0;
|
margin-right: 0;
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .unassigned-sessions .session {
|
|
||||||
min-width: 6em;
|
|
||||||
margin-right: 0.3em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-meeting-schedule .session .session-label {
|
.edit-meeting-schedule .session .session-label {
|
||||||
|
@ -1208,12 +1142,75 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.edit-meeting-schedule .session .comments {
|
|
||||||
font-size: smaller;
|
|
||||||
margin-right: 0.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-meeting-schedule .session .session-info {
|
.edit-meeting-schedule .session .session-info {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* scheduling panel */
|
||||||
|
.edit-meeting-schedule .scheduling-panel {
|
||||||
|
position: sticky;
|
||||||
|
display: flex;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 0.2em solid #ccc;
|
||||||
|
background-color: #fff;
|
||||||
|
opacity: 0.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .scheduling-panel .unassigned-container {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .unassigned-sessions.dropping {
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .scheduling-panel .preferences {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .scheduling-panel .preferences > span {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .sort-unassigned select {
|
||||||
|
width: auto;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .session-parent-toggles {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .session-parent-toggles label {
|
||||||
|
font-weight: normal;
|
||||||
|
margin-right: 1em;
|
||||||
|
padding: 0 1em;
|
||||||
|
border: 0.1em solid #eee;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .scheduling-panel .session-info-container {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
flex: 0 0 20em;
|
||||||
|
max-height: 15em;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-meeting-schedule .scheduling-panel .session-info-container .comments {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ jQuery(document).ready(function () {
|
||||||
let sessions = content.find(".session");
|
let sessions = content.find(".session");
|
||||||
let timeslots = content.find(".timeslot");
|
let timeslots = content.find(".timeslot");
|
||||||
|
|
||||||
|
// 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") {
|
||||||
|
content.find(".scheduling-panel").css("position", "fixed");
|
||||||
|
content.css("padding-bottom", "14em");
|
||||||
|
}
|
||||||
|
|
||||||
// selecting
|
// selecting
|
||||||
function selectSessionElement(element) {
|
function selectSessionElement(element) {
|
||||||
if (element) {
|
if (element) {
|
||||||
|
@ -220,7 +226,7 @@ jQuery(document).ready(function () {
|
||||||
|
|
||||||
function updateAttendeesViolations() {
|
function updateAttendeesViolations() {
|
||||||
sessions.each(function () {
|
sessions.each(function () {
|
||||||
let roomCapacity = jQuery(this).closest(".room-column").data("roomcapacity");
|
let roomCapacity = jQuery(this).closest(".timeline").data("roomcapacity");
|
||||||
if (roomCapacity && this.dataset.attendees)
|
if (roomCapacity && this.dataset.attendees)
|
||||||
jQuery(this).toggleClass("too-many-attendees", +this.dataset.attendees > +roomCapacity);
|
jQuery(this).toggleClass("too-many-attendees", +this.dataset.attendees > +roomCapacity);
|
||||||
});
|
});
|
||||||
|
|
|
@ -48,43 +48,59 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="edit-grid">
|
<div class="edit-grid">
|
||||||
{# in order for all this to align properly vertically, we have the same structure in all columns #}
|
|
||||||
|
|
||||||
<div class="time-labels-column schedule-column">
|
{# using the same markup in both room labels and the actual days ensures they are aligned #}
|
||||||
<div class="room-name"></div>
|
<div class="room-label-column">
|
||||||
|
{% for labels in room_labels %}
|
||||||
|
<div class="day">
|
||||||
|
<div class="day-label">
|
||||||
|
<strong> </strong><br>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
{% for d in time_labels %}
|
<div class="timeline"></div>
|
||||||
<div class="day-label">{{ d.day|date:"l, F j, Y" }}</div>
|
|
||||||
|
|
||||||
<div class="day" style="height: {{ d.height }}em;">
|
{% for room in labels %}
|
||||||
{% for t, vertical_alignment, vertical_offset, horizontal_alignment in d.labels %}
|
<div class="timeline timeslots">
|
||||||
<div class="time-label {{ vertical_alignment }}-aligned text-{{ horizontal_alignment }}" style="{{ vertical_alignment }}: {{ vertical_offset }}em;">
|
<div class="room-name">
|
||||||
<span>{{ t|date:"H:i" }}</span>
|
<strong>{{ room.name }}</strong><br>
|
||||||
|
{% if room.capacity %}{{ room.capacity }} <i class="fa fa-user-o"></i>{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% for r in room_columns %}
|
<div class="day-flow">
|
||||||
<div class="room-column schedule-column" data-roomcapacity="{{ r.room.capacity }}">
|
{% for day in days %}
|
||||||
<div class="room-name">{{ r.room.name }}{% if r.room.capacity %} ({{ r.room.capacity }} <i class="fa fa-user-o"></i>{% endif %})</div>
|
<div class="day" style="width: {{ day.width }}em;">
|
||||||
|
<div class="day-label">
|
||||||
|
<strong>{{ day.day|date:"l" }}</strong><br>
|
||||||
|
{{ day.day|date:"N j, Y" }}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% for d in r.days %}
|
<div class="timeline">
|
||||||
<div class="day-label"></div> {# for spacing purposes #}
|
{% 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>
|
||||||
<div class="day" style="height: {{ d.height }}em;">
|
|
||||||
{% for t in d.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="top: {{ t.offset }}em; height: {{ t.height }}em;">
|
|
||||||
{% for assignment, session in t.timeslot.session_assignments %}
|
|
||||||
{% include "meeting/edit_meeting_schedule_session.html" %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
{% for room, timeslots in day.room_timeslots %}
|
||||||
{% endfor %}
|
<div class="timeline 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 %}
|
||||||
|
{% include "meeting/edit_meeting_schedule_session.html" %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="scheduling-panel">
|
<div class="scheduling-panel">
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
<div id="session{{ session.pk }}" class="session {% if not session.group.parent.scheduling_color %}untoggleable{% endif %} {% if session.parent_acronym %}parent-{{ session.parent_acronym }}{% endif %}" style="height:{{ session.layout_height }}em;" data-duration="{{ session.requested_duration.total_seconds }}" {% if session.attendees != None %}data-attendees="{{ session.attendees }}"{% endif %}>
|
<div id="session{{ session.pk }}" class="session {% if not session.group.parent.scheduling_color %}untoggleable{% endif %} {% if session.parent_acronym %}parent-{{ session.parent_acronym }}{% endif %}" style="width:{{ session.layout_width }}em;" data-duration="{{ session.requested_duration.total_seconds }}" {% if session.attendees != None %}data-attendees="{{ session.attendees }}"{% endif %}>
|
||||||
<div class="session-label">
|
<div class="session-label">
|
||||||
{{ session.scheduling_label }}
|
{{ session.scheduling_label }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if session.constrained_sessions %}
|
<div>
|
||||||
<div class="constraints">
|
{% if session.attendees != None %}
|
||||||
{% for explanation, sessions in session.constrained_sessions %}
|
<span class="attendees">{{ session.attendees }}</span>
|
||||||
<span data-sessions="{{ sessions|join:"," }}">{{ explanation }}</span>
|
{% endif %}
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if session.comments %}
|
{% if session.comments %}
|
||||||
<div class="comments"><i class="fa fa-comment-o"></i></div>
|
<span class="comments"><i class="fa fa-comment-o"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if session.attendees != None %}
|
|
||||||
<div class="attendees">{{ session.attendees }}</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
{% if session.constrained_sessions %}
|
||||||
|
<span class="constraints">
|
||||||
|
{% for explanation, sessions in session.constrained_sessions %}
|
||||||
|
<span data-sessions="{{ sessions|join:"," }}">{{ explanation }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# this is shown elsewhere on the page with JS - we just include it here for convenience #}
|
||||||
<div class="session-info">
|
<div class="session-info">
|
||||||
<label>
|
<label>
|
||||||
{{ session.scheduling_label }}
|
{{ session.scheduling_label }}
|
||||||
|
|
Loading…
Reference in a new issue