Release v2.15.5
This commit is contained in:
1 parent
0e77998e92
commit
2fd059d35a
18 files changed
+385
-30
No files matched your search
@@ -24,7 +24,7 @@ function normalizeTimeZone(value, fallback) {
|
||||
|
||||
function normalizeDisplayMode(value) {
|
||||
const mode = String(value || 'upcoming').trim().toLowerCase();
|
||||
if (mode === 'current' || mode === 'both') {
|
||||
if (mode === 'current' || mode === 'both' || mode === 'all') {
|
||||
return mode;
|
||||
}
|
||||
return 'upcoming';
|
||||
|
||||
@@ -80,6 +80,9 @@ function getVisibleEntries(groupId, displayMode, maxItems, groups, config) {
|
||||
var mode = String(displayMode || 'upcoming').trim().toLowerCase();
|
||||
|
||||
entries = entries.filter(function (entry) {
|
||||
if (mode === 'all') {
|
||||
return true;
|
||||
}
|
||||
if (mode === 'current') {
|
||||
return isLive(entry, now);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ const {
|
||||
renderEditorJsContent,
|
||||
sanitizeFontFamily,
|
||||
sanitizeFontSize,
|
||||
sanitizeRichText,
|
||||
sanitizeTextColor
|
||||
} = require('#src/player/render-helpers');
|
||||
const { createRequestAuthHeaders, createPageAuthToken } = require('#src/request-auth');
|
||||
@@ -21,6 +22,27 @@ const placeholderUtils = (() => {
|
||||
return sandbox.window.placeholderUtils || {};
|
||||
})();
|
||||
|
||||
const timetableScript = new vm.Script(fs.readFileSync(require.resolve('#src/player/regions/timetable'), 'utf8'));
|
||||
|
||||
function buildTimetableRegionMarkup(region, regionContent, options) {
|
||||
let timetableRenderer;
|
||||
const sandbox = {
|
||||
window: {
|
||||
placeholderUtils: placeholderUtils,
|
||||
pulsePlayerRegionTypes: {
|
||||
register(_type, renderer) { timetableRenderer = renderer; }
|
||||
}
|
||||
},
|
||||
initialData: { timetableGroups: Array.isArray(options && options.timetableGroups) ? options.timetableGroups : [] },
|
||||
escapeHtml: escapeHtml,
|
||||
sanitizeRichText: sanitizeRichText
|
||||
};
|
||||
timetableScript.runInNewContext(sandbox);
|
||||
return timetableRenderer.renderRegion(region, regionContent)
|
||||
.replace('class="template-region timetable"', 'class="slide-preview-region slide-preview-timetable-region"')
|
||||
.replace('class="template-region-text-scale"', 'class="slide-preview-text-content"');
|
||||
}
|
||||
|
||||
const SYSTEM_CHROMIUM_PATHS = [
|
||||
process.env.PUPPETEER_EXECUTABLE_PATH,
|
||||
process.env.CHROMIUM_PATH,
|
||||
@@ -233,6 +255,10 @@ function buildRegionInnerHtml(region, regionContent, baseUrl, options) {
|
||||
const regionType = String(regionContent.type || region.region_type || 'text').trim().toLowerCase();
|
||||
const rawValue = normalizeRenderableValue(regionContent && regionContent.value !== undefined ? regionContent.value : '');
|
||||
|
||||
if (regionType === 'timetable') {
|
||||
return buildTimetableRegionMarkup(region, regionContent, options);
|
||||
}
|
||||
|
||||
if (regionType === 'image') {
|
||||
const src = resolveAssetUrl(baseUrl, rawValue);
|
||||
return src
|
||||
|
||||
@@ -25,9 +25,10 @@ module.exports = function registerErrorPageMiddleware(app, pages) {
|
||||
|
||||
res.send = function (body) {
|
||||
const statusCode = Number(res.statusCode) || 200;
|
||||
const isHtml = typeof body === 'string' && /^\s*</.test(body);
|
||||
const isStringBody = typeof body === 'string';
|
||||
const isHtml = isStringBody && /^\s*</.test(body);
|
||||
|
||||
if (statusCode >= 400 && statusCode < 600 && !isHtml && wantsHtmlErrorPage(req, res)) {
|
||||
if (statusCode >= 400 && statusCode < 600 && isStringBody && !isHtml && wantsHtmlErrorPage(req, res)) {
|
||||
return send.call(res, createErrorPage(pages, req, statusCode, body));
|
||||
}
|
||||
|
||||
|
||||
@@ -188,9 +188,17 @@
|
||||
var previewBox = region.querySelector('.slide-image-region-preview-box');
|
||||
if (previewBox) {
|
||||
var safePath = escapeHtml(path);
|
||||
previewBox.innerHTML = type === 'video'
|
||||
? '<div class="slide-image-region-preview-shell"><video class="slide-image-region-preview" src="' + safePath + '" muted playsinline preload="metadata"></video></div>'
|
||||
: '<div class="slide-image-region-preview-shell"><img class="slide-image-region-preview" src="' + safePath + '" alt="Selected media preview" /></div>';
|
||||
var isVideo = type === 'video';
|
||||
var isQrImage = String(hidden.name || '').indexOf('existing_region_qr_image_') === 0;
|
||||
var mediaLabel = isVideo ? 'video' : isQrImage ? 'QR image' : 'image';
|
||||
var removeAction = isVideo ? 'region-video' : isQrImage ? 'region-qr-image' : 'region-image';
|
||||
var regionId = escapeHtml(region.getAttribute('data-region-id') || '');
|
||||
previewBox.innerHTML = '<div class="slide-image-region-preview-shell" data-remove-' + removeAction + '="' + regionId + '" role="button" tabindex="0" aria-label="Remove ' + mediaLabel + '">' +
|
||||
(isVideo
|
||||
? '<video class="slide-image-region-preview" src="' + safePath + '" muted playsinline preload="metadata"></video>'
|
||||
: '<img class="slide-image-region-preview" src="' + safePath + '" alt="Selected ' + mediaLabel + ' preview" />') +
|
||||
'<span class="slide-image-region-preview-remove" aria-hidden="true"><i class="bi bi-trash3" aria-hidden="true"></i></span>' +
|
||||
'</div>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -139,6 +139,9 @@
|
||||
var mode = String(displayMode || 'upcoming').trim().toLowerCase();
|
||||
|
||||
entries = entries.filter(function (entry) {
|
||||
if (mode === 'all') {
|
||||
return true;
|
||||
}
|
||||
if (mode === 'current') {
|
||||
return isLive(entry, now);
|
||||
}
|
||||
@@ -337,7 +340,8 @@
|
||||
'<select id="region_timetable_display_mode_' + region.id + '" name="region_timetable_display_mode_' + region.id + '" class="form-select">' +
|
||||
'<option value="upcoming"' + (currentDisplayMode === 'upcoming' ? ' selected' : '') + '>Upcoming</option>' +
|
||||
'<option value="current"' + (currentDisplayMode === 'current' ? ' selected' : '') + '>Current</option>' +
|
||||
'<option value="both"' + (currentDisplayMode === 'both' ? ' selected' : '') + '>Both</option>' +
|
||||
'<option value="both"' + (currentDisplayMode === 'both' ? ' selected' : '') + '>Current & Upcoming</option>' +
|
||||
'<option value="all"' + (currentDisplayMode === 'all' ? ' selected' : '') + '>All</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'<div class="col-6 col-lg-2">' +
|
||||
|
||||
@@ -1232,8 +1232,18 @@
|
||||
return Boolean(getRegionLockRatio(card));
|
||||
}
|
||||
|
||||
function syncLockedDimensions(card, changedField) {
|
||||
normalizeRegionCard(card, changedField);
|
||||
function syncLockedDimensions(card, changedField, isEditing) {
|
||||
if (isEditing) {
|
||||
var current = readCard(card);
|
||||
var aspect = parseLockRatio(current.lock_ratio);
|
||||
if (aspect && changedField === 'width' && current.width > 0) {
|
||||
writeCard(card, { height: Math.max(12, Math.round(current.width / aspect.ratio)) });
|
||||
} else if (aspect && changedField === 'height' && current.height > 0) {
|
||||
writeCard(card, { width: Math.max(12, Math.round(current.height * aspect.ratio)) });
|
||||
}
|
||||
} else {
|
||||
normalizeRegionCard(card, changedField);
|
||||
}
|
||||
updateRegionLockBadge(card);
|
||||
markTemplateFormDirty();
|
||||
requestOverlayRender();
|
||||
@@ -1327,9 +1337,6 @@
|
||||
card.dataset.regionKey = String(region.region_key || region.label || getRegionName(card) || '').trim();
|
||||
setRegionRemovalState(card);
|
||||
var nameInput = card.querySelector('[name="region_name[]"]');
|
||||
var lockRatioInput = card.querySelector('[name="region_lock_ratio[]"]');
|
||||
var widthInput = card.querySelector('[name="region_width[]"]');
|
||||
var heightInput = card.querySelector('[name="region_height[]"]');
|
||||
var animationPresetInputs = card.querySelectorAll('[data-animation-preset]');
|
||||
var animationResetButtons = card.querySelectorAll('[data-animation-reset-button]');
|
||||
var animationAdvancedButton = card.querySelector('[data-animation-advanced-button]');
|
||||
@@ -1365,21 +1372,24 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
if (lockRatioInput) {
|
||||
lockRatioInput.addEventListener('input', function () {
|
||||
syncLockedDimensions(card, 'width');
|
||||
['x', 'y', 'z', 'width', 'height', 'lock_ratio'].forEach(function (field) {
|
||||
var input = card.querySelector('[name="region_' + field + '[]"]');
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
var changedField = field === 'lock_ratio' ? 'width' : field;
|
||||
input.addEventListener('input', function () {
|
||||
syncLockedDimensions(card, changedField, true);
|
||||
});
|
||||
}
|
||||
if (widthInput) {
|
||||
widthInput.addEventListener('input', function () {
|
||||
syncLockedDimensions(card, 'width');
|
||||
input.addEventListener('change', function () {
|
||||
syncLockedDimensions(card, changedField);
|
||||
});
|
||||
}
|
||||
if (heightInput) {
|
||||
heightInput.addEventListener('input', function () {
|
||||
syncLockedDimensions(card, 'height');
|
||||
});
|
||||
}
|
||||
});
|
||||
card.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Enter' && event.target && event.target.tagName === 'INPUT') {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
card.addEventListener('click', function (event) {
|
||||
if (event.target && event.target.closest && event.target.closest('[data-region-remove-button]')) {
|
||||
return;
|
||||
|
||||
@@ -81,6 +81,7 @@ module.exports = function registerSlidesRoutes(app, deps) {
|
||||
const apiSources = (apiData.apiSources || []).map(function (source) {
|
||||
return Object.assign({}, source, { responseJson: common.parseJsonSafe ? common.parseJsonSafe(source.last_response_json) : null });
|
||||
});
|
||||
const timetableData = typeof common.fetchTimetablesData === 'function' ? await common.fetchTimetablesData(pool) : { timetableGroups: [] };
|
||||
const weatherData = typeof common.fetchWeatherLocationsData === 'function' ? await common.fetchWeatherLocationsData(pool) : { weatherLocations: [] };
|
||||
const weatherLocations = (weatherData.weatherLocations || []).map(function (location) {
|
||||
const snapshot = common.parseJsonSafe ? common.parseJsonSafe(location.last_response_json) : null;
|
||||
@@ -136,6 +137,7 @@ module.exports = function registerSlidesRoutes(app, deps) {
|
||||
fontStylesheetHref: getFontStylesheetHref(mediaDir),
|
||||
weatherIconSets: require('#src/web/lib/media/weather-icon-library').readWeatherIconSets(mediaDir),
|
||||
apiSources: apiSources,
|
||||
timetableGroups: timetableData.timetableGroups,
|
||||
getItem: getItem,
|
||||
getCachedImagePath: getCachedImagePath
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user