Release v2.15.4
This commit is contained in:
1 parent
64aeb1b47e
commit
05c9341b08
25 files changed
+595
-31
No files matched your search
@@ -98,15 +98,40 @@
|
||||
return Boolean(start && now < start);
|
||||
}
|
||||
|
||||
function toLocalInput(value) {
|
||||
var date = toDate(value);
|
||||
if (!date) {
|
||||
return '';
|
||||
}
|
||||
function pad(part) { return String(part).padStart(2, '0'); }
|
||||
return date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate()) + 'T' + pad(date.getHours()) + ':' + pad(date.getMinutes()) + ':' + pad(date.getSeconds());
|
||||
}
|
||||
|
||||
function getDateRangeConfig(regionId, card, current) {
|
||||
var config = {};
|
||||
['date_filter', 'date_from', 'date_to'].forEach(function (field) {
|
||||
var input = card && card.querySelector ? card.querySelector('[name="region_' + field + '_' + regionId + '"]') : null;
|
||||
config[field] = input ? input.value : current[field] || (field === 'date_filter' ? 'all' : '');
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
function isLive(entry, now) {
|
||||
var start = toDate(entry && entry.start_datetime);
|
||||
var end = toDate(entry && entry.end_datetime);
|
||||
return Boolean(start && end && now >= start && now < end);
|
||||
}
|
||||
|
||||
function getVisibleEntries(groupId, displayMode, maxItems, groups) {
|
||||
function getVisibleEntries(groupId, displayMode, maxItems, groups, config) {
|
||||
var now = new Date();
|
||||
var entries = getEntries(groupId, groups).slice().sort(function (left, right) {
|
||||
var range = config || {};
|
||||
var from = toDate(range.date_filter === 'between' || range.date_filter === 'after' ? range.date_from : '');
|
||||
var to = toDate(range.date_filter === 'between' || range.date_filter === 'before' ? range.date_to : '');
|
||||
var candidates = getEntries(groupId, groups).filter(function (entry) {
|
||||
var start = toDate(entry && entry.start_datetime);
|
||||
return (!from && !to) || Boolean(start && (!from || start >= from) && (!to || start <= to));
|
||||
});
|
||||
var entries = candidates.slice().sort(function (left, right) {
|
||||
var leftStart = toDate(left && left.start_datetime);
|
||||
var rightStart = toDate(right && right.start_datetime);
|
||||
return (leftStart ? leftStart.getTime() : 0) - (rightStart ? rightStart.getTime() : 0) || Number(left.id || 0) - Number(right.id || 0);
|
||||
@@ -124,7 +149,7 @@
|
||||
});
|
||||
|
||||
if (!entries.length && mode === 'upcoming') {
|
||||
entries = getEntries(groupId, groups).filter(function (entry) {
|
||||
entries = candidates.filter(function (entry) {
|
||||
return isLive(entry, now);
|
||||
});
|
||||
}
|
||||
@@ -167,6 +192,9 @@
|
||||
display_mode: String(current.display_mode || current.timetable_display_mode || 'upcoming').trim().toLowerCase() || 'upcoming',
|
||||
value: String(current.text !== undefined ? current.text : current.value !== undefined ? current.value : ''),
|
||||
max_items: Math.max(1, Number(current.max_items || current.timetable_max_items || 5)),
|
||||
date_filter: ['between', 'before', 'after'].includes(current.date_filter) ? current.date_filter : 'all',
|
||||
date_from: current.date_from || '',
|
||||
date_to: current.date_to || '',
|
||||
font_family: current.font_family || region.font_family || getDefaultStyle().font_family,
|
||||
font_size: current.font_size || region.font_size || getDefaultStyle().font_size,
|
||||
font_color: current.font_color || region.font_color || getDefaultStyle().font_color
|
||||
@@ -230,8 +258,9 @@
|
||||
var displayMode = timetableDisplayModeInput ? timetableDisplayModeInput.value : String(current.display_mode || current.timetable_display_mode || 'upcoming').trim().toLowerCase() || 'upcoming';
|
||||
var maxItems = Math.max(1, Number(timetableMaxItemsInput ? timetableMaxItemsInput.value : current.max_items || current.timetable_max_items || 5));
|
||||
var group = getGroupById(groupId, timetableGroups);
|
||||
var entries = getVisibleEntries(groupId, displayMode, maxItems, timetableGroups);
|
||||
if (!entries.length) {
|
||||
var range = getDateRangeConfig(regionId, card, current);
|
||||
var entries = getVisibleEntries(groupId, displayMode, maxItems, timetableGroups, range);
|
||||
if (!entries.length && range.date_filter === 'all') {
|
||||
entries = getEntries(groupId, timetableGroups).slice(0, maxItems);
|
||||
}
|
||||
|
||||
@@ -267,9 +296,10 @@
|
||||
var currentGroupId = current.timetable_group_id === undefined || current.timetable_group_id === null || current.timetable_group_id === '' ? '' : Number(current.timetable_group_id);
|
||||
var currentDisplayMode = String(current.display_mode || current.timetable_display_mode || 'upcoming').trim().toLowerCase() || 'upcoming';
|
||||
var currentMaxItems = Math.max(1, Number(current.max_items || current.timetable_max_items || 5));
|
||||
var dateFilter = ['between', 'before', 'after'].includes(current.date_filter) ? current.date_filter : 'all';
|
||||
var currentGroup = getGroupById(currentGroupId, timetableGroups);
|
||||
var currentEntries = getVisibleEntries(currentGroupId, currentDisplayMode, currentMaxItems, timetableGroups);
|
||||
if (!currentEntries.length) {
|
||||
var currentEntries = getVisibleEntries(currentGroupId, currentDisplayMode, currentMaxItems, timetableGroups, current);
|
||||
if (!currentEntries.length && dateFilter === 'all') {
|
||||
currentEntries = getEntries(currentGroupId, timetableGroups).slice(0, currentMaxItems);
|
||||
}
|
||||
var groupOptions = timetableGroups.map(function (group) {
|
||||
@@ -295,7 +325,7 @@
|
||||
'<input type="hidden" name="region_text_' + region.id + '" value="' + escapeHtml(currentValue) + '" />' +
|
||||
'</div>' +
|
||||
'<div class="row g-3">' +
|
||||
'<div class="col-12 col-lg-6">' +
|
||||
'<div class="col-12 col-lg-4">' +
|
||||
'<label class="form-label" for="region_timetable_group_id_' + region.id + '">Timetable group</label>' +
|
||||
'<select id="region_timetable_group_id_' + region.id + '" name="region_timetable_group_id_' + region.id + '" class="form-select">' +
|
||||
'<option value="">Select a group</option>' +
|
||||
@@ -310,12 +340,34 @@
|
||||
'<option value="both"' + (currentDisplayMode === 'both' ? ' selected' : '') + '>Both</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'<div class="col-6 col-lg-3">' +
|
||||
'<div class="col-6 col-lg-2">' +
|
||||
'<label class="form-label" for="region_timetable_max_items_' + region.id + '">Max items</label>' +
|
||||
'<input id="region_timetable_max_items_' + region.id + '" type="number" min="1" step="1" name="region_timetable_max_items_' + region.id + '" class="form-control" value="' + escapeHtml(currentMaxItems || 5) + '" />' +
|
||||
'</div>' +
|
||||
'<div class="col-12 col-lg-3">' +
|
||||
'<label class="form-label" for="region_date_filter_' + region.id + '">Date filter</label>' +
|
||||
'<select id="region_date_filter_' + region.id + '" name="region_date_filter_' + region.id + '" class="form-select">' +
|
||||
'<option value="all"' + (dateFilter === 'all' ? ' selected' : '') + '>All</option>' +
|
||||
'<option value="between"' + (dateFilter === 'between' ? ' selected' : '') + '>Between Dates</option>' +
|
||||
'<option value="before"' + (dateFilter === 'before' ? ' selected' : '') + '>Before Date</option>' +
|
||||
'<option value="after"' + (dateFilter === 'after' ? ' selected' : '') + '>After Date</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div data-timetable-date-range' + (dateFilter === 'all' ? ' hidden' : '') + '>' +
|
||||
'<div class="row g-3">' +
|
||||
['from', 'to'].map(function (boundary) {
|
||||
var field = 'date_' + boundary;
|
||||
var enabled = dateFilter === 'between' || dateFilter === (boundary === 'from' ? 'after' : 'before');
|
||||
var label = boundary === 'from' ? 'Starts on or after (local time)' : 'Starts on or before (local time)';
|
||||
return '<div class="col-12 col-md-6" data-timetable-boundary' + (!enabled ? ' hidden' : '') + '>' +
|
||||
'<label class="form-label" for="region_' + field + '_' + region.id + '">' + label + '</label>' +
|
||||
'<input id="region_' + field + '_' + region.id + '" type="datetime-local" step="1" class="form-control" data-timetable-date="' + field + '" value="' + escapeHtml(toLocalInput(current[field])) + '"' + (!enabled ? ' disabled' : '') + ' />' +
|
||||
'<input type="hidden" name="region_' + field + '_' + region.id + '" value="' + escapeHtml(current[field] || '') + '" />' +
|
||||
'</div>';
|
||||
}).join('') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="text-body-secondary small">Use the selected group and display mode to choose which timetable entry fields are available.</div>' +
|
||||
'<div class="api-region-placeholder-section schedule-placeholder-section" data-schedule-placeholder-chips>' +
|
||||
'<div class="api-region-placeholder-title api-region-placeholder-title-help d-flex align-items-center gap-2">Available placeholders ' + renderPlaceholderInfo(region.id) + '</div>' +
|
||||
'<div class="d-flex flex-wrap gap-2">' + renderSchedulePlaceholderChips(currentGroup, currentEntries) + '</div>' +
|
||||
@@ -350,24 +402,50 @@
|
||||
panel.innerHTML = renderSchedulePlaceholderChips(current.group, current.entries);
|
||||
}
|
||||
|
||||
function updateDateRange(card) {
|
||||
var regionId = card.getAttribute('data-region-id');
|
||||
var config = getDateRangeConfig(regionId, card, {});
|
||||
var panel = card.querySelector('[data-timetable-date-range]');
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
panel.hidden = config.date_filter === 'all';
|
||||
panel.querySelectorAll('[data-timetable-date]').forEach(function (input) {
|
||||
var field = input.getAttribute('data-timetable-date');
|
||||
var enabled = config.date_filter === 'between' || config.date_filter === (field === 'date_from' ? 'after' : 'before');
|
||||
input.closest('[data-timetable-boundary]').hidden = !enabled;
|
||||
input.disabled = !enabled;
|
||||
var date = toDate(input.value);
|
||||
card.querySelector('[name="region_' + input.getAttribute('data-timetable-date') + '_' + regionId + '"]').value = date ? date.toISOString() : '';
|
||||
});
|
||||
var fromInput = panel.querySelector('[data-timetable-date="date_from"]');
|
||||
var toInput = panel.querySelector('[data-timetable-date="date_to"]');
|
||||
var from = toDate(fromInput.value);
|
||||
var to = toDate(toInput.value);
|
||||
toInput.setCustomValidity(config.date_filter === 'between' && from && to && from > to ? 'The end of the date range must be on or after its start.' : '');
|
||||
}
|
||||
|
||||
if (!window.__scheduleRegionPlaceholderRefreshInstalled) {
|
||||
window.__scheduleRegionPlaceholderRefreshInstalled = true;
|
||||
|
||||
document.addEventListener('change', function (event) {
|
||||
function handleTimetableInput(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('select[name^="region_timetable_group_id_"], select[name^="region_timetable_display_mode_"], input[name^="region_timetable_max_items_"]')) {
|
||||
if (!target.closest('select[name^="region_timetable_group_id_"], select[name^="region_timetable_display_mode_"], input[name^="region_timetable_max_items_"], select[name^="region_date_filter_"], [data-timetable-date]')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var card = target.closest('[data-region-id]');
|
||||
if (card) {
|
||||
updateDateRange(card);
|
||||
updateSchedulePlaceholderPanel(card);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
document.addEventListener('input', handleTimetableInput, true);
|
||||
document.addEventListener('change', handleTimetableInput, true);
|
||||
}
|
||||
|
||||
function buildEditorCardContext(context) {
|
||||
@@ -410,6 +488,7 @@
|
||||
tz_long: timezoneValues.tz_long,
|
||||
timeZone: timezoneValues.tz_long,
|
||||
max_items: timetableMaxItemsInput ? timetableMaxItemsInput.value || current.max_items : current.max_items,
|
||||
...getDateRangeConfig(region.id, card, current),
|
||||
existingContent: existingContent || {},
|
||||
timetableGroups: Array.isArray(timetableGroups) ? timetableGroups : []
|
||||
};
|
||||
@@ -423,7 +502,7 @@
|
||||
var displayMode = regionContent && regionContent.display_mode ? regionContent.display_mode : 'upcoming';
|
||||
var maxItems = regionContent && regionContent.max_items !== undefined ? regionContent.max_items : 5;
|
||||
var group = getGroupById(groupId, groups);
|
||||
var entries = getVisibleEntries(groupId, displayMode, maxItems, groups);
|
||||
var entries = getVisibleEntries(groupId, displayMode, maxItems, groups, regionContent);
|
||||
|
||||
if (!value) {
|
||||
return '<div class="slide-preview-region timetable" style="width:100%;height:100%;overflow:hidden;' + (style.font_family ? 'font-family:' + escapeHtml(style.font_family) + ';' : '') + (style.font_size ? 'font-size:' + Math.max(1, Math.round(Number(style.font_size))) + 'px;' : '') + (style.font_color ? 'color:' + escapeHtml(style.font_color) + ';' : '') + '"></div>';
|
||||
|
||||
Reference in new issue
Block a user