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

-
+
-
+
-
+
-