From 45df4f6dfd6e2779548a62adb6e67e9389055d0c Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 7 Apr 2022 15:13:43 -0300 Subject: [PATCH] fix: restore current session indicator/link on the agenda page (#3790) --- ietf/static/css/ietf.scss | 13 +- ietf/static/js/agenda_timezone.js | 533 +++++++++++++++-------------- ietf/static/js/ietf.js | 50 +-- ietf/templates/meeting/agenda.html | 15 +- 4 files changed, 326 insertions(+), 285 deletions(-) diff --git a/ietf/static/css/ietf.scss b/ietf/static/css/ietf.scss index e2378b813..9d822bcec 100644 --- a/ietf/static/css/ietf.scss +++ b/ietf/static/css/ietf.scss @@ -943,12 +943,8 @@ td.position-empty { padding-left: 0px !important; } -.ongoing>td:first-child { - background-color: red !important; -} - -.ongoing>td:last-child { - background-color: red !important; +#agenda-table tbody tr.current-session { + border-top: map.get($border-widths, 2) solid map.get($theme-colors, "info"); } .timetooltip { @@ -996,4 +992,9 @@ td.position-empty { #current-time { display: inline-block; +} + +// righthand nav panel styling +#righthand-nav { + width: inherit; } \ No newline at end of file diff --git a/ietf/static/js/agenda_timezone.js b/ietf/static/js/agenda_timezone.js index 455c4782f..05026b6fe 100644 --- a/ietf/static/js/agenda_timezone.js +++ b/ietf/static/js/agenda_timezone.js @@ -1,5 +1,4 @@ // Copyright The IETF Trust 2021, All Rights Reserved - /* Timezone support specific to the agenda page @@ -8,272 +7,300 @@ returning the current timezone to the set_current_tz_cb() method. This should be done before calling anything else in the file. */ +(function() { + 'use strict'; -var local_timezone = moment.tz.guess(); + const local_timezone = moment.tz.guess(); -// get_current_tz_cb must be overwritten using set_current_tz_cb -function get_current_tz_cb() { - throw new Error('Tried to get current timezone before callback registered. Use set_current_tz_cb().'); -} + // get_current_tz_cb must be overwritten using set_current_tz_cb + let get_current_tz_cb = function() { + throw new Error('Tried to get current timezone before callback registered. Use set_current_tz_cb().'); + }; -// Initialize moments -window.initialize_moments = function () { - var times = $('.time'); - $.each(times, function (i, item) { - item.start_ts = moment.unix(this.getAttribute("data-start-time")) - .utc(); - item.end_ts = moment.unix(this.getAttribute("data-end-time")) - .utc(); - if (this.hasAttribute("weekday")) { - item.format = 2; - } else { - item.format = 1; - } - if (this.hasAttribute("format")) { - item.format = +this.getAttribute("format"); - } - }); - times = $('[data-slot-start-ts]'); - $.each(times, function (i, item) { - item.slot_start_ts = moment.unix(this.getAttribute("data-slot-start-ts")) - .utc(); - item.slot_end_ts = moment.unix(this.getAttribute("data-slot-end-ts")) - .utc(); - }); -}; - -function format_time(t, tz, fmt) { - var out; - var mtz = window.meeting_timezone; - if (mtz == "") { - mtz = "UTC"; - } - switch (fmt) { - case 0: - out = t.tz(tz) - .format('dddd, ') + '' + - t.tz(tz) - .format('MMMM Do YYYY, ') + '' + - t.tz(tz) - .format('HH:mm') + '' + - t.tz(tz) - .format(' Z z') + ''; - break; - case 1: - // Note, this code does not work if the meeting crosses the - // year boundary. - out = t.tz(tz) - .format("HH:mm"); - if (+t.tz(tz) - .dayOfYear() < +t.tz(mtz) - .dayOfYear()) { - out = out + " (-1)"; - } else if (+t.tz(tz) - .dayOfYear() > +t.tz(mtz) - .dayOfYear()) { - out = out + " (+1)"; - } - break; - case 2: - out = t.tz(mtz) - .format("dddd, ") - .toUpperCase() + - t.tz(tz) - .format("HH:mm"); - if (+t.tz(tz) - .dayOfYear() < +t.tz(mtz) - .dayOfYear()) { - out = out + " (-1)"; - } else if (+t.tz(tz) - .dayOfYear() > +t.tz(mtz) - .dayOfYear()) { - out = out + " (+1)"; - } - break; - case 3: - out = t.utc() - .format("YYYY-MM-DD"); - break; - case 4: - out = t.tz(tz) - .format("YYYY-MM-DD HH:mm"); - break; - case 5: - out = t.tz(tz) - .format("HH:mm"); - break; - } - return out; -} - -// Format tooltip notice -function format_tooltip_notice(start, end) { - var notice = ""; - - if (end.isBefore()) { - notice = "Event ended " + end.fromNow(); - } else if (start.isAfter()) { - notice = "Event will start " + start.fromNow(); - } else { - notice = "Event started " + start.fromNow() + " and will end " + - end.fromNow(); - } - return '' + notice + ''; -} - -// Format tooltip table -function format_tooltip_table(start, end) { - var current_timezone = get_current_tz_cb(); - var out = '
'; - if (window.meeting_timezone !== "") { - out += ''; - } - out += ''; - if (current_timezone !== 'UTC') { - out += ''; - } - out += ''; - out += '
Session startSession end
Meeting timezone' + - format_time(start, window.meeting_timezone, 0) + '' + - format_time(end, window.meeting_timezone, 0) + '
Local timezone' + - format_time(start, local_timezone, 0) + '' + - format_time(end, local_timezone, 0) + '
Selected Timezone' + - format_time(start, current_timezone, 0) + '' + - format_time(end, current_timezone, 0) + '
UTC' + - format_time(start, 'UTC', 0) + '' + - format_time(end, 'UTC', 0) + '
' + format_tooltip_notice(start, end) + '
'; - return out; -} - -// Format tooltip for item -function format_tooltip(start, end) { - return '
' + - format_tooltip_table(start, end) + - '
'; -} - -// Add tooltips -window.add_tooltips = function () { - $('.time') - .each(function () { - var tooltip = $(format_tooltip(this.start_ts, this.end_ts)); - tooltip[0].start_ts = this.start_ts; - tooltip[0].end_ts = this.end_ts; - tooltip[0].ustart_ts = moment(this.start_ts) - .add(-2, 'hours'); - tooltip[0].uend_ts = moment(this.end_ts) - .add(2, 'hours'); - $(this) - .closest("th, td") - .attr("data-bs-toggle", "popover") - .attr("data-bs-content", $(tooltip) - .html()) - .popover({ - html: true, - sanitize: false, - trigger: "hover" - }); - }); -}; - -// Update times on the agenda based on the selected timezone -window.update_times = function (newtz) { - $('.current-tz') - .html(newtz); - $('.time') - .each(function () { - if (this.format == 4) { - var tz = this.start_ts.tz(newtz) - .format(" z"); - if (this.start_ts.tz(newtz) - .dayOfYear() == - this.end_ts.tz(newtz) - .dayOfYear()) { - $(this) - .html(format_time(this.start_ts, newtz, this.format) + - '
-' + format_time(this.end_ts, newtz, 5) + tz); - } else { - $(this) - .html(format_time(this.start_ts, newtz, this.format) + - '
-' + - format_time(this.end_ts, newtz, this.format) + tz); - } + // Initialize moments + function initialize_moments() { + const times = $('.time'); + $.each(times, function (i, item) { + item.start_ts = moment.unix(this.getAttribute("data-start-time")) + .utc(); + item.end_ts = moment.unix(this.getAttribute("data-end-time")) + .utc(); + if (this.hasAttribute("weekday")) { + item.format = 2; } else { - $(this) - .html(format_time(this.start_ts, newtz, this.format) + '
-' + - format_time(this.end_ts, newtz, this.format)); + item.format = 1; + } + if (this.hasAttribute("format")) { + item.format = +this.getAttribute("format"); } }); - update_tooltips_all(); - update_clock(); -}; + const things_with_slots = $('[data-slot-start-ts]'); + $.each(things_with_slots, function (i, item) { + item.slot_start_ts = moment.unix(this.getAttribute("data-slot-start-ts")) + .utc(); + item.slot_end_ts = moment.unix(this.getAttribute("data-slot-end-ts")) + .utc(); + }); + } -// Highlight ongoing based on the current time -window.highlight_ongoing = function () { - $("div#now") - .remove("#now"); - $('.table-warning') - .removeClass("table-warning"); - var agenda_rows = $('[data-slot-start-ts]'); - agenda_rows = agenda_rows.filter(function () { - return moment() - .isBetween(this.slot_start_ts, this.slot_end_ts); - }); - agenda_rows.addClass("table-warning"); - agenda_rows.first() - .children("th, td") - .prepend($('
')); -}; + function format_time(t, tz, fmt) { + let out; + const mtz = window.meeting_timezone || "UTC"; + switch (fmt) { + case 0: + out = t.tz(tz) + .format('dddd, ') + '' + + t.tz(tz) + .format('MMMM Do YYYY, ') + '' + + t.tz(tz) + .format('HH:mm') + '' + + t.tz(tz) + .format(' Z z') + ''; + break; + case 1: + // Note, this code does not work if the meeting crosses the + // year boundary. + out = t.tz(tz) + .format("HH:mm"); + if (+t.tz(tz) + .dayOfYear() < +t.tz(mtz) + .dayOfYear()) { + out = out + " (-1)"; + } else if (+t.tz(tz) + .dayOfYear() > +t.tz(mtz) + .dayOfYear()) { + out = out + " (+1)"; + } + break; + case 2: + out = t.tz(mtz) + .format("dddd, ") + .toUpperCase() + + t.tz(tz) + .format("HH:mm"); + if (+t.tz(tz) + .dayOfYear() < +t.tz(mtz) + .dayOfYear()) { + out = out + " (-1)"; + } else if (+t.tz(tz) + .dayOfYear() > +t.tz(mtz) + .dayOfYear()) { + out = out + " (+1)"; + } + break; + case 3: + out = t.utc() + .format("YYYY-MM-DD"); + break; + case 4: + out = t.tz(tz) + .format("YYYY-MM-DD HH:mm"); + break; + case 5: + out = t.tz(tz) + .format("HH:mm"); + break; + } + return out; + } -// Update tooltips -window.update_tooltips = function () { - var tooltips = $('.timetooltiptext'); - tooltips.filter(function () { + // Format tooltip notice + function format_tooltip_notice(start, end) { + let notice = ""; + + if (end.isBefore()) { + notice = "Event ended " + end.fromNow(); + } else if (start.isAfter()) { + notice = "Event will start " + start.fromNow(); + } else { + notice = "Event started " + start.fromNow() + " and will end " + + end.fromNow(); + } + return '' + notice + ''; + } + + // Format tooltip table + function format_tooltip_table(start, end) { + const current_timezone = get_current_tz_cb(); + let out = '
'; + if (window.meeting_timezone !== "") { + out += ''; + } + out += ''; + if (current_timezone !== 'UTC') { + out += ''; + } + out += ''; + out += '
Session startSession end
Meeting timezone' + + format_time(start, window.meeting_timezone, 0) + '' + + format_time(end, window.meeting_timezone, 0) + '
Local timezone' + + format_time(start, local_timezone, 0) + '' + + format_time(end, local_timezone, 0) + '
Selected Timezone' + + format_time(start, current_timezone, 0) + '' + + format_time(end, current_timezone, 0) + '
UTC' + + format_time(start, 'UTC', 0) + '' + + format_time(end, 'UTC', 0) + '
' + format_tooltip_notice(start, end) + '
'; + return out; + } + + // Format tooltip for item + function format_tooltip(start, end) { + return '
' + + format_tooltip_table(start, end) + + '
'; + } + + // Add tooltips + function add_tooltips() { + $('.time') + .each(function () { + const tooltip = $(format_tooltip(this.start_ts, this.end_ts)); + tooltip[0].start_ts = this.start_ts; + tooltip[0].end_ts = this.end_ts; + tooltip[0].ustart_ts = moment(this.start_ts) + .add(-2, 'hours'); + tooltip[0].uend_ts = moment(this.end_ts) + .add(2, 'hours'); + $(this) + .closest("th, td") + .attr("data-bs-toggle", "popover") + .attr("data-bs-content", $(tooltip) + .html()) + .popover({ + html: true, + sanitize: false, + trigger: "hover" + }); + }); + } + + // Update times on the agenda based on the selected timezone + function update_times(newtz) { + $('.current-tz') + .html(newtz); + $('.time') + .each(function () { + if (this.format === 4) { + const tz = this.start_ts.tz(newtz).format(" z"); + const start_doy = this.start_ts.tz(newtz).dayOfYear(); + const end_doy = this.end_ts.tz(newtz).dayOfYear(); + if (start_doy === end_doy) { + $(this) + .html(format_time(this.start_ts, newtz, this.format) + + '
-' + format_time(this.end_ts, newtz, 5) + tz); + } else { + $(this) + .html(format_time(this.start_ts, newtz, this.format) + + '
-' + + format_time(this.end_ts, newtz, this.format) + tz); + } + } else { + $(this) + .html(format_time(this.start_ts, newtz, this.format) + '
-' + + format_time(this.end_ts, newtz, this.format)); + } + }); + update_tooltips_all(); + update_clock(); + } + + // Update hrefs in anchor tags with the "now-link" class. Mark the target with the "current-session" class. + function update_now_link(agenda_rows, ongoing_rows, later_rows) { + agenda_rows.removeClass('current-session'); + const links_to_update = $('a.now-link'); + if (ongoing_rows.length > 0) { + // sessions are ongoing - find those with the latest start time and mark the first of them as "now" + const last_start_time = ongoing_rows[ongoing_rows.length - 1].slot_start_ts; + for (let ii=0; ii < ongoing_rows.length; ii++) { + const dt = ongoing_rows[ii].slot_start_ts.diff(last_start_time, 'seconds'); + if (Math.abs(dt) < 1) { + $(ongoing_rows[ii]).addClass('current-session'); + links_to_update.attr('href', '#' + ongoing_rows[ii].id); + break; + } + } + } else if (later_rows.length > 0) { + // There were no ongoing sessions, look for the next one to start and mark as current + $(later_rows[0]).addClass('current-session'); + links_to_update.attr('href', '#' + later_rows[0].id); + } else { + // No sessions in the future - meeting has apparently ended + links_to_update.attr('href', '#'); + links_to_update.addClass('text-muted text-decoration-line-through'); // mark link + } + } + + function update_ongoing_sessions() { + const agenda_rows = $('[data-slot-start-ts]'); + const now_moment = moment(); + const ongoing_rows = agenda_rows.filter(function () { + return now_moment.isBetween(this.slot_start_ts, this.slot_end_ts); + }); + const later_rows = agenda_rows.filter(function() { return now_moment.isBefore(this.slot_start_ts); }); + // Highlight ongoing based on the current time + agenda_rows.removeClass("table-warning"); + ongoing_rows.addClass("table-warning"); + update_now_link(agenda_rows, ongoing_rows, later_rows); // update any "now-link" anchors + } + + // Update tooltips + function update_tooltips() { + const tooltips = $('.timetooltiptext'); + tooltips.filter(function () { return moment() .isBetween(this.ustart_ts, this.uend_ts); }) - .each(function () { + .each(function () { + $(this) + .html(format_tooltip_table(this.start_ts, this.end_ts)); + }); + } + + // Update all tooltips + function update_tooltips_all() { + const tooltips = $('.timetooltiptext'); + tooltips.each(function () { $(this) .html(format_tooltip_table(this.start_ts, this.end_ts)); }); -}; - -// Update all tooltips -window.update_tooltips_all = function () { - var tooltips = $('.timetooltiptext'); - tooltips.each(function () { - $(this) - .html(format_tooltip_table(this.start_ts, this.end_ts)); - }); -}; - -// Update clock -window.update_clock = function () { - $('#current-time') - .html(format_time(moment(), get_current_tz_cb(), 0)); -}; - -$.urlParam = function (name) { - var results = new RegExp('[\?&]' + name + '=([^&#]*)') - .exec(window.location.href); - if (results == null) { - return null; - } else { - return results[1] || 0; } -}; -window.init_timers = function () { - var fast_timer = 60000 / (speedup > 600 ? 600 : speedup); - update_clock(); - highlight_ongoing(); - setInterval(function () { update_clock(); }, fast_timer); - setInterval(function () { highlight_ongoing(); }, fast_timer); - setInterval(function () { update_tooltips(); }, fast_timer); - setInterval(function () { update_tooltips_all(); }, 3600000 / speedup); -}; + // Update clock + function update_clock() { + $('span.current-time') + .html(format_time(moment(), get_current_tz_cb(), 0)); + } -// set method used to find current time zone -window.set_current_tz_cb = function (fn) { - get_current_tz_cb = fn; -}; \ No newline at end of file + function urlParam(name) { + const results = new RegExp('[\?&]' + name + '=([^&#]*)') + .exec(window.location.href); + if (results === null) { + return null; + } else { + return results[1] || 0; + } + } + + function init_timers(speedup) { + speedup = speedup || 1; + const fast_timer = 60000 / (speedup > 600 ? 600 : speedup); + update_clock(); + update_ongoing_sessions(); + setInterval(function () { update_clock(); }, fast_timer); + setInterval(function () { update_ongoing_sessions(); }, fast_timer); + setInterval(function () { update_tooltips(); }, fast_timer); + setInterval(function () { update_tooltips_all(); }, 3600000 / speedup); + } + + /***** make public interface available on window *****/ + window.initialize_moments = initialize_moments; + window.add_tooltips = add_tooltips; + window.update_times = update_times; + window.urlParam = urlParam; + window.init_timers = init_timers; + + // set method used to find current time zone + window.set_current_tz_cb = function (fn) { + get_current_tz_cb = fn; + }; +})(); \ No newline at end of file diff --git a/ietf/static/js/ietf.js b/ietf/static/js/ietf.js index a63fd09a6..516683783 100644 --- a/ietf/static/js/ietf.js +++ b/ietf/static/js/ietf.js @@ -163,29 +163,39 @@ $(function () { .shift() .trim()); - if ( - contents && - (contents.length > 0) && - ($(headings) - .last() - .offset() - .top > $(window) - .height()) - ) { + const extraNav = contentElement.find('#extra-nav'); + const haveExtraNav = extraNav.length > 0; + + const pageTooTall = !!(contents && + (contents.length > 0) && + ($(headings) + .last() + .offset() + .top > $(window) + .height())); + + if (pageTooTall || haveExtraNav) { // console.log("Enabling nav."); let n = 0; let last_level; - let nav; contentElement .attr("data-bs-offset", 0) .attr("tabindex", 0) .after($(`
- +
+ +
- `)) + `)); + + const nav = $("#righthand-nav") + .append(`