// Region-specific helpers for slide forms. import { createSlideFormPreviewHelpers } from '/assets/js/slides/slide-form-preview.js'; export function createSlideFormRegionHelpers(options) { var settings = options || {}; var templateFields = settings.templateFields || null; var existingContent = settings.existingContent || {}; var rssFeeds = Array.isArray(settings.rssFeeds) ? settings.rssFeeds : []; var apiSources = Array.isArray(settings.apiSources) ? settings.apiSources : []; var timetableGroups = Array.isArray(settings.timetableGroups) ? settings.timetableGroups : []; var getRegionTypeModule = typeof settings.getRegionTypeModule === 'function' ? settings.getRegionTypeModule : function () { return null; }; var requestPreviewRender = typeof settings.requestPreviewRender === 'function' ? settings.requestPreviewRender : function () {}; var placeholderUtils = window.placeholderUtils || {}; var placeholderChips = window.placeholderChips || {}; var escapeHtml = typeof settings.escapeHtml === 'function' ? settings.escapeHtml : function (value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }; var previewHelpers = createSlideFormPreviewHelpers({ getRegionTypeModule: getRegionTypeModule, escapeHtml: escapeHtml }); var defaultFontSize = Math.max(1, Number(settings.defaultFontSize || 32)); var uploadMaxLabel = String(settings.uploadMaxLabel || '100 MB'); var uploadVideoMaxLabel = String(settings.uploadVideoMaxLabel || '1 GB'); function sanitizeFontSize(value) { var raw = String(value || '').trim().toLowerCase(); if (/^\d+(?:\.\d+)?px$/.test(raw)) { return String(Math.max(1, Math.round(Number(raw.replace(/px$/, ''))))); } if (/^\d+(?:\.\d+)?$/.test(raw)) { return String(Math.max(1, Math.round(Number(raw)))); } return String(defaultFontSize); } var sanitizePreviewHtml = previewHelpers.sanitizePreviewHtml; var sanitizeTagAttributes = previewHelpers.sanitizeTagAttributes; var renderPreviewListItem = previewHelpers.renderPreviewListItem; var renderPreviewTable = previewHelpers.renderPreviewTable; var renderPreviewBlock = previewHelpers.renderPreviewBlock; var renderPreviewText = previewHelpers.renderPreviewText; var renderPreviewTextRegion = previewHelpers.renderPreviewTextRegion; var startPreviewVideoPlayback = previewHelpers.startPreviewVideoPlayback; function getCurrentTextStyle(region) { var current = existingContent[region.region_key] || {}; var textRegion = getRegionTypeModule('text'); var defaultStyle = window.pulseRegionTypes && typeof window.pulseRegionTypes.getDefaultRegionStyle === 'function' ? window.pulseRegionTypes.getDefaultRegionStyle('text') : textRegion && typeof textRegion.getDefaultStyle === 'function' ? textRegion.getDefaultStyle() : { font_family: 'Arial', font_size: defaultFontSize, font_color: '#000000' }; 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 || defaultStyle.font_size || defaultFontSize)), font_color: String(current.font_color || region.font_color || defaultStyle.font_color || '#000000').trim() || '#000000' }; } function getRssFeedById(feedId) { var normalizedId = Number(feedId || 0); return rssFeeds.find(function (feed) { return Number(feed.id) === normalizedId; }) || null; } function getRssFeedItemCount(feedId) { var feed = getRssFeedById(feedId); return feed && Array.isArray(feed.items) ? feed.items.length : 0; } function getRssFieldList(feedId) { var module = getRegionTypeModule('rss'); if (module && typeof module.getFieldList === 'function') { return module.getFieldList(feedId, rssFeeds); } var feed = getRssFeedById(feedId); var sampleItem = feed && Array.isArray(feed.items) ? feed.items[0] : null; var sampleJson = sampleItem && sampleItem.itemJson && typeof sampleItem.itemJson === 'object' ? sampleItem.itemJson : null; function walkFields(value, prefix, output) { if (!value || typeof value !== 'object' || Array.isArray(value)) { return; } Object.keys(value).forEach(function (key) { if (key === 'rawXml') { return; } var nextPath = prefix ? prefix + '.' + key : key; var nextValue = value[key]; if (nextValue && typeof nextValue === 'object' && !Array.isArray(nextValue)) { walkFields(nextValue, nextPath, output); return; } if (output.indexOf(nextPath) === -1) { output.push(nextPath); } }); } var fields = []; walkFields(sampleJson, '', fields); return fields; } function buildLimitedPlaceholderChipMarkup(fieldList, emptyLabel) { var fields = Array.isArray(fieldList) ? fieldList : []; var visibleFields = fields.slice(0, 8); var overflowFields = fields.slice(visibleFields.length); if (!fields.length) { return '' + escapeHtml(emptyLabel) + ''; } var visibleMarkup = visibleFields.map(function (field) { return typeof placeholderChips.renderChip === 'function' ? placeholderChips.renderChip(field) : '{{' + escapeHtml(field) + '}}'; }).join(''); var transformHint = '
Placeholder values support transforms, for example {{title.upper()}}, {{title.title()}}, {{title.lower()}}, {{publishedAt.format("MMM D, YYYY")}}.
'; if (!overflowFields.length) { return visibleMarkup + transformHint; } return '' + visibleMarkup + transformHint + '
' + 'Show ' + escapeHtml(overflowFields.length) + ' more fields' + '
' + overflowFields.map(function (field) { return typeof placeholderChips.renderChip === 'function' ? placeholderChips.renderChip(field) : '{{' + escapeHtml(field) + '}}'; }).join('') + '
' + '
'; } function truncateJsonPreview(value, maxLength) { var text = ''; try { text = JSON.stringify(value, null, 2); } catch (_error) { text = String(value === undefined || value === null ? '' : value); } if (!text) { return ''; } var limit = Math.max(200, Number(maxLength || 1100)); if (text.length <= limit) { return text; } return text.slice(0, limit).replace(/\s+$/, '') + '\n...'; } function buildApiSampleDataMarkup(sourceId, itemNumber, itemsPathOverride) { var source = getApiSourceById(sourceId); if (!source) { return '
Select an API source to preview sample data.
'; } var item = getApiSourceItems(sourceId, itemsPathOverride)[Math.max(0, Math.max(1, Number(itemNumber || 1)) - 1)] || null; if (!item) { return '
No sample item is available for the current selection.
'; } return '
' + escapeHtml(truncateJsonPreview(item, 1100)) + '
'; } function updatePlaceholderChipList(card, fieldList, emptyLabel) { if (!card) { return; } var container = card.querySelector('[data-placeholder-chips]'); if (!container) { return; } var chips = Array.isArray(fieldList) ? fieldList.map(function (field) { return typeof placeholderChips.renderChip === 'function' ? placeholderChips.renderChip(field) : '{{' + escapeHtml(field) + '}}'; }).join('') : ''; container.innerHTML = chips || '' + escapeHtml(emptyLabel) + ''; } function updateRssPlaceholderChips(regionId, feedId) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return; } var container = card.querySelector('[data-placeholder-chips]'); if (!container) { return; } container.innerHTML = buildLimitedPlaceholderChipMarkup(getRssFieldList(feedId), 'No RSS fields available.'); } function updateRssItemNumberLimit(regionId, feedId) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return; } var input = card.querySelector('input[name="region_rss_item_number_' + regionId + '"]'); if (!input) { return; } var itemCount = Math.max(1, Number(getRssFeedItemCount(feedId) || 1)); input.setAttribute('max', String(itemCount)); if (Number(input.value || 0) > itemCount) { input.value = String(itemCount); } } function clampRssItemNumber(regionId, feedId, itemNumber) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return ''; } var input = card.querySelector('input[name="region_rss_item_number_' + regionId + '"]'); if (!input) { return ''; } var itemCount = Math.max(1, Number(getRssFeedItemCount(feedId) || 1)); var parsedValue = Math.max(1, Number(itemNumber || 1)); var clampedValue = Math.min(itemCount, Number.isFinite(parsedValue) && parsedValue > 0 ? parsedValue : 1); input.setAttribute('max', String(itemCount)); input.value = String(clampedValue); return String(clampedValue); } function getCurrentRssConfig(region) { var module = getRegionTypeModule('rss'); if (module && typeof module.getCurrentConfig === 'function') { return module.getCurrentConfig(region, existingContent); } var current = existingContent[region.region_key] || {}; var parsedItemNumber = Math.max(1, Number(current.item_number || 1)); return { feed_id: current.feed_id === undefined || current.feed_id === null || current.feed_id === '' ? '' : Number(current.feed_id), item_number: Number.isFinite(parsedItemNumber) && parsedItemNumber > 0 ? parsedItemNumber : 1, value: current.value !== undefined ? current.value : '' }; } function resolvePath(value, path) { var current = value; if (!path) { return current; } String(path).split('.').forEach(function (segment) { if (current === undefined || current === null) { current = ''; return; } current = current[segment]; }); return current === undefined || current === null ? '' : current; } function substituteRssVariables(html, item) { var source = String(html || ''); return source.replace(/\{\{\s*([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_.]+))?\s*\}\}/g, function (_match, tokenName, tokenPath) { if (!item || typeof item !== 'object') { return ''; } var key = tokenName === 'item' && tokenPath ? tokenPath : tokenName; return escapeHtml(resolvePath(item, key || '')); }); } function getRssItem(feedId, itemNumber) { var module = getRegionTypeModule('rss'); if (module && typeof module.getItem === 'function') { return module.getItem(feedId, itemNumber, rssFeeds); } var feed = getRssFeedById(feedId); var items = feed && Array.isArray(feed.items) ? feed.items : []; var parsedItemNumber = Math.max(1, Number(itemNumber || 1)); var index = Number.isFinite(parsedItemNumber) && parsedItemNumber > 0 ? parsedItemNumber - 1 : 0; return items[index] || null; } function getRssPreviewFallback(item) { var module = getRegionTypeModule('rss'); if (module && typeof module.getPreviewFallback === 'function') { return module.getPreviewFallback(item); } if (!item || typeof item !== 'object') { return '
RSS item
'; } var title = String(item.title || '').trim(); var description = String(item.description || '').trim(); var summary = []; if (title) { summary.push('

' + escapeHtml(title) + '

'); } if (description) { summary.push('

' + sanitizePreviewHtml(description) + '

'); } if (!summary.length) { return '
RSS item
'; } return summary.join(''); } function getApiSourceById(sourceId) { var normalizedId = Number(sourceId || 0); return apiSources.find(function (source) { return Number(source.id) === normalizedId; }) || null; } function getApiSourceItemsPath(source, overridePath) { if (overridePath === undefined || overridePath === null) { return String(source && (source.items_path || source.itemsPath) || '').trim(); } return String(overridePath || '').trim(); } function getApiSourceItems(sourceId, itemsPathOverride) { var source = getApiSourceById(sourceId); var module = getRegionTypeModule('api'); if (module && typeof module.getItems === 'function') { return module.getItems(sourceId, apiSources, itemsPathOverride); } var responseJson = source && source.responseJson && typeof source.responseJson === 'object' ? source.responseJson : null; var itemsPath = getApiSourceItemsPath(source, itemsPathOverride); if (itemsPath !== undefined && itemsPath !== null && itemsPath !== '') { var current = responseJson; String(itemsPath).split('.').forEach(function (segment) { if (current === undefined || current === null) { current = ''; return; } current = current[segment]; }); return Array.isArray(current) ? current : []; } if (Array.isArray(responseJson)) { return responseJson; } if (responseJson && Array.isArray(responseJson.items)) { return responseJson.items; } if (responseJson && Array.isArray(responseJson.results)) { return responseJson.results; } if (responseJson && Array.isArray(responseJson.data)) { return responseJson.data; } return responseJson ? [responseJson] : []; } function getApiItemCount(sourceId, itemsPathOverride) { var module = getRegionTypeModule('api'); if (module && typeof module.getItemCount === 'function') { return module.getItemCount(sourceId, apiSources, itemsPathOverride); } return getApiSourceItems(sourceId, itemsPathOverride).length; } function getApiFieldList(sourceId, itemsPathOverride) { var sampleItem = getApiSourceItems(sourceId, itemsPathOverride)[0] || null; if (typeof placeholderUtils.collectPlaceholderFieldPaths === 'function') { return placeholderUtils.collectPlaceholderFieldPaths(sampleItem && typeof sampleItem === 'object' ? sampleItem : null); } return []; } function updateApiPlaceholderChips(regionId, sourceId, itemsPathOverride) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return; } var container = card.querySelector('[data-placeholder-chips]'); if (!container) { return; } container.innerHTML = buildLimitedPlaceholderChipMarkup(getApiFieldList(sourceId, itemsPathOverride), 'No JSON fields available.'); } function updateApiSampleDataPanel(regionId, sourceId, itemNumber, itemsPathOverride) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return; } var container = card.querySelector('[data-api-sample-data-panel]'); if (!container) { return; } container.innerHTML = buildApiSampleDataMarkup(sourceId, itemNumber, itemsPathOverride); } function updateApiItemNumberLimit(regionId, sourceId, itemsPathOverride) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return; } var input = card.querySelector('input[name="region_api_item_number_' + regionId + '"]'); if (!input) { return; } var itemCount = Math.max(1, Number(getApiItemCount(sourceId, itemsPathOverride) || 1)); input.setAttribute('max', String(itemCount)); if (Number(input.value || 0) > itemCount) { input.value = String(itemCount); } } function clampApiItemNumber(regionId, sourceId, itemNumber, itemsPathOverride) { var card = templateFields ? templateFields.querySelector('[data-region-id="' + regionId + '"]') : null; if (!card) { return ''; } var input = card.querySelector('input[name="region_api_item_number_' + regionId + '"]'); if (!input) { return ''; } var itemCount = Math.max(1, Number(getApiItemCount(sourceId, itemsPathOverride) || 1)); var parsedValue = Math.max(1, Number(itemNumber || 1)); var clampedValue = Math.min(itemCount, Number.isFinite(parsedValue) && parsedValue > 0 ? parsedValue : 1); input.setAttribute('max', String(itemCount)); input.value = String(clampedValue); return String(clampedValue); } function getCurrentApiConfig(region) { var module = getRegionTypeModule('api'); if (module && typeof module.getCurrentConfig === 'function') { return module.getCurrentConfig(region, existingContent, apiSources); } var current = existingContent[region.region_key] || {}; var source = getApiSourceById(current.source_id); var parsedItemNumber = Math.max(1, Number(current.item_number || 1)); return { source_id: current.source_id === undefined || current.source_id === null || current.source_id === '' ? '' : Number(current.source_id), item_number: Number.isFinite(parsedItemNumber) && parsedItemNumber > 0 ? parsedItemNumber : 1, items_path: Object.prototype.hasOwnProperty.call(current, 'items_path') ? String(current.items_path === undefined || current.items_path === null ? '' : current.items_path) : undefined, default_items_path: String(source && (source.items_path || source.itemsPath) || '').trim(), value: current.value !== undefined ? current.value : '' }; } function reduceAspectRatio(width, height) { var a = Math.max(1, Math.round(Number(width || 0) || 1)); var b = Math.max(1, Math.round(Number(height || 0) || 1)); var x = a; var y = b; while (y !== 0) { var remainder = x % y; x = y; y = remainder; } return Math.max(1, Math.round(a / x)) + ':' + Math.max(1, Math.round(b / x)); } function getCurrentRegionValue(region) { var current = existingContent[region.region_key]; return current && current.value !== undefined ? current.value : ''; } function getCurrentTimeDateConfig(region) { var current = existingContent[region.region_key] || {}; return { value: current.value !== undefined ? current.value : '', timezone: current.timezone !== undefined ? current.timezone : (current.time_zone !== undefined ? current.time_zone : '') }; } function getCurrentTimetableConfig(region) { var current = existingContent[region.region_key] || {}; return { timetable_group_id: current.timetable_group_id === undefined || current.timetable_group_id === null || current.timetable_group_id === '' ? '' : Number(current.timetable_group_id), display_mode: String(current.display_mode || 'upcoming').trim().toLowerCase() || 'upcoming', max_items: Math.max(1, Number(current.max_items || 5)) }; } function getCurrentRegionVideoDuration(region) { var current = existingContent[region.region_key] || {}; var duration = Math.round(Number(current.duration_seconds || 0) * 1000) / 1000; return Number.isFinite(duration) && duration > 0 ? String(duration) : ''; } function buildRegionEditorCardContext(region) { var module = getRegionTypeModule(region.region_type); if (module && typeof module.buildEditorCardContext === 'function') { return module.buildEditorCardContext({ region: region, current: region.region_type === 'rss' || region.region_type === 'api' || region.region_type === 'time-date' || region.region_type === 'timetable' ? (existingContent[region.region_key] || {}) : getCurrentRegionValue(region), currentDuration: getCurrentRegionVideoDuration(region), regionRatio: reduceAspectRatio(region.width, region.height), uploadMaxLabel: uploadMaxLabel, uploadVideoMaxLabel: uploadVideoMaxLabel, disableAudio: (existingContent[region.region_key] || {}).disable_audio, config: region.region_type === 'api' ? getCurrentApiConfig(region) : region.region_type === 'timetable' ? getCurrentTimetableConfig(region) : getCurrentRssConfig(region), style: getCurrentTextStyle(region), fontSize: getCurrentTextStyle(region).font_size, feedOptions: rssFeeds.map(function (feed) { var selected = Number(feed.id) === Number(getCurrentRssConfig(region).feed_id) ? ' selected' : ''; return ''; }).join(''), sourceOptions: apiSources.map(function (source) { var selected = Number(source.id) === Number(getCurrentApiConfig(region).source_id) ? ' selected' : ''; return ''; }).join(''), placeholderChips: region.region_type === 'rss' ? getRssFieldList(getCurrentRssConfig(region).feed_id).map(function (field) { return '{{' + escapeHtml(field) + '}}'; }).join('') : buildLimitedPlaceholderChipMarkup(getApiFieldList(getCurrentApiConfig(region).source_id, getCurrentApiConfig(region).items_path), 'No JSON fields available.'), placeholderFields: region.region_type === 'api' ? getApiFieldList(getCurrentApiConfig(region).source_id, getCurrentApiConfig(region).items_path) : region.region_type === 'rss' ? getRssFieldList(getCurrentRssConfig(region).feed_id) : [], sampleDataPreview: buildApiSampleDataMarkup(getCurrentApiConfig(region).source_id, getCurrentApiConfig(region).item_number, getCurrentApiConfig(region).items_path), timetableGroups: timetableGroups }, existingContent, region.region_type === 'rss' ? rssFeeds : region.region_type === 'timetable' ? timetableGroups : apiSources); } var textStyle = getCurrentTextStyle(region); var rssConfig = getCurrentRssConfig(region); var apiConfig = getCurrentApiConfig(region); var currentContent = existingContent[region.region_key] || {}; var apiItemsPath = apiConfig.items_path !== undefined ? apiConfig.items_path : apiConfig.default_items_path; return { region: region, current: region.region_type === 'rss' || region.region_type === 'api' ? currentContent : getCurrentRegionValue(region), currentDuration: getCurrentRegionVideoDuration(region), regionRatio: reduceAspectRatio(region.width, region.height), uploadMaxLabel: uploadMaxLabel, uploadVideoMaxLabel: uploadVideoMaxLabel, disableAudio: currentContent.disable_audio, config: region.region_type === 'api' ? apiConfig : region.region_type === 'timetable' ? getCurrentTimetableConfig(region) : rssConfig, style: textStyle, fontSize: textStyle.font_size, feedOptions: rssFeeds.map(function (feed) { var selected = Number(feed.id) === Number(rssConfig.feed_id) ? ' selected' : ''; return ''; }).join(''), sourceOptions: apiSources.map(function (source) { var selected = Number(source.id) === Number(apiConfig.source_id) ? ' selected' : ''; return ''; }).join(''), placeholderChips: region.region_type === 'rss' ? buildLimitedPlaceholderChipMarkup(getRssFieldList(rssConfig.feed_id), 'No RSS fields available.') : buildLimitedPlaceholderChipMarkup(getApiFieldList(apiConfig.source_id, apiItemsPath), 'No JSON fields available.'), placeholderFields: region.region_type === 'api' ? getApiFieldList(apiConfig.source_id, apiItemsPath) : region.region_type === 'rss' ? getRssFieldList(rssConfig.feed_id) : [], sampleDataPreview: buildApiSampleDataMarkup(apiConfig.source_id, apiConfig.item_number, apiItemsPath), timetableGroups: timetableGroups }; } function getRegionEditorCardHtml(region) { var module = getRegionTypeModule(region.region_type); if (!module || typeof module.renderEditorCard !== 'function') { return ''; } return makeRegionCardCollapsible(module.renderEditorCard(buildRegionEditorCardContext(region)), region); } function bindRegionCards() { if (!templateFields) { return; } Array.prototype.forEach.call(templateFields.querySelectorAll('[data-region-id]'), function (card) { var module = null; if (!card || !card.querySelector || !card.querySelector('input[type="url"][name^="region_qr_code_"]')) { return; } module = getRegionTypeModule('qr-code'); if (module && typeof module.bindEditorCard === 'function') { module.bindEditorCard({ card: card, region: { id: card.getAttribute('data-region-id') }, existingContent: existingContent, requestPreviewRender: requestPreviewRender }); } }); } function syncRegionCards() { if (!templateFields) { return Promise.resolve(); } var syncs = []; Array.prototype.forEach.call(templateFields.querySelectorAll('[data-region-id]'), function (card) { if (!card || !card.querySelector || !card.querySelector('input[type="url"][name^="region_qr_code_"]')) { return; } if (typeof card.__pulseQrSync === 'function') { syncs.push(Promise.resolve(card.__pulseQrSync())); } }); return Promise.all(syncs); } function makeRegionCardCollapsible(html, region) { if (typeof html !== 'string' || !html) { return html; } if (html.indexOf('data-lte-toggle="card-collapse"') !== -1) { return html; } var cardHtml = html.replace( 'class="card card-outline card-secondary admin-form-card template-field-card mb-3"', 'class="card card-widget card-outline card-secondary admin-form-card template-field-card mb-3"' ); if (cardHtml === html) { return html; } var bodyOpenMatch = cardHtml.match(/
/); if (bodyOpenMatch) { var bodyClassTokens = String(bodyOpenMatch[1] || '') .trim() .split(/\s+/) .filter(Boolean); var wrapperGapTokens = bodyClassTokens.filter(function (token) { return /^gap-\d+$/i.test(token); }); var wrapperPaddingTokens = bodyClassTokens.filter(function (token) { return /^(?:p|pt|pb|ps|pe|px|py)-\d+$/i.test(token); }); var bodyClassTokensWithoutGrid = bodyClassTokens.filter(function (token) { return token !== 'd-grid' && !/^gap-\d+$/i.test(token) && !/^(?:p|pt|pb|ps|pe|px|py)-\d+$/i.test(token); }); var bodyClassAttribute = ' class="card-body p-0' + (bodyClassTokensWithoutGrid.length ? ' ' + bodyClassTokensWithoutGrid.join(' ') : '') + '"'; var wrapperClassTokens = ['template-field-body', 'd-grid'] .concat(wrapperPaddingTokens) .concat(wrapperGapTokens); var wrapperClassAttribute = ' class="' + wrapperClassTokens.filter(Boolean).join(' ') + '"'; cardHtml = cardHtml.replace(bodyOpenMatch[0], ''); var lastCloseIndex = cardHtml.lastIndexOf('
'); if (lastCloseIndex !== -1) { var bodyCloseIndex = cardHtml.lastIndexOf('', lastCloseIndex - 1); if (bodyCloseIndex !== -1) { cardHtml = cardHtml.slice(0, bodyCloseIndex) + '' + cardHtml.slice(bodyCloseIndex); } } } var collapseLabel = region && region.label ? String(region.label) : 'region'; var collapseButton = '' + ''; var bodyMarkerIndex = cardHtml.indexOf('
'; if (cardHtml.indexOf(actionsMarker) !== -1) { return cardHtml.replace(/(
[\s\S]*?)<\/div>/, '$1' + collapseButton + '
'); } var headerCloseIndex = cardHtml.lastIndexOf('
', bodyMarkerIndex); if (headerCloseIndex === -1) { return cardHtml; } return cardHtml.slice(0, headerCloseIndex) + collapseButton + cardHtml.slice(headerCloseIndex); } function getPreviewRegionContent(card, region) { var module = getRegionTypeModule(region.region_type); if (module && typeof module.buildPreviewRenderContext === 'function') { return module.buildPreviewRenderContext(region, card, existingContent, region.region_type === 'rss' ? rssFeeds : region.region_type === 'timetable' ? timetableGroups : apiSources); } var current = existingContent[region.region_key]; var content = current && typeof current === 'object' ? Object.assign({}, current) : {}; if (!card) { return content; } var hiddenInput = card.querySelector('input[type="hidden"][name="region_text_' + region.id + '"]'); var textAreaInput = card.querySelector('textarea[name="region_text_' + region.id + '"]'); var htmlInput = card.querySelector('textarea[name="region_html_' + region.id + '"]'); var timeDateTimezoneInput = card.querySelector('input[name="region_timezone_' + region.id + '"]'); var imageHidden = card.querySelector('input[type="hidden"][name="existing_region_image_' + region.id + '"]'); var imageFileInput = card.querySelector('input[type="file"][name="region_image_' + region.id + '"]'); var videoHidden = card.querySelector('input[type="hidden"][name="existing_region_video_' + region.id + '"]'); var videoFileInput = card.querySelector('input[type="file"][name="region_video_' + region.id + '"]'); var webpageInput = card.querySelector('input[type="url"][name="region_webpage_' + region.id + '"]'); var rtmpInput = card.querySelector('input[type="url"][name="region_rtmp_' + region.id + '"]'); var rssFeedInput = card.querySelector('select[name="region_rss_feed_id_' + region.id + '"]'); var rssItemInput = card.querySelector('input[name="region_rss_item_number_' + region.id + '"]'); var apiSourceInput = card.querySelector('select[name="region_api_source_id_' + region.id + '"]'); var apiItemInput = card.querySelector('input[name="region_api_item_number_' + region.id + '"]'); var apiItemsPathInput = card.querySelector('input[name="region_api_items_path_' + region.id + '"]'); if (region.region_type === 'image') { content.value = (imageFileInput && imageFileInput.dataset.previewUrl) ? imageFileInput.dataset.previewUrl : (imageHidden ? imageHidden.value : content.value || ''); } else if (region.region_type === 'video') { content.value = (videoFileInput && videoFileInput.dataset.previewUrl) ? videoFileInput.dataset.previewUrl : (videoHidden ? videoHidden.value : content.value || ''); } else if (region.region_type === 'webpage') { content.value = webpageInput ? webpageInput.value : (content.value || ''); } else if (region.region_type === 'rtmp') { content.value = rtmpInput ? rtmpInput.value : (content.value || ''); content.disable_audio = false; } else if (region.region_type === 'html') { content.value = htmlInput ? htmlInput.value : (content.value || ''); } else if (region.region_type === 'time-date') { var timeDateCurrent = getCurrentTimeDateConfig(region); content.value = textAreaInput ? textAreaInput.value : (timeDateCurrent.value || ''); content.timezone = timeDateTimezoneInput ? timeDateTimezoneInput.value : (timeDateCurrent.timezone || ''); } else if (region.region_type === 'rss') { content.value = hiddenInput ? hiddenInput.value : (content.value || ''); content.feed_id = rssFeedInput ? rssFeedInput.value : content.feed_id; content.item_number = rssItemInput ? clampRssItemNumber(region.id, content.feed_id, rssItemInput.value) : content.item_number; } else if (region.region_type === 'api') { content.value = hiddenInput ? hiddenInput.value : (content.value || ''); content.source_id = apiSourceInput ? apiSourceInput.value : content.source_id; content.item_number = apiItemInput ? apiItemInput.value : content.item_number; content.items_path = apiItemsPathInput ? apiItemsPathInput.value : content.items_path; } else if (region.region_type === 'timetable') { var timetableGroupInput = card.querySelector('select[name="region_timetable_group_id_' + region.id + '"]'); var timetableDisplayModeInput = card.querySelector('select[name="region_timetable_display_mode_' + region.id + '"]'); var timetableMaxItemsInput = card.querySelector('input[name="region_timetable_max_items_' + region.id + '"]'); var currentSchedule = getCurrentTimetableConfig(region); content.value = hiddenInput ? hiddenInput.value : (content.value || currentSchedule.value || ''); content.timetable_group_id = timetableGroupInput ? timetableGroupInput.value : currentSchedule.timetable_group_id; content.display_mode = timetableDisplayModeInput ? timetableDisplayModeInput.value : currentSchedule.display_mode; content.max_items = timetableMaxItemsInput ? timetableMaxItemsInput.value : currentSchedule.max_items; } else { content.value = hiddenInput ? hiddenInput.value : (content.value || ''); } return content; } function buildPreviewRenderContext(region, card) { var module = getRegionTypeModule(region.region_type); if (module && typeof module.buildPreviewRenderContext === 'function') { return module.buildPreviewRenderContext(region, card, existingContent, region.region_type === 'rss' ? rssFeeds : region.region_type === 'timetable' ? timetableGroups : apiSources); } var textStyle = getCurrentTextStyle(region); var previewContent = getPreviewRegionContent(card, region); return { value: previewContent.value, timezone: previewContent.timezone, style: textStyle, existingContent: existingContent, feeds: rssFeeds, sources: apiSources, disable_audio: previewContent.disable_audio === undefined ? true : Boolean(previewContent.disable_audio), feed_id: previewContent.feed_id, item_number: previewContent.item_number, source_id: previewContent.source_id, items_path: previewContent.items_path, timetable_group_id: previewContent.timetable_group_id, display_mode: previewContent.display_mode, max_items: previewContent.max_items, timetableGroups: timetableGroups, font_size: textStyle.font_size, font_color: textStyle.font_color, font_family: textStyle.font_family }; } return { sanitizePreviewHtml: sanitizePreviewHtml, sanitizeTagAttributes: sanitizeTagAttributes, getCurrentTextStyle: getCurrentTextStyle, getRssFieldList: getRssFieldList, updateRssPlaceholderChips: updateRssPlaceholderChips, getCurrentRssConfig: getCurrentRssConfig, getApiFieldList: getApiFieldList, updateApiPlaceholderChips: updateApiPlaceholderChips, updateApiSampleDataPanel: updateApiSampleDataPanel, updateApiItemNumberLimit: updateApiItemNumberLimit, updateRssItemNumberLimit: updateRssItemNumberLimit, getCurrentApiConfig: getCurrentApiConfig, reduceAspectRatio: reduceAspectRatio, renderPreviewTextRegion: renderPreviewTextRegion, startPreviewVideoPlayback: startPreviewVideoPlayback, getRegionEditorCardHtml: getRegionEditorCardHtml, bindRegionCards: bindRegionCards, syncRegionCards: syncRegionCards, buildRegionEditorCardContext: buildRegionEditorCardContext, getPreviewRegionContent: getPreviewRegionContent, buildPreviewRenderContext: buildPreviewRenderContext, getCurrentRegionValue: getCurrentRegionValue, getCurrentRegionVideoDuration: getCurrentRegionVideoDuration }; }