/** * GoingsOn - "What's New" after-update dialog * * After an OTA update applies and the app relaunches on the new version, this * surfaces the matching CHANGELOG.md section once, so beta testers see what * changed at the moment they hit the update. Shown at most once per version; * the first-ever launch is owned by the welcome flow, not this dialog. */ (function() { 'use strict'; const LAST_VERSION_KEY = 'go-last-version'; /** * Pull the body of a single version's section out of a Keep a Changelog * document. Matches the `## []` header and collects every line up * to the next `## [` header. Returns '' when the version isn't present. */ function extractSection(markdown, version) { const lines = String(markdown).split('\n'); const body = []; let inSection = false; for (const line of lines) { const header = line.match(/^##\s+\[([^\]]+)\]/); if (header) { if (inSection) break; // next version reached if (header[1] === version) { inSection = true; } continue; // skip the header line itself } if (inSection) body.push(line); } return body.join('\n').trim(); } /** * Render a changelog section (Keep a Changelog format) to safe HTML. * Everything is HTML-escaped; only the structural markup is ours. */ function renderSection(section) { const esc = GoingsOn.utils.escapeHtml; const out = []; let listOpen = false; const closeList = () => { if (listOpen) { out.push(''); listOpen = false; } }; for (const raw of section.split('\n')) { const line = raw.trim(); if (!line) continue; const heading = line.match(/^###\s+(.*)$/); const bullet = line.match(/^[-*]\s+(.*)$/); if (heading) { closeList(); out.push(`

${esc(heading[1])}

`); } else if (bullet) { if (!listOpen) { out.push('