// Timetable region rendering for live playback. var registry = window.pulsePlayerRegionTypes; function substituteTimetableVariables(html, entry) { var source = String(html || ''); return source.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, function (_match, expression) { if (!entry || typeof entry !== 'object') { return ''; } if (!window.placeholderUtils || typeof window.placeholderUtils.resolvePlaceholderExpression !== 'function' || typeof window.placeholderUtils.formatPlaceholderValue !== 'function') { return ''; } return escapeHtml(window.placeholderUtils.formatPlaceholderValue(window.placeholderUtils.resolvePlaceholderExpression(entry, expression))); }); } function renderTemplate(template, context) { var source = String(template || ''); if (!source) { return ''; } return substituteTimetableVariables(source, context); } function getTimetableGroups() { return Array.isArray(initialData && initialData.timetableGroups) ? initialData.timetableGroups : []; } function getGroupById(groupId, groups) { var normalizedId = Number(groupId || 0); return (Array.isArray(groups) ? groups : getTimetableGroups()).find(function (group) { return Number(group.id) === normalizedId; }) || null; } function getEntries(groupId, groups) { var group = getGroupById(groupId, groups); return group && Array.isArray(group.entries) ? group.entries : []; } function toDate(value) { if (!value) { return null; } var date = value instanceof Date ? value : new Date(value); return Number.isNaN(date.getTime()) ? null : date; } function isUpcoming(entry, now) { var start = toDate(entry && entry.start_datetime); return Boolean(start && now < start); } 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) { var now = new Date(); var entries = getEntries(groupId, groups).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); }); var mode = String(displayMode || 'upcoming').trim().toLowerCase(); entries = entries.filter(function (entry) { if (mode === 'current') { return isLive(entry, now); } if (mode === 'both') { return isUpcoming(entry, now) || isLive(entry, now); } return isUpcoming(entry, now); }); if (!entries.length && mode === 'upcoming') { entries = getEntries(groupId, groups).filter(function (entry) { return isLive(entry, now); }); } return entries.slice(0, Math.max(1, Number(maxItems || 5))); } function formatDateTime(value) { var date = toDate(value); if (!date) { return ''; } try { return new Intl.DateTimeFormat(undefined, { month: 'short', day: '2-digit', hour: 'numeric', minute: '2-digit' }).format(date); } catch (_error) { return date.toLocaleString(); } } function getDefaultStyle() { return { font_family: 'Arial', font_size: 28, font_color: '#000000' }; } function getTextStyle(region, regionContent) { var current = regionContent && typeof regionContent === 'object' ? regionContent : {}; var defaultStyle = getDefaultStyle(); return { font_family: String(current.font_family || region.font_family || defaultStyle.font_family || 'Arial').trim() || 'Arial', font_size: Math.max(8, Number(current.font_size || region.font_size || defaultStyle.font_size || 28)), font_color: String(current.font_color || region.font_color || defaultStyle.font_color || '#000000').trim() || '#000000' }; } function renderRegion(region, regionContent) { var value = String(regionContent && (regionContent.value !== undefined ? regionContent.value : regionContent.text !== undefined ? regionContent.text : '') || '').trim(); var style = getTextStyle(region, regionContent || {}); var groups = getTimetableGroups(); var groupId = regionContent && regionContent.timetable_group_id !== undefined ? regionContent.timetable_group_id : ''; 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 timeZone = group && (group.timezone || group.time_zone) ? String(group.timezone || group.time_zone) : ''; var width = Math.max(1, Math.round(Number(region && region.pixelWidth ? region.pixelWidth : 0) || 1)); var height = Math.max(1, Math.round(Number(region && region.pixelHeight ? region.pixelHeight : 0) || 1)); var canvasScale = Number(region && region.canvasScale ? region.canvasScale : 1) || 1; var contentStyle = 'width:' + width + 'px;height:' + height + 'px;transform:scale(' + canvasScale + ');transform-origin:top left;' + (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) + ';' : ''); if (!value) { return '
'; } return ''; } registry.register('timetable', { renderRegion: renderRegion });