@richscripts/richtexteditor 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/migration/README.md +100 -0
- package/migration/cli.js +294 -0
- package/migration/index.d.ts +18 -0
- package/migration/index.js +242 -0
- package/migration/report-schema-v2.json +127 -0
- package/package.json +14 -2
- package/richtexteditor/CHANGELOG.md +326 -1
- package/richtexteditor/all_plugins.js +14982 -4831
- package/richtexteditor/all_plugins.min.js +62 -42
- package/richtexteditor/plugins/accessibilitychecker.js +8 -7
- package/richtexteditor/plugins/aitoolkit.css +17 -8
- package/richtexteditor/plugins/aitoolkit.js +8 -8
- package/richtexteditor/plugins/all_plugins.js +14982 -4831
- package/richtexteditor/plugins/all_plugins.min.js +62 -42
- package/richtexteditor/plugins/autocorrect.js +353 -0
- package/richtexteditor/plugins/bookmarkcard.js +12 -1
- package/richtexteditor/plugins/changecase.js +238 -0
- package/richtexteditor/plugins/comments.js +15 -28
- package/richtexteditor/plugins/contentminimap.js +6 -5
- package/richtexteditor/plugins/crdt-engine.js +2201 -198
- package/richtexteditor/plugins/crdt-engine.min.js +5 -5
- package/richtexteditor/plugins/crossreference.js +408 -0
- package/richtexteditor/plugins/documentimport.js +915 -21
- package/richtexteditor/plugins/documentoutline.js +5 -4
- package/richtexteditor/plugins/docxexport.js +960 -0
- package/richtexteditor/plugins/draghandle.js +309 -0
- package/richtexteditor/plugins/footnotes.js +398 -0
- package/richtexteditor/plugins/formatpainter.js +298 -0
- package/richtexteditor/plugins/formattingmarks.js +246 -0
- package/richtexteditor/plugins/html2pdf.js +108 -4
- package/richtexteditor/plugins/imageeditor.js +37 -7
- package/richtexteditor/plugins/insertgallery.js +553 -170
- package/richtexteditor/plugins/keyboarda11y.js +316 -0
- package/richtexteditor/plugins/linenumbers.js +352 -0
- package/richtexteditor/plugins/linkchecker.js +396 -0
- package/richtexteditor/plugins/mentionplugin.js +4 -3
- package/richtexteditor/plugins/mergefields.js +328 -0
- package/richtexteditor/plugins/multilevellist.js +137 -0
- package/richtexteditor/plugins/pagination.js +505 -0
- package/richtexteditor/plugins/pdfexport.js +1137 -0
- package/richtexteditor/plugins/permanentpen.js +211 -0
- package/richtexteditor/plugins/revisionhistory.js +47 -34
- package/richtexteditor/plugins/rtlui.js +150 -0
- package/richtexteditor/plugins/sanitizer.js +510 -0
- package/richtexteditor/plugins/slashcommand.js +142 -17
- package/richtexteditor/plugins/spellcheck.js +6 -3
- package/richtexteditor/plugins/tableofcontents.js +353 -0
- package/richtexteditor/plugins/tabletools.js +342 -0
- package/richtexteditor/plugins/textdirection.js +313 -0
- package/richtexteditor/plugins/trackedchanges.js +37 -6
- package/richtexteditor/plugins/tui.image-editor/tui-code-snippet.min.js +1 -1
- package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.js +1 -1
- package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.js +1 -1
- package/richtexteditor/plugins/vendor/html2pdf.bundle.min.js +3 -0
- package/richtexteditor/plugins/watermark.js +214 -0
- package/richtexteditor/plugins/wordexport.js +0 -0
- package/richtexteditor/plugins/yjscollab.js +49 -11
- package/richtexteditor/rte-config.js +44 -44
- package/richtexteditor/rte.js +91 -63
- package/richtexteditor/rte_theme_default.css +483 -384
|
@@ -1,6 +1,331 @@
|
|
|
1
1
|
# RichTextEditor Changelog
|
|
2
2
|
|
|
3
|
-
## Version 2.
|
|
3
|
+
## Version 2.4.0 — Long-document authoring, real document export, security and accessibility (Pass 65)
|
|
4
|
+
|
|
5
|
+
Twenty-nine plugins, no `rte.js` core changes. The theme of the release is
|
|
6
|
+
closing the gaps that competitors gate behind paid tiers, and fixing three
|
|
7
|
+
things about our own product that were not true.
|
|
8
|
+
|
|
9
|
+
### Security (three real holes, found by testing rather than by review)
|
|
10
|
+
- **`plugins/sanitizer.js`** — allowlist content filter on input, output **and
|
|
11
|
+
the live DOM**. Unknown elements are unwrapped rather than deleted, so a
|
|
12
|
+
user's words are never silently lost. Parses with `DOMParser` (never
|
|
13
|
+
`innerHTML` on a live node, which fires `<img onerror>` before the filter
|
|
14
|
+
runs) and re-parses until stable to defeat mutation XSS.
|
|
15
|
+
- **Stored XSS:** `<iframe srcdoc="<script>…">` survived the core filter into
|
|
16
|
+
saved HTML and executed when that HTML was rendered downstream. "Nothing
|
|
17
|
+
executes in the editor" was the wrong bar.
|
|
18
|
+
- **Transient XSS:** the first version cleaned up *after* the paste — measured
|
|
19
|
+
execution at +70 ms. Paste is now intercepted in the capture phase and only
|
|
20
|
+
when the clipboard HTML actually executes on insertion, so ordinary Word
|
|
21
|
+
pastes still reach the editor's own Word cleanup untouched.
|
|
22
|
+
- **Collaborator XSS:** a CRDT applies remote edits by writing nodes straight
|
|
23
|
+
into the live document, bypassing both paste and `setHTMLCode`. Any
|
|
24
|
+
participant could run script in every other participant's browser, and the
|
|
25
|
+
payload replicated onward. Closed by a live-DOM guard
|
|
26
|
+
(`sanitizerGuardLiveDom`, on by default) that only engages when an inserted
|
|
27
|
+
node or attribute is executable, so typing costs nothing.
|
|
28
|
+
- **`plugins/restrictedediting.js`** — Word-style protected documents: content
|
|
29
|
+
is read-only except regions tagged `data-rte-editable="true"`.
|
|
30
|
+
|
|
31
|
+
### Accessibility
|
|
32
|
+
- **`plugins/keyboarda11y.js`** — an audit of the running editor found four open
|
|
33
|
+
issues, three of them WCAG Level A: a **keyboard trap** (focus could enter the
|
|
34
|
+
editing area and never leave), `aria-pressed` missing on every toggle button,
|
|
35
|
+
`aria-expanded` missing on every menu button, and 53 toolbar tab stops.
|
|
36
|
+
`Escape` now leaves the editing area (Tab keeps its editing meaning), toggle
|
|
37
|
+
state is mirrored from the existing active class so announced state cannot
|
|
38
|
+
disagree with the highlight, and each toolbar has a single roving tab stop.
|
|
39
|
+
- **`plugins/accessibilitychecker.js`** — flags and one-click repairs missing
|
|
40
|
+
alt text, missing table headers, empty or non-descriptive links, and skipped
|
|
41
|
+
heading levels. Header repair emits `<th scope="col">`, which is what the
|
|
42
|
+
tagged PDF and .docx exports then consume.
|
|
43
|
+
|
|
44
|
+
### Document export and import
|
|
45
|
+
- **`plugins/pdfexport.js`** — PDF written by hand, with **selectable text** and
|
|
46
|
+
a full accessibility tag tree (H1–H6, P, L/LI, Table/TH/TD, Figure; decoration
|
|
47
|
+
emitted as artifacts), so the output passes a Section 508 / EN 301 549 review
|
|
48
|
+
rather than only a copy-paste test. The raster html2pdf path is kept for cases
|
|
49
|
+
where pixel fidelity matters more.
|
|
50
|
+
- **`plugins/docxexport.js`** — a genuine OOXML package built in the browser via
|
|
51
|
+
`CompressionStream`: no library, no server, no upload. Emits exactly what
|
|
52
|
+
`documentimport.js` reads, so HTML → .docx → HTML round-trips.
|
|
53
|
+
- **`plugins/documentimport.js`** — .docx import completeness: text boxes,
|
|
54
|
+
endnotes as well as footnotes, equations (OMML ↔ LaTeX), SmartArt diagrams and
|
|
55
|
+
WMF placeholders. Nothing is dropped silently; what HTML cannot represent
|
|
56
|
+
degrades visibly.
|
|
57
|
+
- **`plugins/wordexport.js`** — Word-compatible HTML export (library-free).
|
|
58
|
+
|
|
59
|
+
### Long-document authoring
|
|
60
|
+
- **`plugins/pagination.js`** — print-layout page view. CKEditor and Tiptap both
|
|
61
|
+
sell this as a paid add-on.
|
|
62
|
+
- **`plugins/multilevellist.js`** — legal numbering (1, 1.1, 1.1.1) via CSS
|
|
63
|
+
counters.
|
|
64
|
+
- **`plugins/footnotes.js`** — inline markers with an auto-renumbering notes
|
|
65
|
+
section.
|
|
66
|
+
- **`plugins/crossreference.js`** — references that keep pointing at the right
|
|
67
|
+
target after the document is edited around them.
|
|
68
|
+
- **`plugins/tableofcontents.js`** — self-updating contents block from the
|
|
69
|
+
document's headings. Premium in both majors.
|
|
70
|
+
- **`plugins/linenumbers.js`** — margin line numbers for pleadings, statutes and
|
|
71
|
+
transcripts.
|
|
72
|
+
- **`plugins/documentoutline.js`**, **`plugins/contentminimap.js`** — navigation
|
|
73
|
+
for long documents.
|
|
74
|
+
- **`plugins/watermark.js`** — DRAFT / CONFIDENTIAL marking behind the content.
|
|
75
|
+
|
|
76
|
+
### Editing and productivity
|
|
77
|
+
- **`plugins/formatpainter.js`** — the clipboard-brush interaction, premium in
|
|
78
|
+
both majors.
|
|
79
|
+
- **`plugins/changecase.js`** — UPPERCASE / lowercase / Title / Sentence /
|
|
80
|
+
tOGGLE. CKEditor gates this behind a plan.
|
|
81
|
+
- **`plugins/autocorrect.js`** — typo fixes, sentence capitalisation, smart
|
|
82
|
+
quotes and dashes as you type.
|
|
83
|
+
- **`plugins/permanentpen.js`** — a fixed format applied to everything typed
|
|
84
|
+
until switched off.
|
|
85
|
+
- **`plugins/draghandle.js`** — grab a block by its grip and drop it elsewhere.
|
|
86
|
+
- **`plugins/tabletools.js`** — column sorting and row numbering; TinyMCE sells
|
|
87
|
+
both as premium "Enhanced Tables".
|
|
88
|
+
- **`plugins/mergefields.js`** — placeholders that turn a document into a
|
|
89
|
+
template for mail merge and invoice runs.
|
|
90
|
+
- **`plugins/linkchecker.js`** — finds broken, unsafe, misleading, or
|
|
91
|
+
assistive-technology-unreachable links, with a host-supplied resolver so no
|
|
92
|
+
vendor infrastructure is required. TinyMCE's equivalent is premium *and*
|
|
93
|
+
requires their service.
|
|
94
|
+
- **`plugins/formattingmarks.js`** — Word's ¶ button, including the invisible
|
|
95
|
+
non-breaking and zero-width characters that cause mysterious layout bugs.
|
|
96
|
+
- **`plugins/charlimit.js`** — enforces a maximum (the built-in statistics
|
|
97
|
+
readout only displays counts).
|
|
98
|
+
- **`plugins/readabilitystats.js`** — local Flesch / Flesch-Kincaid readout, no
|
|
99
|
+
API call.
|
|
100
|
+
|
|
101
|
+
### Right-to-left
|
|
102
|
+
- **`plugins/textdirection.js`** — direction commands, toolbar items and
|
|
103
|
+
language strings for Arabic, Hebrew, Persian and Urdu, which the editor
|
|
104
|
+
previously had no way to express at all.
|
|
105
|
+
- **`plugins/rtlui.js`** — flips the editor chrome (toolbar, dropdowns, menus,
|
|
106
|
+
dialogs) so an RTL user is not typing right-to-left inside a left-to-right
|
|
107
|
+
frame.
|
|
108
|
+
|
|
109
|
+
### Build
|
|
110
|
+
- `build-bundle.ps1` now searches several locations for esbuild and fails hard
|
|
111
|
+
when it finds none. It previously looked at one hardcoded path and, when that
|
|
112
|
+
path was pruned, silently skipped minification while still exiting 0 — so a
|
|
113
|
+
stale `all_plugins.min.js` was mirrored to every tier for several builds.
|
|
114
|
+
|
|
115
|
+
## Version 2.3.0 — Block types, equation editor, bookmark cards, spell check, drag-handles, smart chips, email export, inline Markdown, Mermaid diagrams, read-aloud, emoji autocomplete, task lists, auto-embed, foldable headings, typewriter & focus modes, Markdown export, local-draft recovery, AI ghost-text autocomplete (Pass 64)
|
|
116
|
+
|
|
117
|
+
**New plugin: `plugins/ghostcomplete.js` — AI ghost-text autocomplete**
|
|
118
|
+
- GitHub-Copilot / Notion-AI-style inline completion: after a typing pause a
|
|
119
|
+
greyed suggestion appears after the caret continuing your sentence; **Tab**
|
|
120
|
+
accepts it, **Esc** (or simply continuing to type) dismisses it. Ambient and
|
|
121
|
+
hands-free — distinct from the command-driven AI Toolkit.
|
|
122
|
+
- **Bring-your-own-key**: supply `config.ghostTextResolver({before, after, full})`
|
|
123
|
+
returning a string (or Promise). No model ships and no network call is made
|
|
124
|
+
without it; the feature is inert until both `config.ghostText` and a resolver
|
|
125
|
+
are set. Tunables: `delayMs` (default 600), `minChars` (3), `maxContext` (2000).
|
|
126
|
+
- **Serialization-safe**: the suggestion is a `contenteditable="false"`
|
|
127
|
+
`<span class="rte-ghost">` decoration that is never part of the saved content —
|
|
128
|
+
the caret is kept *before* it so typing/saving behave normally, and
|
|
129
|
+
`getHTMLCode` / `getJSON` are wrapped to strip any ghost span. Accept goes
|
|
130
|
+
through `execCommand("insertText")` so one Ctrl+Z reverts it. Stale-request
|
|
131
|
+
tokens prevent races while typing. API: `editor.requestGhostText()` /
|
|
132
|
+
`acceptGhostText()` / `dismissGhostText()` / `hasGhostText()` /
|
|
133
|
+
`setGhostTextResolver(fn)`; slash `/ai complete`. No core `rte.js` changes.
|
|
134
|
+
Verified live (ghost shows, Tab + API accept inserts undoable text with clean
|
|
135
|
+
serialize, Esc / typing / mousedown / API dismiss, ghost never leaks into saved
|
|
136
|
+
HTML).
|
|
137
|
+
|
|
138
|
+
**New plugin: `plugins/localdraft.js` — local draft autosave & crash recovery**
|
|
139
|
+
- Complements the server-oriented core `config.autoSave` with offline resilience:
|
|
140
|
+
persists the document to `localStorage` as you type (debounced) and, on the
|
|
141
|
+
next load, offers to restore the unsaved draft via an unobtrusive bar
|
|
142
|
+
("An unsaved draft from 3 min ago was found — Restore / Discard"). Gmail /
|
|
143
|
+
Notion style "never lose your work".
|
|
144
|
+
- Opt-in via `config.localDraft = true` or an options object (`key`,
|
|
145
|
+
`intervalMs`, `ttlMs`, `promptRestore`). Safe by design: the draft is **never
|
|
146
|
+
auto-applied** (the server content shows until the user clicks Restore),
|
|
147
|
+
empty/unchanged docs aren't persisted, and stale drafts past the TTL (default
|
|
148
|
+
14 days) are pruned. Also saves on `beforeunload`/`pagehide`. API:
|
|
149
|
+
`editor.saveLocalDraft()` / `hasLocalDraft()` / `getLocalDraft()` /
|
|
150
|
+
`restoreLocalDraft()` / `clearLocalDraft()` (call `clear` after a real save).
|
|
151
|
+
Verified live (autosave→reload→restore-bar→Restore round-trip) + 11 logic
|
|
152
|
+
assertions (TTL prune, blank/baseline skip, restore, clear).
|
|
153
|
+
|
|
154
|
+
**New plugin: `plugins/markdownexport.js` — Copy / Download as Markdown**
|
|
155
|
+
- Surfaces the core HTML→Markdown engine (`editor.toMarkdown()`) as a
|
|
156
|
+
discoverable export, the way Notion "Copy as Markdown" / Obsidian do. Slash
|
|
157
|
+
commands `/copy as markdown` and `/download as markdown`, plus the API
|
|
158
|
+
`editor.getMarkdown()`, `editor.copyAsMarkdown()` (clipboard, with an
|
|
159
|
+
execCommand fallback for older browsers) and `editor.downloadMarkdown(name?)`
|
|
160
|
+
(saves a `.md` Blob; the filename is derived from the first heading when not
|
|
161
|
+
given). Read-only — nothing in the document changes. Toggle with
|
|
162
|
+
`config.markdownExportEnabled`. Verified live (Markdown output for headings /
|
|
163
|
+
bold / italic / lists, clipboard receives the correct text, download filename
|
|
164
|
+
derivation + custom name keep the `.md` extension).
|
|
165
|
+
|
|
166
|
+
**New plugin: `plugins/dialoga11y.js` — dialog accessibility**
|
|
167
|
+
- The editor's dialog popups (`<rte-dropdown-panel>` with an `<rte-dialog-header>`)
|
|
168
|
+
shipped without `role`/`aria-label`, and their fields without programmatic
|
|
169
|
+
labels — so a screen reader announced an unnamed "menu" with unlabeled inputs
|
|
170
|
+
(WCAG 4.1.2 / 1.3.1 / 3.3.2). This plugin adds the missing metadata, deriving
|
|
171
|
+
every name from the editor's OWN markup (never guessing): the dialog name is the
|
|
172
|
+
header text ("Insert Link", "Insert Table"), the role is corrected from `menu`
|
|
173
|
+
to `dialog` on titled form popups, and each field is labelled from its
|
|
174
|
+
`<rte-dialog-line-URL/-TEXT/-TARGET>` wrapper. Natively-labelled fields are left
|
|
175
|
+
untouched, and plain dropdowns (color/font pickers, no header) are deliberately
|
|
176
|
+
skipped so they aren't mislabelled. No core changes; opt out with
|
|
177
|
+
`config.dialogA11y = false`. Verified live on the link/table dialogs (role,
|
|
178
|
+
name, and field labels all correct; native `<label>`s preserved).
|
|
179
|
+
|
|
180
|
+
**New plugin: `plugins/a11yenhance.js` — accessibility metadata**
|
|
181
|
+
- Closes the most common WCAG 2.2 findings for an iframe-based editor by emitting
|
|
182
|
+
the assistive-technology metadata the editing surface needs: the editor iframe
|
|
183
|
+
gets a `title` (WCAG 2.4.1 / 4.1.2), the editing region gets `role="textbox"` +
|
|
184
|
+
`aria-multiline="true"` + an `aria-label` (4.1.2), and the editing document gets
|
|
185
|
+
a `lang` attribute (3.1.1 / 3.1.2). Re-applied on every document remount so the
|
|
186
|
+
metadata survives `setHTMLCode`. Configurable via `config.contentAriaLabel`,
|
|
187
|
+
`config.contentLang` (defaults to the host page `<html lang>` or `en`), and
|
|
188
|
+
`config.a11yEnhance = false` to opt out; API `editor.applyAccessibilityMetadata()`.
|
|
189
|
+
Verified live (iframe title, role, aria-multiline, aria-label, document lang all
|
|
190
|
+
present and surviving remount).
|
|
191
|
+
|
|
192
|
+
**New plugin: `plugins/typewriter.js` — typewriter scrolling + focus mode**
|
|
193
|
+
- Two distraction-free writing modes, both purely presentational (no content or
|
|
194
|
+
DOM mutation — nothing to serialize):
|
|
195
|
+
- **Typewriter mode** keeps the caret line pinned to a fixed vertical anchor
|
|
196
|
+
(default: the middle of the viewport) by scrolling the editable as you type,
|
|
197
|
+
the way iA Writer / Typora / Ulysses do — the text rises to meet a steady
|
|
198
|
+
caret instead of the caret marching down the page. Anchor is configurable
|
|
199
|
+
via `config.typewriterAnchor` (0.15–0.85 fraction of viewport height).
|
|
200
|
+
- **Focus mode** dims every block except the paragraph / heading / list-item
|
|
201
|
+
the caret is in (Notion / iA Writer "focus" behaviour), so the current
|
|
202
|
+
sentence stands out.
|
|
203
|
+
- Toggle either independently: slash `/typewriter` + `/focus mode`, or the API
|
|
204
|
+
`editor.toggleTypewriterMode()` / `editor.toggleFocusMode()` (plus
|
|
205
|
+
`set…`/`is…` variants). Off by default; opt in with `config.typewriterModeEnabled`
|
|
206
|
+
/ `config.focusModeEnabled`.
|
|
207
|
+
- **Serialization-safe**: focus mode toggles a single class on the editable
|
|
208
|
+
(`rte-focus-active`) and a transient class on the active block
|
|
209
|
+
(`rte-focus-current`); typewriter mode only scrolls. `getHTMLCode` / `getJSON`
|
|
210
|
+
are wrapped to strip the transient class around the call, so saved markup is
|
|
211
|
+
always clean even if a save fires mid-keystroke. No core `rte.js` changes.
|
|
212
|
+
Verified live (focus dimming current=1.0 / dimmed=0.28 opacity, typewriter
|
|
213
|
+
scroll pulls the caret line to the anchor, serialization clean) + 19 logic
|
|
214
|
+
assertions.
|
|
215
|
+
|
|
216
|
+
**New plugin: `plugins/foldheadings.js` — collapsible heading sections**
|
|
217
|
+
- Obsidian / Notion / Word-style section folding: hover a heading and click the
|
|
218
|
+
gutter chevron (or call the API) to collapse every block beneath it, up to the
|
|
219
|
+
next heading of the same or higher level. Great for navigating long structured
|
|
220
|
+
documents; pairs with the existing document-outline panel. API:
|
|
221
|
+
`editor.toggleHeadingFold(h)`, `editor.foldAtCaret()`, `editor.unfoldAll()`;
|
|
222
|
+
slash `/fold section` and `/unfold all`. Toggle with `config.foldHeadingsEnabled`.
|
|
223
|
+
- **Serialization-safe by design**: the fold state lives ONLY in runtime CSS
|
|
224
|
+
classes (`rte-fold-collapsed` / `rte-fold-hidden`) and the chevron is a CSS
|
|
225
|
+
`::before` pseudo-element — nothing is injected into the content.
|
|
226
|
+
`getHTMLCode` / `getJSON` / `getHTMLContent` are wrapped to strip those classes
|
|
227
|
+
around the call, so **saved markup is always clean and folded content is never
|
|
228
|
+
lost**. Caret safety: folding a section that contains the caret moves the caret
|
|
229
|
+
to the heading so it is never stuck in hidden content. No core `rte.js` changes.
|
|
230
|
+
Verified live (14 checks: level-aware folds, serialization clean + content
|
|
231
|
+
preserved + restored, caret safety, gutter-click vs text-click).
|
|
232
|
+
|
|
233
|
+
**New plugin: `plugins/autoembed.js` — auto-embed media URLs on paste**
|
|
234
|
+
- Paste a bare YouTube or Vimeo URL on its own line (collapsed caret) and it
|
|
235
|
+
becomes a responsive 16:9 embed — the Notion / Medium behaviour.
|
|
236
|
+
Complements the command-driven Insert Video dialog and the bookmark-card plugin
|
|
237
|
+
(which makes a link-preview card from any URL). Also exposed programmatically as
|
|
238
|
+
`editor.embedUrl(url)`.
|
|
239
|
+
- **Injection-safe by construction**: the iframe `src` is NEVER the raw pasted
|
|
240
|
+
string. The video id is extracted with a strict whitelist regex, constrained to
|
|
241
|
+
`[A-Za-z0-9_-]` / digits, and a trusted provider embed URL is built from a
|
|
242
|
+
template (verified against `youtube.com.evil.com`, `javascript:`,
|
|
243
|
+
`"><script>`, wrong-domain and non-numeric inputs). Mid-paragraph and
|
|
244
|
+
text-selected pastes are left untouched (they stay links). Extend providers via
|
|
245
|
+
`config.autoEmbedResolver(url)` (must return an `https://` embed URL); toggle
|
|
246
|
+
with `config.autoEmbedEnabled` (default true). No core `rte.js` changes.
|
|
247
|
+
- Robust paste hook: the listener attaches to the iframe **document** and
|
|
248
|
+
re-attaches on `ready` / `aftersethtml` (the editor recreates the editable body
|
|
249
|
+
after init, which would orphan a body-level listener). Verified live (13 checks
|
|
250
|
+
+ 14 resolver/security unit tests).
|
|
251
|
+
|
|
252
|
+
**New plugin: `plugins/todolist.js` — interactive to-do / task lists**
|
|
253
|
+
- `editor.execCommand("inserttodolist")` (slash `/to-do`, toolbar) inserts a
|
|
254
|
+
checklist whose items each carry a clickable checkbox; clicking toggles the item
|
|
255
|
+
between open and done (a check + strike-through). Notion / GitHub / Google-Docs
|
|
256
|
+
style. Closes a real gap — the editor shipped an orphan `inserttodolist`
|
|
257
|
+
toolbar icon (`svgCode_inserttodolist`) with no command behind it.
|
|
258
|
+
- Checkboxes are styled `contenteditable="false"` spans (not `<input>`s, which
|
|
259
|
+
misbehave in contenteditable); the done state lives in `data-checked`, so the
|
|
260
|
+
list round-trips through `getHTMLCode` / `getJSON` and re-binds on load via
|
|
261
|
+
click delegation (works for pasted/loaded lists). New items created with Enter
|
|
262
|
+
are auto-normalized to include a checkbox and an open state. CSS injected at
|
|
263
|
+
insert time. No core `rte.js` changes. Verified live (10 checks: insert,
|
|
264
|
+
click-toggle both ways, text-click no-op, style injection, Enter-item
|
|
265
|
+
normalization, round-trip).
|
|
266
|
+
|
|
267
|
+
**New plugin: `plugins/emojiautocomplete.js` — emoji `:shortcode:` autocomplete**
|
|
268
|
+
- GitHub / Slack / Discord-style inline emoji entry, no picker needed. Two
|
|
269
|
+
behaviours: (1) typing a complete `:shortcode:` (closing colon) replaces it with
|
|
270
|
+
the emoji (`:fire:` → 🔥, `:+1:` → 👍, `:tada:` → 🎉); (2) typing `:` + a partial
|
|
271
|
+
query shows a popup of matches — Arrow keys move, Enter/Tab insert, Esc dismisses.
|
|
272
|
+
- Curated built-in shortcode map (~140 common emoji, what people actually type);
|
|
273
|
+
extend or replace via `config.emojiShortcodes`. Toggle with
|
|
274
|
+
`config.emojiAutocompleteEnabled` (default true). Word-boundary gated (a colon
|
|
275
|
+
mid-identifier like `path:fire:` is ignored), inert inside `<code>`/`<pre>`.
|
|
276
|
+
Complements the existing emoji picker (insertemoji) with keyboard-only entry.
|
|
277
|
+
No core `rte.js` changes. Verified live (12 checks: immediate replace, unknown-
|
|
278
|
+
code passthrough, popup matches, Enter-commit, Arrow-nav, mid-word guard,
|
|
279
|
+
code-inert).
|
|
280
|
+
|
|
281
|
+
**New plugin: `plugins/readaloud.js` — read-aloud (text-to-speech)**
|
|
282
|
+
- `editor.execCommand("readaloud")` (slash `/read aloud`, toolbar) opens a small
|
|
283
|
+
non-modal control bar (play/pause, stop, voice, rate) and reads the current
|
|
284
|
+
selection — or the whole document if nothing is selected — aloud, sentence by
|
|
285
|
+
sentence, **highlighting each sentence as it is spoken** (via the native
|
|
286
|
+
selection, so document content is never modified). The speech-OUT complement
|
|
287
|
+
to the dictation plugin's speech-IN, and an accessibility win alongside the
|
|
288
|
+
accessibility checker.
|
|
289
|
+
- Browser-native via the Web Speech API (`window.speechSynthesis`) — **no library
|
|
290
|
+
bundled, no backend, no API key**. Reads cross-paragraph content correctly
|
|
291
|
+
(offset→DOM-range mapping). Public API: `editor.readAloud({ rate, voice })` /
|
|
292
|
+
`editor.stopReadAloud()`. `config.readAloudRate` (default 1.0) and
|
|
293
|
+
`config.readAloudHighlight` (default true). Gracefully detects browsers without
|
|
294
|
+
a synthesizer. Stops on page-hide; pauses on tab-hide. No core `rte.js` changes.
|
|
295
|
+
Verified live (8 checks: sentence split, cross-node highlight, selection-only
|
|
296
|
+
read, control bar, auto-start, toggle-close, stop-restores-caret, API surface).
|
|
297
|
+
|
|
298
|
+
**New plugin: `plugins/mermaiddiagram.js` — Mermaid diagrams (diagrams-as-code)**
|
|
299
|
+
- `editor.execCommand("insertdiagram")` (slash `/diagram`, toolbar) opens a dialog
|
|
300
|
+
to author Mermaid text (flowchart, sequence, gantt, pie, class, state…) with a
|
|
301
|
+
live preview, and renders it to SVG. Closes the diagrams-as-code gap vs GitHub /
|
|
302
|
+
GitLab / Notion / Obsidian. Double-click a block to edit it in place.
|
|
303
|
+
- No renderer is bundled (Mermaid is ~2 MB). Three tiers, mirroring the equation
|
|
304
|
+
editor's "host supplies KaTeX/MathJax" model: (1) `config.diagramResolver(source)`
|
|
305
|
+
→ `Promise<{svg}|{imageUrl}>` for server-side render (e.g. Kroki); (2) a
|
|
306
|
+
`window.mermaid` instance loaded by the host page; (3) neither — the source is
|
|
307
|
+
stored and shown as a `<pre>` fallback, re-renderable later via
|
|
308
|
+
`editor.renderDiagrams()`. The Mermaid source always round-trips in
|
|
309
|
+
`data-diagram`, so blocks stay editable regardless of how they were rendered.
|
|
310
|
+
- Mermaid source is HTML-escaped into the attribute and the fallback `<pre>`;
|
|
311
|
+
blocks are `contenteditable="false"`. CSS injected at insert time. No core
|
|
312
|
+
`rte.js` changes. Verified live (14 checks: render via host renderer, BYOK
|
|
313
|
+
resolver, no-renderer fallback, injection-safety, `renderDiagrams()`, round-trip).
|
|
314
|
+
|
|
315
|
+
**Inline Markdown autoformat (core)**
|
|
316
|
+
- Typing the closing delimiter of an inline Markdown span now converts it in
|
|
317
|
+
place: `**bold**` / `__bold__` → `<strong>`, `*italic*` / `_italic_` → `<em>`,
|
|
318
|
+
`` `code` `` → `<code>`, `~~strike~~` → `<s>`. Completes the Markdown story —
|
|
319
|
+
the editor already had block shortcuts (`# `, `> `, `- `, `1. `, `---`); this
|
|
320
|
+
adds the inline half that Notion / Slack / GitHub / Typora users expect.
|
|
321
|
+
- The opening delimiter must sit at a **word boundary**, so `2*3*` (math),
|
|
322
|
+
`*.txt*` is reduced, `snake_case_` and intraword `a*b*` are left untouched.
|
|
323
|
+
Inert inside `<code>` / `<pre>` / links. Output uses the editor's own semantic
|
|
324
|
+
tags (`<strong>`/`<em>`), so it round-trips with the existing Markdown
|
|
325
|
+
import/export. Undoable with Ctrl+Z. Toggle with `config.markdownInlineEnabled`
|
|
326
|
+
(default `true`). No new toolbar/command surface — pure typing UX. Verified
|
|
327
|
+
live (14 checks: 8 conversions, 4 false-positive guards, code-inert, end-to-end
|
|
328
|
+
typing).
|
|
4
329
|
|
|
5
330
|
**New plugin: `plugins/emailtoolkit.js` — email inline-style export**
|
|
6
331
|
- `editor.getEmailHTML(options?)` returns email-client-safe HTML: a curated set
|