@Abu_Hasan thank you for your effort, but I would like to kindly request you to improve the security of the code of these themes, especially highly vulnerable/risk are:
Critical: API data is injected with innerHTML without escaping. Nearly every dynamic value (recipient.name, address, fields, table.description, cell.text, total.text, status.text, business.name, etc.) can become executable HTML. If any field is user-controlled, this is an XSS issue. Use textContent / DOM creation, or sanitize with a strict allowlist.
Critical: Although this is “legacy” but guess the reason for @Lubos to stop using it. Footer scripts are intentionally re-executed. This block makes injected scripts run:
root.querySelectorAll('#footers script').forEach(...)
Combined with raw data.footers insertion, this allows arbitrary script execution from API content. Remove this.
High: table header markup is malformed. headersHtml already wraps cells in , then it is inserted inside another :
<tr id="table-headers">${headersHtml}</tr>
This creates nested markup and browser repair behaviour may break styling/print layout. headersHtml should only contain elements.
Warning external Google Fonts import can hurt document rendering reliability. For invoices/PDF/print themes, remote font loading can fail, delay rendering, or produce inconsistent output. Consider bundling the font or using system fonts. Especially those that use Desktop versions may face difficulty when not online.
With help form AI find below an example of your Corporate Blue · Column Shell theme, but much safer because it uses zero innerHTML, does not execute footer scripts, renders dynamic text with text nodes, and validates dynamic links/images. As it no longer imports google fonts either dependency on internet access and potential PDF breaking is removed also.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Corporate Blue · Column Shell</title>
<style>
:root {
--accent: #2563EB;
--accent-soft: #eff6ff;
--accent-strong: #1e40af;
--text-main: #0f172a;
--text-muted: #64748b;
--border: #e2e8f0;
--border-soft: #f8fafc;
--border-strong: #cbd5e1;
--inspiron-cyan: #00D2FF;
--inspiron-gold: #FFD700;
--bg: #f5f5f5;
--paper: #fff;
}
body {
background-color: var(--bg);
display: flex;
margin: 0;
padding: 0;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
color: var(--text-main);
-webkit-font-smoothing: antialiased;
}
main {
background-color: var(--paper);
margin: 1.5rem auto;
border: 1px solid #e5e5e5;
border-radius: 5px;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.06);
padding: 35px;
width: 210mm;
min-height: 297mm;
box-sizing: border-box;
position: relative;
display: flex;
flex-direction: column;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1c1917;
--paper: #1c1917;
--text-main: #f5f5f5;
--text-muted: #a8a29e;
--border: #2e2a24;
--border-strong: #443e34;
--accent-soft: #172554;
--accent-strong: #3b82f6;
--accent: #3b82f6;
}
main {
border: 1px solid #2e2a24;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.50);
}
}
@page { size: A4; margin: 0; }
@media print {
body { background-color: initial; display: initial; }
main {
padding: 0;
border: initial;
box-shadow: initial;
border-radius: initial;
margin: 0;
width: 100%;
min-height: initial;
background-color: transparent;
}
}
.top-bar {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 0;
border: 1px solid var(--border-strong);
border-radius: 8px;
overflow: hidden;
margin-bottom: 18px;
}
.top-col {
padding: 14px 16px;
background: var(--paper);
}
.top-col.center {
border-left: 1px solid var(--border-strong);
border-right: 1px solid var(--border-strong);
background: var(--accent);
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
min-width: 220px;
}
.top-col.right {
display: flex;
justify-content: flex-end;
align-items: flex-start;
}
#title {
font-size: 24px;
font-weight: 900;
letter-spacing: 0.18em;
text-transform: uppercase;
color: #fff;
margin: 0;
}
.title-kicker {
font-size: 9px;
font-weight: 700;
letter-spacing: 0.26em;
text-transform: uppercase;
opacity: 0.75;
margin-top: 5px;
}
.doc-subtitle {
font-size: 10px;
font-weight: 600;
opacity: 0.85;
margin: 3px 0 0 0;
text-transform: uppercase;
letter-spacing: 0.1em;
color: #fff;
}
#business-logo img {
max-height: 55px;
max-width: 200px;
object-fit: contain;
display: inline-block;
}
.business-name-logo {
font-weight: 800;
font-size: 16px;
color: var(--accent-strong);
text-transform: uppercase;
}
.party-label {
font-size: 9px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--accent-strong);
margin-bottom: 6px;
border-bottom: 1px solid var(--border);
padding-bottom: 4px;
}
.party-name {
font-size: 13px;
font-weight: 700;
margin-bottom: 4px;
color: var(--text-main);
}
.party-text {
font-size: 11px;
color: var(--text-muted);
white-space: pre-line;
}
.rec-details {
font-size: 10px;
color: var(--text-muted);
margin-top: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.meta-strip {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 0;
border: 1px solid var(--border-strong);
border-radius: 8px;
overflow: hidden;
margin-bottom: 18px;
}
.meta-cell {
padding: 10px 14px;
border-right: 1px solid var(--border-strong);
background: var(--paper);
}
.meta-cell:last-child {
border-right: 0;
}
.meta-cell-head {
font-size: 8px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.2em;
color: var(--text-muted);
margin-bottom: 4px;
}
.meta-cell-value {
font-size: 13px;
font-weight: 700;
color: var(--text-main);
}
#description {
margin-bottom: 16px;
padding: 10px 13px;
background: var(--accent-soft);
border-left: 3px solid var(--accent);
font-size: 12px;
font-weight: 600;
color: var(--text-main);
margin-top: 0;
}
.table-shell {
border: 1px solid var(--border-strong);
border-radius: 8px;
overflow: hidden;
background: var(--paper);
margin-bottom: 25px;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
#table-headers th {
font-weight: 700;
font-size: 10px;
text-transform: uppercase;
letter-spacing: .11em;
padding: 10px;
background: var(--accent-strong);
color: #fff;
text-align: start;
border-right: 1px solid rgba(255,255,255,.12);
}
#table-headers th:last-child {
border-right: 0;
}
#table-rows td {
padding: 9px 10px;
vertical-align: top;
border-top: 1px solid var(--border-soft);
color: var(--text-main);
}
#table-rows tr.row:nth-child(even) td {
background: var(--border-soft);
}
#table-rows tr.last-row td {
padding-bottom: 16px;
border-bottom: 2px solid var(--border-strong);
}
#table-rows tr.total td {
border-top: none;
}
#table-rows tr.total td:first-child {
text-align: end;
font-size: 10px;
text-transform: uppercase;
color: var(--text-muted);
}
#table-rows tr.total td:last-child {
border: 1px solid var(--border-strong);
text-align: right;
font-weight: 700;
background: var(--paper);
padding: 7px 10px;
min-width: 130px;
color: var(--text-main);
}
#table-rows tr.total:last-child td:last-child {
background: var(--accent-soft);
color: var(--accent-strong);
font-size: 16px;
font-weight: 900;
border-color: var(--accent);
}
#custom-fields {
margin-top: 15px;
font-size: 12px;
color: var(--text-main);
}
.custom-field {
margin-bottom: 10px;
}
.custom-field-label {
color: var(--accent-strong);
font-weight: 700;
}
#footers {
margin-top: 20px;
font-size: 11px;
line-height: 1.6;
color: var(--text-muted);
}
.footer-item {
margin-top: 15px;
}
#status {
text-align: center;
margin-top: 15px;
margin-bottom: 15px;
}
.status-badge {
border: 2px solid var(--accent);
padding: 8px 18px;
font-size: 16px;
font-weight: 800;
text-transform: uppercase;
color: var(--accent-strong);
background: var(--accent-soft);
display: inline-block;
}
.status-badge.negative {
border-color: red;
color: red;
background: #fff5f5;
}
.status-badge.positive {
border-color: #059669;
color: #059669;
background: #ecfdf5;
}
.footer-shell {
margin-top: 40px;
padding-top: 10px;
border-top: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: flex-end;
gap: 16px;
}
.it-authority-seal {
display: flex;
align-items: center;
gap: 8px;
}
.it-authority-text {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
font-size: 7.5px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1px;
color: #94a3b8;
line-height: 1.1;
}
.it-link {
color: var(--inspiron-cyan);
text-decoration: none;
font-weight: 900;
}
.footer-right {
text-align: right;
font-size: 8px;
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--text-muted);
}
.footer-right span {
display: block;
color: var(--accent-strong);
font-weight: 700;
margin-top: 2px;
}
.error-box {
padding: 3rem;
color: #dc2626;
font-weight: 700;
text-align: center;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
</style>
</head>
<body>
<main id="document-root">
<div style="padding: 2rem; text-align: center; color: var(--text-muted); font-weight: 600;">
Rendering System Architecture...
</div>
</main>
<script>
fetch('/api4/view-v1' + window.location.search, {
headers: { 'Accept': 'application/json' },
credentials: 'same-origin'
})
.then(function(res) {
if (!res.ok) throw new Error('Failed to fetch view data');
return res.json();
})
.then(function(data) {
document.title = [
data && data.title,
data && data.reference,
data && data.business && data.business.name ? data.business.name : data && data.businessName
].filter(Boolean).join(' - ') || 'Document';
renderDocument(data);
})
.catch(function(error) {
showError(error);
});
function renderDocument(data) {
var root = document.getElementById('document-root');
root.replaceChildren();
if (!data) {
showError(new Error('No document data returned'));
return;
}
var content = document.createElement('div');
content.style.flexGrow = '1';
content.appendChild(createTopBar(data));
var metaStrip = createMetaStrip(data);
if (metaStrip) content.appendChild(metaStrip);
if (data.table && data.table.description) {
var description = document.createElement('p');
description.id = 'description';
appendTextWithBreaks(description, data.table.description);
content.appendChild(description);
}
var table = createTable(data);
if (table) content.appendChild(table);
var customFields = createCustomFields(data);
if (customFields) content.appendChild(customFields);
var footers = createFooters(data);
if (footers) content.appendChild(footers);
var status = createStatus(data);
if (status) content.appendChild(status);
root.appendChild(content);
root.appendChild(createAuthorityFooter());
}
function createTopBar(data) {
var topBar = div('top-bar');
topBar.appendChild(createPartyColumn(data));
var center = div('top-col center');
var title = document.createElement('h1');
title.id = 'title';
title.textContent = safeText(data.title || 'Document');
center.appendChild(title);
var kicker = div('title-kicker');
kicker.textContent = 'Corporate Blue · Column Shell';
center.appendChild(kicker);
array(data.subtitles).forEach(function(subtitle) {
var p = document.createElement('p');
p.className = 'doc-subtitle';
p.textContent = safeText(subtitle);
center.appendChild(p);
});
topBar.appendChild(center);
var right = div('top-col right');
right.appendChild(createLogoBlock(data));
topBar.appendChild(right);
return topBar;
}
function createPartyColumn(data) {
var column = div('top-col');
if (data.recipient) {
appendDiv(column, 'Bill To', 'party-label');
appendDiv(column, data.recipient.name, 'party-name');
appendMultiline(column, data.recipient.address, 'party-text');
var details = [];
if (data.recipient.code) details.push('Code: ' + data.recipient.code);
if (data.recipient.email) details.push('Email: ' + data.recipient.email);
if (details.length) {
appendMultiline(column, details.join('\n'), 'rec-details');
}
} else {
appendDiv(column, 'Issued By', 'party-label');
appendDiv(column, businessName(data), 'party-name');
if (data.business) {
appendMultiline(column, data.business.address, 'party-text');
}
}
return column;
}
function createLogoBlock(data) {
if (data.business && data.business.logo) {
var logoUrl = safeImageUrl(data.business.logo);
if (logoUrl) {
var wrap = document.createElement('div');
wrap.id = 'business-logo';
var img = document.createElement('img');
img.src = logoUrl;
img.alt = businessName(data);
wrap.appendChild(img);
return wrap;
}
}
var fallback = div('business-name-logo');
fallback.textContent = businessName(data);
return fallback;
}
function createMetaStrip(data) {
var fields = [];
if (data.reference) {
fields.push({ label: 'Reference', text: data.reference });
}
array(data.fields).forEach(function(field) {
if (field && (field.displayAtTheTop || !data.recipient)) {
fields.push({ label: field.label, text: field.text });
}
});
fields.push({ label: 'Issued By', text: businessName(data) });
if (!fields.length) return null;
var strip = div('meta-strip');
strip.id = 'meta-strip';
fields.forEach(function(field) {
var cell = div('meta-cell');
appendDiv(cell, field.label, 'meta-cell-head');
appendDiv(cell, field.text, 'meta-cell-value');
strip.appendChild(cell);
});
return strip;
}
function createTable(data) {
if (!data.table) return null;
var columns = getLeafColumns(data.table.columns);
if (!columns.length) return null;
var shell = div('table-shell');
var table = document.createElement('table');
var thead = document.createElement('thead');
var headerRow = document.createElement('tr');
headerRow.id = 'table-headers';
columns.forEach(function(column) {
var th = document.createElement('th');
th.className = 'align-' + safeAlignToken(column.align || 'start');
th.style.textAlign = safeCssAlign(column.align);
if (column.shrinkToFit) {
th.style.width = '1%';
th.style.whiteSpace = 'nowrap';
}
th.textContent = safeText(column.label);
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
var tbody = document.createElement('tbody');
tbody.id = 'table-rows';
array(data.table.rows).forEach(function(row) {
renderRow(tbody, row, columns);
});
var rowEls = tbody.querySelectorAll('tr.row');
if (rowEls.length) {
rowEls[rowEls.length - 1].classList.add('last-row');
}
renderTotals(tbody, data, columns);
table.appendChild(tbody);
shell.appendChild(table);
return shell;
}
function renderRow(tbody, row, columns) {
if (!row || !row.cells) return;
if (array(row.rows).length && array(row.cells).length === 1) {
var groupTr = document.createElement('tr');
groupTr.className = 'row row-group';
var groupTd = document.createElement('td');
groupTd.colSpan = Math.max(columns.length, 1);
groupTd.style.fontWeight = '700';
groupTd.style.color = 'var(--accent-strong)';
appendCell(groupTd, row.cells[0]);
groupTr.appendChild(groupTd);
tbody.appendChild(groupTr);
array(row.rows).forEach(function(childRow) {
renderRow(tbody, childRow, columns);
});
return;
}
var tr = document.createElement('tr');
tr.className = row.isTotalRow ? 'row row-total' : 'row';
if (row.isTotalRow) {
tr.style.fontWeight = '700';
}
var cells = array(row.cells);
columns.forEach(function(column, index) {
var td = document.createElement('td');
td.className = 'align-' + safeAlignToken(column.align || 'start');
td.style.textAlign = safeCssAlign(column.align);
if (column.nowrap) td.style.whiteSpace = 'nowrap';
if (column.emphasis || row.isTotalRow) td.style.fontWeight = '700';
appendCell(td, cells[index]);
tr.appendChild(td);
});
tbody.appendChild(tr);
array(row.rows).forEach(function(childRow) {
renderRow(tbody, childRow, columns);
});
}
function renderTotals(tbody, data, columns) {
var totals = array(data.totals);
if (!totals.length || !columns.length) return;
totals.forEach(function(total, index) {
var tr = document.createElement('tr');
tr.className = index === totals.length - 1 ? 'total last-total' : 'total';
if (columns.length === 1) {
var onlyTd = document.createElement('td');
onlyTd.style.textAlign = 'right';
onlyTd.style.fontWeight = total.emphasis ? '800' : '700';
onlyTd.textContent = [total.label, total.text].filter(Boolean).join(' ');
tr.appendChild(onlyTd);
tbody.appendChild(tr);
return;
}
var labelTd = document.createElement('td');
labelTd.colSpan = Math.max(columns.length - 1, 1);
labelTd.style.textAlign = 'right';
labelTd.style.fontWeight = total.emphasis ? '800' : '700';
labelTd.textContent = safeText(total.label);
var valueTd = document.createElement('td');
valueTd.style.textAlign = 'right';
valueTd.style.fontWeight = total.emphasis ? '800' : '700';
valueTd.textContent = safeText(total.text);
tr.appendChild(labelTd);
tr.appendChild(valueTd);
tbody.appendChild(tr);
});
}
function createCustomFields(data) {
var fields = array(data.fields).filter(function(field) {
return field && !field.displayAtTheTop;
});
if (!fields.length) return null;
var wrap = document.createElement('div');
wrap.id = 'custom-fields';
fields.forEach(function(field) {
var item = div('custom-field');
var label = document.createElement('strong');
label.className = 'custom-field-label';
label.textContent = safeText(field.label) + ':';
item.appendChild(label);
item.appendChild(document.createElement('br'));
appendFieldValue(item, field);
wrap.appendChild(item);
});
return wrap;
}
function createFooters(data) {
var footers = array(data.footers);
if (!footers.length) return null;
var wrap = document.createElement('div');
wrap.id = 'footers';
footers.forEach(function(footerText) {
var item = div('footer-item');
appendTextWithBreaks(item, footerText);
wrap.appendChild(item);
});
return wrap;
}
function createStatus(data) {
if (!data.status || !data.status.text) return null;
var wrap = document.createElement('div');
wrap.id = 'status';
var badge = document.createElement('span');
badge.className = 'status-badge ' + safeStatusTone(data.status.tone);
badge.textContent = safeText(data.status.text);
wrap.appendChild(badge);
return wrap;
}
function createAuthorityFooter() {
var footer = div('footer-shell');
var seal = div('it-authority-seal');
seal.appendChild(createAuthoritySvg());
var text = div('it-authority-text');
text.appendChild(document.createTextNode('Architected by MD ABU HASAN'));
text.appendChild(document.createElement('br'));
var link = document.createElement('a');
link.href = 'https://inspiron.tech';
link.target = '_blank';
link.rel = 'noopener noreferrer';
link.className = 'it-link';
link.textContent = 'inspiron.tech';
text.appendChild(link);
seal.appendChild(text);
footer.appendChild(seal);
var right = div('footer-right');
right.appendChild(document.createTextNode('Corporate Billing Series'));
right.appendChild(document.createElement('br'));
var span = document.createElement('span');
span.textContent = 'Blue Column Shell · v2026';
right.appendChild(span);
footer.appendChild(right);
return footer;
}
function createAuthoritySvg() {
var svgNs = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNs, 'svg');
svg.setAttribute('viewBox', '0 0 358.846 350.3');
svg.setAttribute('width', '22');
svg.setAttribute('height', '22');
svg.setAttribute('fill', 'none');
svg.setAttribute('aria-hidden', 'true');
appendSvgPath(svg, 'M321.346 350c-10.6-1-19.3-6.1-26-15.3-.3-.6-4.3-7.3-10-16.5-49.2-81.1-52.8-87.8-52.6-88.4 5.5-8.8 19.4-31.2 27.4-43.8 3.3-5.4 5.7-9 6-9.4 1.6 2.7 27.4 45.3 49.4 81.8 17 28.2 31.9 52.8 32.2 53.5 4.2 7 4.2 15.2 0 22.5-5.2 9-15.4 14.9-25.6 14.9h-.8z', '#00D2FF');
appendSvgPath(svg, 'M87.046 349.3c-30.8 0-57.9-14.8-74.3-40.9-15.4-24.2-16.9-55-4.2-80.5 7.8-14.2 32.9-53.9 57.4-92.4 15.1-23.7 29.3-46.1 39.3-62.6 2.7-4.3 4.8-7.8 8.4-11.5 11.4-13.1 28.1-20.6 45.6-20.6s33.8 8.1 43.8 22.1c5.5 7.8 9.1 16.9 10.3 26.4.3 2.5-.4 4.8-2.1 7.5-1.9 3.3-21.8 34.6-21.8 34.6-.6.9-1.2 1.9-1.8 2.8-1.3 2.2-2.4 4.2-3.9 4.2s-1.2-.3-1.8-.9c-4.2-4.9-8.2-11.5-12-18-2.4-4-4.5-7.9-6.9-11.2-1.8-2.8-4.8-4.5-7.8-4.5s-4.2 1-5.8 3c-5.2 8.1-27.5 43.8-45.6 72.7-11.8 18.9-22.1 35.3-25.4 40.4-2.2 3.6-5.2 8.1-7.9 12.5-1.6 2.7-3.3 5.4-4.8 7.8-.6 1-1.3 2.1-1.9 3.1-2.5 4-4.6 7.5-6.1 11.1-5.2 12.4-.4 27.3 10.9 34.6 5.5 3.6 11.4 5.4 17.5 5.4 12.3 0 25-7.6 32.9-20 5.5-8.1 23.6-37 45-70.6 31.7-50.4 67.9-107.5 76.1-118.7 6.3-6.7 14.5-10.8 22.7-10.8 9.3 0 18.2 5.1 23.2 13.1 4.8 7.9 5.4 16.8 1 24.7-3.6 7-6.6 11.3-10.9 18-3.1 4.9-7.3 11.2-13 20.6-14.4 22.5-31 48.7-47 74.2-24.4 38.9-47.7 75.7-55.3 86.8-17.5 24.1-45.5 38.6-75.1 38.6z', '#00D2FF');
var circle = document.createElementNS(svgNs, 'circle');
circle.setAttribute('cx', '321.346');
circle.setAttribute('cy', '37.5');
circle.setAttribute('r', '37.5');
circle.setAttribute('fill', '#FFD700');
svg.appendChild(circle);
return svg;
}
function appendSvgPath(svg, d, fill) {
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute('d', d);
path.setAttribute('fill', fill);
svg.appendChild(path);
}
function appendFieldValue(parent, field) {
if (!field) return;
if (field.image && field.image.url) {
var imageUrl = safeImageUrl(field.image.url);
if (imageUrl) {
var img = document.createElement('img');
img.src = imageUrl;
img.alt = safeText(field.text || field.label);
if (field.image.width) img.width = safeDimension(field.image.width);
if (field.image.height) img.height = safeDimension(field.image.height);
parent.appendChild(img);
}
} else if (field.link && field.link.url) {
var linkUrl = safeLinkUrl(field.link.url);
if (linkUrl) {
var a = document.createElement('a');
a.href = linkUrl;
a.target = '_top';
a.rel = 'noopener noreferrer';
a.textContent = safeText(field.text);
parent.appendChild(a);
} else {
appendMultiline(parent, field.text);
}
} else {
appendMultiline(parent, field.text);
}
array(field.fields).forEach(function(subfield) {
appendDiv(parent, subfield.label, 'custom-field-label');
appendFieldValue(parent, subfield);
});
}
function appendCell(parent, cell) {
if (!cell) return;
var content;
if (cell.image && cell.image.url) {
var imageUrl = safeImageUrl(cell.image.url);
if (!imageUrl) return;
content = document.createElement('img');
content.src = imageUrl;
content.alt = safeText(cell.text);
content.style.maxWidth = '100px';
if (cell.image.width) content.width = safeDimension(cell.image.width);
if (cell.image.height) content.height = safeDimension(cell.image.height);
} else {
content = document.createElement('span');
appendTextWithBreaks(content, cell.text || '');
}
if (cell.link && cell.link.url) {
var linkUrl = safeLinkUrl(cell.link.url);
if (linkUrl) {
var a = document.createElement('a');
a.href = linkUrl;
a.target = '_top';
a.rel = 'noopener noreferrer';
a.style.color = 'var(--accent)';
a.style.textDecoration = 'none';
a.appendChild(content);
parent.appendChild(a);
} else {
parent.appendChild(content);
}
} else {
parent.appendChild(content);
}
}
function appendDiv(parent, text, className) {
if (text === null || text === undefined || text === '') return;
var el = div(className);
el.textContent = safeText(text);
parent.appendChild(el);
}
function appendMultiline(parent, text, className) {
if (text === null || text === undefined || text === '') return;
var el = div(className);
appendTextWithBreaks(el, text);
parent.appendChild(el);
}
function appendTextWithBreaks(parent, text) {
String(text || '').split('\n').forEach(function(line, index) {
if (index > 0) parent.appendChild(document.createElement('br'));
parent.appendChild(document.createTextNode(line));
});
}
function div(className) {
var el = document.createElement('div');
if (className) el.className = className;
return el;
}
function businessName(data) {
return safeText(data.business && data.business.name ? data.business.name : data.businessName);
}
function getLeafColumns(columns) {
var result = [];
array(columns).forEach(function(column) {
if (column && array(column.subcolumns).length) {
result = result.concat(getLeafColumns(column.subcolumns));
} else if (column) {
result.push(column);
}
});
return result;
}
function safeText(value) {
return value === null || value === undefined ? '' : String(value);
}
function safeUrl(value, allowedProtocols) {
if (!value) return '';
try {
var url = new URL(String(value), window.location.origin);
if (allowedProtocols.indexOf(url.protocol) === -1) {
return '';
}
return url.href;
} catch (_error) {
return '';
}
}
function safeLinkUrl(value) {
return safeUrl(value, ['http:', 'https:', 'mailto:', 'tel:']);
}
function safeImageUrl(value) {
return safeUrl(value, ['http:', 'https:']);
}
function safeCssAlign(value) {
if (value === 'right' || value === 'center' || value === 'left') return value;
if (value === 'end') return 'right';
if (value === 'start') return 'left';
return 'left';
}
function safeAlignToken(value) {
if (value === 'right' || value === 'center' || value === 'left' || value === 'start' || value === 'end') {
return value;
}
return 'start';
}
function safeStatusTone(value) {
if (value === 'positive' || value === 'negative') return value;
return 'neutral';
}
function safeDimension(value) {
var number = Number(value);
if (!Number.isFinite(number) || number <= 0) {
return 1;
}
return Math.min(Math.round(number), 2000);
}
function array(value) {
return Array.isArray(value) ? value : [];
}
function showError(error) {
var root = document.getElementById('document-root');
if (!root) return;
root.replaceChildren();
var box = div('error-box');
box.textContent = 'SYSTEM FAULT: FAILED TO FETCH VIEW DATA';
if (error && error.message) {
box.appendChild(document.createElement('br'));
box.appendChild(document.createTextNode(error.message));
}
root.appendChild(box);
}
</script>
</body>
</html>