| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| function escapeHtmlText(s) { |
| return String(s) |
| .replace(/&/g, '&') |
| .replace(/</g, '<') |
| .replace(/>/g, '>') |
| .replace(/"/g, '"'); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function documentTitleEn(meta) { |
| const title = String(meta.title ?? '').trim(); |
| const subtitle = String(meta.subtitle ?? '').trim(); |
| if (!title) return subtitle; |
| if (!subtitle) return title; |
| const joiner = subtitle.startsWith('-') ? ' ' : ' - '; |
| return title + joiner + subtitle; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function injectDataPageBlock(html, attrToken, text) { |
| const esc = escapeHtmlText(text); |
| const re = new RegExp( |
| `<([a-z][a-z0-9]*)([^>]*\\b${attrToken}\\b[^>]*)>([\\s\\S]*?)<\\/\\1>`, |
| 'gi' |
| ); |
| return html.replace(re, (_m, tag, attrs) => `<${tag}${attrs}>${esc}</${tag}>`); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function injectPageMeta(html, pageKey, doc) { |
| const meta = doc.pages[pageKey]; |
| if (!meta) { |
| throw new Error(`injectPageMeta: unknown pageKey "${pageKey}"`); |
| } |
|
|
| const dt = documentTitleEn(meta); |
| html = html.replace(/<title[^>]*>[^<]*<\/title>/i, `<title data-i18n>${escapeHtmlText(dt)}</title>`); |
|
|
| html = injectDataPageBlock(html, 'data-page-title', meta.title); |
| html = injectDataPageBlock(html, 'data-page-subtitle', meta.subtitle); |
|
|
| const heartlineElRe = /<([a-z][a-z0-9]*)([^>]*\bdata-page-heartline\b[^>]*)>([\s\S]*?)<\/\1>/gi; |
| if (meta.heartline) { |
| html = html.replace(heartlineElRe, (_m, tag, attrs) => `<${tag}${attrs}>${escapeHtmlText(meta.heartline)}</${tag}>`); |
| } else { |
| html = html.replace(heartlineElRe, ''); |
| } |
|
|
| const formulaElRe = /<([a-z][a-z0-9]*)([^>]*\bdata-page-formula\b[^>]*)>([\s\S]*?)<\/\1>/gi; |
| if (meta.formula) { |
| html = html.replace(formulaElRe, (_m, tag, attrs) => `<${tag}${attrs}>${escapeHtmlText(meta.formula)}</${tag}>`); |
| } else { |
| html = html.replace(formulaElRe, ''); |
| } |
|
|
| if (pageKey === 'home' && Array.isArray(doc.navPageKeys)) { |
| for (const navKey of doc.navPageKeys) { |
| const navMeta = doc.pages[navKey]; |
| if (!navMeta) { |
| throw new Error(`injectPageMeta: navPageKeys references missing page "${navKey}"`); |
| } |
| const navTitle = documentTitleEn(navMeta); |
| const re = new RegExp( |
| `(<a\\b[^>]*\\bdata-nav-page=["']?${navKey}["']?[^>]*>)([\\s\\S]*?)(<\\/a>)`, |
| 'i' |
| ); |
| const m = html.match(re); |
| if (!m) { |
| throw new Error(`injectPageMeta: missing <a data-nav-page="${navKey}"> in home HTML`); |
| } |
| let openTag = m[1]; |
| if (navMeta.href) { |
| if (/\bhref\s*=/.test(openTag)) { |
| openTag = openTag.replace( |
| /\bhref\s*=\s*("[^"]*"|'[^']*')/i, |
| `href="${escapeHtmlText(navMeta.href)}"` |
| ); |
| } else { |
| openTag = openTag.replace(/>$/, ` href="${escapeHtmlText(navMeta.href)}">`); |
| } |
| } |
| if (/\btitle\s*=/.test(openTag)) { |
| openTag = openTag.replace(/\btitle\s*=\s*("[^"]*"|'[^']*')/i, `title="${escapeHtmlText(navTitle)}"`); |
| } else { |
| openTag = openTag.replace(/>$/, ` title="${escapeHtmlText(navTitle)}">`); |
| } |
| const shot = |
| navKey === 'genAttribute' |
| ? `<video class="nav-landing-card-shot" muted loop playsinline autoplay preload="metadata" aria-hidden="true"></video>` |
| : `<div class="nav-landing-card-shot" aria-hidden="true"></div>`; |
| const inner = |
| `<div class="nav-landing-card-text">` + |
| `<span class="nav-landing-card-title" data-i18n>${escapeHtmlText(navMeta.title)}</span>` + |
| `<span class="nav-landing-card-subtitle" data-i18n>${escapeHtmlText(navMeta.subtitle)}</span>` + |
| `</div>` + |
| shot; |
| html = html.replace(re, `${openTag}${inner}${m[3]}`); |
| } |
| } |
|
|
| return html; |
| } |
|
|
| module.exports = { injectPageMeta, escapeHtmlText, documentTitleEn }; |
|
|