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 = '
| Session start | Session end |
';
- if (window.meeting_timezone !== "") {
- out += 'Meeting timezone | ' +
- format_time(start, window.meeting_timezone, 0) + ' | ' +
- format_time(end, window.meeting_timezone, 0) + ' |
';
- }
- out += 'Local timezone | ' +
- format_time(start, local_timezone, 0) + ' | ' +
- format_time(end, local_timezone, 0) + ' |
';
- if (current_timezone !== 'UTC') {
- out += 'Selected Timezone | ' +
- format_time(start, current_timezone, 0) + ' | ' +
- format_time(end, current_timezone, 0) + ' |
';
- }
- out += 'UTC | ' +
- format_time(start, 'UTC', 0) + ' | ' +
- format_time(end, 'UTC', 0) + ' |
';
- out += '
' + 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 = ' | Session start | Session end |
';
+ if (window.meeting_timezone !== "") {
+ out += 'Meeting timezone | ' +
+ format_time(start, window.meeting_timezone, 0) + ' | ' +
+ format_time(end, window.meeting_timezone, 0) + ' |
';
+ }
+ out += 'Local timezone | ' +
+ format_time(start, local_timezone, 0) + ' | ' +
+ format_time(end, local_timezone, 0) + ' |
';
+ if (current_timezone !== 'UTC') {
+ out += 'Selected Timezone | ' +
+ format_time(start, current_timezone, 0) + ' | ' +
+ format_time(end, current_timezone, 0) + ' |
';
+ }
+ out += 'UTC | ' +
+ format_time(start, 'UTC', 0) + ' | ' +
+ format_time(end, 'UTC', 0) + ' |
';
+ out += '
' + 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(`