captureAttributes and renderCaptured dropped only on* names, so id,
name, style, srcset, background and the like from stored HTML were
rendered by ProseMirror into the live admin DOM (DOM clobbering of
document.querySelector, fixed-position overlays, remote loads). htmlAttrs
now keeps an allowlist: class, title, alt, width, height, colspan,
rowspan, start, rel, target and data-*; href and src stay with the link
and image nodes. Other attributes are dropped from a block once it is
edited; untouched documents and untouched blocks keep their bytes.
- preservationExtensions: raw HTML cards for unmodelled blocks (shown as
text), figure with figcaption, the YouTube embed placeholder node, span
marks, a global attribute map (never on* handlers), tables without
colgroup or min-width, inline images without base64
- serializeDocument keeps the original bytes of every top-level block still
equal to the loaded one, so editing one paragraph changes only that
paragraph; tables serialize with thead and bare cell text
- Links accept only http, https, mailto and relative URLs (isPolicyUrl, the
rule both sanitizer policies apply) and gain no target, rel or class
- Toolbar with headings, marks, lists, links, blockquote, table editing,
images, embeds, raw HTML block, undo and redo; en and pl labels
- Images from the picker or a drop go out as summer-upload and are inserted
on summer-upload-result with alt text and an optional caption
- editor-corpus.json: the editor own output, rebuilt and checked by
corpus.test.ts (UPDATE_CORPUS=1 rewrites it) for the policy tests
- README Blog Editor section