Release v2.14.1
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m53s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 32s

This commit is contained in:
lzstealth committed 2026-10-11 18:54:43 +01:00
1 parent 635e1a9942
commit c3299abaac
174 files changed
+4483 -1687

No files matched your search

+1 -21
View File
@@ -112,28 +112,8 @@ function getApiPreviewFallback(item) {
return summary.join('');
}
function normalizeRenderableValue(value) {
if (value && typeof value === 'object') {
if (value.value !== undefined) {
return value.value;
}
if (value.text !== undefined) {
return value.text;
}
if (value.html !== undefined) {
return value.html;
}
try {
return JSON.stringify(value);
} catch (_error) {
return '';
}
}
return value;
}
function renderApiRegion(region, regionContent) {
var content = normalizeRenderableValue(regionContent && regionContent.value !== undefined ? regionContent.value : '');
var content = window.pulsePlayerRenderingShared.normalizeRegionValue(regionContent && regionContent.value !== undefined ? regionContent.value : '', ['value', 'text', 'html']);
var sourceId = regionContent && regionContent.source_id !== undefined ? regionContent.source_id : null;
var itemNumber = regionContent && regionContent.item_number !== undefined ? regionContent.item_number : 1;
var itemsPath = regionContent && regionContent.items_path !== undefined ? regionContent.items_path : '';
+55
View File
@@ -0,0 +1,55 @@
// Chart region rendering and lifecycle management.
var registry = window.pulsePlayerRegionTypes;
var chartInstances = [];
function getChartData(regionContent) {
var sources = Array.isArray(window.initialData && window.initialData.apiSources) ? window.initialData.apiSources : [];
return window.pulseChartData.fromContent(regionContent || {}, sources);
}
function renderChartRegion(region, regionContent) {
var canvasId = 'player-chart-' + String(region && (region.regionKey || region.label) || '').replace(/[^a-zA-Z0-9_-]/g, '-');
var chartJson = escapeHtml(JSON.stringify(regionContent || {}));
return '<div class="template-region chart" style="' + region.baseStyle + 'position:relative;background:transparent;"><canvas id="' + canvasId + '" data-chart-json="' + chartJson + '" aria-label="Chart" style="width:100%;height:100%;display:block;background:transparent;"></canvas></div>';
}
function initChartRegions(root) {
if (typeof window.Chart !== 'function' || !window.pulseChartData || !root || !root.querySelectorAll) {
return;
}
root.querySelectorAll('.template-region.chart canvas').forEach(function (canvas) {
var region = canvas.parentElement;
var regionKey = region && region.getAttribute('data-region-key');
var content = {};
try {
content = JSON.parse(canvas.getAttribute('data-chart-json') || '{}');
} catch (_error) {
content = {};
}
var chartData = getChartData(content);
var chart = new window.Chart(canvas.getContext('2d'), {
type: chartData.type,
data: { labels: chartData.labels, datasets: chartData.datasets },
options: window.pulseChartData.getChartOptions(chartData)
});
chartInstances.push({ canvas: canvas, chart: chart, regionKey: regionKey });
});
}
function destroyChartRegions(root) {
chartInstances = chartInstances.filter(function (entry) {
if (!entry || !entry.canvas || !root || !root.contains(entry.canvas)) {
return true;
}
entry.chart.destroy();
return false;
});
}
registry.register('chart', {
renderRegion: renderChartRegion,
initRegion: initChartRegions,
destroyRegion: destroyChartRegions
});
+2 -35
View File
@@ -2,46 +2,13 @@
var registry = window.pulsePlayerRegionTypes;
function normalizeRenderableValue(value) {
if (value && typeof value === 'object') {
if (value.value !== undefined) {
return normalizeRenderableValue(value.value);
}
if (value.text !== undefined) {
return normalizeRenderableValue(value.text);
}
if (value.html !== undefined) {
return normalizeRenderableValue(value.html);
}
if (value.content !== undefined) {
return normalizeRenderableValue(value.content);
}
return '';
}
return String(value === undefined || value === null ? '' : value);
}
function buildHtmlDocument(html) {
var raw = String(html || '').trim();
if (!raw) {
return '';
}
if (/^<!doctype\b/i.test(raw) || /^<html\b/i.test(raw)) {
return raw;
}
return '<!doctype html><html><head><style>html,body{margin:0;width:100%;height:100%;overflow:hidden;background:transparent;}html,body{background:transparent !important;}</style></head><body>' + raw + '</body></html>';
}
function renderHtmlRegionContent(value) {
var html = normalizeRenderableValue(value).trim();
var html = window.pulsePlayerRenderingShared.normalizeRenderableString(value, ['value', 'text', 'html', 'content']).trim();
if (!html) {
return '';
}
if (/^<!doctype\b/i.test(html) || /^<html\b/i.test(html)) {
return '<iframe class="template-region-html-frame" sandbox="" allowtransparency="true" scrolling="no" srcdoc="' + escapeHtml(html) + '" title="HTML region" loading="eager" style="width:100%;height:100%;border:0;display:block;background:transparent;overflow:hidden;"></iframe>';
return '<iframe class="template-region-html-frame" sandbox="" allowtransparency="true" scrolling="no" srcdoc="' + escapeHtml(window.pulsePlayerRenderingShared.buildHtmlDocument(html, true)) + '" title="HTML region" loading="eager" style="width:100%;height:100%;border:0;display:block;background:transparent;overflow:hidden;"></iframe>';
}
return '<div class="template-region-html-content" style="width:100%;height:100%;overflow:hidden;background:transparent;">' + html + '</div>';
}
+1 -1
View File
@@ -3,7 +3,7 @@
var registry = window.pulsePlayerRegionTypes;
function renderImageRegion(region, regionContent) {
var src = regionContent.value || '';
var src = selectPlayerMediaSource(regionContent.value || '', regionContent.media_variants, Math.max(region.canvasWidth || 0, region.canvasHeight || 0));
if (!String(src || '').trim()) {
return '';
}
+1 -21
View File
@@ -11,26 +11,6 @@ function getDefaultStyle() {
};
}
function normalizeRenderableValue(value) {
if (value && typeof value === 'object') {
if (value.value !== undefined) {
return value.value;
}
if (value.text !== undefined) {
return value.text;
}
if (value.html !== undefined) {
return value.html;
}
try {
return JSON.stringify(value);
} catch (_error) {
return '';
}
}
return value;
}
function getRssFeedById(feedId) {
var feeds = Array.isArray(initialData && initialData.rssFeeds) ? initialData.rssFeeds : [];
var normalizedId = Number(feedId || 0);
@@ -99,7 +79,7 @@ function substituteRssVariables(html, item, feedId) {
}
function renderRssRegion(region, regionContent) {
var content = normalizeRenderableValue(regionContent && regionContent.value !== undefined ? regionContent.value : '');
var content = window.pulsePlayerRenderingShared.normalizeRegionValue(regionContent && regionContent.value !== undefined ? regionContent.value : '', ['value', 'text', 'html']);
var feedId = regionContent && regionContent.feed_id !== undefined ? regionContent.feed_id : null;
var itemNumber = regionContent && regionContent.item_number !== undefined ? regionContent.item_number : 1;
var defaultStyle = getDefaultStyle();
+1 -21
View File
@@ -10,28 +10,8 @@ function getDefaultStyle() {
};
}
function normalizeRenderableValue(value) {
if (value && typeof value === 'object') {
if (value.value !== undefined) {
return value.value;
}
if (value.text !== undefined) {
return value.text;
}
if (value.html !== undefined) {
return value.html;
}
try {
return JSON.stringify(value);
} catch (_error) {
return '';
}
}
return value;
}
function renderTextRegion(region, regionContent) {
var rawValue = normalizeRenderableValue(regionContent && regionContent.value !== undefined ? regionContent.value : '');
var rawValue = window.pulsePlayerRenderingShared.normalizeRegionValue(regionContent && regionContent.value !== undefined ? regionContent.value : '', ['value', 'text', 'html']);
if (!String(rawValue || '').trim()) {
return '';
}
+5 -1
View File
@@ -1,5 +1,6 @@
// Video region playback, retry, and source probe helpers.
// These page-lifetime caches retain fallback sources while mirrored replacements are probed.
var videoRegionLastGoodSrcCache = Object.create(null);
var videoRegionProbeStateCache = Object.create(null);
var videoRegionProbeTimerCache = Object.create(null);
@@ -10,6 +11,7 @@ function getVideoRegionCacheKey(region) {
}
function isDirectlyRenderableSource(src) {
// URL-shaped sources go directly to the browser; this bypass is not a readiness check.
return /^(?:https?:)?\/\//i.test(src) || /^data:/i.test(src) || /^blob:/i.test(src) || /^\/media\//i.test(src);
}
@@ -67,6 +69,7 @@ function scheduleVideoSourceProbe(regionKey, src, isRetry) {
return;
}
// Regions sharing a source also share its pending probe, avoiding duplicate HEAD requests.
if (videoRegionProbeTimerCache[key]) {
return;
}
@@ -106,7 +109,7 @@ function scheduleVideoSourceProbe(regionKey, src, isRetry) {
}
function renderVideoRegion(region, regionContent) {
var requestedSrc = String(regionContent && regionContent.value || '').trim();
var requestedSrc = selectPlayerMediaSource(regionContent && regionContent.value || '', regionContent && regionContent.media_variants, Math.max(region.canvasWidth || 0, region.canvasHeight || 0));
var requestedSrcVersioned = appendCacheBust(requestedSrc, regionContent && regionContent.cache_bust);
var regionKey = getVideoRegionCacheKey(region);
var cachedSrc = regionKey ? String(videoRegionLastGoodSrcCache[regionKey] || '').trim() : '';
@@ -139,6 +142,7 @@ function renderVideoRegion(region, regionContent) {
scheduleVideoSourceProbe(regionKey, requestedSrc, false);
// Keep the previous source visible while the requested mirrored file is unavailable.
if (cachedSrc) {
if (cachedSrc !== requestedSrc) {
logVideoRegionStatus('Keeping the previous playable video until the new mirrored file finishes transferring.', 'region=' + regionKey + ' old=' + cachedSrc + ' new=' + requestedSrc);
+1 -27
View File
@@ -2,34 +2,8 @@
var registry = window.pulsePlayerRegionTypes;
function normalizeRenderableValue(value) {
if (value && typeof value === 'object') {
if (value.value !== undefined) {
return normalizeRenderableValue(value.value);
}
if (value.text !== undefined) {
return normalizeRenderableValue(value.text);
}
if (value.url !== undefined) {
return normalizeRenderableValue(value.url);
}
if (value.href !== undefined) {
return normalizeRenderableValue(value.href);
}
if (value.src !== undefined) {
return normalizeRenderableValue(value.src);
}
if (value.content !== undefined) {
return normalizeRenderableValue(value.content);
}
return '';
}
return String(value === undefined || value === null ? '' : value);
}
function renderWebpageRegion(region, regionContent) {
var url = normalizeRenderableValue(regionContent && regionContent.value !== undefined ? regionContent.value : '').trim();
var url = window.pulsePlayerRenderingShared.normalizeRenderableString(regionContent && regionContent.value !== undefined ? regionContent.value : '', ['value', 'text', 'url', 'href', 'src', 'content']).trim();
if (!url) {
return '';
}