`;
if (payload.previous_page_params) {
paginationHTML += `
`;
}
if (payload.next_page_params) {
paginationHTML += `
`;
}
paginationHTML += '
';
parent.querySelector("table").insertAdjacentHTML("afterend", paginationHTML);
}
addListener(parent.querySelectorAll(".js-show-history"), "click", showHistoryModal);
}
// Show a modal window overlayed on the page.
function showModal() {
const modal = document.querySelector("#modal");
const content = document.querySelector(".super-settings-modal-content");
modal.style.display = "block";
modal.setAttribute("aria-hidden", "false");
modal.activator = document.activeElement;
focusableElements(document).forEach(function(element) {
if (!modal.contains(element)) {
element.dataset.saveTabIndex = element.getAttribute("tabindex");
element.setAttribute("tabindex", -1);
}
});
document.querySelector("body").style.overflow = "hidden";
}
// Hide the modal window overlayed on the page.
function hideModal() {
const modal = document.querySelector("#modal");
const content = document.querySelector(".super-settings-modal-content");
modal.style.display = "none";
modal.setAttribute("aria-hidden", "true");
focusableElements(document).forEach(function(element) {
const tabIndex = element.dataset.saveTabIndex;
delete element.dataset.saveTabIndex;
if (tabIndex) {
element.setAttribute("tabindex", tabIndex);
}
});
if (modal.activator) {
modal.activator.focus();
delete modal.activator;
}
content.innerHTML = "";
document.querySelector("body").style.overflow = "visible";
}
// Returns a list of all focusable elements so that they can be set to not take the focus
// when a modal is opened.
function focusableElements(parent) {
return parent.querySelectorAll("a[href], area[href], button, input:not([type=hidden]), select, textarea, iframe, [tabindex], [contentEditable=true]")
}
// Find a setting by key.
function findSetting(id) {
let found = null;
id = "" + id;
activeSettings.forEach(function(setting) {
if ("" + setting.id === id) {
found = setting;
return;
}
});
return found;
}
/*** Event Listeners ***/
// Listener for showing the setting history modal.
function showHistoryModal(event) {
event.preventDefault();
if (!event.target.dataset) {
return;
}
const modal = document.querySelector("#modal");
const content = document.querySelector(".super-settings-modal-content");
let key = event.target.dataset.key;
if (!key) {
const row = event.target.closest("tr");
if (row) {
const id = row.dataset.id;
const setting = findSetting(id);
if (setting) {
key = setting.key;
if (!key) {
return;
}
}
}
}
const params = {key: key, limit: 25};
if (event.target.dataset.limit) {
params["limit"] = event.target.dataset.limit;
}
if (event.target.dataset.offset) {
params["offset"] = event.target.dataset.offset;
}
SuperSettingsAPI.fetchHistory(params, function(settingHistory){
renderHistoryTable(content, settingHistory);
showModal();
});
}
// Listener for closing the modal window overlay.
function closeModal(event) {
if (event.target.classList.contains("js-close-modal")) {
event.preventDefault();
hideModal();
}
}
// Listener to just capture events.
function noOp(event) {
event.preventDefault();
}
// Listener for changing the setting value type select element. Different types will have
// different input elements for the setting value.
function changeSettingType(event) {
event.preventDefault();
const row = event.target.closest("tr");
const valueType = event.target.options[event.target.selectedIndex].value;
var setting = {
id: row.dataset.id,
key: row.querySelector(".super-settings-key input").value,
value: getSettingEditValue(row),
value_type: valueType,
description: row.querySelector(".super-settings-description textarea").value,
new_record: row.dataset.newrecord
}
const addedRow = addRowToTable(editSettingRow(setting));
if (addedRow.querySelector(".super-settings-value .js-date-input")) {
addedRow.querySelector(".super-settings-value .js-date-input").focus();
} else {
addedRow.querySelector(".super-settings-value .js-setting-value").focus();
}
}
// Listener for date and time input elements the combine the values into a hidden datetime field.
function changeDateTime(event) {
const parentNode = event.target.closest("span")
const dateValue = parentNode.querySelector(".js-date-input").value;
let timeValue = parentNode.querySelector(".js-time-input").value;
if (timeValue === "") {
timeValue = "00:00:00";
}
parentNode.querySelector(".js-setting-value").value = `${dateValue}T${timeValue}Z`
}
// Listener for the add setting button.
function addSetting(event) {
event.preventDefault();
const row = addRowToTable(newSettingRow());
row.querySelector(".super-settings-key input").focus();
}
// Listener for the edit setting button.
function editSetting(event) {
event.preventDefault();
const id = event.target.closest("tr").dataset.id;
const setting = findSetting(id);
const row = addRowToTable(editSettingRow(setting));
if (row.querySelector(".super-settings-value .js-date-input")) {
row.querySelector(".super-settings-value .js-date-input").focus();
} else {
row.querySelector(".super-settings-value .js-setting-value").focus();
}
}
// Listener for the restore setting button.
function restoreSetting(event) {
event.preventDefault();
const row = event.target.closest("tr");
const id = row.dataset.id;
const setting = findSetting(id);
if (setting) {
const newRow = settingRow(setting);
bindSettingControlEvents(newRow);
row.replaceWith(newRow);
} else {
row.remove();
}
enableSaveButton();
}
// Listener for the remove setting button.
function removeSetting(event) {
event.preventDefault();
const settingRow = event.target.closest("tr");
if (settingRow.dataset["id"]) {
settingRow.querySelector("input.js-setting-deleted").value = "1";
settingRow.dataset.edited = true;
settingRow.dataset.deleted = true;
settingRow.querySelector(".js-remove-setting").style.display = "none";
settingRow.querySelector(".js-restore-setting").style.display = "inline-block";
} else {
settingRow.remove();
}
enableSaveButton();
}
// Update the settings via the API.
function updateSettings(event) {
event.preventDefault();
event.target.disabled = true;
const settingsData = [];
document.querySelectorAll("#settings-table tbody tr[data-edited=true]").forEach(function(row) {
const data = {};
settingsData.push(data);
data.key = row.querySelector(".js-setting-key").value;
const deleted = row.querySelector(".js-setting-deleted");
if (deleted && deleted.value === "1") {
data.deleted = true;
} else {
if (row.querySelector(".js-setting-value")) {
data.value = getSettingEditValue(row);
}
if (row.querySelector(".js-setting-value-type")) {
const valueTypeSelect = row.querySelector(".js-setting-value-type");
data.value_type = valueTypeSelect.options[valueTypeSelect.selectedIndex].value;
}
if (row.querySelector(".super-settings-description textarea")) {
data.description = row.querySelector(".super-settings-description textarea").value;
}
}
});
SuperSettingsAPI.updateSettings({settings: settingsData}, function(results) {
if (results.success) {
fetchActiveSettings();
showFlash("Settings saved", true)
} else {
event.target.disabled = false;
showFlash("Failed to save settings", false)
if (results.errors) {
showValidationErrors(results.errors)
}
}
});
}
// Listener for the filter input field.
function filterListener(event) {
const filter = event.target.value;
filterSettings(filter);
updateFilterURL(filter);
}
// Listener for refresh page button.
function refreshPage(event) {
event.preventDefault();
let url = window.location.href.replace(/\?.*/, "");
const filter = document.querySelector("#filter").value;
if (filter !== "") {
url += "?filter=" + escape(filter);
}
window.location = url;
}
// Attach event listener to one or more elements.
function addListener(elements, event, handler) {
if (elements.addEventListener) {
elements = [elements];
}
elements.forEach(function(element) {
if (element) {
element.addEventListener(event, handler);
}
});
}
// Bind event listeners for setting controls on a setting table row.
function bindSettingControlEvents(parent) {
addListener(parent.querySelectorAll(".js-remove-setting"), "click", removeSetting);
addListener(parent.querySelectorAll(".js-edit-setting"), "click", editSetting);
addListener(parent.querySelectorAll(".js-restore-setting"), "click", restoreSetting);
addListener(parent.querySelectorAll(".js-show-history"), "click", showHistoryModal);
addListener(parent.querySelectorAll(".js-no-op"), "click", noOp);
addListener(parent.querySelectorAll(".js-setting-value-type"), "change", changeSettingType);
addListener(parent.querySelectorAll(".js-date-input"), "change", changeDateTime);
addListener(parent.querySelectorAll(".js-time-input"), "change", changeDateTime);
}
// Initialize the table with all the settings plus any changes from a failed form submission.
function renderSettingsTable(settings) {
const tbody = document.querySelector("#settings-table tbody");
tbody.innerHTML = "";
let count = settings.length;
settings.forEach(function(setting) {
const randomId = "setting" + Math.floor((Math.random() * 0xFFFFFFFFFFFFFF)).toString(16);
setting.id = (setting.id || randomId);
const row = settingRow(setting);
tbody.appendChild(row);
bindSettingControlEvents(row);
});
document.querySelector(".js-settings-count").textContent = `${count} ${count === 1 ? "Setting" : "Settings"}`;
const filter = document.querySelector("#filter");
if (filter) {
filter.dispatchEvent(new Event("input"));
}
}
function promptUnsavedChanges(event) {
if (changesCount() > 0) {
return "Are you sure you want to leave?";
} else {
return undefined;
}
}
// Run the supplied function when the document has been marked ready.
function docReady(fn) {
if (document.readyState === "complete" || document.readyState === "interactive") {
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
function fetchActiveSettings() {
SuperSettingsAPI.fetchSettings(function(settings_hash) {
const settings = settings_hash["settings"];
activeSettings = settings;
renderSettingsTable(settings);
enableSaveButton();
});
}
let activeSettings = [];
docReady(function() {
addListener(document.querySelector("#filter"), "input", filterListener);
addListener(document.querySelector("#add-setting"), "click", addSetting);
addListener(document.querySelector("#discard-changes"), "click", refreshPage);
addListener(document.querySelector("#save-settings"), "click", updateSettings);
addListener(document.querySelector("#modal"), "click", closeModal);
const queryParams = new URLSearchParams(window.location.search);
applyFilter(queryParams.get("filter"));
fetchActiveSettings();
window.onbeforeunload = promptUnsavedChanges;
})
})();