diff --git a/ietf/meeting/tests_js.py b/ietf/meeting/tests_js.py index c66beace9..60384b6aa 100644 --- a/ietf/meeting/tests_js.py +++ b/ietf/meeting/tests_js.py @@ -285,10 +285,6 @@ class SlideReorderTests(MeetingTestCase): @skipIf(skip_selenium, skip_message) class AgendaTests(MeetingTestCase): - # Groups whose display logic is inverted in agenda.html. These have - # toggles with class 'pickviewneg' in the template. - PICKVIEWNEG = ['iepg', 'tools', 'edu', 'ietf', 'iesg', 'iab'] - def setUp(self): super(AgendaTests, self).setUp() self.meeting = make_meeting_test_data() @@ -377,40 +373,75 @@ class AgendaTests(MeetingTestCase): self.assertEqual(result[4], ['item1', 'item3'], 'Removing middle item from list failed') self.assertEqual(result[5], ['item1', 'item2'], 'Removing last item from list failed') + def do_agenda_view_filter_test(self, querystring, visible_groups=()): + self.login() + self.driver.get(self.absreverse('ietf.meeting.views.agenda') + querystring) + self.assert_agenda_item_visibility(visible_groups) + weekview_iframe = self.driver.find_element_by_id('weekview') + if len(querystring) == 0: + self.assertFalse(weekview_iframe.is_displayed(), 'Weekview should be hidden when filters off') + else: + self.assertTrue(weekview_iframe.is_displayed(), 'Weekview should be visible when filters on') + self.driver.switch_to.frame(weekview_iframe) + self.assert_weekview_item_visibility(visible_groups) + self.driver.switch_to.default_content() + def test_agenda_view_filter_show_one(self): """Filtered agenda view should display only matching rows (one group selected)""" - self.login() - self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?show=mars') - self.assert_agenda_item_visibility(['mars'] + self.PICKVIEWNEG) # ames and secretariat not selected + self.do_agenda_view_filter_test('?show=mars', ['mars']) def test_agenda_view_filter_show_two(self): """Filtered agenda view should display only matching rows (two groups selected)""" - self.login() - self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?show=mars,ames') - self.assert_agenda_item_visibility(['mars', 'ames'] + self.PICKVIEWNEG) # secretariat not selected + self.do_agenda_view_filter_test('?show=mars,ames', ['mars', 'ames']) def test_agenda_view_filter_all(self): """Filtered agenda view should display only matching rows (all groups selected)""" - self.login() - self.driver.get(self.absreverse('ietf.meeting.views.agenda')) - self.assert_agenda_item_visibility() + self.do_agenda_view_filter_test('', None) # None means all should be visible def test_agenda_view_filter_hide(self): - self.login() - self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?hide=ietf') - self.assert_agenda_item_visibility([g for g in self.PICKVIEWNEG if g != 'ietf']) + self.do_agenda_view_filter_test('?hide=ietf', []) def test_agenda_view_filter_show_and_hide(self): - self.login() - self.driver.get(self.absreverse('ietf.meeting.views.agenda') + '?show=mars&hide=ietf') - self.assert_agenda_item_visibility( - ['mars'] + [g for g in self.PICKVIEWNEG if g != 'ietf'] - ) + self.do_agenda_view_filter_test('?show=mars&hide=ietf', ['mars']) - def assert_agenda_item_visibility(self, visible_groups=()): + def test_agenda_view_filter_show_and_hide_same_group(self): + self.do_agenda_view_filter_test('?show=mars&hide=mars', []) + + def test_agenda_view_filter_showtypes(self): + self.do_agenda_view_filter_test('?showtypes=plenary', ['ietf']) # ietf has a plenary session + + def test_agenda_view_filter_hidetypes(self): + self.do_agenda_view_filter_test('?hidetypes=plenary', []) + + def test_agenda_view_filter_showtypes_and_hidetypes(self): + self.do_agenda_view_filter_test('?showtypes=plenary&hidetypes=regular', ['ietf']) # ietf has a plenary session + + def test_agenda_view_filter_showtypes_and_hidetypes_same_type(self): + self.do_agenda_view_filter_test('?showtypes=plenary&hidetypes=plenary', []) + + def test_agenda_view_filter_show_and_showtypes(self): + self.do_agenda_view_filter_test('?show=mars&showtypes=plenary', ['mars', 'ietf']) # ietf has a plenary session + + def test_agenda_view_filter_show_and_hidetypes(self): + self.do_agenda_view_filter_test('?show=ietf,mars&hidetypes=plenary', ['mars']) # ietf has a plenary session + + def test_agenda_view_filter_hide_and_hidetypes(self): + self.do_agenda_view_filter_test('?hide=ietf,mars&hidetypes=plenary', []) + + def test_agenda_view_filter_show_hide_and_showtypes(self): + self.do_agenda_view_filter_test('?show=mars&hide=ames&showtypes=plenary,regular', ['mars', 'ietf']) # ietf has plenary session + + def test_agenda_view_filter_show_hide_and_hidetypes(self): + self.do_agenda_view_filter_test('?show=mars,ietf&hide=ames&hidetypes=plenary', ['mars']) # ietf has plenary session + + def test_agenda_view_filter_all_params(self): + self.do_agenda_view_filter_test('?show=secretariat,ietf&hide=ames&showtypes=regular&hidetypes=plenary', + ['secretariat', 'mars']) + + def assert_agenda_item_visibility(self, visible_groups=None): """Assert that correct items are visible in current browser window - If visible_groups is empty (the default), expects all items to be visible. + If visible_groups is None (the default), expects all items to be visible. """ for item in self.get_expected_items(): row_id = self.row_id_for_item(item) @@ -419,11 +450,33 @@ class AgendaTests(MeetingTestCase): except NoSuchElementException: item_row = None self.assertIsNotNone(item_row, 'No row for schedule item "%s"' % row_id) - if len(visible_groups) == 0 or item.session.group.acronym in visible_groups: + if visible_groups is None or item.session.group.acronym in visible_groups: self.assertTrue(item_row.is_displayed(), 'Row for schedule item "%s" is not displayed but should be' % row_id) else: self.assertFalse(item_row.is_displayed(), 'Row for schedule item "%s" is displayed but should not be' % row_id) + def assert_weekview_item_visibility(self, visible_groups=None): + for item in self.get_expected_items(): + if item.session.name: + label = item.session.name + elif item.timeslot.type_id == 'break': + label = item.timeslot.name + elif item.session.group: + label = item.session.group.name + else: + label = 'Free Slot' + + try: + item_div = self.driver.find_element_by_xpath('//div/span[contains(text(),"%s")]/..' % label) + except NoSuchElementException: + item_div = None + + if visible_groups is None or item.session.group.acronym in visible_groups: + self.assertIsNotNone(item_div, 'No weekview entry for "%s" (%s)' % (label, item.slug())) + self.assertTrue(item_div.is_displayed(), 'Entry for "%s (%s)" is not displayed but should be' % (label, item.slug())) + else: + self.assertIsNone(item_div, 'Unexpected weekview entry for "%s" (%s)' % (label, item.slug())) + def test_agenda_view_group_filter_toggle(self): """Clicking a group toggle enables/disables agenda filtering""" group_acronym = 'mars' @@ -449,7 +502,7 @@ class AgendaTests(MeetingTestCase): group_button.click() # Check visibility - self.assert_agenda_item_visibility([group_acronym] + self.PICKVIEWNEG) + self.assert_agenda_item_visibility([group_acronym]) # Click the group button again group_button = WebDriverWait(self.driver, 2).until( diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 31ed45ed3..78a6e4436 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -801,7 +801,7 @@ class MeetingTests(TestCase): # ames regular session should be suppressed self.do_ical_filter_test( meeting, - querystring='?show=mars&hide=ames&showtypes=plenary,regular', + querystring='?show=ietf&hide=ames&showtypes=regular', expected_session_summaries=[ 'IETF Plenary', 'mars - Martian Special Interest Group', diff --git a/ietf/templates/meeting/agenda.html b/ietf/templates/meeting/agenda.html index 4f753ce5b..91b077bec 100644 --- a/ietf/templates/meeting/agenda.html +++ b/ietf/templates/meeting/agenda.html @@ -120,12 +120,12 @@ {% endif %}

Also show special sessions of these groups:

-
-
-
-
-
-
+
+
+
+
+
+
@@ -362,10 +362,13 @@ function parse_query_params(qs) { var params = {}; qs = qs.replace(/^\?/, ''); - $.each(qs.split('&'), function(i, v) { - var toks = v.split('=', 2) - params[toks[0]] = toks[1].toLowerCase(); - }); + if (qs) { + var param_strs = qs.split('&'); + for (var ii = 0; ii < param_strs.length; ii++) { + var toks = param_strs[ii].split('=', 2) + params[toks[0]] = toks[1] || true; + } + } return params; } @@ -374,43 +377,56 @@ return qparams[filt] ? qparams[filt].split(',') : []; } - function toggle_visibility() { - var qparams = parse_query_params(window.location.search); - var show_groups = get_filter_from_qparams(qparams, 'show'); - var hide_groups = get_filter_from_qparams(qparams, 'hide'); + function get_filter_params(qparams) { + return { + show_groups: get_filter_from_qparams(qparams, 'show'), + hide_groups: get_filter_from_qparams(qparams, 'hide'), + show_types: get_filter_from_qparams(qparams, 'showtypes'), + hide_types: get_filter_from_qparams(qparams, 'hidetypes'), + }; + } + function toggle_visibility(filter_params) { // reset UI elements to default state $(".pickview").removeClass("active disabled"); $(".pickviewneg").addClass("active"); - if (show_groups.length || hide_groups.length) { - // if groups were selected for filtering, hide all rows that are - // hidden by default, show all rows that are shown by default + if (filter_params['show_groups'].length || + filter_params['hide_groups'].length || + filter_params['show_types'].length || + filter_params['hide_types'].length + ) { + // if groups were selected for filtering, hide all rows by default $('[id^="row-"]').hide(); - $.each($(".pickviewneg").text().trim().split(/ +/), function (i, v) { - v = v.trim().toLowerCase(); - $('[id^="row-"]').filter('[id*="-' + v + '"]').show(); - }); // show the customizer $("#customize").collapse("show"); // loop through the has items and change the UI element and row visibilities accordingly - $.each(hide_groups, function (i, v) { - // this is a "negative" item: when present, hide these rows - $('[id^="row-"]').filter('[id*="-' + v + '"]').hide(); - $(".view." + v).find("button").removeClass("active disabled"); - $("button.pickviewneg." + v).removeClass("active"); - }); - $.each(show_groups, function (i, v) { - // this is a regular item: when present, show these rows + $.each(filter_params['show_groups'], function (i, v) { + // this is a regular item by wg: when present, show these rows $('[id^="row-"]').filter('[id*="-' + v + '"]').show(); $(".view." + v).find("button").addClass("active disabled"); $("button.pickview." + v).addClass("active"); }); + $.each(filter_params['show_types'], function (i, v) { + // this is a regular item by type: when present, show these rows + $('[id^="row-"]').filter('[timeslot-type*="' + v + '"]').show(); + }); + $.each(filter_params['hide_groups'], function (i, v) { + // this is a "negative" item by wg: when present, hide these rows + $('[id^="row-"]').filter('[id*="-' + v + '"]').hide(); + $(".view." + v).find("button").removeClass("active disabled"); + $("button.pickviewneg." + v).removeClass("active"); + }); + $.each(filter_params['hide_types'], function (i, v) { + // this is a "negative" item by type: when present, hide these rows + $('[id^="row-"]').filter('[timeslot-type*="' + v + '"]').hide(); + }); // show the week view - $("#weekview").attr("src", "week-view.html" + window.location.search).removeClass("hidden"); + update_weekview(); + $("#weekview").removeClass("hidden"); // show the custom .ics link $("#ical-link").attr("href",$("#ical-link").attr("href").split("?")[0]+window.location.search); @@ -426,16 +442,14 @@ $(".pickview, .pickviewneg").click(function () { // Get clicked item label var item = $(this).text().trim().toLowerCase(); - var qparams = parse_query_params(window.location.search); - var show_groups = get_filter_from_qparams(qparams, 'show'); - var hide_groups = get_filter_from_qparams(qparams, 'hide'); + var fp = get_filter_params(parse_query_params(window.location.search)); if ($(this).hasClass("pickviewneg")) { - toggle_list_item(hide_groups, item); + toggle_list_item(fp['hide_groups'], item); } else { - toggle_list_item(show_groups, item); + toggle_list_item(fp['show_groups'], item); } - update_filters(show_groups, hide_groups); + update_filters(fp); }); /* Add to list if not present, remove if present */ @@ -448,14 +462,20 @@ } } - function update_filters(show, hide) { + function update_filters(filter_params) { var qparams = []; var search = ''; - if (show.length > 0) { - qparams.push('show=' + show.join()); + if (filter_params['show_groups'].length > 0) { + qparams.push('show=' + filter_params['show_groups'].join()); } - if (hide.length > 0) { - qparams.push('hide=' + hide.join()); + if (filter_params['hide_groups'].length > 0) { + qparams.push('hide=' + filter_params['hide_groups'].join()); + } + if (filter_params['show_types'].length > 0) { + qparams.push('showtypes=' + filter_params['show_types'].join()); + } + if (filter_params['hide_types'].length > 0) { + qparams.push('hidetypes=' + filter_params['hide_types'].join()); } if (qparams.length > 0) { search = '?' + qparams.join('&'); @@ -466,15 +486,32 @@ if (window.history && window.history.replaceState) { // Keep current origin, replace search string, no page reload history.replaceState({}, document.title, new_url); - toggle_visibility(); + toggle_visibility(filter_params); } else { // No window.history.replaceState support, page reload required window.location = new_url; } } + function update_weekview() { + var wv_iframe = document.getElementById('weekview'); + var wv_window = wv_iframe.contentWindow; + var new_url = 'week-view.html' + window.location.search; + if (wv_iframe.src && wv_window.history && wv_window.history.replaceState) { + wv_window.history.replaceState({}, '', new_url); + wv_window.draw_calendar() + } else { + // ho history.replaceState, page reload required + wv_iframe.src = new_url; + } + } + $(document).ready(function () { - toggle_visibility(); + toggle_visibility( + get_filter_params( + parse_query_params(window.location.search) + ) + ); }); $(".modal").on("show.bs.modal", function () { diff --git a/ietf/templates/meeting/week-view.html b/ietf/templates/meeting/week-view.html index e73d18f5c..e97da16f2 100644 --- a/ietf/templates/meeting/week-view.html +++ b/ietf/templates/meeting/week-view.html @@ -107,33 +107,60 @@ } } + //=========================================================================== - function is_visible(include) { + function parse_query_params(qs) { + var params = {}; + qs = qs.replace(/^\?/, '').toLowerCase(); + if (qs) { + var param_strs = qs.split('&'); + for (var ii = 0; ii < param_strs.length; ii++) { + var toks = param_strs[ii].split('=', 2) + params[toks[0]] = toks[1] || true; + } + } + return params; + } + + //=========================================================================== + + function get_filter_from_qparams(qparams, filt) { + return qparams[filt] ? qparams[filt].split(',') : []; + } + + function get_filter_params(qparams) { + return { + show_groups: get_filter_from_qparams(qparams, 'show'), + hide_groups: get_filter_from_qparams(qparams, 'hide'), + show_types: get_filter_from_qparams(qparams, 'showtypes'), + hide_types: get_filter_from_qparams(qparams, 'hidetypes'), + }; + } + //=========================================================================== + + function is_visible(query_params) { + // Returns a method to filter objects for visibility + // Accepts show, hide, showtypes, and hidetypes filters. Also accepts + // '@' to show sessions in a particular state (e.g., @bof). + // Current types are: + // Session, Other, Break, Plenary + var fp = get_filter_params(query_params); + return function (item) { - // "-wgname" will remove a working group from the output. - // "~Type" will add that type to the output. - // "-~Type" will remove that type from the output - // "@bof" will include all BOFs - // Current types are: - // Session, Other, Break, Plenary + var item_group = (item.group || '').toLowerCase(); + var item_type = (item.type || '').toLowerCase(); + var item_area = (item.area || '').toLowerCase(); + var item_state = (item.state || '').toLowerCase(); - if ("group" in item) { - if (include[(item.group).toLowerCase()]) { return true; } - if (include["-"+(item.group).toLowerCase()]) { return false; } + if ((fp['hide_groups'].indexOf(item_group) >= 0) || + (fp['hide_types'].indexOf(item_type) >= 0)) { + return false; } - if ("state" in item) { - if (include["@"+(item.state).toLowerCase()]) { return true; } - } - if (include["~"+(item.type).toLowerCase()]) { return true; } - if (include["-~"+(item.type).toLowerCase()]) { return false; } - if ("area" in item) { - if (include[(item.area).toLowerCase()]) { return true; } - } - if (item.type === "Plenary") { return true; } - if (item.type === "Other") { return true; } - - return false; + return ((fp['show_groups'].indexOf(item_group) >= 0) || + (fp['show_groups'].indexOf(item_area) >= 0) || + (fp['show_types'].indexOf(item_type) >= 0) || + query_params['@'+item_state]); } } @@ -143,16 +170,23 @@ var width = document.body.clientWidth; var height = document.body.clientHeight; - var include = {}; - window.location.hash.replace("#",'').split(',').forEach(function(key){ - include[(key + "").toLowerCase()] = true; - }); + var visible_items = all_items; + var qs = window.location.search; + if (qs.length > 1) { + visible_items = visible_items.filter(is_visible(parse_query_params(qs))); + } - var visible_items = all_items.filter(is_visible(include)); - - var start_day = visible_items[0].day; + var start_day; + var day_start; + if (visible_items.length > 0) { + start_day = visible_items[0].day; + day_start = visible_items[0].start_time; + } else { + // fallback in case all items were filtered + start_day = all_items[0].day; + day_start = all_items[0].start_time; + } var end_day = start_day; - var day_start = visible_items[0].start_time; var day_end = 0; compute_swimlanes(visible_items); @@ -324,6 +358,11 @@ document.body.appendChild(e); }); + + // Div to indicate rendering has occurred, for testing purposes. + var elt = document.createElement('div'); + elt.id = 'wv-end'; + document.body.appendChild(elt); } //===========================================================================