// Shared browser helpers for web UI escaping and formatting. (function () { function escapeHtml(value) { return String(value ?? '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function formatDashboardDate(value, useTwentyFourHour) { if (!value) { return ''; } var date = new Date(value); if (Number.isNaN(date.getTime())) { return ''; } var formatOptions = { month: 'short', day: '2-digit', year: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit' }; if (useTwentyFourHour) { formatOptions.hour12 = false; } return new Intl.DateTimeFormat('en-US', formatOptions).format(date); } function getClientRowKey(client) { var clientName = String(client && client.client_name ? client.client_name : '').trim(); if (clientName) { return clientName; } return String(client && client.screen_slug ? client.screen_slug : client && client.deviceId ? client.deviceId : client && client.id ? client.id : client && client.clientId ? client.clientId : '').trim(); } function getClientDisplayName(client) { if (client && client.client_name) { return String(client.client_name).trim(); } var clientId = String(client && client.clientId ? client.clientId : '').trim(); if (clientId) { return clientId; } return ''; } function setButtonVariant(button, classesToRemove, classToAdd) { if (!button) { return; } if (button.classList) { classesToRemove.forEach(function (className) { button.classList.remove(className); }); if (classToAdd) { button.classList.add(classToAdd); } return; } var className = String(button.className || ''); classesToRemove.forEach(function (removeClass) { className = className.replace(new RegExp('(^|\\s)' + removeClass + '(?=\\s|$)', 'g'), ' '); }); if (classToAdd) { className += ' ' + classToAdd; } button.className = className.replace(/\s+/g, ' ').trim(); } function normalizeDisplayIp(value) { var ip = String(value || '').trim(); if (!ip) { return ''; } if (ip.toLowerCase().indexOf('::ffff:') === 0) { return ip.slice(7).trim(); } return ip; } window.escapeHtml = escapeHtml; var defaultQrOptions = window.defaultQrOptions || { width: 1000, height: 1000, type: 'canvas', margin: 10, qrOptions: {}, dotsOptions: { color: '#000000', type: 'square' }, cornersSquareOptions: { color: '#000000', type: 'square' }, cornersDotOptions: { color: '#000000', type: 'square' }, backgroundOptions: { color: '#ffffff' } }; var qrDotTypes = window.qrDotTypes || [ { value: 'square', label: 'Square' }, { value: 'dots', label: 'Dots' }, { value: 'rounded', label: 'Rounded' }, { value: 'extra-rounded', label: 'Extra rounded' }, { value: 'classy', label: 'Classy' }, { value: 'classy-rounded', label: 'Classy rounded' } ]; var qrCornerSquareTypes = window.qrCornerSquareTypes || [ { value: 'square', label: 'Square' }, { value: 'dot', label: 'Dot' }, { value: 'rounded', label: 'Rounded' }, { value: 'extra-rounded', label: 'Extra rounded' }, { value: 'dots', label: 'Dots' }, { value: 'classy', label: 'Classy' }, { value: 'classy-rounded', label: 'Classy rounded' } ]; var qrCornerDotTypes = window.qrCornerDotTypes || [ { value: 'square', label: 'Square' }, { value: 'dot', label: 'Dot' }, { value: 'rounded', label: 'Rounded' }, { value: 'extra-rounded', label: 'Extra rounded' }, { value: 'classy', label: 'Classy' }, { value: 'classy-rounded', label: 'Classy rounded' } ]; function getOptionValue(option) { if (option && typeof option === 'object' && option.value !== undefined && option.value !== null) { return String(option.value).trim(); } return String(option === undefined || option === null ? '' : option).trim(); } function normalizeMarginValue(value, fallback) { var parsed = Number(value); return Number.isFinite(parsed) && parsed >= 0 ? Math.round(parsed) : fallback; } function normalizeHexColorValue(value, fallback) { var raw = String(value === undefined || value === null ? '' : value).trim(); return raw || fallback; } function normalizeBooleanValue(value, fallback) { if (value === undefined || value === null || value === '') { return Boolean(fallback); } if (typeof value === 'boolean') { return value; } var text = String(value).trim().toLowerCase(); if (text === 'true' || text === '1' || text === 'yes' || text === 'on') { return true; } if (text === 'false' || text === '0' || text === 'no' || text === 'off') { return false; } return Boolean(value); } function normalizeOptionValue(value, options, fallback) { var text = String(value === undefined || value === null ? '' : value).trim(); for (var index = 0; index < options.length; index += 1) { if (getOptionValue(options[index]) === text) { return text; } } return fallback; } function normalizeRatioValue(value, fallback) { var parsed = Number(value); return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback; } function normalizeGradientTypeValue(value, fallback) { var text = String(value === undefined || value === null ? '' : value).trim().toLowerCase(); return text === 'radial' ? 'radial' : 'linear'; } function normalizeGradientRotationValue(value, fallback) { var parsed = Number(value); return Number.isFinite(parsed) ? Math.round(parsed) : fallback; } function normalizeColorModeValue(value, fallback) { var text = String(value === undefined || value === null ? '' : value).trim().toLowerCase(); return text === 'gradient' ? 'gradient' : 'single'; } function normalizeColorValue(value, fallback) { return normalizeHexColorValue(value, fallback); } function renderSelectOptions(options, currentValue) { return options.map(function (option) { var optionValue = getOptionValue(option); var optionLabel = option && typeof option === 'object' && option.label !== undefined ? option.label : optionValue; return ''; }).join(''); } function normalizeSvgMarkup(svg) { var markup = String(svg || '').trim(); if (!markup || markup.charAt(0) !== '<') { return markup; } return markup.replace(/^]*)>/i, function (_match, attrText) { var attrs = String(attrText || ''); if (!/\bwidth\s*=\s*/i.test(attrs)) { attrs += ' width="95%"'; } if (!/\bheight\s*=\s*/i.test(attrs)) { attrs += ' height="95%"'; } if (!/\bpreserveAspectRatio\s*=\s*/i.test(attrs)) { attrs += ' preserveAspectRatio="xMidYMid meet"'; } if (!/\bstyle\s*=\s*/i.test(attrs)) { attrs += ' style="display:block;width:95%;height:95%;"'; } return ''; }); } function normalizeQrSvg(svg) { return normalizeSvgMarkup(svg); } async function blobToText(blob) { if (!blob) { return ''; } if (typeof blob.text === 'function') { return blob.text(); } if (typeof FileReader === 'function') { return await new Promise(function (resolve, reject) { var reader = new FileReader(); reader.onload = function () { resolve(String(reader.result || '')); }; reader.onerror = function () { reject(reader.error || new Error('Failed to read blob.')); }; reader.readAsText(blob); }); } return ''; } window.defaultQrOptions = defaultQrOptions; window.qrDotTypes = qrDotTypes; window.qrCornerSquareTypes = qrCornerSquareTypes; window.qrCornerDotTypes = qrCornerDotTypes; window.normalizeMarginValue = normalizeMarginValue; window.normalizeHexColorValue = normalizeHexColorValue; window.normalizeBooleanValue = normalizeBooleanValue; window.normalizeOptionValue = normalizeOptionValue; window.normalizeRatioValue = normalizeRatioValue; window.normalizeGradientTypeValue = normalizeGradientTypeValue; window.normalizeGradientRotationValue = normalizeGradientRotationValue; window.normalizeColorModeValue = normalizeColorModeValue; window.normalizeColorValue = normalizeColorValue; window.renderSelectOptions = renderSelectOptions; window.normalizeSvgMarkup = normalizeSvgMarkup; window.normalizeQrSvg = normalizeQrSvg; window.blobToText = blobToText; window.pendingByRegionId = window.pendingByRegionId || Object.create(null); window.webUiHelpers = { escapeHtml: escapeHtml, formatDashboardDate: formatDashboardDate, getClientRowKey: getClientRowKey, getClientDisplayName: getClientDisplayName, setButtonVariant: setButtonVariant, normalizeDisplayIp: normalizeDisplayIp }; }());