@richscripts/richtexteditor 2.4.0 → 2.4.1

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.
Files changed (58) hide show
  1. package/migration/README.md +100 -0
  2. package/migration/cli.js +294 -0
  3. package/migration/index.d.ts +18 -0
  4. package/migration/index.js +242 -0
  5. package/migration/report-schema-v2.json +127 -0
  6. package/package.json +11 -1
  7. package/richtexteditor/CHANGELOG.md +326 -1
  8. package/richtexteditor/all_plugins.js +14959 -4832
  9. package/richtexteditor/all_plugins.min.js +62 -42
  10. package/richtexteditor/plugins/accessibilitychecker.js +8 -7
  11. package/richtexteditor/plugins/aitoolkit.css +17 -8
  12. package/richtexteditor/plugins/aitoolkit.js +8 -8
  13. package/richtexteditor/plugins/all_plugins.js +14959 -4832
  14. package/richtexteditor/plugins/all_plugins.min.js +62 -42
  15. package/richtexteditor/plugins/autocorrect.js +353 -0
  16. package/richtexteditor/plugins/bookmarkcard.js +12 -1
  17. package/richtexteditor/plugins/changecase.js +238 -0
  18. package/richtexteditor/plugins/comments.js +15 -28
  19. package/richtexteditor/plugins/contentminimap.js +6 -5
  20. package/richtexteditor/plugins/crossreference.js +408 -0
  21. package/richtexteditor/plugins/documentimport.js +915 -21
  22. package/richtexteditor/plugins/documentoutline.js +5 -4
  23. package/richtexteditor/plugins/docxexport.js +960 -0
  24. package/richtexteditor/plugins/draghandle.js +309 -0
  25. package/richtexteditor/plugins/footnotes.js +398 -0
  26. package/richtexteditor/plugins/formatpainter.js +298 -0
  27. package/richtexteditor/plugins/formattingmarks.js +246 -0
  28. package/richtexteditor/plugins/html2pdf.js +108 -4
  29. package/richtexteditor/plugins/imageeditor.js +37 -7
  30. package/richtexteditor/plugins/insertgallery.js +553 -170
  31. package/richtexteditor/plugins/keyboarda11y.js +316 -0
  32. package/richtexteditor/plugins/linenumbers.js +352 -0
  33. package/richtexteditor/plugins/linkchecker.js +396 -0
  34. package/richtexteditor/plugins/mentionplugin.js +4 -3
  35. package/richtexteditor/plugins/mergefields.js +328 -0
  36. package/richtexteditor/plugins/multilevellist.js +137 -0
  37. package/richtexteditor/plugins/pagination.js +505 -0
  38. package/richtexteditor/plugins/pdfexport.js +1137 -0
  39. package/richtexteditor/plugins/permanentpen.js +211 -0
  40. package/richtexteditor/plugins/revisionhistory.js +47 -34
  41. package/richtexteditor/plugins/rtlui.js +150 -0
  42. package/richtexteditor/plugins/sanitizer.js +486 -0
  43. package/richtexteditor/plugins/slashcommand.js +142 -17
  44. package/richtexteditor/plugins/spellcheck.js +6 -3
  45. package/richtexteditor/plugins/tableofcontents.js +353 -0
  46. package/richtexteditor/plugins/tabletools.js +342 -0
  47. package/richtexteditor/plugins/textdirection.js +313 -0
  48. package/richtexteditor/plugins/trackedchanges.js +37 -6
  49. package/richtexteditor/plugins/tui.image-editor/tui-code-snippet.min.js +1 -1
  50. package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.js +1 -1
  51. package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.js +1 -1
  52. package/richtexteditor/plugins/vendor/html2pdf.bundle.min.js +3 -0
  53. package/richtexteditor/plugins/watermark.js +214 -0
  54. package/richtexteditor/plugins/wordexport.js +0 -0
  55. package/richtexteditor/plugins/yjscollab.js +49 -11
  56. package/richtexteditor/rte-config.js +44 -44
  57. package/richtexteditor/rte.js +91 -63
  58. package/richtexteditor/rte_theme_default.css +462 -384
@@ -0,0 +1,214 @@
1
+ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
2
+
3
+ // 2026-07-28 Watermark. Draws DRAFT / CONFIDENTIAL / a customer name behind the
4
+ // content — the marking that tells a reader at a glance not to treat a document
5
+ // as final or not to circulate it.
6
+ //
7
+ // Design notes:
8
+ // - PRESENTATIONAL. The watermark is an overlay, never content, and it is
9
+ // stripped around every serialize. That is the whole point: a watermark
10
+ // baked into the saved HTML would survive into a published page long after
11
+ // the document stopped being a draft, and worse, "CONFIDENTIAL" written into
12
+ // content is trivially deleted while a rendering-layer mark is not.
13
+ // - It also does NOT print by default. Screen marking and print marking are
14
+ // different decisions: config.watermarkPrint opts in.
15
+ // - Rendered as an SVG data URI background rather than DOM text, so it cannot
16
+ // be selected, cannot be caught by find-and-replace, and cannot land in a
17
+ // copy-paste of the document body.
18
+ RTE_DefaultConfig.plugin_watermark = RTE_Plugin_Watermark;
19
+
20
+ if (typeof RTE_DefaultConfig.watermarkText === "undefined") RTE_DefaultConfig.watermarkText = "DRAFT";
21
+ if (typeof RTE_DefaultConfig.watermarkColor === "undefined") RTE_DefaultConfig.watermarkColor = "#94a3b8";
22
+ if (typeof RTE_DefaultConfig.watermarkOpacity === "undefined") RTE_DefaultConfig.watermarkOpacity = 0.18;
23
+ if (typeof RTE_DefaultConfig.watermarkAngle === "undefined") RTE_DefaultConfig.watermarkAngle = -30;
24
+ if (typeof RTE_DefaultConfig.watermarkFontSize === "undefined") RTE_DefaultConfig.watermarkFontSize = 48;
25
+ // "tile" repeats across the page; "single" draws one centred mark.
26
+ if (typeof RTE_DefaultConfig.watermarkMode === "undefined") RTE_DefaultConfig.watermarkMode = "tile";
27
+ // Include the watermark when printing / exporting to PDF via the print pipeline.
28
+ if (typeof RTE_DefaultConfig.watermarkPrint === "undefined") RTE_DefaultConfig.watermarkPrint = false;
29
+ // Optional image watermark (data URI or URL); overrides the text when set.
30
+ if (typeof RTE_DefaultConfig.watermarkImage === "undefined") RTE_DefaultConfig.watermarkImage = null;
31
+
32
+ function RTE_Plugin_Watermark() {
33
+ var obj = this;
34
+ var config, editor;
35
+ var boundDoc = null;
36
+ var active = false;
37
+ var wrapped = false;
38
+
39
+ obj.PluginName = "Watermark";
40
+
41
+ obj.InitConfig = function (argconfig) { config = argconfig; };
42
+
43
+ obj.InitEditor = function (argeditor) {
44
+ editor = argeditor;
45
+
46
+ editor.attachEvent("exec_command_watermark", function (state) {
47
+ state.returnValue = true;
48
+ obj.Toggle();
49
+ });
50
+
51
+ setup();
52
+ try { editor.attachEvent("ready", setup); } catch (e) {}
53
+ try { editor.attachEvent("aftersethtml", setup); } catch (e) {}
54
+ setTimeout(setup, 0);
55
+
56
+ editor.setWatermark = function (on) { active = !!on; apply(); return active; };
57
+ editor.toggleWatermark = function () { active = !active; apply(); return active; };
58
+ editor.isWatermark = function () { return active; };
59
+ editor.setWatermarkOptions = function (o) {
60
+ if (o && typeof o === "object") {
61
+ var keys = ["watermarkText", "watermarkColor", "watermarkOpacity", "watermarkAngle",
62
+ "watermarkFontSize", "watermarkMode", "watermarkPrint", "watermarkImage"];
63
+ var short = { text: 0, color: 1, opacity: 2, angle: 3, fontSize: 4, mode: 5, print: 6, image: 7 };
64
+ for (var k in o) {
65
+ if (!o.hasOwnProperty(k)) continue;
66
+ if (short[k] !== undefined) config[keys[short[k]]] = o[k];
67
+ else if (keys.indexOf(k) >= 0) config[k] = o[k];
68
+ }
69
+ }
70
+ apply();
71
+ return obj.Options();
72
+ };
73
+ editor.getWatermarkOptions = function () { return obj.Options(); };
74
+ };
75
+
76
+ obj.Options = function () {
77
+ return {
78
+ text: config.watermarkText, color: config.watermarkColor,
79
+ opacity: config.watermarkOpacity, angle: config.watermarkAngle,
80
+ fontSize: config.watermarkFontSize, mode: config.watermarkMode,
81
+ print: config.watermarkPrint, image: config.watermarkImage
82
+ };
83
+ };
84
+
85
+ function setup() {
86
+ var doc = getDoc();
87
+ if (!doc) return;
88
+ wrapSerializers();
89
+ if (doc !== boundDoc) boundDoc = doc;
90
+ if (active) apply();
91
+ }
92
+
93
+ function getDoc() { try { return editor.getDocument(); } catch (e) { return null; } }
94
+ function getEditable() { try { return editor.getEditable(); } catch (e) { return null; } }
95
+
96
+ function esc(s) {
97
+ return String(s == null ? "" : s)
98
+ .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
99
+ .replace(/"/g, "&quot;").replace(/'/g, "&apos;");
100
+ }
101
+
102
+ // An SVG data URI, so the mark is a background image: unselectable,
103
+ // uncopyable, and invisible to find-and-replace.
104
+ function backgroundUri() {
105
+ if (config.watermarkImage) return String(config.watermarkImage);
106
+ var text = String(config.watermarkText == null ? "" : config.watermarkText);
107
+ if (!text) return null;
108
+ var size = parseInt(config.watermarkFontSize, 10) || 48;
109
+ var angle = parseFloat(config.watermarkAngle);
110
+ if (isNaN(angle)) angle = -30;
111
+ // Tile big enough that rotated text does not clip at the edges.
112
+ var w = Math.max(240, text.length * size * 0.72);
113
+ var h = Math.max(160, size * 3.2);
114
+ var svg =
115
+ '<svg xmlns="http://www.w3.org/2000/svg" width="' + Math.round(w) + '" height="' + Math.round(h) + '">' +
116
+ '<text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" ' +
117
+ 'transform="rotate(' + angle + ' ' + Math.round(w / 2) + ' ' + Math.round(h / 2) + ')" ' +
118
+ 'font-family="Segoe UI, Arial, sans-serif" font-size="' + size + '" font-weight="700" ' +
119
+ 'fill="' + esc(config.watermarkColor || "#94a3b8") + '">' + esc(text) + '</text></svg>';
120
+ return "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
121
+ }
122
+
123
+ function apply() {
124
+ var editable = getEditable();
125
+ var doc = getDoc();
126
+ if (!editable || !doc) return;
127
+ injectStyles(doc);
128
+
129
+ if (!active) {
130
+ editable.style.backgroundImage = "";
131
+ editable.style.backgroundRepeat = "";
132
+ editable.style.backgroundPosition = "";
133
+ editable.removeAttribute("data-rte-watermark");
134
+ return;
135
+ }
136
+ var uri = backgroundUri();
137
+ if (!uri) return;
138
+ var single = String(config.watermarkMode) === "single";
139
+ editable.setAttribute("data-rte-watermark", "true");
140
+ editable.style.backgroundImage = "url(\"" + uri + "\")";
141
+ editable.style.backgroundRepeat = single ? "no-repeat" : "repeat";
142
+ editable.style.backgroundPosition = single ? "center center" : "0 0";
143
+ // Opacity has to live on the background, not the element, or the text
144
+ // on top fades with it.
145
+ var op = parseFloat(config.watermarkOpacity);
146
+ editable.style.opacity = "";
147
+ var st = doc.getElementById("rte-watermark-dynamic");
148
+ if (!st) {
149
+ st = doc.createElement("style");
150
+ st.id = "rte-watermark-dynamic";
151
+ (doc.head || doc.documentElement).appendChild(st);
152
+ }
153
+ st.textContent =
154
+ "[data-rte-watermark]{background-blend-mode:multiply;}" +
155
+ "[data-rte-watermark]::before{content:'';position:absolute;inset:0;pointer-events:none;" +
156
+ "background-image:inherit;background-repeat:inherit;background-position:inherit;" +
157
+ "opacity:" + (isNaN(op) ? 0.18 : op) + ";z-index:0;}" +
158
+ (config.watermarkPrint
159
+ ? ""
160
+ : "@media print{[data-rte-watermark]{background-image:none !important;}" +
161
+ "[data-rte-watermark]::before{display:none !important;}}");
162
+ }
163
+
164
+ // ---- serialization safety -------------------------------------------
165
+
166
+ // The watermark lives in inline styles on the editable, so a serializer that
167
+ // reads them would carry DRAFT into the saved document. Park them.
168
+ function stripFor() {
169
+ var editable = getEditable();
170
+ if (!editable || !active) return function () {};
171
+ var bg = editable.style.backgroundImage;
172
+ var rep = editable.style.backgroundRepeat;
173
+ var pos = editable.style.backgroundPosition;
174
+ var attr = editable.getAttribute("data-rte-watermark");
175
+ editable.style.backgroundImage = "";
176
+ editable.style.backgroundRepeat = "";
177
+ editable.style.backgroundPosition = "";
178
+ editable.removeAttribute("data-rte-watermark");
179
+ return function restore() {
180
+ editable.style.backgroundImage = bg;
181
+ editable.style.backgroundRepeat = rep;
182
+ editable.style.backgroundPosition = pos;
183
+ if (attr) editable.setAttribute("data-rte-watermark", attr);
184
+ };
185
+ }
186
+
187
+ function wrapSerializers() {
188
+ if (wrapped) return;
189
+ var names = ["getHTMLCode", "getJSON", "getHTMLContent", "getText"];
190
+ var did = false;
191
+ for (var i = 0; i < names.length; i++) {
192
+ (function (name) {
193
+ var orig = editor[name];
194
+ if (typeof orig !== "function" || orig.__rteWmWrapped) return;
195
+ var w = function () {
196
+ var restore = stripFor();
197
+ try { return orig.apply(editor, arguments); } finally { restore(); }
198
+ };
199
+ w.__rteWmWrapped = true;
200
+ editor[name] = w;
201
+ did = true;
202
+ })(names[i]);
203
+ }
204
+ if (did) wrapped = true;
205
+ }
206
+
207
+ function injectStyles(doc) {
208
+ if (!doc || doc.getElementById("rte-watermark-styles")) return;
209
+ var st = doc.createElement("style");
210
+ st.id = "rte-watermark-styles";
211
+ st.appendChild(doc.createTextNode("[data-rte-watermark]{position:relative;}"));
212
+ (doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement).appendChild(st);
213
+ }
214
+ }
@@ -2,12 +2,10 @@ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
2
2
 
3
3
  RTE_DefaultConfig.plugin_yjscollab = RTE_Plugin_YjsCollab;
4
4
 
5
- // Yjs collaboration — Option B scope:
5
+ // Yjs collaboration:
6
6
  // • Awareness (live cursors + presence)
7
7
  // • Shared reviewLedger (AI suggestions, tracked changes, comments all sync)
8
- //
9
- // NOT in scope:
10
- // • Concurrent text editing (no content-level CRDT binding — see v1.1 / Option C)
8
+ // • Opt-in per-node content CRDT via textSync: "crdt" and crdt-engine.js
11
9
  //
12
10
  // Yjs is a PEER DEPENDENCY. Customers load Y.Doc + a provider themselves; this plugin
13
11
  // binds to whatever they pass in.
@@ -41,6 +39,7 @@ function RTE_Plugin_YjsCollab() {
41
39
  detach: function () { return detach(); },
42
40
  isAttached: function () { return !!session; },
43
41
  getSession: function () { return session; },
42
+ getStatus: function () { return getStatus(); },
44
43
  peers: function () { return session ? getRemotePeers() : []; },
45
44
  setUser: function (user) { if (session) updateLocalUser(user); }
46
45
  };
@@ -80,6 +79,7 @@ function RTE_Plugin_YjsCollab() {
80
79
  : (config.collabTextSync === true);
81
80
  }
82
81
  var textSyncMode; // "off" | "legacy" | "crdt"
82
+ var fallbackReason = null;
83
83
  var textMap = null;
84
84
  var crdtBinding = null;
85
85
  if (requestedTextSync === "crdt") {
@@ -87,9 +87,11 @@ function RTE_Plugin_YjsCollab() {
87
87
  if (Crdt && typeof Crdt.attachCrdtBinding === "function") {
88
88
  textSyncMode = "crdt";
89
89
  } else {
90
- console.warn("yjscollab: textSync \"crdt\" requested but richtexteditor/plugins/crdt-engine.js is not loaded — falling back to legacy snapshot mode.");
91
- textSyncMode = "legacy";
92
- textMap = doc.getText(config.collabTextName || "richtextbox.body");
90
+ fallbackReason = "crdt-engine-unavailable";
91
+ textSyncMode = options.requireCrdt || config.collabRequireCrdt ? "off" : "legacy";
92
+ if (textSyncMode === "legacy") {
93
+ textMap = doc.getText(config.collabTextName || "richtextbox.body");
94
+ }
93
95
  }
94
96
  } else if (requestedTextSync === true) {
95
97
  textSyncMode = "legacy";
@@ -106,6 +108,8 @@ function RTE_Plugin_YjsCollab() {
106
108
  textMap: textMap,
107
109
  textSyncEnabled: textSyncMode !== "off",
108
110
  textSyncMode: textSyncMode,
111
+ requestedTextSync: requestedTextSync || false,
112
+ fallbackReason: fallbackReason,
109
113
  crdtBinding: crdtBinding,
110
114
  user: user,
111
115
  cleanup: []
@@ -152,10 +156,15 @@ function RTE_Plugin_YjsCollab() {
152
156
  catch (ignore) { }
153
157
  });
154
158
  } catch (err) {
155
- console.warn("yjscollab: CRDT engine attach failed; falling back to legacy mode.", err);
156
- session.textSyncMode = "legacy";
157
- session.textMap = doc.getText(config.collabTextName || "richtextbox.body");
158
- wireTextSync();
159
+ session.fallbackReason = "crdt-attach-failed";
160
+ session.crdtError = err;
161
+ if (options.requireCrdt || config.collabRequireCrdt) {
162
+ session.textSyncMode = "off";
163
+ } else {
164
+ session.textSyncMode = "legacy";
165
+ session.textMap = doc.getText(config.collabTextName || "richtextbox.body");
166
+ wireTextSync();
167
+ }
159
168
  }
160
169
  } else if (session.textSyncMode === "legacy" && session.textMap) {
161
170
  wireTextSync();
@@ -167,9 +176,38 @@ function RTE_Plugin_YjsCollab() {
167
176
  renderPresence();
168
177
  renderRemoteCursors();
169
178
 
179
+ notifyStatus();
180
+
170
181
  return session;
171
182
  }
172
183
 
184
+ function getStatus() {
185
+ if (!session) {
186
+ return { attached: false, textSyncMode: "off", requestedTextSync: false, fallbackReason: null };
187
+ }
188
+ return {
189
+ attached: true,
190
+ textSyncMode: session.textSyncMode,
191
+ requestedTextSync: session.requestedTextSync,
192
+ fallbackReason: session.fallbackReason || null,
193
+ peerCount: getRemotePeers().length
194
+ };
195
+ }
196
+
197
+ function notifyStatus() {
198
+ var status = getStatus();
199
+ if (status.fallbackReason) {
200
+ var modeNote = status.textSyncMode === "legacy"
201
+ ? " Falling back to legacy snapshot synchronization."
202
+ : " Content synchronization is disabled; presence and the review ledger remain active.";
203
+ console.warn("yjscollab: " + status.fallbackReason + "." + modeNote);
204
+ }
205
+ var callback = config.onCollabStatus;
206
+ if (typeof callback === "function") {
207
+ try { callback(status); } catch (ignore) { }
208
+ }
209
+ }
210
+
173
211
  function detach() {
174
212
  if (!session) return;
175
213
  for (var i = 0; i < session.cleanup.length; i++) {
@@ -57,29 +57,29 @@ RTE_DefaultConfig.smartLinkPaste = true; // Paste a URL while text is selected
57
57
  RTE_DefaultConfig.aiContextMenu = true; // Right-click on selected text shows Ask AI / Rewrite / Summarize / Translate (when AI Toolkit is loaded).
58
58
  RTE_DefaultConfig.tableColumnResize = true; // Hover near a table column border to drag-resize the column.
59
59
  RTE_DefaultConfig.tableRowResize = true; // Hover near a table row's bottom edge to drag-resize its height.
60
- RTE_DefaultConfig.imageHoverQuickBar = true; // Show a small "Alt / Replace / X" floating bar when hovering an inline <img>.
61
- RTE_DefaultConfig.inlineMath = true; // When true, editor.applyMathMarkup() wraps $...$ runs in <span class="rte-math-inline" data-tex="..."> so a math renderer (KaTeX/MathJax) can target them.
62
- RTE_DefaultConfig.imageLazyLoad = true; // Newly-inserted <img> tags get loading="lazy" + decoding="async" so big documents stay responsive.
63
- RTE_DefaultConfig.documentUploadAccept = ".txt,.text,.rtf,.md,.markdown,.html,.htm,.pdf,.doc,.docx,.odt,.xls,.xlsx,.csv,.tsv,.json,.xml,.zip,.rar"; // Default Insert Document chooser filter.
64
- RTE_DefaultConfig.fileUploadLocalObjectUrl = true; // Without file_upload_handler, local document files insert as temporary blob: links instead of failing.
65
- // Reading-mode persistence key. Default is session-only so refresh restores the toolbar.
66
- // Set to true for per-editor localStorage persistence, or to a custom string to share state across editors.
67
- // RTE_DefaultConfig.readingModePersistenceKey = false;
60
+ RTE_DefaultConfig.imageHoverQuickBar = true; // Show a small "Alt / Replace / X" floating bar when hovering an inline <img>.
61
+ RTE_DefaultConfig.inlineMath = true; // When true, editor.applyMathMarkup() wraps $...$ runs in <span class="rte-math-inline" data-tex="..."> so a math renderer (KaTeX/MathJax) can target them.
62
+ RTE_DefaultConfig.imageLazyLoad = true; // Newly-inserted <img> tags get loading="lazy" + decoding="async" so big documents stay responsive.
63
+ RTE_DefaultConfig.documentUploadAccept = ".txt,.text,.rtf,.md,.markdown,.html,.htm,.pdf,.doc,.docx,.odt,.xls,.xlsx,.csv,.tsv,.json,.xml,.zip,.rar"; // Default Insert Document chooser filter.
64
+ RTE_DefaultConfig.fileUploadLocalObjectUrl = true; // Without file_upload_handler, local document files insert as temporary blob: links instead of failing.
65
+ // Reading-mode persistence key. Default is session-only so refresh restores the toolbar.
66
+ // Set to true for per-editor localStorage persistence, or to a custom string to share state across editors.
67
+ // RTE_DefaultConfig.readingModePersistenceKey = false;
68
68
  RTE_DefaultConfig.spellcheck = true; // When true, the browser's spellcheck wavy underline is enabled inside the editor.
69
69
  RTE_DefaultConfig.wordCountGoal = 0; // When > 0, the status bar shows progress toward the target word count.
70
70
  RTE_DefaultConfig.restrictedEditingMode = false; // When true, the editor is locked except for spans tagged data-rte-editable="true".
71
71
  RTE_DefaultConfig.text_restrictedediting = "Restricted editing";
72
- RTE_DefaultConfig.svgCode_restrictedediting = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="9" rx="1.5"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>';
72
+ RTE_DefaultConfig.svgCode_restrictedediting = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="9" rx="1.5"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>';
73
73
 
74
74
  // 2026-05-19 New toolbar entries (icons + labels) for the editor-experience push.
75
75
  RTE_DefaultConfig.text_printpreview = "Print preview";
76
- RTE_DefaultConfig.svgCode_printpreview = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="7" y="3" width="10" height="6" rx="1"/><path d="M7 14h10v6H7z"/><path d="M6 9h12a1 1 0 0 1 1 1v5H5v-5a1 1 0 0 1 1-1z"/><circle cx="16" cy="12" r="0.6" fill="currentColor"/></svg>';
76
+ RTE_DefaultConfig.svgCode_printpreview = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="7" y="3" width="10" height="6" rx="1"/><path d="M7 14h10v6H7z"/><path d="M6 9h12a1 1 0 0 1 1 1v5H5v-5a1 1 0 0 1 1-1z"/><circle cx="16" cy="12" r="0.6" fill="currentColor"/></svg>';
77
77
  RTE_DefaultConfig.text_readingmode = "Reading mode";
78
- RTE_DefaultConfig.svgCode_readingmode = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 5h7a3 3 0 0 1 3 3v12"/><path d="M21 5h-7a3 3 0 0 0-3 3v12"/></svg>';
78
+ RTE_DefaultConfig.svgCode_readingmode = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 5h7a3 3 0 0 1 3 3v12"/><path d="M21 5h-7a3 3 0 0 0-3 3v12"/></svg>';
79
79
  RTE_DefaultConfig.text_highlight = "Highlight";
80
- RTE_DefaultConfig.svgCode_highlight = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M14 4l6 6-9 9H5v-6z"/><path d="M14 4l-9 9"/></svg>';
80
+ RTE_DefaultConfig.svgCode_highlight = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 4l6 6-9 9H5v-6z"/><path d="M14 4l-9 9"/></svg>';
81
81
  RTE_DefaultConfig.text_sortlines = "Sort lines";
82
- RTE_DefaultConfig.svgCode_sortlines = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7l3-3 3 3"/><path d="M10 4v16"/><path d="M17 17l-3 3-3-3"/><path d="M14 20V4"/></svg>';
82
+ RTE_DefaultConfig.svgCode_sortlines = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7l3-3 3 3"/><path d="M10 4v16"/><path d="M17 17l-3 3-3-3"/><path d="M14 20V4"/></svg>';
83
83
 
84
84
  // Smart typography: auto-convert common typing patterns to typographic glyphs.
85
85
  // Master switch + per-feature toggles. Skipped inside <code>/<pre>/<kbd>.
@@ -185,24 +185,24 @@ RTE_DefaultConfig.linkItems = [
185
185
  "https://www.apple.com"
186
186
  ] // A predefined set of links.
187
187
 
188
- RTE_DefaultConfig.imageItems = [
189
- "https://richtexteditor.com/uploads/1.jpg",
190
- "https://richtexteditor.com/uploads/2.jpg",
191
- "https://richtexteditor.com/uploads/3.jpg",
192
- "https://richtexteditor.com/uploads/4.jpg",
193
- "https://richtexteditor.com/uploads/5.jpg",
194
- "https://richtexteditor.com/uploads/6.jpg"
195
- ] // For insert image by URL
196
-
197
-
198
- RTE_DefaultConfig.galleryImages = [
199
- "https://richtexteditor.com/uploads/1.jpg",
200
- "https://richtexteditor.com/uploads/2.jpg",
201
- "https://richtexteditor.com/uploads/3.jpg",
202
- "https://richtexteditor.com/uploads/4.jpg",
203
- "https://richtexteditor.com/uploads/5.jpg",
204
- "https://richtexteditor.com/uploads/6.jpg"
205
- ]; // Default images for gallery Images dialog.
188
+ RTE_DefaultConfig.imageItems = [
189
+ "https://richtexteditor.com/uploads/1.jpg",
190
+ "https://richtexteditor.com/uploads/2.jpg",
191
+ "https://richtexteditor.com/uploads/3.jpg",
192
+ "https://richtexteditor.com/uploads/4.jpg",
193
+ "https://richtexteditor.com/uploads/5.jpg",
194
+ "https://richtexteditor.com/uploads/6.jpg"
195
+ ] // For insert image by URL
196
+
197
+
198
+ RTE_DefaultConfig.galleryImages = [
199
+ "https://richtexteditor.com/uploads/1.jpg",
200
+ "https://richtexteditor.com/uploads/2.jpg",
201
+ "https://richtexteditor.com/uploads/3.jpg",
202
+ "https://richtexteditor.com/uploads/4.jpg",
203
+ "https://richtexteditor.com/uploads/5.jpg",
204
+ "https://richtexteditor.com/uploads/6.jpg"
205
+ ]; // Default images for gallery Images dialog.
206
206
 
207
207
  RTE_DefaultConfig.htmlTemplates = [
208
208
  ["My Doc 1", "<h2>MyTitleMyTitleMyTitleMyTitleMyTitleMyTitleMyTitle</h2><p>Paragraph 1 </p><p>Paragraph 2 </p><p>Paragraph 3 </p><p>Paragraph 4 </p><p>Paragraph 5 </p>"]
@@ -324,11 +324,11 @@ RTE_DefaultConfig.text_tableproperties = "Table Properties";
324
324
  RTE_DefaultConfig.text_tablecelltype = "Toggle Header Cell";
325
325
  RTE_DefaultConfig.text_tabledistributecolumns = "Distribute Columns";
326
326
  RTE_DefaultConfig.text_tabledistributerows = "Distribute Rows";
327
- RTE_DefaultConfig.svgCode_tablecellproperties = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 7h14"/><path d="M5 12h14"/><path d="M5 17h14"/><circle cx="9" cy="7" r="1.7"/><circle cx="15" cy="12" r="1.7"/><circle cx="8" cy="17" r="1.7"/></svg>';
328
- RTE_DefaultConfig.svgCode_tableproperties = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 13.5a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-2.82 1.17V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-2.82-1.17l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 13.5H4.5a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.17-2.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 2.82-1.17V2.5a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 2.82 1.17l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-1.17 2.82h.09a2 2 0 0 1 0 4h-.09z"/></svg>';
329
- RTE_DefaultConfig.svgCode_tablecelltype = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="1.5"/><rect x="3" y="4" width="18" height="5" rx="1.5" fill="currentColor" stroke="none"/><path d="M3 9h18"/><path d="M12 9v11"/></svg>';
330
- RTE_DefaultConfig.svgCode_tabledistributecolumns = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="1.5"/><path d="M9 5v14"/><path d="M15 5v14"/></svg>';
331
- RTE_DefaultConfig.svgCode_tabledistributerows = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="1.5"/><path d="M3 9.67h18"/><path d="M3 14.33h18"/></svg>';
327
+ RTE_DefaultConfig.svgCode_tablecellproperties = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 7h14"/><path d="M5 12h14"/><path d="M5 17h14"/><circle cx="9" cy="7" r="1.7"/><circle cx="15" cy="12" r="1.7"/><circle cx="8" cy="17" r="1.7"/></svg>';
328
+ RTE_DefaultConfig.svgCode_tableproperties = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 13.5a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-2.82 1.17V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-2.82-1.17l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 13.5H4.5a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.17-2.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 2.82-1.17V2.5a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 2.82 1.17l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-1.17 2.82h.09a2 2 0 0 1 0 4h-.09z"/></svg>';
329
+ RTE_DefaultConfig.svgCode_tablecelltype = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="1.5"/><rect x="3" y="4" width="18" height="5" rx="1.5" fill="currentColor" stroke="none"/><path d="M3 9h18"/><path d="M12 9v11"/></svg>';
330
+ RTE_DefaultConfig.svgCode_tabledistributecolumns = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="1.5"/><path d="M9 5v14"/><path d="M15 5v14"/></svg>';
331
+ RTE_DefaultConfig.svgCode_tabledistributerows = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="1.5"/><path d="M3 9.67h18"/><path d="M3 14.33h18"/></svg>';
332
332
  RTE_DefaultConfig.subtoolbar_tablecolumn = "tablecolumninsertleft,tablecolumninsertright,tablecolumndelete"; // A set of buttons that appears in the tablecolumn subtoolbar.
333
333
  RTE_DefaultConfig.subtoolbar_tableinsert = "tablerowinsertabove,tablerowinsertbelow,tablecolumninsertleft,tablecolumninsertright"; // A set of buttons that appears in the tableinsert subtoolbar.
334
334
  RTE_DefaultConfig.subtoolbar_tabledelete = "tablecolumndelete,tablerowdelete,tabledelete"; // A set of buttons that appears in the tabledelete subtoolbar.
@@ -358,9 +358,9 @@ RTE_DefaultConfig.pngCode_all = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA
358
358
  + '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';
359
359
 
360
360
  RTE_DefaultConfig.svgCode_default = '<svg viewBox="2 1 20 20"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"/></svg>';
361
- RTE_DefaultConfig.svgCode_insertcode = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="8 7 3 12 8 17"/><polyline points="16 7 21 12 16 17"/><line x1="14" y1="5" x2="10" y2="19"/></svg>';
362
- RTE_DefaultConfig.svgCode_aiassist = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" aria-hidden="true"><defs><linearGradient id="rte-ai-robot-face" x1="5.2" y1="6.2" x2="18.8" y2="17.2" gradientUnits="userSpaceOnUse"><stop stop-color="#38bdf8"/><stop offset=".55" stop-color="#2563eb"/><stop offset="1" stop-color="#7c3aed"/></linearGradient></defs><path d="M12 4.2V2.5" stroke="#f59e0b" stroke-width="1.7" stroke-linecap="round"/><rect x="5.2" y="6.2" width="13.6" height="11" rx="3.1" fill="url(#rte-ai-robot-face)" stroke="#1d4ed8" stroke-width="1.35"/><circle cx="9.4" cy="11.4" r="1.2" fill="#fef3c7"/><circle cx="14.6" cy="11.4" r="1.2" fill="#fef3c7"/><path d="M9.7 14.5c.7.55 1.45.82 2.3.82s1.6-.27 2.3-.82" stroke="#ffffff" stroke-width="1.55" stroke-linecap="round"/><path d="M7.2 19.4l1.1-2.2M16.8 19.4l-1.1-2.2" stroke="#2563eb" stroke-width="1.55" stroke-linecap="round"/></svg>';
363
- RTE_DefaultConfig.svgCode_aiassist = '<svg viewBox="0 0 24 24" width="16" height="16" fill="none" aria-hidden="true"><defs><linearGradient id="rte-ai-bot-v4-shell" x1="4.2" y1="5.8" x2="19.8" y2="18.4" gradientUnits="userSpaceOnUse"><stop stop-color="#22d3ee"/><stop offset=".52" stop-color="#2563eb"/><stop offset="1" stop-color="#4338ca"/></linearGradient><linearGradient id="rte-ai-bot-v4-visor" x1="7.8" y1="9" x2="16.2" y2="13.8" gradientUnits="userSpaceOnUse"><stop stop-color="#f8fafc"/><stop offset="1" stop-color="#bfdbfe"/></linearGradient></defs><path d="M12 2.6v2.3" stroke="#f59e0b" stroke-width="1.7" stroke-linecap="round"/><circle cx="12" cy="2.6" r=".9" fill="#fbbf24"/><path d="M4.9 12.2h-1a1.4 1.4 0 010-2.8h1M19.1 9.4h1a1.4 1.4 0 010 2.8h-1" stroke="#2563eb" stroke-width="1.25" stroke-linecap="round"/><rect x="5.2" y="5.9" width="13.6" height="12.2" rx="4" fill="url(#rte-ai-bot-v4-shell)" stroke="#1e40af" stroke-width="1.15"/><rect x="7.6" y="8.8" width="8.8" height="5.2" rx="2.6" fill="url(#rte-ai-bot-v4-visor)" opacity=".98"/><circle cx="10.2" cy="11.4" r=".9" fill="#0f172a"/><circle cx="13.8" cy="11.4" r=".9" fill="#0f172a"/><path d="M9.5 15.3c.78.52 1.6.78 2.5.78s1.72-.26 2.5-.78" stroke="#eff6ff" stroke-width="1.35" stroke-linecap="round"/><path d="M7.7 20.2l1.15-2.15M16.3 20.2l-1.15-2.15" stroke="#2563eb" stroke-width="1.45" stroke-linecap="round"/><path d="M18.6 5.1l.45-.95.45.95.95.45-.95.45-.45.95-.45-.95-.95-.45z" fill="#fde68a"/></svg>';
361
+ RTE_DefaultConfig.svgCode_insertcode = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="8 7 3 12 8 17"/><polyline points="16 7 21 12 16 17"/><line x1="14" y1="5" x2="10" y2="19"/></svg>';
362
+ RTE_DefaultConfig.svgCode_aiassist = '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" aria-hidden="true"><defs><linearGradient id="rte-ai-robot-face" x1="5.2" y1="6.2" x2="18.8" y2="17.2" gradientUnits="userSpaceOnUse"><stop stop-color="#38bdf8"/><stop offset=".55" stop-color="#2563eb"/><stop offset="1" stop-color="#7c3aed"/></linearGradient></defs><path d="M12 4.2V2.5" stroke="#f59e0b" stroke-width="1.7" stroke-linecap="round"/><rect x="5.2" y="6.2" width="13.6" height="11" rx="3.1" fill="url(#rte-ai-robot-face)" stroke="#1d4ed8" stroke-width="1.35"/><circle cx="9.4" cy="11.4" r="1.2" fill="#fef3c7"/><circle cx="14.6" cy="11.4" r="1.2" fill="#fef3c7"/><path d="M9.7 14.5c.7.55 1.45.82 2.3.82s1.6-.27 2.3-.82" stroke="#ffffff" stroke-width="1.55" stroke-linecap="round"/><path d="M7.2 19.4l1.1-2.2M16.8 19.4l-1.1-2.2" stroke="#2563eb" stroke-width="1.55" stroke-linecap="round"/></svg>';
363
+ RTE_DefaultConfig.svgCode_aiassist = '<svg viewBox="0 0 24 24" width="20" height="20" fill="none" aria-hidden="true"><defs><linearGradient id="rte-ai-bot-v4-shell" x1="4.2" y1="5.8" x2="19.8" y2="18.4" gradientUnits="userSpaceOnUse"><stop stop-color="#22d3ee"/><stop offset=".52" stop-color="#2563eb"/><stop offset="1" stop-color="#4338ca"/></linearGradient><linearGradient id="rte-ai-bot-v4-visor" x1="7.8" y1="9" x2="16.2" y2="13.8" gradientUnits="userSpaceOnUse"><stop stop-color="#f8fafc"/><stop offset="1" stop-color="#bfdbfe"/></linearGradient></defs><path d="M12 2.6v2.3" stroke="#f59e0b" stroke-width="1.7" stroke-linecap="round"/><circle cx="12" cy="2.6" r=".9" fill="#fbbf24"/><path d="M4.9 12.2h-1a1.4 1.4 0 010-2.8h1M19.1 9.4h1a1.4 1.4 0 010 2.8h-1" stroke="#2563eb" stroke-width="1.25" stroke-linecap="round"/><rect x="5.2" y="5.9" width="13.6" height="12.2" rx="4" fill="url(#rte-ai-bot-v4-shell)" stroke="#1e40af" stroke-width="1.15"/><rect x="7.6" y="8.8" width="8.8" height="5.2" rx="2.6" fill="url(#rte-ai-bot-v4-visor)" opacity=".98"/><circle cx="10.2" cy="11.4" r=".9" fill="#0f172a"/><circle cx="13.8" cy="11.4" r=".9" fill="#0f172a"/><path d="M9.5 15.3c.78.52 1.6.78 2.5.78s1.72-.26 2.5-.78" stroke="#eff6ff" stroke-width="1.35" stroke-linecap="round"/><path d="M7.7 20.2l1.15-2.15M16.3 20.2l-1.15-2.15" stroke="#2563eb" stroke-width="1.45" stroke-linecap="round"/><path d="M18.6 5.1l.45-.95.45.95.95.45-.95.45-.45.95-.45-.95-.95-.45z" fill="#fde68a"/></svg>';
364
364
  RTE_DefaultConfig.svgCode_empty = '<svg viewBox="0 0 20 20"></svg>';
365
365
  RTE_DefaultConfig.svgCode_close = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>';
366
366
  RTE_DefaultConfig.svgCode_DialogClose = '<svg viewBox="0 0 18 18"><path fill="currentColor" d="M11.5,9.5l5-5c0.2-0.2,0.2-0.6-0.1-0.9l-1-1c-0.3-0.3-0.7-0.3-0.9-0.1l-5,5l-5-5C4.3,2.3,3.9,2.4,3.6,2.6l-1,1 C2.4,3.9,2.3,4.3,2.5,4.5l5,5l-5,5c-0.2,0.2-0.2,0.6,0.1,0.9l1,1c0.3,0.3,0.7,0.3,0.9,0.1l5-5l5,5c0.2,0.2,0.6,0.2,0.9-0.1l1-1 c0.3-0.3,0.3-0.7,0.1-0.9L11.5,9.5z"/></svg>';
@@ -477,8 +477,8 @@ RTE_DefaultConfig.svgCode_floatright = '<svg viewBox="0 0 24 24" fill="none" str
477
477
  RTE_DefaultConfig.svgCode_pmoveup = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>';
478
478
  RTE_DefaultConfig.svgCode_pmovedown = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg>';
479
479
  RTE_DefaultConfig.svgCode_plusbtn = '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M 9.9999997,4.3983051 A 0.62241054,0.62241054 0 0 0 9.3775887,5.0207156 V 9.3775893 H 5.0207156 a 0.62241067,0.62241067 0 0 0 0,1.2448207 h 4.3568731 v 4.356874 a 0.62241054,0.62241054 0 0 0 1.2448213,0 V 10.62241 h 4.356874 a 0.62241067,0.62241067 0 0 0 0,-1.2448207 H 10.62241 V 5.0207156 A 0.62241054,0.62241054 0 0 0 9.9999997,4.3983051 Z" clip-rule="evenodd"/></svg>'
480
- RTE_DefaultConfig.svgCode_imageupload = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><circle cx="8.5" cy="10.5" r="1.5"/><path d="M21 17l-5-5-6 6"/><path d="M12 3v8"/><path d="M8.5 6.5L12 3l3.5 3.5"/></svg>'
481
- RTE_DefaultConfig.svgCode_documentupload = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3h7l5 5v13H7z"/><path d="M14 3v5h5"/><path d="M12 17V9"/><path d="M8.5 12.5L12 9l3.5 3.5"/></svg>';
480
+ RTE_DefaultConfig.svgCode_imageupload = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><circle cx="8.5" cy="10.5" r="1.5"/><path d="M21 17l-5-5-6 6"/><path d="M12 3v8"/><path d="M8.5 6.5L12 3l3.5 3.5"/></svg>'
481
+ RTE_DefaultConfig.svgCode_documentupload = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3h7l5 5v13H7z"/><path d="M14 3v5h5"/><path d="M12 17V9"/><path d="M8.5 12.5L12 9l3.5 3.5"/></svg>';
482
482
 
483
483
  RTE_DefaultConfig.svgCode_tablecellmerge = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="12" x2="8" y2="12"/><line x1="16" y1="12" x2="21" y2="12"/><polyline points="6 9 9 12 6 15"/><polyline points="18 9 15 12 18 15"/></svg>';
484
484
  RTE_DefaultConfig.svgCode_tablecellsplitver = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="12" x2="8" y2="12"/><line x1="16" y1="12" x2="21" y2="12"/><polyline points="11 9 8 12 11 15"/><polyline points="13 9 16 12 13 15"/></svg>';
@@ -565,15 +565,15 @@ RTE_DefaultConfig.text_titlecase = "Title Case";
565
565
  // content-minimap, and accessibility-checker panels. Each plugin reads
566
566
  // these defaults at toolbar-build time so customers can re-skin or
567
567
  // translate without forking the plugin source.
568
- RTE_DefaultConfig.svgCode_documentoutline = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="6" x2="20" y2="6"/><line x1="9" y1="11" x2="20" y2="11"/><line x1="12" y1="16" x2="20" y2="16"/><line x1="3" y1="6" x2="3.5" y2="6"/><line x1="6" y1="11" x2="6.5" y2="11"/><line x1="9" y1="16" x2="9.5" y2="16"/></svg>';
568
+ RTE_DefaultConfig.svgCode_documentoutline = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="6" x2="20" y2="6"/><line x1="9" y1="11" x2="20" y2="11"/><line x1="12" y1="16" x2="20" y2="16"/><line x1="3" y1="6" x2="3.5" y2="6"/><line x1="6" y1="11" x2="6.5" y2="11"/><line x1="9" y1="16" x2="9.5" y2="16"/></svg>';
569
569
  RTE_DefaultConfig.text_documentoutline = "Document outline";
570
570
  RTE_DefaultConfig.text_documentoutlinehint = "Live table of contents — click any heading to jump to it.";
571
571
 
572
- RTE_DefaultConfig.svgCode_contentminimap = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="6" y1="7" x2="14" y2="7"/><line x1="6" y1="11" x2="18" y2="11"/><line x1="6" y1="15" x2="12" y2="15"/><line x1="6" y1="19" x2="16" y2="19"/></svg>';
572
+ RTE_DefaultConfig.svgCode_contentminimap = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="6" y1="7" x2="14" y2="7"/><line x1="6" y1="11" x2="18" y2="11"/><line x1="6" y1="15" x2="12" y2="15"/><line x1="6" y1="19" x2="16" y2="19"/></svg>';
573
573
  RTE_DefaultConfig.text_contentminimap = "Content minimap";
574
574
  RTE_DefaultConfig.text_contentminimaphint = "Bird's-eye view of the document — drag the highlight box to scroll.";
575
575
 
576
- RTE_DefaultConfig.svgCode_accessibilitychecker = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="7" r="1.4" fill="currentColor"/><path d="M9 11.5h6"/><path d="M12 11.5v8"/><path d="M9 19.5l3-4 3 4"/></svg>';
576
+ RTE_DefaultConfig.svgCode_accessibilitychecker = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="7" r="1.4" fill="currentColor"/><path d="M9 11.5h6"/><path d="M12 11.5v8"/><path d="M9 19.5l3-4 3 4"/></svg>';
577
577
  RTE_DefaultConfig.text_accessibilitychecker = "Accessibility checker";
578
578
  RTE_DefaultConfig.text_accessibilitycheckerhint = "Scan the document for missing alt text, empty headings, low contrast, and other a11y issues.";
579
579