Add onboarding weather and template gradients
This commit is contained in:
1 parent
aa07a78912
commit
3960931ebe
80 files changed
+12750
-519
No files matched your search
@@ -440,6 +440,34 @@ function isEditableTarget(target) {
|
||||
return ['INPUT', 'TEXTAREA', 'SELECT', 'OPTION'].indexOf(tagName) !== -1;
|
||||
}
|
||||
|
||||
var keyboardFeedbackTimer = null;
|
||||
|
||||
function showKeyboardFeedback(message) {
|
||||
if (typeof document === 'undefined' || !document.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
var feedback = document.querySelector('.player-keyboard-feedback');
|
||||
if (!feedback) {
|
||||
feedback = document.createElement('div');
|
||||
feedback.className = 'player-keyboard-feedback';
|
||||
feedback.setAttribute('aria-live', 'polite');
|
||||
document.body.appendChild(feedback);
|
||||
}
|
||||
|
||||
feedback.textContent = String(message || '');
|
||||
feedback.classList.remove('is-visible');
|
||||
void feedback.offsetWidth;
|
||||
feedback.classList.add('is-visible');
|
||||
if (keyboardFeedbackTimer) {
|
||||
window.clearTimeout(keyboardFeedbackTimer);
|
||||
}
|
||||
keyboardFeedbackTimer = window.setTimeout(function () {
|
||||
feedback.classList.remove('is-visible');
|
||||
keyboardFeedbackTimer = null;
|
||||
}, 900);
|
||||
}
|
||||
|
||||
function handlePlayerKeydown(event) {
|
||||
if (!event || event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {
|
||||
return;
|
||||
@@ -452,12 +480,28 @@ function handlePlayerKeydown(event) {
|
||||
if (event.key === 'ArrowLeft') {
|
||||
event.preventDefault();
|
||||
navigateSlides(-1);
|
||||
showKeyboardFeedback('Previous slide');
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === 'ArrowRight') {
|
||||
event.preventDefault();
|
||||
navigateSlides(1);
|
||||
showKeyboardFeedback('Next slide');
|
||||
return;
|
||||
}
|
||||
|
||||
if (String(event.key || '').toLowerCase() === 'p') {
|
||||
event.preventDefault();
|
||||
setPaused(!isPaused);
|
||||
showKeyboardFeedback(isPaused ? 'Paused' : 'Playing');
|
||||
return;
|
||||
}
|
||||
|
||||
if (String(event.key || '').toLowerCase() === 'b') {
|
||||
event.preventDefault();
|
||||
setBlackout(!isBlackout);
|
||||
showKeyboardFeedback(isBlackout ? 'Blackout on' : 'Blackout off');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,6 +533,10 @@ function handleCommandMessage(rawMessage) {
|
||||
} catch (_error) {
|
||||
return;
|
||||
}
|
||||
if (payload && payload.type === 'client-id-conflict') {
|
||||
handleClientIdConflict();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload || payload.type !== 'command') {
|
||||
return;
|
||||
@@ -505,7 +553,17 @@ function handleCommandMessage(rawMessage) {
|
||||
return;
|
||||
case 'redirect':
|
||||
if (payload.url) {
|
||||
window.location.replace(String(payload.url));
|
||||
var redirectUrl = String(payload.url);
|
||||
var authorizeMove = payload.moveToken
|
||||
? fetch('/api/screen-move-authorize', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
||||
body: JSON.stringify({ moveToken: String(payload.moveToken) })
|
||||
})
|
||||
: Promise.resolve();
|
||||
authorizeMove.finally(function () {
|
||||
window.location.replace(redirectUrl);
|
||||
});
|
||||
}
|
||||
return;
|
||||
case 'pause':
|
||||
@@ -541,6 +599,13 @@ function handleCommandMessage(rawMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleClientIdConflict() {
|
||||
var replacementClientId = regenerateCommandClientId();
|
||||
var onboardingUrl = new URL('/', window.location.origin);
|
||||
onboardingUrl.searchParams.set('clientId', replacementClientId);
|
||||
window.location.replace(onboardingUrl.toString());
|
||||
}
|
||||
|
||||
// Retry the command websocket after a disconnect.
|
||||
function scheduleCommandReconnect() {
|
||||
if (commandReconnectTimer) {
|
||||
@@ -577,8 +642,12 @@ function connectCommandSocket() {
|
||||
handleCommandMessage(event.data);
|
||||
};
|
||||
|
||||
socket.onclose = function () {
|
||||
socket.onclose = function (event) {
|
||||
commandSocket = null;
|
||||
if (event && event.code === 4009) {
|
||||
handleClientIdConflict();
|
||||
return;
|
||||
}
|
||||
scheduleCommandReconnect();
|
||||
};
|
||||
|
||||
|
||||
@@ -156,6 +156,9 @@ function refresh() {
|
||||
if (window.__pulsePageAuthToken) {
|
||||
request.setRequestHeader('x-pulse-page-auth', window.__pulsePageAuthToken);
|
||||
}
|
||||
if (typeof getCommandClientId === 'function') {
|
||||
request.setRequestHeader('x-pulse-client-id', getCommandClientId());
|
||||
}
|
||||
if (currentPlaylistEtag) {
|
||||
request.setRequestHeader('If-None-Match', currentPlaylistEtag);
|
||||
}
|
||||
@@ -172,6 +175,10 @@ function refresh() {
|
||||
return;
|
||||
}
|
||||
if (request.status < 200 || request.status >= 300) {
|
||||
if (request.status === 401 || request.status === 403) {
|
||||
window.location.replace('/');
|
||||
return;
|
||||
}
|
||||
setOfflineBannerVisible(true);
|
||||
scheduleRefreshRetry();
|
||||
logDebug(
|
||||
@@ -189,16 +196,21 @@ function refresh() {
|
||||
const nextActiveSlides = getActiveSlidesFrom(nextSlides);
|
||||
const nextFadeBetweenSlides = Boolean(data && data.playlist && data.playlist.fade_between_slides);
|
||||
const nextSkipUnavailableRtmp = Boolean(data && data.playlist && data.playlist.skip_unavailable_rtmp);
|
||||
if (window.initialData && typeof window.initialData === 'object') {
|
||||
window.initialData.screen = data.screen || window.initialData.screen || null;
|
||||
window.initialData.playlist = data.playlist || null;
|
||||
window.initialData.slides = nextSlides;
|
||||
window.initialData.rssFeeds = Array.isArray(data.rssFeeds) ? data.rssFeeds : [];
|
||||
window.initialData.apiSources = Array.isArray(data.apiSources) ? data.apiSources : [];
|
||||
window.initialData.timetableGroups = Array.isArray(data.timetableGroups) ? data.timetableGroups : [];
|
||||
window.initialData.weatherLocations = Array.isArray(data.weatherLocations) ? data.weatherLocations : [];
|
||||
window.initialData.revision = nextSignature;
|
||||
var refreshedInitialData = Object.assign({},
|
||||
typeof initialData !== 'undefined' && initialData ? initialData : (window.initialData || {}), {
|
||||
screen: data.screen || null,
|
||||
playlist: data.playlist || null,
|
||||
slides: nextSlides,
|
||||
rssFeeds: Array.isArray(data.rssFeeds) ? data.rssFeeds : [],
|
||||
apiSources: Array.isArray(data.apiSources) ? data.apiSources : [],
|
||||
timetableGroups: Array.isArray(data.timetableGroups) ? data.timetableGroups : [],
|
||||
weatherLocations: Array.isArray(data.weatherLocations) ? data.weatherLocations : [],
|
||||
revision: nextSignature
|
||||
});
|
||||
if (typeof initialData !== 'undefined') {
|
||||
initialData = refreshedInitialData;
|
||||
}
|
||||
window.initialData = refreshedInitialData;
|
||||
savePlaylistSnapshot({
|
||||
slides: nextSlides,
|
||||
signature: nextSignature,
|
||||
|
||||
@@ -211,6 +211,16 @@ function getCommandClientId() {
|
||||
return commandClientId;
|
||||
}
|
||||
|
||||
function regenerateCommandClientId() {
|
||||
commandClientId = null;
|
||||
try {
|
||||
window.sessionStorage.removeItem(commandClientStorageKey);
|
||||
} catch (_error) {
|
||||
// ignore storage errors
|
||||
}
|
||||
return getCommandClientId();
|
||||
}
|
||||
|
||||
// Load the most recent playlist snapshot from browser storage.
|
||||
function loadPlaylistSnapshot() {
|
||||
try {
|
||||
|
||||
@@ -782,6 +782,7 @@ function getTemplateLayout(template) {
|
||||
canvasHeight: canvasSize.height,
|
||||
background: template.background_image_path ? '<img class="template-background" src="' + escapeHtml(template.background_image_path) + '" alt="" />' : '',
|
||||
backgroundColor: template.background_color || '#111111',
|
||||
backgroundGradient: template.background_gradient || '',
|
||||
regions: regions
|
||||
};
|
||||
|
||||
@@ -790,17 +791,31 @@ function getTemplateLayout(template) {
|
||||
}
|
||||
|
||||
// Build a dark backdrop style for template and media canvases.
|
||||
function buildBackdropStyle(backgroundColor, backgroundImagePath) {
|
||||
function buildBackdropStyle(backgroundColor, backgroundImagePath, backgroundGradient) {
|
||||
var color = String(backgroundColor || '#111111').trim() || '#111111';
|
||||
var style = 'background-color:' + escapeHtml(color) + ';';
|
||||
var gradient = '';
|
||||
try {
|
||||
var gradientData = typeof backgroundGradient === 'string' ? JSON.parse(backgroundGradient) : backgroundGradient;
|
||||
if (gradientData && gradientData.type === 'linear' && Array.isArray(gradientData.colors) && gradientData.colors.length >= 2) {
|
||||
var stops = Array.isArray(gradientData.stops) ? gradientData.stops : (gradientData.colors || []).map(function (color, index, colors) { return { color: color, position: colors.length > 1 ? Math.round(index * 100 / (colors.length - 1)) : 0 }; });
|
||||
stops = stops.filter(function (stop) { return stop && /^#[0-9a-fA-F]{3,8}$/.test(String(stop.color || '').trim()); }).slice(0, 12);
|
||||
if (stops.length >= 2) {
|
||||
var angle = Number(gradientData.angle);
|
||||
gradient = 'linear-gradient(' + (Number.isFinite(angle) ? Math.max(0, Math.min(360, angle)) : 90) + 'deg,' + stops.map(function (stop) { return stop.color + ' ' + Math.max(0, Math.min(100, Number(stop.position) || 0)) + '%'; }).join(',') + ')';
|
||||
}
|
||||
}
|
||||
} catch (_error) {
|
||||
gradient = '';
|
||||
}
|
||||
|
||||
if (backgroundImagePath) {
|
||||
style += 'background-image:url("' + escapeHtml(backgroundImagePath) + '");';
|
||||
style += 'background-position:center;background-size:contain;background-repeat:no-repeat;';
|
||||
style += 'background-image:url("' + escapeHtml(backgroundImagePath) + '")' + (gradient ? ',' + gradient : '') + ';';
|
||||
style += 'background-position:center,center;background-size:contain,cover;background-repeat:no-repeat,no-repeat;';
|
||||
return style;
|
||||
}
|
||||
|
||||
style += 'background-image:none;background-position:center;background-size:cover;background-repeat:no-repeat;';
|
||||
style += 'background-image:' + (gradient || 'none') + ';background-position:center;background-size:cover;background-repeat:no-repeat;';
|
||||
return style;
|
||||
}
|
||||
|
||||
@@ -876,7 +891,7 @@ function renderTemplateSlideMarkup(slide) {
|
||||
animationConfig: normalizePlayerAnimationConfig(region.animationJson)
|
||||
});
|
||||
}).join('') : '';
|
||||
const stageStyle = layout ? buildBackdropStyle(layout.backgroundColor || '#111111', template.background_image_path) : '';
|
||||
const stageStyle = layout ? buildBackdropStyle(layout.backgroundColor || '#111111', template.background_image_path, layout.backgroundGradient) : '';
|
||||
if (layout) {
|
||||
setPlayerCanvasDimensions(layout.canvasWidth, layout.canvasHeight);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user