// Storage for the options that the server gives us. This will define our filters. var options = {}; // Last time we updated the spots/alerts list on display. var lastUpdateTime; // For a parameter, such as dx_continent, get the query string for the current filter options. function getQueryStringFor(parameter) { return parameter + "=" + encodeURIComponent(getSelectedFilterOptions(parameter)); } // For a parameter, such as dx_continent, get the filter options that are currently selected in the UI. function getSelectedFilterOptions(parameter) { return $(".filter-button-" + parameter).filter(function() { return this.checked; }).map(function() { return this.value; }).get().join(","); } // For a parameter, such as dx_continent, return true if all possible options are enabled. (In this case, we don't need // to bother sending this as one of the query parameters to the API; no parameter provided implies "send everything".) function allFilterOptionsSelected(parameter) { var filter = $(".filter-button-" + parameter).filter(function() { return !this.checked; }).get(); return filter.length == 0; } // Generate a filter card with multiple toggle buttons plus All/None buttons function generateMultiToggleFilterCard(displayName, filterQuery, options) { let $col = $("
"); // Create a button for each option options.forEach(o => { $p.append(` `); }); // Create All/None buttons $p.append(` `); // Compile HTML elements to return $card_body.append($p); $card.append($card_body); $col.append($card); return $col; } // Method called when "All" or "None" is clicked function toggleFilterButtons(filterQuery, state) { $(".filter-button-" + filterQuery).each(function() { $(this).prop('checked', state); }); filtersUpdated(); } // Update the refresh timing display function updateRefreshDisplay() { if (lastUpdateTime != null) { let count = REFRESH_INTERVAL_SEC; let secSinceUpdate = moment.duration(moment().diff(lastUpdateTime)).asSeconds(); updatingString = "Updating..." if (secSinceUpdate < REFRESH_INTERVAL_SEC) { count = REFRESH_INTERVAL_SEC - secSinceUpdate; if (count <= 60) { var number = count.toFixed(0); updatingString = "Updating in " + number + " second" + (number != "1" ? "s" : "") + "."; } else { var number = Math.round(count / 60.0).toFixed(0); updatingString = "Updating in " + number + " minute" + (number != "1" ? "s" : "") + "."; } } $("#timing-container").html("Last updated at " + lastUpdateTime.format('HH:mm') + " UTC. " + updatingString); } } // Utility function to escape HTML characters from a string. function escapeHtml(str) { if (typeof str !== 'string') { return ''; } const escapeCharacter = (match) => { switch (match) { case '&': return '&'; case '<': return '<'; case '>': return '>'; case '"': return '"'; case '\'': return '''; case '`': return '`'; default: return match; } }; return str.replace(/[&<>"'`]/g, escapeCharacter); } // When the "use local time" field is changed, reload the table and save settings function localTimeUpdated() { updateTable(); saveSettings(); } // Save settings to local storage function saveSettings() { // Find all storeable UI elements, store a key of "element id:property name" mapped to the value of that // property. For a checkbox, that's the "checked" property. $(".storeable-checkbox").each(function() { localStorage.setItem("#" + $(this)[0].id + ":checked", $(this)[0].checked); }); $(".storeable-select").each(function() { localStorage.setItem("#" + $(this)[0].id + ":value", $(this)[0].value); }); } // Load settings from local storage and set up the filter selectors function loadSettings() { // Find all local storage entries and push their data to the corresponding UI element Object.keys(localStorage).forEach(function(key) { if (key.startsWith("#") && key.includes(":")) { // Split the key back into an element ID and a property var split = key.split(":"); $(split[0]).prop(split[1], JSON.parse(localStorage.getItem(key))); } }); }