Release v2.2.0
This commit is contained in:
@@ -80,6 +80,37 @@
|
||||
}
|
||||
|
||||
function initAsyncCommandForms() {
|
||||
function getAnnouncementActionState(actionPath) {
|
||||
var isPlay = /\/play$/.test(actionPath);
|
||||
return {
|
||||
nextActionPath: actionPath.replace(/\/(?:play|stop)$/, isPlay ? '/stop' : '/play'),
|
||||
nextLabel: isPlay ? 'Stop' : 'Play',
|
||||
nextIcon: isPlay ? 'bi-stop-fill' : 'bi-play-fill',
|
||||
nextClassName: isPlay ? 'btn-outline-warning' : 'btn-outline-success',
|
||||
nextConfirmMessage: isPlay
|
||||
? 'Stop this announcement on the selected screens now?'
|
||||
: 'Send this announcement to the selected screens now?'
|
||||
};
|
||||
}
|
||||
|
||||
function updateAnnouncementActionButton(form, actionPath) {
|
||||
if (!form) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var state = getAnnouncementActionState(actionPath);
|
||||
var visibleButton = form.querySelector('button[type="submit"]') || (form.id ? document.querySelector('button[form="' + form.id + '"]') : null);
|
||||
if (!visibleButton) {
|
||||
return false;
|
||||
}
|
||||
|
||||
form.action = state.nextActionPath;
|
||||
form.setAttribute('data-confirm-message', state.nextConfirmMessage);
|
||||
visibleButton.className = visibleButton.className.replace(/btn-outline-(success|warning)/g, state.nextClassName);
|
||||
visibleButton.innerHTML = '<i class="bi ' + state.nextIcon + ' me-1" aria-hidden="true"></i>' + state.nextLabel;
|
||||
return true;
|
||||
}
|
||||
|
||||
document.addEventListener('submit', function (event) {
|
||||
var form = event.target;
|
||||
if (!form || !form.hasAttribute || !form.hasAttribute('data-async-command')) {
|
||||
@@ -97,6 +128,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var actionPath = '';
|
||||
try {
|
||||
actionPath = new URL(form.action, window.location.href).pathname;
|
||||
} catch (_error) {
|
||||
actionPath = String(form.action || '');
|
||||
}
|
||||
var shouldReloadAfterSuccess = /^\/announcements\/\d+\/(?:play|stop)$/.test(actionPath);
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
form.dataset.busy = 'true';
|
||||
@@ -116,6 +155,11 @@
|
||||
},
|
||||
body: body.toString(),
|
||||
credentials: 'same-origin'
|
||||
}).then(function (response) {
|
||||
if (shouldReloadAfterSuccess && response && response.ok) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
}).finally(function () {
|
||||
delete form.dataset.busy;
|
||||
});
|
||||
@@ -426,6 +470,52 @@
|
||||
});
|
||||
}
|
||||
|
||||
function renderJsonPrimitive(value) {
|
||||
if (value === null) {
|
||||
return '<span class="text-body-secondary">null</span>';
|
||||
}
|
||||
if (value === true || value === false) {
|
||||
return '<span class="text-success">' + String(value) + '</span>';
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return '<span class="text-info">' + escapeHtml(String(value)) + '</span>';
|
||||
}
|
||||
return '<span class="text-body">"' + escapeHtml(String(value)) + '"</span>';
|
||||
}
|
||||
|
||||
function renderJsonNode(key, value, isRoot) {
|
||||
var isArray = Array.isArray(value);
|
||||
var isObject = value && typeof value === 'object' && !isArray;
|
||||
|
||||
if (!isArray && !isObject) {
|
||||
var primitiveLabel = isRoot ? 'value' : String(key);
|
||||
return '<div class="json-tree-leaf"><span class="json-tree-key">' + escapeHtml(primitiveLabel) + '</span><span class="mx-1">:</span>' + renderJsonPrimitive(value) + '</div>';
|
||||
}
|
||||
|
||||
var entries = isArray
|
||||
? value.map(function (entry, index) {
|
||||
return renderJsonNode('[' + index + ']', entry, false);
|
||||
}).join('')
|
||||
: Object.keys(value).map(function (childKey) {
|
||||
return renderJsonNode(childKey, value[childKey], false);
|
||||
}).join('');
|
||||
|
||||
var summaryLabel = isRoot ? (isArray ? 'Array' : 'Object') : String(key);
|
||||
var summaryMeta = isArray ? '[' + value.length + ']' : '{' + Object.keys(value).length + '}';
|
||||
return '' +
|
||||
'<details class="json-tree-node" open>' +
|
||||
'<summary><span class="json-tree-key">' + escapeHtml(summaryLabel) + '</span><span class="mx-1">:</span><span class="text-body-secondary">' + escapeHtml(summaryMeta) + '</span></summary>' +
|
||||
'<div class="ms-3 ps-3 border-start">' + entries + '</div>' +
|
||||
'</details>';
|
||||
}
|
||||
|
||||
function renderJsonTree(value) {
|
||||
if (Array.isArray(value) || (value && typeof value === 'object')) {
|
||||
return renderJsonNode('', value, true);
|
||||
}
|
||||
return renderJsonNode('value', value, true);
|
||||
}
|
||||
|
||||
function initJsonTogglePanels(root) {
|
||||
var scope = root && root.querySelectorAll ? root : document;
|
||||
var panels = scope.querySelectorAll('[data-json-toggle-panel]');
|
||||
@@ -436,8 +526,8 @@
|
||||
}
|
||||
|
||||
var card = panel.closest ? panel.closest('.card') : null;
|
||||
var button = card ? card.querySelector('[data-json-toggle]') : null;
|
||||
var label = button ? button.querySelector('[data-json-toggle-label]') : null;
|
||||
var collapseButton = card ? card.querySelector('[data-json-toggle-collapse-all]') : null;
|
||||
var expandButton = card ? card.querySelector('[data-json-toggle-expand-all]') : null;
|
||||
var sourceNode = panel.querySelector('[data-json-toggle-source]');
|
||||
var rawJson = '';
|
||||
try {
|
||||
@@ -463,32 +553,47 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var compactJson = JSON.stringify(parsedJson);
|
||||
var formattedJson = JSON.stringify(parsedJson, null, 2);
|
||||
var isFormatted = true;
|
||||
var formattedTree = renderJsonTree(parsedJson);
|
||||
|
||||
function syncButtonLabel() {
|
||||
if (!button || !label) {
|
||||
return;
|
||||
function setAllSectionsExpanded(expanded) {
|
||||
var details = output.querySelectorAll('details');
|
||||
Array.prototype.forEach.call(details, function (detail) {
|
||||
detail.open = expanded;
|
||||
});
|
||||
|
||||
if (collapseButton) {
|
||||
collapseButton.disabled = !details.length || !expanded;
|
||||
}
|
||||
if (expandButton) {
|
||||
expandButton.disabled = !details.length || expanded;
|
||||
}
|
||||
label.textContent = isFormatted
|
||||
? String(button.getAttribute('data-json-toggle-label-compact') || 'Unformat JSON')
|
||||
: String(button.getAttribute('data-json-toggle-label-formatted') || 'Format JSON');
|
||||
button.setAttribute('aria-pressed', isFormatted ? 'true' : 'false');
|
||||
}
|
||||
|
||||
function syncOutput() {
|
||||
output.textContent = isFormatted ? formattedJson : compactJson;
|
||||
syncButtonLabel();
|
||||
function syncButtons() {
|
||||
if (collapseButton) {
|
||||
collapseButton.setAttribute('aria-pressed', 'false');
|
||||
}
|
||||
if (expandButton) {
|
||||
expandButton.setAttribute('aria-pressed', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
output.textContent = formattedJson;
|
||||
syncButtonLabel();
|
||||
output.innerHTML = formattedTree;
|
||||
syncButtons();
|
||||
setAllSectionsExpanded(true);
|
||||
|
||||
if (button) {
|
||||
button.addEventListener('click', function () {
|
||||
isFormatted = !isFormatted;
|
||||
syncOutput();
|
||||
if (collapseButton) {
|
||||
collapseButton.addEventListener('click', function () {
|
||||
setAllSectionsExpanded(false);
|
||||
syncButtons();
|
||||
});
|
||||
}
|
||||
|
||||
if (expandButton) {
|
||||
expandButton.addEventListener('click', function () {
|
||||
setAllSectionsExpanded(true);
|
||||
syncButtons();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user