Release v2.5.3

This commit is contained in:
2026-08-03 20:04:43 +01:00
parent 9d5029eff6
commit a5e8ecb21f
8 changed files with 106 additions and 11 deletions
+11 -1
View File
@@ -210,6 +210,15 @@
return savedMessage;
}
function parseAsyncSaveErrorMessage(responseText) {
var errorMessage = parseAsyncSaveResponseMessage(responseText);
if (errorMessage) {
return errorMessage;
}
return String(responseText || '').trim();
}
function getAsyncSaveActionField(form) {
if (!form || !form.querySelector) {
return null;
@@ -302,7 +311,8 @@
});
if (!response.ok) {
throw new Error(await response.text() || (settings.errorMessage || 'Unable to save changes.'));
var responseText = await response.text();
throw new Error(parseAsyncSaveErrorMessage(responseText) || (settings.errorMessage || 'Unable to save changes.'));
}
if (isLoginRedirect(response)) {
@@ -478,9 +478,18 @@
});
}
function closeScheduleModal() {
function closeScheduleModal(options) {
var dialog = document.getElementById('slide-schedule-dialog');
var content = document.getElementById('slide-schedule-content');
var shouldDiscardDraft = Boolean(options && options.discardDraft);
var shouldPreserveChanges = Boolean(options && options.preserveChanges);
if (shouldDiscardDraft && !shouldPreserveChanges && typeof window.restorePlaylistScheduleDraft === 'function') {
window.restorePlaylistScheduleDraft();
}
if (shouldDiscardDraft && typeof window.clearPlaylistScheduleDraft === 'function') {
window.clearPlaylistScheduleDraft();
}
if (content) {
content.innerHTML = '';
@@ -629,6 +638,7 @@
var isDraftMode = Boolean(form.getAttribute('data-schedule-draft') === 'true');
var rowKeyInput = form.querySelector('[name="row_key"]');
var draftStore = window.__playlistScheduleDraftStore = window.__playlistScheduleDraftStore || {};
var draftSnapshotStore = window.__playlistScheduleDraftSnapshotStore = window.__playlistScheduleDraftSnapshotStore || {};
var cancelButton = scope.querySelector('[data-schedule-cancel]');
// Draft state is keyed by the row being edited so cancel/save can restore it later.
@@ -659,6 +669,41 @@
};
}
function captureScheduleDraftState() {
return getRuleCards().map(function (card) {
return {
rule: readRuleDraftFromCard(card),
isCollapsed: Boolean(card && card.classList && card.classList.contains('collapsed-card'))
};
});
}
function renderScheduleDraftState(ruleStates) {
var states = Array.isArray(ruleStates) ? ruleStates : [];
scheduleRuleList.innerHTML = '';
states.forEach(function (ruleState, index) {
var card = createRuleCardElement(ruleState && ruleState.rule ? ruleState.rule : {}, index + 1, { isCollapsed: Boolean(ruleState && ruleState.isCollapsed) });
if (card) {
scheduleRuleList.appendChild(card);
}
});
refreshRuleNumbers();
syncScheduleRulesField();
}
function restoreScheduleDraft() {
var draftKey = getScheduleDraftKey();
var snapshot = draftKey && Object.prototype.hasOwnProperty.call(draftSnapshotStore, draftKey) ? draftSnapshotStore[draftKey] : null;
if (!draftKey || !Array.isArray(snapshot)) {
return;
}
renderScheduleDraftState(snapshot);
}
function getScheduleDraftRules() {
var draftKey = getScheduleDraftKey();
if (!draftKey || !Object.prototype.hasOwnProperty.call(draftStore, draftKey)) {
@@ -687,9 +732,18 @@
if (draftKey && Object.prototype.hasOwnProperty.call(draftStore, draftKey)) {
delete draftStore[draftKey];
}
if (draftKey && Object.prototype.hasOwnProperty.call(draftSnapshotStore, draftKey)) {
delete draftSnapshotStore[draftKey];
}
}
window.clearPlaylistScheduleDraft = clearScheduleDraft;
window.restorePlaylistScheduleDraft = restoreScheduleDraft;
var draftKey = getScheduleDraftKey();
if (draftKey && !Object.prototype.hasOwnProperty.call(draftSnapshotStore, draftKey)) {
draftSnapshotStore[draftKey] = captureScheduleDraftState();
}
function getRuleCards() {
return Array.prototype.slice.call(scheduleRuleList.querySelectorAll('[data-schedule-rule-card]'));
@@ -1047,11 +1101,7 @@
var draftRules = getScheduleDraftRules();
if (draftRules !== null) {
scheduleRuleList.innerHTML = '';
draftRules.forEach(function (rule) {
addRule(rule && rule.rule ? rule.rule : {}, { isCollapsed: Boolean(rule && rule.isCollapsed) });
});
syncScheduleRulesField();
renderScheduleDraftState(draftRules);
} else if (!getRuleCards().length) {
syncScheduleRulesField();
} else {
+6 -2
View File
@@ -434,8 +434,12 @@ import { createSlideFormPreviewHelpers } from '/assets/js/slides/slide-form-prev
};
}
function buildPreviewPopupHash() {
return encodeURIComponent(JSON.stringify(buildPreviewPopupPayload()));
}
function buildPreviewPopupUrl() {
return '/slides/popup-preview#' + encodeURIComponent(JSON.stringify(buildPreviewPopupPayload()));
return '/slides/popup-preview#' + buildPreviewPopupHash();
}
function syncPopupPreview() {
@@ -444,7 +448,7 @@ import { createSlideFormPreviewHelpers } from '/assets/js/slides/slide-form-prev
return;
}
previewPopupWindow = window.open(buildPreviewPopupUrl(), 'slide-preview-popup', previewPopupFeatures);
previewPopupWindow.location.hash = buildPreviewPopupHash();
}
function openPreviewPopup() {
@@ -52,6 +52,7 @@ function buildUsersEditViewModel(user, message, currentUser, roles) {
footerCancelUrl: '/users',
footerDeleteUrl: '/users/' + user.id + '/delete',
footerDeleteDisabled: Boolean(user && user.inUse),
footerDeleteConfirmMessage: 'Delete this user?',
footerDeleteTitle: user && user.inUse ? 'Delete is disabled while this user is the only account left.' : '',
footerShowDelete: true,
message: message,
+1 -1
View File
@@ -26,7 +26,7 @@
</div>
<div class="card-footer d-flex justify-content-end">
<div class="btn-group" role="group" aria-label="{{#if isEdit}}Profile actions{{else}}User actions{{/if}}">
{{{saveActionButtons formId=formId saveUrl=footerSaveUrl cancelUrl=footerCancelUrl deleteUrl=footerDeleteUrl deleteDisabled=footerDeleteDisabled deleteTitle=footerDeleteTitle showSaveAndClose=false showSaveAndNew=false showDelete=footerShowDelete}}}
{{{saveActionButtons formId=formId saveUrl=footerSaveUrl cancelUrl=footerCancelUrl deleteUrl=footerDeleteUrl deleteConfirmMessage=footerDeleteConfirmMessage deleteDisabled=footerDeleteDisabled deleteTitle=footerDeleteTitle showSaveAndClose=false showSaveAndNew=false showDelete=footerShowDelete}}}
</div>
</div>
</div>