type OfflineContent = {
title: string;
kind: string;
sourcePath: string;
rows: [string, string][];
sections: { title: string; text: string }[];
notice: string;
};
export const offlineValue = (value?: string | null) =>
value?.trim() || 'Não indicado';
const escapeHtml = (value: string) =>
value.replace(
/[&<>"']/g,
(character) =>
({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
})[character]!,
);
/** All content is plain text; assets and executable content are excluded. */
export function publicRecordOfflineHtml(
content: OfflineContent,
origin: string,
savedAt: Date,
): string {
const base = new URL(origin);
if (!['http:', 'https:'].includes(base.protocol))
throw new Error('Origem do portal inválida.');
const source = new URL(content.sourcePath, base.origin);
if (
source.origin !== base.origin ||
!content.sourcePath.startsWith('/') ||
content.sourcePath.startsWith('//')
)
throw new Error('Referência da ficha inválida.');
return `
${escapeHtml(content.title)} — consulta offline${escapeHtml(content.title)}
${escapeHtml(content.kind)} — InvesteMoz
Cópia guardada em ${escapeHtml(savedAt.toISOString())}. Consulte a ficha online para verificar actualizações.
${content.rows.map(([label, value]) => `- ${escapeHtml(label)}
- ${escapeHtml(value)}
`).join('')}
${content.sections.map((section) => `${escapeHtml(section.title)}
${escapeHtml(section.text)}
`).join('')}${escapeHtml(content.notice)}
Consultar a ficha de origem online
`;
}
export function downloadOfflineHtml(
html: string,
prefix: string,
slug: string,
): void {
const url = URL.createObjectURL(
new Blob([html], { type: 'text/html;charset=utf-8' }),
);
const link = document.createElement('a');
link.href = url;
link.download =
`${prefix}-${slug}`.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 120) +
'.html';
try {
document.body.appendChild(link);
link.click();
} finally {
link.remove();
window.setTimeout(() => URL.revokeObjectURL(url), 1000);
}
}