Files
edentext/src/lib/storage/autoText.ts
T
Steffen Becker 572e3a760d fix: an AutoText entry keeps a text box
Entries were stored as an HTML string, where any block tag inside a <p>
closes it — so a copied text box, which holds blocks, lost its place in
the line. They now keep the slice's nodes; an entry written earlier keeps
its HTML string, which insertContent takes just as well.
2026-09-04 19:30:01 +02:00

48 lines
1.9 KiB
TypeScript

// LibreOffice's Tools ▸ AutoText / Word's Insert ▸ Quick Parts: named blocks of text
// kept beside the documents, not in one. Both products store them in a template of
// their own (`.bau`, a `.dotx`); here they live in localStorage, so they outlive the
// document that made them.
import type { JSONContent } from '@tiptap/core';
export type AutoTextEntry = {
name: string;
/** Typed in the text, then F3 — LibreOffice's shortcut, case-insensitive. */
shortcut: string;
/** The entry's nodes, or the HTML an entry stored before they were kept as JSON. */
content: JSONContent[] | string;
};
const KEY = 'edentext-autotext';
/** The entry's content, taking an older entry's `html` as the string it already is. */
function contentOf(e: AutoTextEntry & { html?: unknown }): AutoTextEntry['content'] | null {
if (Array.isArray(e.content) || typeof e.content === 'string') return e.content;
return typeof e.html === 'string' ? e.html : null;
}
export function loadAutoText(): AutoTextEntry[] {
try {
const raw = localStorage.getItem(KEY);
const data = raw ? (JSON.parse(raw) as AutoTextEntry[]) : [];
if (!Array.isArray(data)) return [];
return data.flatMap((e) => {
const content = e && typeof e.name === 'string' ? contentOf(e) : null;
return content === null ? [] : [{ name: e.name, shortcut: String(e.shortcut ?? ''), content }];
});
} catch {
return [];
}
}
export function saveAutoText(list: AutoTextEntry[]): void {
if (list.length) localStorage.setItem(KEY, JSON.stringify(list));
else localStorage.removeItem(KEY);
}
/** The entry a typed shortcut names, matched as LibreOffice matches it: ignoring case. */
export function entryForShortcut(list: AutoTextEntry[], word: string): AutoTextEntry | null {
const key = word.trim().toLowerCase();
return key ? list.find((e) => e.shortcut.toLowerCase() === key) ?? null : null;
}