diff --git a/.eslintrc.js b/.eslintrc.js
index 000d6bd402..d213e9b85a 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -6,6 +6,7 @@ module.exports = {
"no-multiple-empty-lines": ["error", { max: 2, maxEOF: 0 }],
"quote-props": ["error", "as-needed"],
"brace-style": ["error", "1tbs", { allowSingleLine: true }],
+ "semi": ["error", "always"],
},
env: {
browser: true,
diff --git a/ietf/static/css/ietf.scss b/ietf/static/css/ietf.scss
index 50cf558dff..d018877b9d 100644
--- a/ietf/static/css/ietf.scss
+++ b/ietf/static/css/ietf.scss
@@ -6,6 +6,8 @@ $enable-negative-margins: true;
// Don't add carets to dropdowns by default.
// $enable-caret: false;
+$tooltip-max-width: 100%;
+
// Only import what we need:
// https://getbootstrap.com/docs/5.1/customize/optimize/
diff --git a/ietf/static/js/agenda_timezone.js b/ietf/static/js/agenda_timezone.js
index e590ce7aa9..bef58d6cb2 100644
--- a/ietf/static/js/agenda_timezone.js
+++ b/ietf/static/js/agenda_timezone.js
@@ -9,85 +9,105 @@
This should be done before calling anything else in the file.
*/
-var meeting_timezone;
var local_timezone = moment.tz.guess();
// get_current_tz_cb must be overwritten using set_current_tz_cb
-window.get_current_tz_cb = function () {
+function get_current_tz_cb() {
throw new Error('Tried to get current timezone before callback registered. Use set_current_tz_cb().')
};
// Initialize moments
window.initialize_moments = function () {
- var times=$('span.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();
+ var times = $('div.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;
+ item.format = 2;
} else {
- item.format=1;
+ item.format = 1;
}
if (this.hasAttribute("format")) {
item.format = +this.getAttribute("format");
}
});
- var 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();
+ var 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();
});
}
-window.format_time = function (t, tz, fmt) {
+function format_time(t, tz, fmt) {
var out;
- var mtz = meeting_timezone;
+ 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') + '';
+ 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 = 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()) {
+ } 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 = 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()) {
+ } else if (+t.tz(tz)
+ .dayOfYear() > +t.tz(mtz)
+ .dayOfYear()) {
out = out + " (+1)";
}
break;
case 3:
- out = t.utc().format("YYYY-MM-DD");
+ out = t.utc()
+ .format("YYYY-MM-DD");
break;
case 4:
- out = t.tz(tz).format("YYYY-MM-DD HH:mm");
+ out = t.tz(tz)
+ .format("YYYY-MM-DD HH:mm");
break;
case 5:
- out = t.tz(tz).format("HH:mm");
+ out = t.tz(tz)
+ .format("HH:mm");
break;
}
return out;
}
-
// Format tooltip notice
-window.format_tooltip_notice = function (start, end) {
+function format_tooltip_notice(start, end) {
var notice = "";
if (end.isBefore()) {
@@ -102,31 +122,31 @@ window.format_tooltip_notice = function (start, end) {
}
// Format tooltip table
-window.format_tooltip_table = function (start, end) {
+function format_tooltip_table(start, end) {
var current_timezone = get_current_tz_cb();
- var out = '
Timezone | Start | End |
';
- if (meeting_timezone !== "") {
- out += 'Meeting timezone: | ' +
- format_time(start, meeting_timezone, 0) + ' | ' +
- format_time(end, meeting_timezone, 0) + ' |
';
+ 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: | ' +
+ out += ' |
Local timezone | ' +
format_time(start, local_timezone, 0) + ' | ' +
format_time(end, local_timezone, 0) + ' |
';
if (current_timezone !== 'UTC') {
- out += 'Selected Timezone: | ' +
+ out += ' |
Selected Timezone | ' +
format_time(start, current_timezone, 0) + ' | ' +
format_time(end, current_timezone, 0) + ' |
';
}
- out += 'UTC: | ' +
+ out += ' |
UTC | ' +
format_time(start, 'UTC', 0) + ' | ' +
format_time(end, 'UTC', 0) + ' |
';
- out += '
' + format_tooltip_notice(start, end);
+ out += '
' + format_tooltip_notice(start, end) + '';
return out;
}
// Format tooltip for item
-window.format_tooltip = function (start, end) {
+function format_tooltip(start, end) {
return '' +
format_tooltip_table(start, end) +
'
';
@@ -134,78 +154,108 @@ window.format_tooltip = function (start, end) {
// Add tooltips
window.add_tooltips = function () {
- $('span.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).parent().append(tooltip);
- });
+ $('div.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", "tooltip")
+ .attr("title", $(tooltip)
+ .html())
+ .tooltip({
+ html: true,
+ sanitize: false
+ });
+ });
}
// Update times on the agenda based on the selected timezone
window.update_times = function (newtz) {
- $('span.current-tz').html(newtz);
- $('span.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);
+ $('span.current-tz')
+ .html(newtz);
+ $('div.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);
+ }
} else {
- $(this).html(format_time(this.start_ts, newtz, this.format) +
- '-' +
- format_time(this.end_ts, newtz, this.format) + tz);
+ $(this)
+ .html(format_time(this.start_ts, newtz, this.format) + '-' +
+ format_time(this.end_ts, newtz, this.format));
}
- } else {
- $(this).html(format_time(this.start_ts, newtz, this.format) + '-' +
- format_time(this.end_ts, newtz, this.format));
- }
- });
+ });
update_tooltips_all();
update_clock();
}
// Highlight ongoing based on the current time
window.highlight_ongoing = function () {
- $("div#now").remove("#now");
- $('.ongoing').removeClass("ongoing");
- var agenda_rows=$('[data-slot-start-ts]')
- agenda_rows = agenda_rows.filter(function() {
- return moment().isBetween(this.slot_start_ts, this.slot_end_ts);
+ $("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("ongoing");
- agenda_rows.first().children("th, td").
+ agenda_rows.addClass("table-warning");
+ agenda_rows.first()
+ .children("th, td")
+ .
prepend($(''));
}
// Update tooltips
window.update_tooltips = function () {
- var tooltips=$('.timetooltiptext');
- tooltips.filter(function() {
- return moment().isBetween(this.ustart_ts, this.uend_ts);
- }).each(function () {
- $(this).html(format_tooltip_table(this.start_ts, this.end_ts));
- });
+ var tooltips = $('.timetooltiptext');
+ tooltips.filter(function () {
+ return moment()
+ .isBetween(this.ustart_ts, this.uend_ts);
+ })
+ .each(function () {
+ $(this)
+ .html(format_tooltip_table(this.start_ts, this.end_ts));
+ });
}
// Update all tooltips
window.update_tooltips_all = function () {
- var tooltips=$('.timetooltiptext');
+ var tooltips = $('.timetooltiptext');
tooltips.each(function () {
- $(this).html(format_tooltip_table(this.start_ts, this.end_ts));
+ $(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));
+ $('#current-time')
+ .html(format_time(moment(), get_current_tz_cb(), 0));
}
-$.urlParam = function(name) {
- var results = new RegExp('[\?&]' + name + '=([^]*)').exec(window.location.href);
+$.urlParam = function (name) {
+ var results = new RegExp('[\?&]' + name + '=([^]*)')
+ .exec(window.location.href);
if (results == null) {
return null;
} else {
@@ -217,10 +267,10 @@ 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);
+ 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);
}
// set method used to find current time zone
diff --git a/ietf/static/js/room_params.js b/ietf/static/js/room_params.js
new file mode 100644
index 0000000000..3addb2ed89
--- /dev/null
+++ b/ietf/static/js/room_params.js
@@ -0,0 +1,184 @@
+var verbose = 0;
+
+window.suffixmap = function (nm)
+// Given a name like "foo-ab" or "foo-X-and-Y", change it to the "list-of-room-names" format, "foo-a/foo-b".
+{
+ var andsuffix = /^(.*-)([^-]+)-and-(.*)$/;
+ var andMatch = andsuffix.exec(nm);
+ if (andMatch && andMatch[0] != '') {
+ nm = andMatch[1] + andMatch[2] + "-" + andMatch[3];
+ }
+ // xyz-a/b/c => xyz-a/xyz-b/xyz-c
+ var abcsuffix = /^(.*)-([a-h0-9]+)[-\/]([a-h0-9]+)([-\/][a-h0-9]+)?$/;
+ var suffixMatch = abcsuffix.exec(nm);
+ if (verbose) alert("nm=" + nm);
+ if (suffixMatch && suffixMatch[0] != '') {
+ if (verbose) alert("matched");
+ nm = suffixMatch[1] + "-" + suffixMatch[2] + "/" +
+ suffixMatch[1] + "-" + suffixMatch[3];
+ if (verbose) alert("nm=>" + nm);
+ if (suffixMatch[4] && suffixMatch[4] != '')
+ nm += "/" + suffixMatch[1] + "-" + suffixMatch[4];
+ if (verbose) alert("nm=>" + nm);
+ }
+ // xyz-abc => xyz-a/xyz-b/xyz-c
+ abcsuffix = /^(.*)-([a-h])([a-h]+)([a-h])?$/;
+ var suffixMatch = abcsuffix.exec(nm);
+ if (suffixMatch && suffixMatch[0] != '') {
+ nm = suffixMatch[1] + "-" + suffixMatch[2] + "/" +
+ suffixMatch[1] + "-" + suffixMatch[3];
+ if (suffixMatch[4] && suffixMatch[4] != '')
+ nm += "/" + suffixMatch[1] + "-" + suffixMatch[4];
+ }
+ if (verbose) alert("suffixmap returning: " + nm);
+ return nm;
+}
+
+window.roomcoords = function (nm)
+// Find the coordinates of a room or list of room names separated by "/".
+// Calls the function findroom() to get the coordinates for a specific room.
+{
+ if (!nm) return null;
+
+ if (nm.match("/")) {
+ var nms = nm.split("/");
+ var nm0 = findroom(nms[0]);
+ if (!nm0) return null;
+ for (var i = 1; i < nms.length; i++) {
+ var nmi = roomcoords(nms[i]);
+ if (!nmi) return null;
+ if (nmi[0] < nm0[0]) nm0[0] = nmi[0];
+ if (nmi[1] < nm0[1]) nm0[1] = nmi[1];
+ if (nmi[2] > nm0[2]) nm0[2] = nmi[2];
+ if (nmi[3] > nm0[3]) nm0[3] = nmi[3];
+ }
+ return [nm0[0], nm0[1], nm0[2], nm0[3], nm0[4], nm0[5]];
+ } else {
+ return findroom(nm);
+ }
+}
+
+window.setarrow = function (nm)
+// Place an arrow at the center of a given room name (or list of room names separated by "/").
+{
+ for (var f = 0; f < floorlist.length; f++) {
+ floor = floorlist[f];
+ for (var i = 0; i < arrowsuffixlist.length; i++) {
+ removearrow(arrowsuffixlist[i], floor);
+ }
+ }
+
+ for (var i = 0; i < arguments.length; i+=2) {
+ nm = roommap(arguments[i]);
+ if (verbose) alert("nm=" + nm);
+ var rooms = nm.split(/[|]/);
+ for (var j = 0; j < rooms.length; j++) {
+ var room = rooms[j];
+ var ret = roomcoords(room);
+ if (verbose) alert("roomcoords returned: " + ret);
+ if (!ret) continue;
+
+ var left = ret[0], top = ret[1], right = ret[2], bottom = ret[3], floor=ret[4], width=ret[5], offsetleft = -25, offsettop = -25;
+ if (verbose) alert("left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom + ", floor=" + floor + ", width=" + width);
+ //alert("left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom);
+ // calculate arrow position
+ arrow_left = (left + (right - left) / 2 );
+ arrow_top = (top + (bottom - top) / 2 );
+ // scale the coordinates to match image scaling
+ var img = document.getElementById(floor+"-image");
+ scale = img.width / width;
+ arrow_left = arrow_left * scale;
+ arrow_top = arrow_top * scale;
+ var arrowdiv = floor+'-arrowdiv'+j;
+ //if (verbose) alert("arrowdiv: " + arrowdiv);
+ var adiv = document.getElementById(arrowdiv);
+ if (adiv) {
+ adiv.style.left = arrow_left + offsetleft + "px";
+ adiv.style.top = arrow_top + offsettop + "px";
+ adiv.style.visibility = "visible";
+ window.location.hash = floor;
+ }
+ }
+ }
+}
+
+window.removearrow = function (which, fl)
+{
+ for (var i = 0; i < arguments.length; i++) {
+ var which = arguments[i];
+ var arrowdiv = fl+'-arrowdiv' + (which ? which : "");
+ var adiv = document.getElementById(arrowdiv);
+ // if (verbose) alert("looking for '" + arrowdiv + "'");
+ if (adiv) {
+ // if (verbose) alert("adiv found");
+ adiv.style.left = -500;
+ adiv.style.top = -500;
+ adiv.style.visibility = "hidden";
+ }
+ }
+}
+
+window.setarrowlist = function (which, names)
+{
+ for (var i = 1; i < arguments.length; i++) {
+ setarrow(arguments[i], which);
+ }
+}
+
+window.QueryString = function ()
+// Create a QueryString object
+{
+ // get the query string, ignore the ? at the front.
+ var querystring = location.search.substring(1);
+
+ // parse out name/value pairs separated via &
+ var args = querystring.split('&');
+
+ // split out each name = value pair
+ for (var i = 0; i < args.length; i++) {
+ var pair = args[i].split('=');
+
+ // Fix broken unescaping
+ var temp = unescape(pair[0]).split('+');
+ var name_ = temp.join(' ');
+
+ var value_ = '';
+ if (typeof pair[1] == 'string') {
+ temp = unescape(pair[1]).split('+');
+ value_ = temp.join(' ');
+ }
+
+ this[name_] = value_;
+ }
+
+ this.get = function(nm, def) {
+ var value_ = this[nm];
+ if (value_ == null) return def;
+ else return value_;
+ };
+}
+
+window.checkParams = function ()
+// Check the parameters for one named "room". If found, call setarrow(room).
+{
+ var querystring = new QueryString();
+ var room = querystring.get("room");
+ if (room && room != "") setarrow(room);
+}
+
+// new functions
+window.located = function (loc)
+{
+ if (loc.civic && loc.civic.ROOM) {
+ // map from "TerminalRoom" to "terminal-room" as necessary.
+ setarrow(loc.civic.ROOM.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(), "-green");
+ }
+}
+
+// this needs to be called onload
+window.automaticarrow = function ()
+{
+ // if (navigator.geolocation) {
+ // navigator.geolocation.getCurrentPosition(located);
+ // }
+}
\ No newline at end of file
diff --git a/ietf/static/js/timezone.js b/ietf/static/js/timezone.js
index 3457b4299c..fda6f7f47d 100644
--- a/ietf/static/js/timezone.js
+++ b/ietf/static/js/timezone.js
@@ -54,7 +54,7 @@ window.ietf_timezone; // public interface
}))
}
})
- select.on("change", function () {use_timezone(this.value)});
+ select.on("change", function () { use_timezone(this.value)});
/* When navigating back/forward, the browser may change the select input's
* value after the window load event. It does not fire the change event on
* the input when it does this. The pageshow event occurs after such an update,
diff --git a/ietf/templates/api/index.html b/ietf/templates/api/index.html
index 13b8a47e62..6f024fd89c 100644
--- a/ietf/templates/api/index.html
+++ b/ietf/templates/api/index.html
@@ -362,7 +362,7 @@ Signing Keys
-