Two marks carry a revision with its author and date: an insertion is marked text, a deletion is text kept and struck through. Consecutive typing joins one change; accept/reject work at the cursor or on all. ODF splits the pair — text:change-start/-end around an insertion, a text:change where a deletion was, its text in the tracked-changes registry. DOCX uses w:ins/w:del with w:delText. Both round-trip, and accepting every change gives the document an unrecorded edit would.
7.8 KiB
7.8 KiB
src/lib/storage/
Page layout settings
pageMargins.ts—PageMarginsin cm (default{ top: 2, bottom: 2, left: 2, right: 2 }— LibreOffice's; clamped 0–10).applyMarginVarssets--user-margin-*(px) on:root;PX_PER_CM = 96/2.54. Optionalmirrored(ODFstyle:page-usage="mirrored", Wordw:mirrorMargins) makes left/right the inner/outer pair, which an even page swaps:--user-margin-mirrorcarries the difference,pageBreaks.tsinsets an even page's blocks by it andHeaderFooterLayer.sveltemoves the band. The key is absent, neverfalse, when off — margins are compared whole in the round-trip tests.tabInterval.ts— the document's default tab interval in cm (DEFAULT_TAB_INTERVAL_CM = 1.25, LibreOffice's for a new document; clamped 0.05–10).applyTabIntervalVarsets--tab-interval, which is.tiptap'stab-size. A file that declares none falls back to its format's own value, neither of them ours:ODF_IMPLIED_TAB_CM2cm (measured against LibreOffice),DOCX_IMPLIED_TAB_CM1.27cm — so both exports always write the value out.spacingModel.ts— how the gap between two blocks is measured:'add'(LibreOffice's own — space-below plus space-above) or'max'(the larger of the two, what it uses for a Word document). Probed against soffice; per document, read from ODFsettings.xml(AddParaTableSpacing), always'max'on DOCX import, and written back on ODF export.editor.cssturns--space-beforeinto padding or margin accordingly (CSS margins can only collapse, so'add'cannot be a margin).writingMode.ts— the page's text direction (loadPageRtl/savePageRtl,edentext-page-rtl), from ODFstyle:writing-mode="rl-tb"or Word's section-levelw:bidi.Editor.svelteputs it on the body host asdir, which is what makes a multi-column page fill from the right; the header/footer band is left alone (LibreOffice lays those out unchanged — measured). The vertical modes are not read.pageNumbering.ts— the page-number field's format and start value (edentext-page-numbering, absent at the 1/1 default).HeaderFooterLayer.svelteformats each page throughformatOrdinal; the page count stays decimal, as the field both word processors write does. ODF keeps the format on the page layout and the start on the first paragraph's own style (style:page-number— probed, ODF has no document-level start); Word keeps both in the first section'sw:pgNumType.hyphenation.ts— automatic hyphenation for the whole document (edentext-hyphenation, off by default as in both word processors).Editor.svelteputshyphens: autoand the documentlangon the body host — the browser needs the language to pick its patterns. ODF keeps it asfo:hyphenatein the text properties of the base paragraph style (probed: in paragraph-properties LibreOffice ignores it and drops it on the next save), Word asw:autoHyphenationin settings.xml.pageDecor.ts— the page's own decoration (edentext-page-decor, the key removed when all three are off): background colour, a border around the text area atpaddingCmfrom it, and a text watermark (LibreOffice's Format ▸ Watermark, field for field). All three ride the ODF page layout — the watermark as afontwork-plain-text<draw:custom-shape>namedPowerPlusWaterMarkObjectin the master page's header, the only place LibreOffice reads one from (probed: hung off the master page directly it is dropped, and an undeclaredxmlns:drawin styles.xml drops it too). Word keeps the background onw:document(plusw:displayBackgroundShape), the border inw:sectPrafterw:pgMar— the child order is fixed, and ahead of the header references Word's reader loses those — and the watermark as the VML_x0000_t136shape, whose definition has to travel or LibreOffice cannot resolve it.PageDecorLayer.sveltedraws border and watermark per page; the background is a--color-page-bgoverride on.paper.trackChanges.svelte.ts— whether the editor records revisions (edentext-record-changes, the key removed when off, as it is by default in both word processors). A reactive singleton because the extension reads it on every transaction while the Review tab flips it; the recorded changes themselves live in the document, on the marks.lineNumbering.ts— numbers in the left margin (edentext-line-numbering, the key removed when off, as it is by default in both word processors). ODF keeps one<text:linenumbering-configuration>inoffice:styles, Word a<w:lnNumType>perw:sectPr(probed).LineNumberLayer.sveltemeasures the lines: CSS exposes no line boxes, so a Range per block is taken and its distinct client-rect tops are the lines.pageOrientation.ts—'portrait' | 'landscape'.applyOrientationVarssets--user-page-{width,height}; landscape swaps the A4 dimensions (matching odf-kit's automatic swap).
Both margins and orientation are passed into the ODT export so the exported document's geometry/line-wrapping matches the on-screen preview.
localStorage keys
All keys share the edentext- prefix — a namespace, not a description: on GitHub Pages every repo of an account shares one origin, so a generic prefix would collide.
- Document:
edentext-doc— TipTap JSON, debounced 1 s on everyonUpdate(autosave.ts). Loading it raisesedentext-doc-loading, which only a completed startup clears (markDocumentLoaded, two frames afterEditor.svelte's mount). Still set at the next load = that document hung or crashed the editor: it moves toedentext-doc-brokenand the app starts empty, so a reload escapes the freeze instead of repeating it. - Theme:
edentext-theme—'light' | 'dark' | 'allBlack' | 'auto'. - Toolbar expanded:
edentext-toolbar-expanded— boolean string. - Chrome:
edentext-chrome—'classic' | 'ribbon'; absent = classic. - Ribbon collapsed:
edentext-ribbon-collapsed— boolean string; absent = expanded. - Formatting marks:
edentext-formatting-marks— boolean string. - Ruler:
edentext-ruler— boolean string; absent = on. - Zoom:
edentext-zoom— integer percent. - Page margins:
edentext-page-margins— JSON cm values. - Page orientation:
edentext-page-orientation—'portrait' | 'landscape'. - Tab interval:
edentext-tab-interval— cm as a decimal string. - Spacing model:
edentext-spacing-model—'add' | 'max'. - Recent fonts:
edentext-recent-fonts— JSON string array (ToolbarExpanded). - Header/footer:
edentext-header/-footer(HfDoc),edentext-hf-distances. - Styles:
edentext-styles— the style registry (styles/sheet.svelte.ts). - Document properties:
edentext-doc-properties— title/subject/author/keywords/comments (docProperties.ts); the key is removed when every field is empty, so a fresh document writes nothing intometa.xml. - AutoCorrect:
edentext-autocorrect— one flag per rule (autoCorrect.ts, reactive singleton inautoCorrect.svelte.ts), LibreOffice's defaults (all on). - Notes:
edentext-notes— footnote/endnote numbering and the separator (noteSettings.ts, reactive singleton innotes.svelte.ts);applyNoteVarsputs the separator on:root, whereeditor.cssdraws it andpageBreaks.tsreserves its band.
Themes (theme.ts, styles/global.css)
Four modes: light, dark, allBlack (forces font colors white), auto (follows prefers-color-scheme). Applied by setting data-theme on <html>; CSS variables for each theme live in global.css. The sheet keeps its own pair through light and dark — white paper, black text, the colour LibreOffice and Word draw an uncoloured run in (the app's slate would also differ from a run the file colours #000000); only allBlack inverts it.