/** * Export naar één zelfdragende HTML-pagina. * * Bedoeld als laatste vangnet: als de app niet meer draait, de database weg is * en er geen backup ligt, moet dit ene bestand nog steeds al je gegevens tonen. * Daarom zit alles erin — opmaak inline, geen scripts, geen lettertypen of * afbeeldingen van buiten. Het bestand is op een computer zonder internet, over * tien jaar, in elke browser nog te openen. * * Het is bovendien tegelijk een backup. Onderaan de pagina staat de complete * ruwe data in een `` in de gegevens het blok voortijdig // af en is zowel de pagina als de backup stuk. const jsonBlok = ruweData ? `\n\n` : ""; return ` VibeFinance — overzicht ${esc(exportDatum)}

VibeFinance

Volledig overzicht · geëxporteerd op ${esc(exportDatum)}${gebruiker ? ` · ${esc(gebruiker)}` : ""}

Samenvatting

${kpis.map(([l, v]) => `
${esc(l)}${esc(v)}
`).join("")}
${sectie("Eigen vermogen", evRijen.length ? maakTabel(["Categorie", "Post", "Waarde"], evRijen, [2]) : "", "Geen vermogensposten ingevoerd.")} ${sectie("Schulden", schuldRijen.length ? maakTabel(["Blok", "Onderdeel", "Waarde"], schuldRijen, [2]) : "", "Geen schulden ingevoerd.")} ${sectie("Voortgang eigen vermogen", voortgangRijen.length ? maakTabel( [ "Datum", ...cats.map((c) => c.naam), // Een verwijderde categorie heeft geen naam meer; de sleutel is dan // het enige wat er nog van over is. ...wezen.map((k) => `Verwijderd (${k})`), "Totaal storting", "Netto waarde", "Verschil", "Opmerkingen", ], voortgangRijen, // Alle bedragkolommen: vanaf kolom 1 tot en met "Verschil". Array.from({ length: kolomIds.length + 3 }, (_, i) => i + 1), ) : "", "Geen voortgangsmomenten vastgelegd.")} ${sectie("Historie eigen vermogen en schuld", historieRijen.length ? maakTabel(["Datum", "Eigen vermogen", "Schuld", "Netto waarde", "Opmerkingen"], historieRijen, [1, 2, 3]) : "", "Geen historie vastgelegd.")}
${jsonBlok} `; } /** * Haalt de ingebakken backup uit een geëxporteerde pagina terug. * * Bewust met DOMParser en niet met een reguliere expressie: de gegevens kunnen * zelf van alles bevatten, en een parser die HTML écht begrijpt trapt daar niet * in. De pagina wordt niet uitgevoerd — DOMParser draait geen scripts, en het * blok is `type="application/json"`, dus ook in een browser geen code. * * @returns {object|null} de data, of null als het geen export-pagina is */ export function leesHtmlBackup(htmlTekst) { const doc = new DOMParser().parseFromString(htmlTekst, "text/html"); const blok = doc.getElementById("vibefinance-backup"); if (!blok) return null; return JSON.parse(blok.textContent); }