Skip to content

Commit 5cbe402

Browse files
Improvements to the timeslot and schedule editors (move new toggles to modals, handle overflowing session names, fix timeslot editor scrolling, add buttons to quickly create single timeslot, accept trailing slash on edit URL)
- Legacy-Id: 19449
1 parent 446ac7a commit 5cbe402

8 files changed

Lines changed: 184 additions & 75 deletions

File tree

ietf/meeting/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
url(r'^agendas/edit$', RedirectView.as_view(pattern_name='ietf.meeting.views.list_schedules', permanent=True)),
5555
url(r'^agendas/diff/$', views.diff_schedules),
5656
url(r'^agenda/new/$', views.new_meeting_schedule),
57-
url(r'^timeslots/edit$', views.edit_timeslots),
57+
url(r'^timeslots/edit/?$', views.edit_timeslots),
5858
url(r'^timeslot/new$', views.create_timeslot),
5959
url(r'^timeslot/(?P<slot_id>\d+)/edit$', views.edit_timeslot),
6060
url(r'^timeslot/(?P<slot_id>\d+)/edittype$', views.edit_timeslot_type),

ietf/static/ietf/css/ietf.css

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,9 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
12391239
.edit-meeting-schedule .session .session-label {
12401240
flex-grow: 1;
12411241
margin-left: 0.1em;
1242+
overflow: hidden;
1243+
text-overflow: ellipsis;
1244+
white-space: nowrap;
12421245
}
12431246

12441247
.edit-meeting-schedule .session .session-label .bof-tag {
@@ -1333,38 +1336,32 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
13331336

13341337
.edit-meeting-schedule .scheduling-panel .preferences {
13351338
margin: 0.5em 0;
1336-
display: flex;
1337-
align-items: flex-start;
1338-
}
1339-
1340-
.edit-meeting-schedule .scheduling-panel .preferences > div {
1341-
display: flex;
1342-
flex-direction: column;
1343-
align-items: flex-start;
13441339
}
13451340

1346-
.edit-meeting-schedule .scheduling-panel .preferences > div > span {
1341+
.edit-meeting-schedule .scheduling-panel .preferences > span {
13471342
margin-top: 0;
13481343
margin-right: 1em;
1349-
white-space: nowrap;
13501344
}
13511345

13521346
.edit-meeting-schedule .sort-unassigned select {
13531347
width: auto;
13541348
display: inline-block;
13551349
}
13561350

1357-
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body {
1351+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body > div {
1352+
margin-bottom: 1.5em;
1353+
}
1354+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body .individual-timeslots {
13581355
/*column-count: 3;*/
13591356
display: flex;
13601357
flex-flow: row wrap;
13611358
}
13621359

1363-
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body > * {
1360+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body .individual-timeslots > * {
13641361
margin-right: 1.5em;
13651362
}
13661363

1367-
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body label {
1364+
.edit-meeting-schedule #timeslot-group-toggles-modal .modal-body .individual-timeslots label {
13681365
display: block;
13691366
font-weight: normal;
13701367
}

ietf/static/ietf/js/edit-meeting-schedule.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -738,13 +738,13 @@ jQuery(document).ready(function () {
738738
timeslots.not(checked.join(",")).addClass('hidden-timeslot-type');
739739
}
740740
if (timeSlotTypeInputs.length > 0) {
741-
timeSlotTypeInputs.on("click", updateTimeSlotTypeToggling);
741+
timeSlotTypeInputs.on("change", updateTimeSlotTypeToggling);
742742
updateTimeSlotTypeToggling();
743743
}
744744

745745
// Toggling session purposes
746746
let sessionPurposeInputs = content.find('.session-purpose-toggles input');
747-
function updateSessionPurposeToggling() {
747+
function updateSessionPurposeToggling(evt) {
748748
let checked = [];
749749
sessionPurposeInputs.filter(":checked").each(function () {
750750
checked.push(".purpose-" + this.value);
@@ -754,12 +754,24 @@ jQuery(document).ready(function () {
754754
sessions.not(checked.join(",")).addClass('hidden-purpose');
755755
}
756756
if (sessionPurposeInputs.length > 0) {
757-
sessionPurposeInputs.on("click", updateSessionPurposeToggling);
757+
sessionPurposeInputs.on("change", updateSessionPurposeToggling);
758758
updateSessionPurposeToggling();
759+
content.find('#session-toggles-modal .select-all').get(0).addEventListener(
760+
'click',
761+
function() {
762+
sessionPurposeInputs.prop('checked', true);
763+
updateSessionPurposeToggling();
764+
});
765+
content.find('#session-toggles-modal .clear-all').get(0).addEventListener(
766+
'click',
767+
function() {
768+
sessionPurposeInputs.prop('checked', false);
769+
updateSessionPurposeToggling();
770+
});
759771
}
760772

761773
// toggling visible timeslots
762-
let timeslotGroupInputs = content.find("#timeslot-group-toggles-modal .modal-body input");
774+
let timeslotGroupInputs = content.find("#timeslot-group-toggles-modal .modal-body .individual-timeslots input");
763775
function updateTimeslotGroupToggling() {
764776
let checked = [];
765777
timeslotGroupInputs.filter(":checked").each(function () {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright The IETF Trust 2021, All Rights Reserved
2+
/* global URLSearchParams */
3+
(function() {
4+
'use strict';
5+
6+
function initialize() {
7+
const form = document.getElementById('timeslot-form');
8+
if (!form) {
9+
return;
10+
}
11+
12+
const params = new URLSearchParams(document.location.search);
13+
const day = params.get('day');
14+
const date = params.get('date');
15+
const location = params.get('location');
16+
const time = params.get('time');
17+
const duration = params.get('duration');
18+
19+
if (day) {
20+
const inp = form.querySelector('#id_days input[value="' + day +'"]');
21+
if (inp) {
22+
inp.checked = true;
23+
} else if (date) {
24+
const date_field = form.querySelector('#id_other_date');
25+
date_field.value = date;
26+
}
27+
}
28+
if (location) {
29+
const inp = form.querySelector('#id_locations input[value="' + location + '"]');
30+
inp.checked=true;
31+
}
32+
if (time) {
33+
const inp = form.querySelector('input#id_time');
34+
inp.value = time;
35+
}
36+
if (duration) {
37+
const inp = form.querySelector('input#id_duration');
38+
inp.value = duration;
39+
}
40+
}
41+
42+
window.addEventListener('load', initialize);
43+
})();

ietf/templates/meeting/create_timeslot.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{% extends "base.html" %}
22
{# Copyright The IETF Trust 2021, All Rights Reserved #}
3-
{% load origin %}
3+
{% load origin static %}
44
{% load bootstrap3 %}
55

66
{% block pagehead %}
@@ -12,7 +12,7 @@
1212
{% block content %}
1313
{% origin %}
1414
<h1>Create timeslot for {{meeting}}</h1>
15-
<form method="post">
15+
<form id="timeslot-form" method="post">
1616
{% csrf_token %}
1717
{% bootstrap_form form %}
1818
{% buttons %}
@@ -23,5 +23,6 @@ <h1>Create timeslot for {{meeting}}</h1>
2323
{% endblock %}
2424

2525
{% block js %}
26+
<script src="{% static 'ietf/js/meeting/create_timeslot.js' %}"></script>
2627
{{ form.media.js }}
2728
{% endblock %}

ietf/templates/meeting/edit_meeting_schedule.html

Lines changed: 63 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -175,74 +175,91 @@
175175
</div>
176176

177177
<div class="preferences">
178-
<div>
179-
<span class="sort-unassigned">
180-
Sort unassigned:
181-
<select name="sort_unassigned" class="form-control">
182-
<option value="name" selected="selected">By name</option>
183-
<option value="parent">By area</option>
184-
<option value="duration">By duration</option>
185-
<option value="comments">Special requests</option>
186-
</select>
187-
</span>
188-
189-
<span class="timeslot-group-toggles">
190-
<button class="btn btn-default" data-toggle="modal" data-target="#timeslot-group-toggles-modal"><input type="checkbox" checked="checked" disabled> Timeslots</button>
191-
</span>
192-
</div>
178+
<span class="sort-unassigned">
179+
Sort unassigned:
180+
<select name="sort_unassigned" class="form-control">
181+
<option value="name" selected="selected">By name</option>
182+
<option value="parent">By area</option>
183+
<option value="duration">By duration</option>
184+
<option value="comments">Special requests</option>
185+
</select>
186+
</span>
187+
188+
<span class="toggle-inputs session-parent-toggles">
189+
Show:
190+
{% for p in session_parents %}
191+
<label class="parent-{{ p.acronym }}"><input type="checkbox" checked value="{{ p.acronym }}"> {{ p.acronym }}</label>
192+
{% endfor %}
193+
</span>
193194

194-
<div>
195-
<span class="toggle-inputs session-parent-toggles">
196-
Show:
197-
{% for p in session_parents %}
198-
<label class="parent-{{ p.acronym }}"><input type="checkbox" checked value="{{ p.acronym }}"> {{ p.acronym }}</label>
199-
{% endfor %}
200-
</span>
195+
{% if session_purposes|length > 1 %}
196+
<button class="btn btn-default" data-toggle="modal" data-target="#session-toggles-modal"><input type="checkbox" checked="checked" disabled> Sessions</button>
197+
{% endif %}
198+
<button class="btn btn-default" data-toggle="modal" data-target="#timeslot-group-toggles-modal"><input type="checkbox" checked="checked" disabled> Timeslots</button>
199+
</div>
200+
</div>
201201

202-
{% if session_purposes|length > 1 %}
203-
<span class="toggle-inputs session-purpose-toggles">
204-
Purpose:
205-
{% for purpose in session_purposes %}
206-
<label class="purpose-{{ purpose.slug }}"><input type="checkbox" checked value="{{ purpose.slug }}"> {{ purpose }}</label>
207-
{% endfor %}
208-
</span>
209-
{% endif %}
202+
<div class="session-info-container"></div>
203+
</div>
210204

211-
{% if timeslot_types|length > 1 %}
212-
<span class="toggle-inputs timeslot-type-toggles">
205+
<div id="timeslot-group-toggles-modal" class="modal" role="dialog" aria-labelledby="timeslot-group-toggles-modal-title">
206+
<div class="modal-dialog modal-lg" role="document">
207+
<div class="modal-content">
208+
<div class="modal-header">
209+
<button type="button" class="close" data-dismiss="modal">
210+
<span aria-hidden="true">&times;</span>
211+
<span class="sr-only">Close</span>
212+
</button>
213+
<h4 class="modal-title" id="timeslot-group-toggles-modal-title">Displayed timeslots</h4>
214+
</div>
215+
216+
<div class="modal-body">
217+
<div class="individual-timeslots">
218+
{% for day, t_groups in timeslot_groups %}
219+
<div>
220+
<div><strong>{{ day|date:"M. d" }}</strong></div>
221+
{% for start, end, key in t_groups %}
222+
<label><input type="checkbox" name="timeslot-group" value="{{ key }}" checked="checked"> {{ start|date:"H:i" }} - {{ end|date:"H:i" }}</label>
223+
{% endfor %}
224+
</div>
225+
{% endfor %}
226+
</div>
227+
<div class="timeslots-by-type timeslot-type-toggles">
213228
Type:
214229
{% for type in timeslot_types %}
215230
<label class="timeslot-type-{{ type.slug }}"><input type="checkbox" checked value="{{ type.slug }}"> {{ type }}</label>
216231
{% endfor %}
217-
</span>
218-
{% endif %}
232+
</div>
233+
</div>
234+
235+
<div class="modal-footer">
236+
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
219237
</div>
220238
</div>
221239
</div>
222-
223-
<div class="session-info-container"></div>
224240
</div>
225241

226-
<div id="timeslot-group-toggles-modal" class="modal" role="dialog" aria-labelledby="timeslot-group-toggles-modal-title">
242+
<div id="session-toggles-modal" class="modal" role="dialog" aria-labelledby="session-toggles-modal-title">
227243
<div class="modal-dialog modal-lg" role="document">
228244
<div class="modal-content">
229245
<div class="modal-header">
230246
<button type="button" class="close" data-dismiss="modal">
231247
<span aria-hidden="true">&times;</span>
232248
<span class="sr-only">Close</span>
233249
</button>
234-
<h4 class="modal-title" id="timeslot-group-toggles-modal-title">Displayed timeslots</h4>
250+
<h4 class="modal-title" id="session-toggles-modal-title">Displayed sessions</h4>
235251
</div>
236252

237253
<div class="modal-body">
238-
{% for day, t_groups in timeslot_groups %}
239-
<div>
240-
<div><strong>{{ day|date:"M. d" }}</strong></div>
241-
{% for start, end, key in t_groups %}
242-
<label><input type="checkbox" name="timeslot-group" value="{{ key }}" checked="checked"> {{ start|date:"H:i" }} - {{ end|date:"H:i" }}</label>
243-
{% endfor %}
244-
</div>
245-
{% endfor %}
254+
<div class="session-purpose-toggles">
255+
{% for purpose in session_purposes %}
256+
<div>
257+
<label class="purpose-{{ purpose.slug }}"><input type="checkbox" checked value="{{ purpose.slug }}"> {{ purpose }}</label>
258+
</div>
259+
{% endfor %}
260+
<button type="button" class="btn btn-default select-all">Select all</button>
261+
<button type="button" class="btn btn-default clear-all">Clear all</button>
262+
</div>
246263
</div>
247264

248265
<div class="modal-footer">

ietf/templates/meeting/timeslot_edit.html

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
{% extends "base.html" %}
22
{# Copyright The IETF Trust 2015, All Rights Reserved #}
33
{% load origin %}
4-
{% load agenda_custom_tags %}
4+
{% load agenda_custom_tags misc_filters %}
55

66
{% block title %}IETF {{ meeting.number }} Meeting Agenda: Timeslots and Room Availability{% endblock %}
77

88
{% block morecss %}
9-
.tstable { width: 100%;}
9+
{% comment %}
10+
Put scrollbars on the editor table. Requires fixed height so the scroll bars appear on the div, not the page body.
11+
Note that 100vh is viewport height. Using that minus 25rem seems to leave space for the page header/footer.
12+
{% endcomment %}
13+
.timeslot-edit { overflow: auto; height: max(30rem, calc(100vh - 25rem));}
14+
.tstable { width: 100%; border-collapse: separate; } {# "separate" to ensure sticky cells keep their borders #}
15+
.tstable thead { position: sticky; top: 0; z-index: 2; background-color: white;}
16+
.tstable th:first-child, .tstable td:first-child {
17+
background-color: white; {# needs to match the lighter of the striped-table colors! #}
18+
position: sticky;
19+
left: 0;
20+
z-index: 1.5; {# render above other cells / borders but below thead (z-index 2, above) #}
21+
}
22+
.tstable tbody > tr:nth-of-type(odd) > th:first-child {
23+
background-color: rgb(249, 249, 249); {# needs to match the darker of the striped-table colors! #}
24+
}
25+
1026
.tstable th { white-space: nowrap;}
1127
.tstable td { white-space: nowrap;}
1228
.capacity { font-size:80%; font-weight: normal;}
29+
30+
a.new-timeslot-link { color: lightgray; font-size: large;}
1331
{% endblock %}
1432

1533
{% block content %}
@@ -90,15 +108,21 @@
90108
<a href="{% url "ietf.meeting.views.create_timeslot" num=meeting.number %}">Create a timeslot.</a>
91109
</td>
92110
{% else %}
93-
{% for day in time_slices %}
94-
{% for slice in date_slices|lookup:day %}{% with cell_ts=ts_list.popleft %}
111+
{% for day in time_slices %}{% with slots=slot_slices|lookup:day %}
112+
{% for slice in date_slices|lookup:day %}{% with cell_ts=ts_list.popleft slot=slots|index:forloop.counter0 %}
95113
<td class="tscell {% if cell_ts|length > 1 %}timeslot-collision {% endif %}{% for ts in cell_ts %}tstype_{{ ts.type.slug }} {% endfor %}">
96-
{% for ts in cell_ts %}
97-
{% include 'meeting/timeslot_edit_timeslot.html' with ts=ts in_use=ts_with_any_assignments in_official_use=ts_with_official_assignments only %}
98-
{% endfor %}
114+
{% if cell_ts %}
115+
{% for ts in cell_ts %}
116+
{% include 'meeting/timeslot_edit_timeslot.html' with ts=ts in_use=ts_with_any_assignments in_official_use=ts_with_official_assignments only %}
117+
{% endfor %}
118+
{% endif %}
119+
<a class="new-timeslot-link {% if cell_ts %}hidden{% endif %}"
120+
href="{% url "ietf.meeting.views.create_timeslot" num=meeting.number %}?day={{ day.toordinal }}&date={{ day|date:"Y-m-d" }}&location={{ room.pk }}&time={{ slot.time|date:'H:i' }}&duration={{ slot.duration }}">
121+
<span class="fa fa-plus-square"></span>
122+
</a>
99123
{% endwith %}{% endfor %}
100124
</td>
101-
{% endfor %}
125+
{% endwith %}{% endfor %}
102126
{% endif %}
103127
</tr>
104128
{% endfor %}
@@ -378,7 +402,12 @@ <h4 class="modal-title">Confirm Delete</h4>
378402
.error(function(jqXHR, textStatus) {
379403
displayError('Error deleting timeslot: ' + jqXHR.responseText)
380404
})
381-
.done(function () {timeslotElts.forEach(tse => tse.parentNode.removeChild(tse))})
405+
.done(function () {timeslotElts.forEach(
406+
tse => {
407+
tse.closest('td.tscell').querySelector('.new-timeslot-link').classList.remove('hidden');
408+
tse.parentNode.removeChild(tse);
409+
}
410+
)})
382411
.always(function () {deleteModal.modal('hide')});
383412
}
384413

0 commit comments

Comments
 (0)