Add the scripts and dependencies for the agenda page back, and make them work.
- Legacy-Id: 19652
This commit is contained in:
parent
273feec52d
commit
be3a8f71ce
310
ietf/static/js/agenda_filter.js
Normal file
310
ietf/static/js/agenda_filter.js
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
window.agenda_filter; // public interface
|
||||||
|
window.agenda_filter_for_testing; // methods to be accessed for automated testing
|
||||||
|
|
||||||
|
// closure to create private scope
|
||||||
|
(function () {
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/* n.b., const refers to the opts object itself, not its contents.
|
||||||
|
* Use camelCase for easy translation into element.dataset keys,
|
||||||
|
* which are automatically camel-cased from the data attribute name.
|
||||||
|
* (e.g., data-always-show -> elt.dataset.alwaysShow) */
|
||||||
|
const opts = {
|
||||||
|
alwaysShow: false,
|
||||||
|
updateCallback: null // function(filter_params)
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Remove from list, if present */
|
||||||
|
function remove_list_item (list, item) {
|
||||||
|
var item_index = list.indexOf(item);
|
||||||
|
if (item_index !== -1) {
|
||||||
|
list.splice(item_index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add to list if not present, remove if present
|
||||||
|
*
|
||||||
|
* Returns true if added to the list, otherwise false.
|
||||||
|
*/
|
||||||
|
function toggle_list_item (list, item) {
|
||||||
|
var item_index = list.indexOf(item);
|
||||||
|
if (item_index === -1) {
|
||||||
|
list.push(item)
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
list.splice(item_index, 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_query_params (qs) {
|
||||||
|
var params = {}
|
||||||
|
qs = decodeURI(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
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filt = 'show' or 'hide' */
|
||||||
|
function get_filter_from_qparams (qparams, filt) {
|
||||||
|
if (!qparams[filt] || (qparams[filt] === true)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var result = [];
|
||||||
|
var qp = qparams[filt].split(',');
|
||||||
|
|
||||||
|
for (var ii = 0; ii < qp.length; ii++) {
|
||||||
|
result.push(qp[ii].trim());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_filter_params (qparams) {
|
||||||
|
var enabled = opts.alwaysShow || qparams.show || qparams.hide;
|
||||||
|
return {
|
||||||
|
enabled: enabled,
|
||||||
|
show: get_filter_from_qparams(qparams, 'show'),
|
||||||
|
hide: get_filter_from_qparams(qparams, 'hide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_keywords(elt) {
|
||||||
|
var keywords = $(elt).attr('data-filter-keywords');
|
||||||
|
if (keywords) {
|
||||||
|
return keywords.toLowerCase().split(',');
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_item(elt) {
|
||||||
|
return $(elt).attr('data-filter-item');
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility method - is there a match between two lists of keywords?
|
||||||
|
function keyword_match(list1, list2) {
|
||||||
|
for (var ii = 0; ii < list1.length; ii++) {
|
||||||
|
if (list2.indexOf(list1[ii]) !== -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the items corresponding to a keyword
|
||||||
|
function get_items_with_keyword (keyword) {
|
||||||
|
var items = [];
|
||||||
|
|
||||||
|
$('.view button.pickview').filter(function(index, elt) {
|
||||||
|
return keyword_match(get_keywords(elt), [keyword]);
|
||||||
|
}).each(function (index, elt) {
|
||||||
|
items.push(get_item($(elt)));
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filtering_is_enabled (filter_params) {
|
||||||
|
return filter_params.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the filter / customization UI to match the current filter parameters
|
||||||
|
function update_filter_ui (filter_params) {
|
||||||
|
var buttons = $('.pickview');
|
||||||
|
|
||||||
|
if (!filtering_is_enabled(filter_params)) {
|
||||||
|
// Not filtering - set to default and exit
|
||||||
|
buttons.removeClass('active');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_href_querystrings(filter_params_as_querystring(filter_params))
|
||||||
|
|
||||||
|
// show the customizer - it will stay visible even if filtering is disabled
|
||||||
|
const customizer = $('#customize');
|
||||||
|
if (customizer.hasClass('collapse')) {
|
||||||
|
customizer.collapse('show')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update button state to match visibility
|
||||||
|
buttons.each(function (index, elt) {
|
||||||
|
elt = $(elt);
|
||||||
|
var keywords = get_keywords(elt);
|
||||||
|
keywords.push(get_item(elt)); // treat item as one of its keywords
|
||||||
|
var hidden = keyword_match(filter_params.hide, keywords);
|
||||||
|
var shown = keyword_match(filter_params.show, keywords);
|
||||||
|
if (shown && !hidden) {
|
||||||
|
elt.addClass('active');
|
||||||
|
} else {
|
||||||
|
elt.removeClass('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update state of the view to match the filters
|
||||||
|
*
|
||||||
|
* Calling the individual update_* functions outside of this method will likely cause
|
||||||
|
* various parts of the page to get out of sync.
|
||||||
|
*/
|
||||||
|
function update_view () {
|
||||||
|
var filter_params = get_filter_params(parse_query_params(window.location.search))
|
||||||
|
update_filter_ui(filter_params)
|
||||||
|
if (opts.updateCallback) {
|
||||||
|
opts.updateCallback(filter_params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trigger an update so the user will see the page appropriate for given filter_params
|
||||||
|
*
|
||||||
|
* Updates the URL to match filter_params, then updates the history / display to match
|
||||||
|
* (if supported) or loads the new URL.
|
||||||
|
*/
|
||||||
|
function update_filters (filter_params) {
|
||||||
|
var new_url = replace_querystring(
|
||||||
|
window.location.href,
|
||||||
|
filter_params_as_querystring(filter_params)
|
||||||
|
)
|
||||||
|
update_href_querystrings(filter_params_as_querystring(filter_params))
|
||||||
|
if (window.history && window.history.replaceState) {
|
||||||
|
// Keep current origin, replace search string, no page reload
|
||||||
|
history.replaceState({}, document.title, new_url)
|
||||||
|
update_view()
|
||||||
|
} else {
|
||||||
|
// No window.history.replaceState support, page reload required
|
||||||
|
window.location = new_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the querystring in the href filterable agenda links
|
||||||
|
*/
|
||||||
|
function update_href_querystrings(querystring) {
|
||||||
|
Array.from(
|
||||||
|
document.getElementsByClassName('agenda-link filterable')
|
||||||
|
).forEach(
|
||||||
|
(elt) => elt.href = replace_querystring(elt.href, querystring)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter_params_as_querystring(filter_params) {
|
||||||
|
var qparams = []
|
||||||
|
if (filter_params.show.length > 0) {
|
||||||
|
qparams.push('show=' + filter_params.show.join())
|
||||||
|
}
|
||||||
|
if (filter_params.hide.length > 0) {
|
||||||
|
qparams.push('hide=' + filter_params.hide.join())
|
||||||
|
}
|
||||||
|
if (qparams.length > 0) {
|
||||||
|
return '?' + qparams.join('&')
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function replace_querystring(url, new_querystring) {
|
||||||
|
return url.replace(/(\?.*)?(#.*)?$/, new_querystring + window.location.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper for pick group/type button handlers - toggles the appropriate parameter entry
|
||||||
|
* elt - the jquery element that was clicked
|
||||||
|
*/
|
||||||
|
function handle_pick_button (elt) {
|
||||||
|
var fp = get_filter_params(parse_query_params(window.location.search));
|
||||||
|
var item = get_item(elt);
|
||||||
|
|
||||||
|
/* Normally toggle in and out of the 'show' list. If this item is active because
|
||||||
|
* one of its keywords is active, invert the sense and toggle in and out of the
|
||||||
|
* 'hide' list instead. */
|
||||||
|
var inverted = keyword_match(fp.show, get_keywords(elt));
|
||||||
|
var just_showed_item = false;
|
||||||
|
if (inverted) {
|
||||||
|
toggle_list_item(fp.hide, item);
|
||||||
|
remove_list_item(fp.show, item);
|
||||||
|
} else {
|
||||||
|
just_showed_item = toggle_list_item(fp.show, item);
|
||||||
|
remove_list_item(fp.hide, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we just showed an item, remove its children from the
|
||||||
|
* show/hide lists to keep things consistent. This way, selecting
|
||||||
|
* an area will enable all items in the row as one would expect. */
|
||||||
|
if (just_showed_item) {
|
||||||
|
var children = get_items_with_keyword(item);
|
||||||
|
$.each(children, function(index, child) {
|
||||||
|
remove_list_item(fp.show, child);
|
||||||
|
remove_list_item(fp.hide, child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the show list is empty, clear the hide list because there is nothing to hide
|
||||||
|
if (fp.show.length === 0) {
|
||||||
|
fp.hide = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_disabled(elt) {
|
||||||
|
return elt.hasClass('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
function register_handlers() {
|
||||||
|
$('.pickview').on("click", function () {
|
||||||
|
if (is_disabled($(this))) { return; }
|
||||||
|
var fp = handle_pick_button($(this));
|
||||||
|
update_filters(fp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read options from the template
|
||||||
|
*/
|
||||||
|
function read_template_options() {
|
||||||
|
const opts_elt = document.getElementById('agenda-filter-options');
|
||||||
|
opts.keys().forEach((opt) => {
|
||||||
|
if (opt in opts_elt.dataset) {
|
||||||
|
opts[opt] = opts_elt.dataset[opt];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Entry point to filtering code when page loads
|
||||||
|
*
|
||||||
|
* This must be called if you are using the HTML template to provide a customization
|
||||||
|
* button UI. Do not call if you only want to use the parameter parsing routines.
|
||||||
|
*/
|
||||||
|
function enable () {
|
||||||
|
// ready handler fires immediately if document is already "ready"
|
||||||
|
$(document).ready(function () {
|
||||||
|
register_handlers();
|
||||||
|
update_view();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility method - filter a jquery set to those matching a keyword
|
||||||
|
function rows_matching_filter_keyword(rows, kw) {
|
||||||
|
return rows.filter(function(index, element) {
|
||||||
|
var row_kws = get_keywords(element);
|
||||||
|
return keyword_match(row_kws, [kw.toLowerCase()]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make private functions available for unit testing
|
||||||
|
agenda_filter_for_testing = {
|
||||||
|
parse_query_params: parse_query_params,
|
||||||
|
toggle_list_item: toggle_list_item
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make public interface methods accessible
|
||||||
|
agenda_filter = {
|
||||||
|
enable: enable,
|
||||||
|
filtering_is_enabled: filtering_is_enabled,
|
||||||
|
get_filter_params: get_filter_params,
|
||||||
|
keyword_match: keyword_match,
|
||||||
|
parse_query_params: parse_query_params,
|
||||||
|
rows_matching_filter_keyword: rows_matching_filter_keyword,
|
||||||
|
set_update_callback: function (cb) {opts.updateCallback = cb}
|
||||||
|
};
|
||||||
|
})();
|
84
ietf/static/js/agenda_materials.js
Normal file
84
ietf/static/js/agenda_materials.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright The IETF Trust 2021, All Rights Reserved
|
||||||
|
|
||||||
|
/*
|
||||||
|
Javascript support for the materials modal rendered by session_agenda_include.html
|
||||||
|
|
||||||
|
Requires jquery be loaded
|
||||||
|
*/
|
||||||
|
|
||||||
|
var agenda_materials; // public interface
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
/**
|
||||||
|
* Retrieve and display materials for a session
|
||||||
|
*
|
||||||
|
* If output_elt exists and has a "data-src" attribute, retrieves the document
|
||||||
|
* from that URL and displays under output_elt. Handles text/plain, text/markdown,
|
||||||
|
* and text/html.
|
||||||
|
*
|
||||||
|
* @param output_elt Element, probably a div, to hold the output
|
||||||
|
*/
|
||||||
|
function retrieve_session_materials(output_elt) {
|
||||||
|
if (!output_elt) {return;}
|
||||||
|
output_elt = $(output_elt);
|
||||||
|
var data_src = output_elt.attr("data-src");
|
||||||
|
if (!data_src) {
|
||||||
|
output_elt.html("<p>Error: missing data-src attribute</p>");
|
||||||
|
} else {
|
||||||
|
output_elt.html("<p>Loading " + data_src + "...</p>");
|
||||||
|
var outer_xhr = $.ajax({url:data_src,headers:{'Accept':'text/plain;q=0.8,text/html;q=0.9'}})
|
||||||
|
outer_xhr.done(function(data, status, xhr) {
|
||||||
|
var t = xhr.getResponseHeader("content-type");
|
||||||
|
if (!t) {
|
||||||
|
data = "<p>Error retrieving " + data_src
|
||||||
|
+ ": Missing content-type in response header</p>";
|
||||||
|
} else if (t.indexOf("text/plain") > -1) {
|
||||||
|
data = "<pre class='agenda'>" + data + "</pre>";
|
||||||
|
} else if (t.indexOf("text/markdown") > -1) {
|
||||||
|
data = "<pre class='agenda'>" + data + "</pre>";
|
||||||
|
} else if(t.indexOf("text/html") > -1) {
|
||||||
|
// nothing to do here
|
||||||
|
} else {
|
||||||
|
data = "<p>Unknown type: " + xhr.getResponseHeader("content-type") + "</p>";
|
||||||
|
}
|
||||||
|
output_elt.html(data);
|
||||||
|
}).fail(function() {
|
||||||
|
output_elt.html("<p>Error retrieving " + data_src
|
||||||
|
+ ": (" + outer_xhr.status.toString() + ") "
|
||||||
|
+ outer_xhr.statusText + "</p>");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve contents of a session materials modal
|
||||||
|
*
|
||||||
|
* Expects output_elt to exist and have a "data-src" attribute. Retrieves the
|
||||||
|
* contents of that URL, then attempts to populate the .agenda-frame and
|
||||||
|
* .minutes-frame elements.
|
||||||
|
*
|
||||||
|
* @param output_elt Element, probably a div, to hold the output
|
||||||
|
*/
|
||||||
|
function retrieve_session_modal(output_elt) {
|
||||||
|
if (!output_elt) {return;}
|
||||||
|
output_elt = $(output_elt);
|
||||||
|
var data_src = output_elt.attr("data-src");
|
||||||
|
if (!data_src) {
|
||||||
|
output_elt.html("<p>Error: missing data-src attribute</p>");
|
||||||
|
} else {
|
||||||
|
output_elt.html("<p>Loading...</p>");
|
||||||
|
$.get(data_src).done(function(data) {
|
||||||
|
output_elt.html(data);
|
||||||
|
retrieve_session_materials(output_elt.find(".agenda-frame"));
|
||||||
|
retrieve_session_materials(output_elt.find(".minutes-frame"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$(".modal").on("show.bs.modal", function () {
|
||||||
|
retrieve_session_modal($(this).find(".session-materials"));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})();
|
229
ietf/static/js/agenda_timezone.js
Normal file
229
ietf/static/js/agenda_timezone.js
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// Copyright The IETF Trust 2021, All Rights Reserved
|
||||||
|
|
||||||
|
/*
|
||||||
|
Timezone support specific to the agenda page
|
||||||
|
|
||||||
|
To properly handle timezones other than local, needs a method to retrieve
|
||||||
|
the current timezone. Set this by passing a method taking no parameters and
|
||||||
|
returning the current timezone to the set_current_tz_cb() method.
|
||||||
|
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 () {
|
||||||
|
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();
|
||||||
|
if (this.hasAttribute("weekday")) {
|
||||||
|
item.format=2;
|
||||||
|
} else {
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.format_time = function (t, tz, fmt) {
|
||||||
|
var out;
|
||||||
|
var mtz = meeting_timezone;
|
||||||
|
if (mtz == "") {
|
||||||
|
mtz = "UTC";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fmt) {
|
||||||
|
case 0:
|
||||||
|
out = t.tz(tz).format('dddd, ') + '<span class="hidden-xs">' +
|
||||||
|
t.tz(tz).format('MMMM Do YYYY, ') + '</span>' +
|
||||||
|
t.tz(tz).format('HH:mm') + '<span class="hidden-xs">' +
|
||||||
|
t.tz(tz).format(' Z z') + '</span>';
|
||||||
|
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
|
||||||
|
window.format_tooltip_notice = function (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 '<span class="tooltipnotice">' + notice + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format tooltip table
|
||||||
|
window.format_tooltip_table = function (start, end) {
|
||||||
|
var current_timezone = get_current_tz_cb();
|
||||||
|
var out = '<table><tr><th>Timezone</th><th>Start</th><th>End</th></tr>';
|
||||||
|
if (meeting_timezone !== "") {
|
||||||
|
out += '<tr><td class="timehead">Meeting timezone:</td><td>' +
|
||||||
|
format_time(start, meeting_timezone, 0) + '</td><td>' +
|
||||||
|
format_time(end, meeting_timezone, 0) + '</td></tr>';
|
||||||
|
}
|
||||||
|
out += '<tr><td class="timehead">Local timezone:</td><td>' +
|
||||||
|
format_time(start, local_timezone, 0) + '</td><td>' +
|
||||||
|
format_time(end, local_timezone, 0) + '</td></tr>';
|
||||||
|
if (current_timezone !== 'UTC') {
|
||||||
|
out += '<tr><td class="timehead">Selected Timezone:</td><td>' +
|
||||||
|
format_time(start, current_timezone, 0) + '</td><td>' +
|
||||||
|
format_time(end, current_timezone, 0) + '</td></tr>';
|
||||||
|
}
|
||||||
|
out += '<tr><td class="timehead">UTC:</td><td>' +
|
||||||
|
format_time(start, 'UTC', 0) + '</td><td>' +
|
||||||
|
format_time(end, 'UTC', 0) + '</td></tr>';
|
||||||
|
out += '</table>' + format_tooltip_notice(start, end);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format tooltip for item
|
||||||
|
window.format_tooltip = function (start, end) {
|
||||||
|
return '<div class="timetooltiptext">' +
|
||||||
|
format_tooltip_table(start, end) +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
} 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
agenda_rows.addClass("ongoing");
|
||||||
|
agenda_rows.first().children("th, td").
|
||||||
|
prepend($('<div id="now" class="anchor-target"></div>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set method used to find current time zone
|
||||||
|
window.set_current_tz_cb = function (fn) {
|
||||||
|
get_current_tz_cb = fn;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
import "moment-timezone/builds/moment-timezone-with-data-10-year-range";
|
3
ietf/static/js/moment.js
Normal file
3
ietf/static/js/moment.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
const moment = require("moment");
|
||||||
|
|
||||||
|
global.moment = moment;
|
74
ietf/static/js/timezone.js
Normal file
74
ietf/static/js/timezone.js
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright The IETF Trust 2021, All Rights Reserved
|
||||||
|
|
||||||
|
/*
|
||||||
|
Timezone selection handling. Relies on the moment.js library.
|
||||||
|
|
||||||
|
To use, create one (or more) select inputs with class "tz-select". When the initialize()
|
||||||
|
method is called, the options in the select will be replaced with the recognized time zone
|
||||||
|
names. Time zone can be changed via the select input or by calling the use() method with
|
||||||
|
the name of a time zone (or 'local' to guess the user's local timezone).
|
||||||
|
*/
|
||||||
|
window.ietf_timezone; // public interface
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
// Callback for timezone change - called after current_timezone is updated
|
||||||
|
var timezone_change_callback;
|
||||||
|
var current_timezone;
|
||||||
|
|
||||||
|
// Select timezone to use. Arg is name of a timezone or 'local' to guess local tz.
|
||||||
|
function use_timezone (newtz) {
|
||||||
|
// Guess local timezone if necessary
|
||||||
|
if (newtz.toLowerCase() === 'local') {
|
||||||
|
newtz = moment.tz.guess()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_timezone !== newtz) {
|
||||||
|
current_timezone = newtz
|
||||||
|
// Update values of tz-select inputs but do not trigger change event
|
||||||
|
$('select.tz-select').val(newtz)
|
||||||
|
if (timezone_change_callback) {
|
||||||
|
timezone_change_callback(newtz)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize timezone system
|
||||||
|
*
|
||||||
|
* This will set the timezone to the value of 'current'. Set up the tz_change callback
|
||||||
|
* before initializing.
|
||||||
|
*/
|
||||||
|
function timezone_init (current) {
|
||||||
|
var tz_names = moment.tz.names()
|
||||||
|
var select = $('select.tz-select')
|
||||||
|
|
||||||
|
select.empty()
|
||||||
|
$.each(tz_names, function (i, item) {
|
||||||
|
if (current === item) {
|
||||||
|
select.append($('<option/>', {
|
||||||
|
selected: 'selected', html: item, value: item
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
select.append($('<option/>', {
|
||||||
|
html: item, value: item
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
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,
|
||||||
|
* so trigger the change event ourselves to be sure the UI stays consistent
|
||||||
|
* with the timezone select input. */
|
||||||
|
window.addEventListener('pageshow', function(){select.trigger("change"); })
|
||||||
|
use_timezone(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose public interface
|
||||||
|
ietf_timezone = {
|
||||||
|
get_current_tz: function() {return current_timezone},
|
||||||
|
initialize: timezone_init,
|
||||||
|
set_tz_change_callback: function(cb) {timezone_change_callback=cb},
|
||||||
|
use: use_timezone
|
||||||
|
}
|
||||||
|
})();
|
|
@ -346,7 +346,7 @@
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_filter.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_filter.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
// Update the agenda display with specified filters
|
// Update the agenda display with specified filters
|
||||||
function update_agenda_display(filter_params) {
|
function update_agenda_display(filter_params) {
|
||||||
|
@ -435,13 +435,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script src="{% static 'moment/min/moment.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment.js' %}"></script>
|
||||||
<script src="{% static 'moment-timezone/builds/moment-timezone-with-data-10-year-range.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment-timezone-with-data-10-year-range.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/timezone.js' %}"></script>
|
<script src="{% static 'ietf/js/timezone.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_materials.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_materials.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_timezone.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_timezone.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
{% if settings.DEBUG and settings.DEBUG_AGENDA %}
|
{% if settings.DEBUG and settings.DEBUG_AGENDA %}
|
||||||
speedup = +$.urlParam('speedup');
|
speedup = +$.urlParam('speedup');
|
||||||
if (speedup < 1) {
|
if (speedup < 1) {
|
||||||
|
|
|
@ -374,11 +374,11 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script src="{% static 'moment/min/moment.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment.js' %}"></script>
|
||||||
<script src="{% static 'moment-timezone/builds/moment-timezone-with-data-10-year-range.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment-timezone-with-data-10-year-range.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/timezone.js' %}"></script>
|
<script src="{% static 'ietf/js/timezone.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_timezone.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_timezone.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_filter.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_filter.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_personalize.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda/agenda_personalize.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
{% block title %}{{ schedule.name }}: IETF {{ meeting.number }} meeting agenda{% endblock %}
|
{% block title %}{{ schedule.name }}: IETF {{ meeting.number }} meeting agenda{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script type="text/javascript" src="{% static 'moment/min/moment.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'ietf/js/moment.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'moment-timezone/builds/moment-timezone-with-data-10-year-range.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'ietf/js/moment-timezone-with-data-10-year-range.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'ietf/js/edit-meeting-schedule.js' %}"></script>
|
<script type="text/javascript" src="{% static 'ietf/js/edit-meeting-schedule.js' %}"></script>
|
||||||
{% endblock js %}
|
{% endblock js %}
|
||||||
|
|
||||||
|
|
|
@ -178,11 +178,11 @@
|
||||||
<script src="{% static "ietf/js/datatables.js" %}"></script>
|
<script src="{% static "ietf/js/datatables.js" %}"></script>
|
||||||
<script src="{% static 'fullcalendar/core/main.js' %}"></script>
|
<script src="{% static 'fullcalendar/core/main.js' %}"></script>
|
||||||
<script src="{% static 'fullcalendar/daygrid/main.js' %}"></script>
|
<script src="{% static 'fullcalendar/daygrid/main.js' %}"></script>
|
||||||
<script src="{% static 'moment/min/moment.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment.js' %}"></script>
|
||||||
<script src="{% static 'moment-timezone/builds/moment-timezone-with-data-10-year-range.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment-timezone-with-data-10-year-range.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_filter.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_filter.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_materials.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_materials.js' %}"></script>
|
||||||
<script src="{% static 'ietf/js/agenda/timezone.js' %}"></script>
|
<script src="{% static 'ietf/js/timezone.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
// List of all events with meta-info needed for filtering
|
// List of all events with meta-info needed for filtering
|
||||||
var all_event_list = [{% for entry in entries %}
|
var all_event_list = [{% for entry in entries %}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
{% load origin %}{% origin %}
|
{% load origin %}{% origin %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<html> <head>
|
<html> <head>
|
||||||
<script src="{% static 'ietf/js/agenda/agenda_filter.js' %}"></script>
|
<script src="{% static 'ietf/js/agenda_filter.js' %}"></script>
|
||||||
<script src="{% static 'moment/min/moment.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment.js' %}"></script>
|
||||||
<script src="{% static 'moment-timezone/builds/moment-timezone-with-data-10-year-range.min.js' %}"></script>
|
<script src="{% static 'ietf/js/moment-timezone-with-data-10-year-range.js' %}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var all_items = {{ items|safe }};
|
var all_items = {{ items|safe }};
|
||||||
|
|
38
package-lock.json
generated
38
package-lock.json
generated
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "7.39.1.dev3-bs5",
|
"name": "7.39.1.dev4-bs5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
@ -12,7 +12,9 @@
|
||||||
"datatables.net": "^1.11.3",
|
"datatables.net": "^1.11.3",
|
||||||
"datatables.net-bs5": "^1.11.3",
|
"datatables.net-bs5": "^1.11.3",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"js-cookie": "^3.0.1"
|
"js-cookie": "^3.0.1",
|
||||||
|
"moment": "^2.29.1",
|
||||||
|
"moment-timezone": "^0.5.34"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@parcel/transformer-sass": "^2.0.1",
|
"@parcel/transformer-sass": "^2.0.1",
|
||||||
|
@ -5810,6 +5812,25 @@
|
||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moment": {
|
||||||
|
"version": "2.29.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||||
|
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/moment-timezone": {
|
||||||
|
"version": "0.5.34",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
|
||||||
|
"integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
|
||||||
|
"dependencies": {
|
||||||
|
"moment": ">= 2.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
@ -13191,6 +13212,19 @@
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.29.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||||
|
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||||
|
},
|
||||||
|
"moment-timezone": {
|
||||||
|
"version": "0.5.34",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
|
||||||
|
"integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
|
||||||
|
"requires": {
|
||||||
|
"moment": ">= 2.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
|
12
package.json
12
package.json
|
@ -7,7 +7,9 @@
|
||||||
"datatables.net": "^1.11.3",
|
"datatables.net": "^1.11.3",
|
||||||
"datatables.net-bs5": "^1.11.3",
|
"datatables.net-bs5": "^1.11.3",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"js-cookie": "^3.0.1"
|
"js-cookie": "^3.0.1",
|
||||||
|
"moment": "^2.29.1",
|
||||||
|
"moment-timezone": "^0.5.34"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@parcel/transformer-sass": "^2.0.1",
|
"@parcel/transformer-sass": "^2.0.1",
|
||||||
|
@ -20,6 +22,12 @@
|
||||||
"ietf/static/js/datatables.js",
|
"ietf/static/js/datatables.js",
|
||||||
"ietf/static/js/document_timeline.js",
|
"ietf/static/js/document_timeline.js",
|
||||||
"ietf/static/js/d3.js",
|
"ietf/static/js/d3.js",
|
||||||
|
"ietf/static/js/moment.js",
|
||||||
|
"ietf/static/js/agenda_filter.js",
|
||||||
|
"ietf/static/js/agenda_materials.js",
|
||||||
|
"ietf/static/js/agenda_timezone.js",
|
||||||
|
"ietf/static/js/timezone.js",
|
||||||
|
"ietf/static/js/moment-timezone-with-data-10-year-range.js",
|
||||||
"ietf/static/css/ietf.scss",
|
"ietf/static/css/ietf.scss",
|
||||||
"ietf/static/css/datatables.scss",
|
"ietf/static/css/datatables.scss",
|
||||||
"ietf/static/images/ietflogo-small-transparent.png",
|
"ietf/static/images/ietflogo-small-transparent.png",
|
||||||
|
@ -32,4 +40,4 @@
|
||||||
"distDir": "ietf/static/dist/ietf"
|
"distDir": "ietf/static/dist/ietf"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue