// Schedule region rendering for live playback. var registry = window.pulsePlayerRegionTypes; function escapeHtml(value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function sanitizeRichTextAttributes(tagName, attrText) { var allowedAttributes = { a: ['href', 'title', 'target', 'rel', 'class', 'style'], blockquote: ['class', 'style'], col: ['class', 'style', 'span', 'width'], colgroup: ['class', 'style', 'span'], div: ['class', 'style'], figure: ['class', 'style'], figcaption: ['class', 'style'], h1: ['class', 'style'], h2: ['class', 'style'], h3: ['class', 'style'], h4: ['class', 'style'], h5: ['class', 'style'], h6: ['class', 'style'], li: ['class', 'style'], ol: ['class', 'style', 'start'], p: ['class', 'style'], pre: ['class', 'style'], span: ['class', 'style'], table: ['class', 'style'], tbody: ['class', 'style'], td: ['class', 'style', 'colspan', 'rowspan'], th: ['class', 'style', 'colspan', 'rowspan', 'scope'], thead: ['class', 'style'], tr: ['class', 'style'], ul: ['class', 'style'] }; var allowed = allowedAttributes[tagName] || []; if (!allowed.length) { return ''; } var attrs = []; String(attrText || '').replace(/([a-zA-Z0-9:-]+)(?:\s*=\s*("([^"]*)"|'([^']*)'|([^\s"'>/=`]+)))?/g, function (_full, key, _valuePart, doubleQuoted, singleQuoted, bareValue) { var lowerKey = String(key || '').toLowerCase(); if (allowed.indexOf(lowerKey) === -1) { return ''; } var value = doubleQuoted !== undefined ? doubleQuoted : singleQuoted !== undefined ? singleQuoted : bareValue !== undefined ? bareValue : ''; if (lowerKey === 'href' && /^(?:\s*javascript:|\s*data:)/i.test(String(value || ''))) { return ''; } if (lowerKey === 'style' && /(?:expression\s*\(|javascript:|url\s*\()/i.test(String(value || ''))) { return ''; } if (lowerKey === 'target') { var targetValue = String(value || '').trim(); if (targetValue === '_blank') { attrs.push(' target="_blank"'); if (attrs.indexOf(' rel="noreferrer noopener"') === -1) { attrs.push(' rel="noreferrer noopener"'); } return ''; } } attrs.push(' ' + lowerKey + '="' + escapeHtml(value) + '"'); return ''; }); return attrs.join(''); } function sanitizeRichText(html) { var output = String(html || ''); output = output.replace(//gi, ''); output = output.replace(//gi, ''); return output.replace(/<[^>]+>/g, function (tag) { var match = tag.match(/^<\s*(\/?)\s*([a-z0-9]+)([\s\S]*?)(\/?)>$/i); if (!match) { return ''; } var closing = Boolean(match[1]); var name = String(match[2] || '').toLowerCase(); var allowed = ['a', 'b', 'blockquote', 'br', 'code', 'col', 'colgroup', 'div', 'em', 'figure', 'figcaption', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'li', 'ol', 'p', 'pre', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul']; if (allowed.indexOf(name) === -1) { return ''; } if (closing) { return ''; } return '<' + name + sanitizeRichTextAttributes(name, String(match[3] || '')) + '>'; }); } function substituteScheduleVariables(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 substituteScheduleVariables(source, context); } function getScheduleGroups() { return Array.isArray(initialData && initialData.scheduleGroups) ? initialData.scheduleGroups : []; } function getGroupById(groupId, groups) { var normalizedId = Number(groupId || 0); return (Array.isArray(groups) ? groups : getScheduleGroups()).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); }); 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 = getScheduleGroups(); var groupId = regionContent && regionContent.schedule_group_id !== undefined ? regionContent.schedule_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); if (!entries.length) { entries = getEntries(groupId, groups).slice(0, Math.max(1, Number(maxItems || 5))); } if (!value) { return '
'; } return '
' + entries.map(function (entry, index) { return '
' + sanitizeRichText(substituteScheduleVariables(value, Object.assign({}, entry || {}, { start: entry && entry.start_datetime !== undefined ? entry.start_datetime : '', end: entry && entry.end_datetime !== undefined ? entry.end_datetime : '', group: group || {}, entries: entries, index: index + 1 }))) + '
'; }).join('') + '
'; } registry.register('schedule', { renderRegion: renderRegion });