Editing one paragraph silently un-aligned the others. A right-aligned line lost its alignment because
somebody justified something else — which reads as the alignment buttons applying to the whole document
rather than the selection, and is not that at all.
THE ROUND TRIP WAS LOSSY IN ONE DIRECTION. The editor emits `style="text-align: right"`; the site's
sanitiser refuses style attributes — one is a way to position something over the rest of the page — and
converts alignment to `class="rt-right"`. That half always worked.
Coming back out, tiptap parses styles and knows nothing about those classes. So a document loaded from
the database arrived with every alignment already gone, and the next save wrote the loss back. Whatever
you set in the current session survived; everything set before it did not.
Converting classes to styles as the editor is seeded makes the two ends symmetric, and the conversion is
the sanitiser's own table read backwards. The comparison in the re-seed effect had to move into the
editor's dialect too, or every load looks like a change: the stored html and getHTML() never match.
`rt-font-*` is not converted, and that is a known gap rather than an oversight — this editor has no font
control, so a stored font class has nothing to become and would be dropped either way. It wants a font
button before it wants a parser.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`rt-justify` has been in the sanitiser's allowlist all along, and styles.css gives it `text-align:
justify` with `hyphens: auto` — hyphenation being what stops justified text opening rivers of white
space between words. Only the toolbar was missing it.
The four are now a list beside the toolbar rather than a ternary chain, and the comment says what it has
to match: ALIGN_CLASSES in the site's rich-text.ts. A fifth offered here would be stripped on save,
silently, leaving somebody pressing a button that appears to do nothing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two things.
`?media=` is Media's own folder and now goes when you leave it. It survived
every navigation, so `?section=home&media=GALLERY/CALAVERA+1` was an ordinary
URL — a parameter naming a folder in a section that is not open, carried into
every link and shared or bookmarked that way.
And the intro is a tiptap editor rather than a textarea of raw HTML. HTML in and
HTML out, because that is already what the site's database holds and renders —
introducing a second format would buy a migration and a round-tripping bug class
for nothing.
Declared as the PLUGIN's npmDependencies, not added to the platform's
package.json. That lockfile is frozen and shared, and npm-deps.ts exists for
exactly this: everything lands in plugins/node_modules/, so a plugin's editor
cannot move a version the platform depends on.
The toolbar is only what the site's stylesheet can render. Anything more would
produce copy that looks right while editing and wrong when published, which the
person only discovers after saying it was done.
The content effect compares against getHTML() before writing back, and that
comparison is the whole thing: while somebody types the two already agree, so
nothing is pushed in and the caret stays put. Without it this is the classic
controlled-contentEditable bug where the cursor jumps to the end on every
keystroke.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>