@richscripts/richtexteditor 2.14.0 → 2.15.0

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 (238) hide show
  1. package/README.md +173 -10
  2. package/angular/build-manifest.json +23 -0
  3. package/angular/index.d.ts +71 -76
  4. package/angular/index.mjs +2 -0
  5. package/angular/package.json +4 -0
  6. package/headless/index.d.ts +3 -1
  7. package/headless/index.js +72 -16
  8. package/index.d.ts +33 -54
  9. package/integrations/initialization-scope.js +27 -0
  10. package/integrations/native-mount.js +30 -0
  11. package/integrations/shared.d.ts +23 -1
  12. package/integrations/shared.js +58 -22
  13. package/package.json +25 -3
  14. package/react/index.js +118 -37
  15. package/react/index.mjs +29 -0
  16. package/richtexteditor/all_plugins.js +7113 -1111
  17. package/richtexteditor/all_plugins.min.js +62 -59
  18. package/richtexteditor/lang/emoji/LICENSE-CLDR.txt +41 -0
  19. package/richtexteditor/lang/emoji/rte-emoji-de.js +3 -0
  20. package/richtexteditor/lang/emoji/rte-emoji-es.js +3 -0
  21. package/richtexteditor/lang/emoji/rte-emoji-fr.js +3 -0
  22. package/richtexteditor/lang/emoji/rte-emoji-it.js +3 -0
  23. package/richtexteditor/lang/emoji/rte-emoji-ja.js +3 -0
  24. package/richtexteditor/lang/emoji/rte-emoji-ko.js +3 -0
  25. package/richtexteditor/lang/emoji/rte-emoji-nl.js +3 -0
  26. package/richtexteditor/lang/emoji/rte-emoji-pt-pt.js +3 -0
  27. package/richtexteditor/lang/emoji/rte-emoji-pt.js +3 -0
  28. package/richtexteditor/lang/emoji/rte-emoji-ru.js +3 -0
  29. package/richtexteditor/lang/emoji/rte-emoji-zh-Hans.js +3 -0
  30. package/richtexteditor/lang/emoji/rte-emoji-zh-Hant.js +3 -0
  31. package/richtexteditor/lang/rte-lang-af.js +1 -0
  32. package/richtexteditor/lang/rte-lang-ar.js +1 -0
  33. package/richtexteditor/lang/rte-lang-bg.js +1 -0
  34. package/richtexteditor/lang/rte-lang-bn.js +1 -0
  35. package/richtexteditor/lang/rte-lang-bs.js +1 -0
  36. package/richtexteditor/lang/rte-lang-ca.js +1 -0
  37. package/richtexteditor/lang/rte-lang-cs.js +1 -0
  38. package/richtexteditor/lang/rte-lang-cy.js +1 -0
  39. package/richtexteditor/lang/rte-lang-da.js +1 -0
  40. package/richtexteditor/lang/rte-lang-de.js +1017 -2
  41. package/richtexteditor/lang/rte-lang-el.js +1 -0
  42. package/richtexteditor/lang/rte-lang-en.js +1 -0
  43. package/richtexteditor/lang/rte-lang-es.js +1023 -2
  44. package/richtexteditor/lang/rte-lang-et.js +1 -0
  45. package/richtexteditor/lang/rte-lang-fa.js +1 -0
  46. package/richtexteditor/lang/rte-lang-fi.js +1 -0
  47. package/richtexteditor/lang/rte-lang-fil.js +1 -0
  48. package/richtexteditor/lang/rte-lang-fj.js +1 -0
  49. package/richtexteditor/lang/rte-lang-fr.js +1023 -2
  50. package/richtexteditor/lang/rte-lang-ga.js +1 -0
  51. package/richtexteditor/lang/rte-lang-gu.js +1 -0
  52. package/richtexteditor/lang/rte-lang-he.js +1 -0
  53. package/richtexteditor/lang/rte-lang-hi.js +1 -0
  54. package/richtexteditor/lang/rte-lang-hr.js +1 -0
  55. package/richtexteditor/lang/rte-lang-ht.js +1 -0
  56. package/richtexteditor/lang/rte-lang-hu.js +1 -0
  57. package/richtexteditor/lang/rte-lang-id.js +1 -0
  58. package/richtexteditor/lang/rte-lang-is.js +1 -0
  59. package/richtexteditor/lang/rte-lang-it.js +1023 -2
  60. package/richtexteditor/lang/rte-lang-ja.js +1023 -2
  61. package/richtexteditor/lang/rte-lang-kn.js +1 -0
  62. package/richtexteditor/lang/rte-lang-ko.js +1023 -2
  63. package/richtexteditor/lang/rte-lang-lt.js +1 -0
  64. package/richtexteditor/lang/rte-lang-lv.js +1 -0
  65. package/richtexteditor/lang/rte-lang-mg.js +1 -0
  66. package/richtexteditor/lang/rte-lang-mi.js +1 -0
  67. package/richtexteditor/lang/rte-lang-ml.js +1 -0
  68. package/richtexteditor/lang/rte-lang-mr.js +1 -0
  69. package/richtexteditor/lang/rte-lang-ms.js +1 -0
  70. package/richtexteditor/lang/rte-lang-mt.js +1 -0
  71. package/richtexteditor/lang/rte-lang-mww.js +1 -0
  72. package/richtexteditor/lang/rte-lang-nb.js +1 -0
  73. package/richtexteditor/lang/rte-lang-nl.js +1023 -2
  74. package/richtexteditor/lang/rte-lang-otq.js +1 -0
  75. package/richtexteditor/lang/rte-lang-pa.js +1 -0
  76. package/richtexteditor/lang/rte-lang-pl.js +1 -0
  77. package/richtexteditor/lang/rte-lang-pt-pt.js +1023 -2
  78. package/richtexteditor/lang/rte-lang-pt.js +1023 -2
  79. package/richtexteditor/lang/rte-lang-ro.js +1 -0
  80. package/richtexteditor/lang/rte-lang-ru.js +1023 -2
  81. package/richtexteditor/lang/rte-lang-sk.js +1 -0
  82. package/richtexteditor/lang/rte-lang-sl.js +1 -0
  83. package/richtexteditor/lang/rte-lang-sm.js +1 -0
  84. package/richtexteditor/lang/rte-lang-sr-Cyrl.js +1 -0
  85. package/richtexteditor/lang/rte-lang-sr-Latn.js +1 -0
  86. package/richtexteditor/lang/rte-lang-sv.js +1 -0
  87. package/richtexteditor/lang/rte-lang-sw.js +1 -0
  88. package/richtexteditor/lang/rte-lang-ta.js +1 -0
  89. package/richtexteditor/lang/rte-lang-te.js +1 -0
  90. package/richtexteditor/lang/rte-lang-th.js +1 -0
  91. package/richtexteditor/lang/rte-lang-tlh-Latn.js +1 -0
  92. package/richtexteditor/lang/rte-lang-tlh-Piqd.js +1 -0
  93. package/richtexteditor/lang/rte-lang-to.js +1 -0
  94. package/richtexteditor/lang/rte-lang-tr.js +1 -0
  95. package/richtexteditor/lang/rte-lang-ty.js +1 -0
  96. package/richtexteditor/lang/rte-lang-uk.js +1 -0
  97. package/richtexteditor/lang/rte-lang-ur.js +1 -0
  98. package/richtexteditor/lang/rte-lang-vi.js +1 -0
  99. package/richtexteditor/lang/rte-lang-yua.js +1 -0
  100. package/richtexteditor/lang/rte-lang-zh-Hans.js +1017 -2
  101. package/richtexteditor/lang/rte-lang-zh-Hant.js +1017 -2
  102. package/richtexteditor/plugins/a11yenhance.js +2 -1
  103. package/richtexteditor/plugins/a11yenhance.min.js +1 -1
  104. package/richtexteditor/plugins/accessibilitychecker.js +252 -60
  105. package/richtexteditor/plugins/accessibilitychecker.min.js +1 -1
  106. package/richtexteditor/plugins/aitoolkit.js +966 -303
  107. package/richtexteditor/plugins/aitoolkit.min.js +7 -7
  108. package/richtexteditor/plugins/all_plugins.js +7113 -1111
  109. package/richtexteditor/plugins/all_plugins.min.js +62 -59
  110. package/richtexteditor/plugins/autocorrect.js +66 -31
  111. package/richtexteditor/plugins/autocorrect.min.js +1 -1
  112. package/richtexteditor/plugins/autoembed.js +17 -0
  113. package/richtexteditor/plugins/autoembed.min.js +1 -1
  114. package/richtexteditor/plugins/blocktypes.js +18 -9
  115. package/richtexteditor/plugins/blocktypes.min.js +1 -1
  116. package/richtexteditor/plugins/bookmarkcard.js +12 -5
  117. package/richtexteditor/plugins/bookmarkcard.min.js +2 -2
  118. package/richtexteditor/plugins/changecase.js +72 -19
  119. package/richtexteditor/plugins/changecase.min.js +1 -1
  120. package/richtexteditor/plugins/charlimit.js +62 -2
  121. package/richtexteditor/plugins/charlimit.min.js +2 -2
  122. package/richtexteditor/plugins/comments.js +458 -59
  123. package/richtexteditor/plugins/comments.min.js +4 -3
  124. package/richtexteditor/plugins/contentminimap.js +25 -6
  125. package/richtexteditor/plugins/contentminimap.min.js +1 -1
  126. package/richtexteditor/plugins/crossreference.js +1 -1
  127. package/richtexteditor/plugins/crossreference.min.js +1 -1
  128. package/richtexteditor/plugins/dialoga11y.js +26 -4
  129. package/richtexteditor/plugins/dialoga11y.min.js +1 -1
  130. package/richtexteditor/plugins/dictation.js +1 -1
  131. package/richtexteditor/plugins/documentimport.js +220 -51
  132. package/richtexteditor/plugins/documentimport.min.js +4 -4
  133. package/richtexteditor/plugins/documentoutline.js +88 -38
  134. package/richtexteditor/plugins/documentoutline.min.js +1 -1
  135. package/richtexteditor/plugins/docxexport.js +204 -32
  136. package/richtexteditor/plugins/docxexport.min.js +2 -2
  137. package/richtexteditor/plugins/draghandle.js +267 -3
  138. package/richtexteditor/plugins/draghandle.min.js +1 -1
  139. package/richtexteditor/plugins/emailtoolkit.js +28 -14
  140. package/richtexteditor/plugins/emailtoolkit.min.js +1 -1
  141. package/richtexteditor/plugins/emojiautocomplete.js +110 -56
  142. package/richtexteditor/plugins/emojiautocomplete.min.js +1 -1
  143. package/richtexteditor/plugins/footnotes.js +65 -11
  144. package/richtexteditor/plugins/footnotes.min.js +1 -1
  145. package/richtexteditor/plugins/formatpainter.js +10 -0
  146. package/richtexteditor/plugins/formatpainter.min.js +1 -1
  147. package/richtexteditor/plugins/formattingmarks.js +53 -8
  148. package/richtexteditor/plugins/formattingmarks.min.js +1 -1
  149. package/richtexteditor/plugins/gapcursor.js +60 -0
  150. package/richtexteditor/plugins/gapcursor.min.js +1 -1
  151. package/richtexteditor/plugins/ghostcomplete.js +1 -1
  152. package/richtexteditor/plugins/html2pdf.js +1 -1
  153. package/richtexteditor/plugins/html2pdf.min.js +1 -1
  154. package/richtexteditor/plugins/imageeditor.js +12 -6
  155. package/richtexteditor/plugins/imageeditor.min.js +1 -1
  156. package/richtexteditor/plugins/importstyles.js +1 -1
  157. package/richtexteditor/plugins/inlinecode.js +25 -0
  158. package/richtexteditor/plugins/inlinecode.min.js +1 -1
  159. package/richtexteditor/plugins/insertcode.js +21 -3
  160. package/richtexteditor/plugins/insertcode.min.js +4 -4
  161. package/richtexteditor/plugins/insertemoji.js +112 -15
  162. package/richtexteditor/plugins/insertemoji.min.js +1 -1
  163. package/richtexteditor/plugins/insertgallery.js +42 -36
  164. package/richtexteditor/plugins/insertgallery.min.js +1 -1
  165. package/richtexteditor/plugins/inserttemplate.js +33 -17
  166. package/richtexteditor/plugins/inserttemplate.min.js +1 -1
  167. package/richtexteditor/plugins/keyboarda11y.js +66 -3
  168. package/richtexteditor/plugins/keyboarda11y.min.js +1 -1
  169. package/richtexteditor/plugins/layouttable.js +20 -0
  170. package/richtexteditor/plugins/layouttable.min.js +1 -1
  171. package/richtexteditor/plugins/linkchecker.js +29 -9
  172. package/richtexteditor/plugins/linkchecker.min.js +1 -1
  173. package/richtexteditor/plugins/localdraft.js +51 -7
  174. package/richtexteditor/plugins/localdraft.min.js +1 -1
  175. package/richtexteditor/plugins/markdownexport.js +159 -0
  176. package/richtexteditor/plugins/markdownexport.min.js +2 -2
  177. package/richtexteditor/plugins/mathdialog.js +11 -5
  178. package/richtexteditor/plugins/mathdialog.min.js +1 -1
  179. package/richtexteditor/plugins/mentionplugin.js +88 -25
  180. package/richtexteditor/plugins/mentionplugin.min.js +1 -1
  181. package/richtexteditor/plugins/mermaiddiagram.js +9 -3
  182. package/richtexteditor/plugins/mermaiddiagram.min.js +2 -2
  183. package/richtexteditor/plugins/multilevellist.js +4 -0
  184. package/richtexteditor/plugins/multilevellist.min.js +1 -1
  185. package/richtexteditor/plugins/pdfexport.js +235 -35
  186. package/richtexteditor/plugins/pdfexport.min.js +12 -12
  187. package/richtexteditor/plugins/permanentpen.js +3 -3
  188. package/richtexteditor/plugins/permanentpen.min.js +1 -1
  189. package/richtexteditor/plugins/readabilitystats.js +25 -11
  190. package/richtexteditor/plugins/readabilitystats.min.js +1 -1
  191. package/richtexteditor/plugins/readaloud.js +29 -15
  192. package/richtexteditor/plugins/readaloud.min.js +1 -1
  193. package/richtexteditor/plugins/restrictedediting.js +166 -0
  194. package/richtexteditor/plugins/restrictedediting.min.js +2 -2
  195. package/richtexteditor/plugins/revisionhistory.js +169 -37
  196. package/richtexteditor/plugins/revisionhistory.min.js +3 -3
  197. package/richtexteditor/plugins/rubyannotation.js +19 -9
  198. package/richtexteditor/plugins/rubyannotation.min.js +1 -1
  199. package/richtexteditor/plugins/sanitizer.js +86 -4
  200. package/richtexteditor/plugins/sanitizer.min.js +1 -1
  201. package/richtexteditor/plugins/slashcommand.js +30 -16
  202. package/richtexteditor/plugins/slashcommand.min.js +2 -2
  203. package/richtexteditor/plugins/smartchips.js +36 -22
  204. package/richtexteditor/plugins/smartchips.min.js +2 -2
  205. package/richtexteditor/plugins/spellcheck.js +17 -8
  206. package/richtexteditor/plugins/spellcheck.min.js +2 -2
  207. package/richtexteditor/plugins/stateinspector.js +19 -9
  208. package/richtexteditor/plugins/stateinspector.min.js +2 -2
  209. package/richtexteditor/plugins/structured-content-bridge.js +56 -24
  210. package/richtexteditor/plugins/structured-content-bridge.min.js +7 -7
  211. package/richtexteditor/plugins/tableofcontents.js +5 -2
  212. package/richtexteditor/plugins/tableofcontents.min.js +1 -1
  213. package/richtexteditor/plugins/tabletools.js +388 -3
  214. package/richtexteditor/plugins/tabletools.min.js +1 -1
  215. package/richtexteditor/plugins/textdirection.js +18 -5
  216. package/richtexteditor/plugins/textdirection.min.js +1 -1
  217. package/richtexteditor/plugins/textpartlanguage.js +161 -32
  218. package/richtexteditor/plugins/textpartlanguage.min.js +1 -1
  219. package/richtexteditor/plugins/todolist.js +90 -6
  220. package/richtexteditor/plugins/todolist.min.js +1 -1
  221. package/richtexteditor/plugins/trackedchanges.js +1812 -25
  222. package/richtexteditor/plugins/trackedchanges.min.js +5 -3
  223. package/richtexteditor/plugins/wordexport.js +2 -2
  224. package/richtexteditor/plugins/yjscollab.js +9 -4
  225. package/richtexteditor/plugins/yjscollab.min.js +1 -1
  226. package/richtexteditor/plugins/zz_richtextbox_dialog_style.js +22 -13
  227. package/richtexteditor/plugins/zz_richtextbox_dialog_style.min.js +1 -1
  228. package/richtexteditor/rte-config.js +131 -50
  229. package/richtexteditor/rte-headless.js +19 -4
  230. package/richtexteditor/rte-webcomponent.js +89 -16
  231. package/richtexteditor/rte.js +133 -52
  232. package/richtexteditor/runtime/colorpicker_more_ns.htm +93 -16
  233. package/scripts/build-angular.mjs +97 -0
  234. package/svelte/index.d.ts +2 -1
  235. package/svelte/index.js +80 -9
  236. package/vue/index.js +130 -34
  237. package/angular/component.ts +0 -297
  238. package/angular/index.ts +0 -24
@@ -42,6 +42,165 @@ function RTE_Plugin_MarkdownExport() {
42
42
  var name = base ? (base + ".md") : defaultName();
43
43
  return triggerDownload(md, name);
44
44
  };
45
+
46
+ // 2026-10-13 Markdown mode (tools/markdown/markdown-mode.mjs): the document is edited as Markdown text in place.
47
+ // A toggle without an edit changes nothing. An edit applies as one undoable step. While the mode is open,
48
+ // getHTML() returns the HTML the Markdown text describes, so a host that saves mid-edit keeps the change.
49
+ var mdMode = null;
50
+ editor.isMarkdownMode = function () { return !!mdMode; };
51
+ editor.toggleMarkdownMode = function () { return mdMode ? exitMarkdownMode() : enterMarkdownMode(); };
52
+ // 2026-10-17 a live preview beside the source (competitor matrix F6): it renders what the text will become,
53
+ // from the editor's own importer, so raw HTML and javascript: links show as text. On by default; the button
54
+ // in the note row and setMarkdownPreview(bool) turn it off and on. tools/markdown/markdown-preview.mjs
55
+ var mdPreviewOn = true;
56
+ editor.isMarkdownPreview = function () { return !!mdMode && mdPreviewOn; };
57
+ editor.setMarkdownPreview = function (on) {
58
+ mdPreviewOn = !!on;
59
+ if (mdMode) applyPreviewState();
60
+ return editor.isMarkdownPreview();
61
+ };
62
+ var baseGetHTML = editor.getHTMLCode;
63
+ var htmlWhileMarkdown = function () {
64
+ if (mdMode && !mdMode.locked) return editor.fromMarkdown(mdMode.area.value, { apply: false });
65
+ return baseGetHTML.apply(editor, arguments);
66
+ };
67
+ editor.getHTML = htmlWhileMarkdown;
68
+ editor.getHTMLCode = htmlWhileMarkdown;
69
+
70
+ // 2026-10-17 labels speak the page's language: their own config.text_ key first, then - when a non-English
71
+ // language pack is loaded (text_language is not "Language") - the pack's existing translation, else English.
72
+ // tools/i18n/block-menu-language.mjs
73
+ function label(own, packKey, fallback) {
74
+ if (config && config["text_" + own]) return config["text_" + own];
75
+ if (packKey && config && config.text_language && config.text_language !== "Language" && config["text_" + packKey]) return config["text_" + packKey];
76
+ return fallback;
77
+ }
78
+
79
+ function enterMarkdownMode() {
80
+ var frame = editor.iframe;
81
+ if (!frame || !frame.parentNode) return false;
82
+ var host = frame.ownerDocument;
83
+ injectMarkdownStyles(host);
84
+ var original = editor.toMarkdown();
85
+ var note = host.createElement("div");
86
+ note.className = "rte-markdown-note";
87
+ note.textContent = ((config && config.text_md_note) || "Markdown mode. Markdown keeps headings, lists, links, emphasis, code and tables. Colours, footnotes, comments and other formatting are not kept when you change the text.");
88
+ var area = host.createElement("textarea");
89
+ area.className = "rte-markdown-mode";
90
+ area.setAttribute("spellcheck", "false");
91
+ // 2026-10-14 A named text box, described by the note above it (what Markdown keeps and loses), so a
92
+ // screen reader does not announce a bare "edit text" (WCAG 4.1.2). tools/markdown/markdown-mode-a11y.mjs
93
+ area.setAttribute("aria-label", ((config && config.text_md_source) || "Markdown source"));
94
+ note.id = "rte-markdown-note-" + new Date().getTime() + "-" + Math.floor(Math.random() * 1e6);
95
+ area.setAttribute("aria-describedby", note.id);
96
+ area.value = original;
97
+ // 2026-10-17 a locked document stays locked: in read-only and comments-only mode the source box was
98
+ // editable and leaving applied the edit; in suggesting mode the edit replaced the document untracked. The
99
+ // source now opens view-only there and leaving never applies. tools/markdown/markdown-mode-locked.mjs
100
+ var locked = false;
101
+ try { locked = !!((editor.getReadOnly && editor.getReadOnly()) || (editor.getCommentsOnly && editor.getCommentsOnly())); } catch (e) { locked = false; }
102
+ if (!locked && editor.__trackHook && editor.__trackHook("refuse", { message: ((config && config.text_md_suggestlocked) || "Suggesting is on, so the Markdown source is view only. Turn suggesting off to edit as Markdown.") }) === true) locked = true;
103
+ if (locked) {
104
+ area.readOnly = true;
105
+ note.textContent = ((config && config.text_md_viewonly) || "Markdown source, view only: this document cannot be changed here right now.");
106
+ }
107
+ var toggle = host.createElement("button");
108
+ toggle.type = "button";
109
+ toggle.className = "rte-markdown-preview-toggle";
110
+ var bar = host.createElement("div");
111
+ bar.className = "rte-markdown-bar";
112
+ bar.appendChild(toggle);
113
+ var split = host.createElement("div");
114
+ split.className = "rte-markdown-split";
115
+ var preview = host.createElement("div");
116
+ preview.className = "rte-markdown-preview";
117
+ preview.setAttribute("role", "region");
118
+ preview.setAttribute("aria-label", label("markdownpreview", "preview", "Markdown preview"));
119
+ split.appendChild(area);
120
+ split.appendChild(preview);
121
+ frame.style.display = "none";
122
+ frame.parentNode.insertBefore(note, frame.nextSibling);
123
+ frame.parentNode.insertBefore(bar, note.nextSibling);
124
+ frame.parentNode.insertBefore(split, bar.nextSibling);
125
+ mdMode = { area: area, note: note, frame: frame, original: original, split: split, preview: preview, toggle: toggle, bar: bar, timer: 0, locked: locked };
126
+ toggle.onclick = function () { editor.setMarkdownPreview(!mdPreviewOn); };
127
+ // 2026-10-17 the preview follows the source as it scrolls (proportional, as side-by-side Markdown editors
128
+ // do): with a long document the part being edited was off screen in the preview.
129
+ // tools/markdown/markdown-preview-scroll.mjs
130
+ area.addEventListener("scroll", syncPreviewScroll);
131
+ area.addEventListener("input", function () {
132
+ var state = mdMode;
133
+ if (!state || !mdPreviewOn) return;
134
+ clearTimeout(state.timer);
135
+ state.timer = setTimeout(renderPreview, 120);
136
+ });
137
+ applyPreviewState();
138
+ try { area.focus(); } catch (e) { /* focus is best effort */ }
139
+ return true;
140
+ }
141
+
142
+ function exitMarkdownMode() {
143
+ var state = mdMode;
144
+ var text = state.area.value;
145
+ mdMode = null;
146
+ if (!state.locked && text !== state.original) editor.setHTMLCode(editor.fromMarkdown(text, { apply: false }), { undoable: true });
147
+ clearTimeout(state.timer);
148
+ if (state.split.parentNode) state.split.parentNode.removeChild(state.split);
149
+ if (state.bar.parentNode) state.bar.parentNode.removeChild(state.bar);
150
+ if (state.note.parentNode) state.note.parentNode.removeChild(state.note);
151
+ state.frame.style.display = "";
152
+ // the text box that held focus is gone: focus goes back to the editor, not to the page body (WCAG 2.4.3)
153
+ try { editor.focus(); } catch (e) { /* ignore */ }
154
+ return true;
155
+ }
156
+
157
+ function renderPreview() {
158
+ var state = mdMode;
159
+ if (!state) return;
160
+ var html = "";
161
+ try { html = editor.fromMarkdown(state.area.value, { apply: false }); } catch (e) { html = ""; }
162
+ state.preview.innerHTML = html;
163
+ syncPreviewScroll();
164
+ }
165
+
166
+ function syncPreviewScroll() {
167
+ var state = mdMode;
168
+ if (!state || !mdPreviewOn) return;
169
+ var a = state.area, pv = state.preview;
170
+ var range = a.scrollHeight - a.clientHeight;
171
+ var ratio = range > 0 ? a.scrollTop / range : 0;
172
+ pv.scrollTop = Math.round(ratio * Math.max(0, pv.scrollHeight - pv.clientHeight));
173
+ }
174
+
175
+ function applyPreviewState() {
176
+ var state = mdMode;
177
+ state.preview.style.display = mdPreviewOn ? "" : "none";
178
+ state.split.className = "rte-markdown-split" + (mdPreviewOn ? " has-preview" : "");
179
+ state.toggle.setAttribute("aria-pressed", mdPreviewOn ? "true" : "false");
180
+ state.toggle.textContent = mdPreviewOn ? label("markdownpreview_hide", "", "Hide preview") : label("markdownpreview_show", "", "Show preview");
181
+ if (mdPreviewOn) renderPreview();
182
+ }
183
+
184
+ function injectMarkdownStyles(doc) {
185
+ if (doc.getElementById("rte-markdown-mode-styles")) return;
186
+ var st = doc.createElement("style");
187
+ st.id = "rte-markdown-mode-styles";
188
+ st.appendChild(doc.createTextNode(
189
+ ".rte-markdown-mode{display:block;box-sizing:border-box;width:100%;min-height:240px;margin:0;padding:12px 14px;" +
190
+ "border:1px solid #cbd5e1;border-radius:8px;font:14px/1.6 ui-monospace,SFMono-Regular,Consolas,monospace;" +
191
+ "color:#0f172a;background:#fff;resize:vertical;}" +
192
+ ".rte-markdown-note{margin:0 0 6px;font:13px/1.4 system-ui,sans-serif;color:#475569;}" +
193
+ ".rte-markdown-split.has-preview{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;}" +
194
+ "@media (max-width:640px){.rte-markdown-split.has-preview{grid-template-columns:minmax(0,1fr);}}" +
195
+ ".rte-markdown-preview{box-sizing:border-box;min-height:240px;max-height:70vh;overflow:auto;padding:12px 14px;" +
196
+ "border:1px solid #cbd5e1;border-radius:8px;background:#f8fafc;color:#0f172a;font:15px/1.6 system-ui,sans-serif;overflow-wrap:anywhere;}" +
197
+ ".rte-markdown-preview img{max-width:100%;height:auto;}" +
198
+ ".rte-markdown-preview table{border-collapse:collapse;}.rte-markdown-preview th,.rte-markdown-preview td{border:1px solid #cbd5e1;padding:4px 8px;}" +
199
+ ".rte-markdown-bar{margin:0 0 6px;}.rte-markdown-preview-toggle{padding:2px 10px;min-height:24px;border:1px solid #94a3b8;border-radius:6px;" +
200
+ "background:#fff;color:#0f172a;font:12px/1.4 system-ui,sans-serif;cursor:pointer;}" +
201
+ ".rte-markdown-preview-toggle:focus-visible{outline:2px solid #1d4ed8;outline-offset:2px;}"));
202
+ (doc.head || doc.documentElement).appendChild(st);
203
+ }
45
204
  };
46
205
 
47
206
  function defaultName() {
@@ -1,2 +1,2 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_markdownexport=RTE_Plugin_MarkdownExport,typeof RTE_DefaultConfig.markdownExportEnabled>"u"&&(RTE_DefaultConfig.markdownExportEnabled=!0);function RTE_Plugin_MarkdownExport(){var a=this,f,i;a.PluginName="MarkdownExport",a.InitConfig=function(e){f=e},a.InitEditor=function(e){i=e,i.getMarkdown=function(){if(typeof i.toMarkdown=="function")return i.toMarkdown();var t=i.getEditable();return t&&(t.innerText||t.textContent)||""},i.copyAsMarkdown=function(){var t=i.getMarkdown();return w(t)},i.downloadMarkdown=function(t){var n=i.getMarkdown(),r=d(t),o=r?r+".md":l();return p(n,o)}};function l(){try{var e=i.getEditable();if(e){var t=e.querySelector("h1,h2,h3"),n=t?t.textContent:e.textContent||"";n=(n||"").trim().split(`
2
- `)[0].slice(0,60);var r=d(n);if(r)return r+".md"}}catch{}return"document.md"}function d(e){return e?(e=String(e).replace(/\.md$/i,""),e=e.replace(/[\\/:*?"<>|\u0000-\u001f]+/g," ").replace(/\s+/g," ").trim(),e=e.replace(/[ .]+$/,""),e):""}function w(e){try{if(navigator.clipboard&&navigator.clipboard.writeText)return navigator.clipboard.writeText(e).then(function(){return!0},function(){return c(e)})}catch{}return Promise.resolve(c(e))}function c(e){try{var t=document,n=t.createElement("textarea");n.value=e,n.style.position="fixed",n.style.top="-1000px",n.style.opacity="0",t.body.appendChild(n),n.focus(),n.select();var r=!1;try{r=t.execCommand("copy")}catch{r=!1}return t.body.removeChild(n),r}catch{return!1}}function p(e,t){try{var n=new Blob([e],{type:"text/markdown;charset=utf-8"}),r=(window.URL||window.webkitURL).createObjectURL(n),o=document.createElement("a");return o.href=r,o.download=t,o.style.display="none",document.body.appendChild(o),o.click(),setTimeout(function(){try{document.body.removeChild(o)}catch{}try{(window.URL||window.webkitURL).revokeObjectURL(r)}catch{}},0),!0}catch{return!1}}}
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_markdownexport=RTE_Plugin_MarkdownExport,typeof RTE_DefaultConfig.markdownExportEnabled>"u"&&(RTE_DefaultConfig.markdownExportEnabled=!0);function RTE_Plugin_MarkdownExport(){var h=this,i,t;h.PluginName="MarkdownExport",h.InitConfig=function(o){i=o},h.InitEditor=function(o){t=o,t.getMarkdown=function(){if(typeof t.toMarkdown=="function")return t.toMarkdown();var e=t.getEditable();return e&&(e.innerText||e.textContent)||""},t.copyAsMarkdown=function(){var e=t.getMarkdown();return _(e)},t.downloadMarkdown=function(e){var r=t.getMarkdown(),d=x(e),l=d?d+".md":E();return T(r,l)};var n=null;t.isMarkdownMode=function(){return!!n},t.toggleMarkdownMode=function(){return n?L():N()};var a=!0;t.isMarkdownPreview=function(){return!!n&&a},t.setMarkdownPreview=function(e){return a=!!e,n&&C(),t.isMarkdownPreview()};var p=t.getHTMLCode,u=function(){return n&&!n.locked?t.fromMarkdown(n.area.value,{apply:!1}):p.apply(t,arguments)};t.getHTML=u,t.getHTMLCode=u;function c(e,r,d){return i&&i["text_"+e]?i["text_"+e]:r&&i&&i.text_language&&i.text_language!=="Language"&&i["text_"+r]?i["text_"+r]:d}function N(){var e=t.iframe;if(!e||!e.parentNode)return!1;var r=e.ownerDocument;R(r);var d=t.toMarkdown(),l=r.createElement("div");l.className="rte-markdown-note",l.textContent=i&&i.text_md_note||"Markdown mode. Markdown keeps headings, lists, links, emphasis, code and tables. Colours, footnotes, comments and other formatting are not kept when you change the text.";var s=r.createElement("textarea");s.className="rte-markdown-mode",s.setAttribute("spellcheck","false"),s.setAttribute("aria-label",i&&i.text_md_source||"Markdown source"),l.id="rte-markdown-note-"+new Date().getTime()+"-"+Math.floor(Math.random()*1e6),s.setAttribute("aria-describedby",l.id),s.value=d;var m=!1;try{m=!!(t.getReadOnly&&t.getReadOnly()||t.getCommentsOnly&&t.getCommentsOnly())}catch{m=!1}!m&&t.__trackHook&&t.__trackHook("refuse",{message:i&&i.text_md_suggestlocked||"Suggesting is on, so the Markdown source is view only. Turn suggesting off to edit as Markdown."})===!0&&(m=!0),m&&(s.readOnly=!0,l.textContent=i&&i.text_md_viewonly||"Markdown source, view only: this document cannot be changed here right now.");var f=r.createElement("button");f.type="button",f.className="rte-markdown-preview-toggle";var w=r.createElement("div");w.className="rte-markdown-bar",w.appendChild(f);var g=r.createElement("div");g.className="rte-markdown-split";var v=r.createElement("div");v.className="rte-markdown-preview",v.setAttribute("role","region"),v.setAttribute("aria-label",c("markdownpreview","preview","Markdown preview")),g.appendChild(s),g.appendChild(v),e.style.display="none",e.parentNode.insertBefore(l,e.nextSibling),e.parentNode.insertBefore(w,l.nextSibling),e.parentNode.insertBefore(g,w.nextSibling),n={area:s,note:l,frame:e,original:d,split:g,preview:v,toggle:f,bar:w,timer:0,locked:m},f.onclick=function(){t.setMarkdownPreview(!a)},s.addEventListener("scroll",M),s.addEventListener("input",function(){var k=n;!k||!a||(clearTimeout(k.timer),k.timer=setTimeout(y,120))}),C();try{s.focus()}catch{}return!0}function L(){var e=n,r=e.area.value;n=null,!e.locked&&r!==e.original&&t.setHTMLCode(t.fromMarkdown(r,{apply:!1}),{undoable:!0}),clearTimeout(e.timer),e.split.parentNode&&e.split.parentNode.removeChild(e.split),e.bar.parentNode&&e.bar.parentNode.removeChild(e.bar),e.note.parentNode&&e.note.parentNode.removeChild(e.note),e.frame.style.display="";try{t.focus()}catch{}return!0}function y(){var e=n;if(e){var r="";try{r=t.fromMarkdown(e.area.value,{apply:!1})}catch{r=""}e.preview.innerHTML=r,M()}}function M(){var e=n;if(!(!e||!a)){var r=e.area,d=e.preview,l=r.scrollHeight-r.clientHeight,s=l>0?r.scrollTop/l:0;d.scrollTop=Math.round(s*Math.max(0,d.scrollHeight-d.clientHeight))}}function C(){var e=n;e.preview.style.display=a?"":"none",e.split.className="rte-markdown-split"+(a?" has-preview":""),e.toggle.setAttribute("aria-pressed",a?"true":"false"),e.toggle.textContent=a?c("markdownpreview_hide","","Hide preview"):c("markdownpreview_show","","Show preview"),a&&y()}function R(e){if(!e.getElementById("rte-markdown-mode-styles")){var r=e.createElement("style");r.id="rte-markdown-mode-styles",r.appendChild(e.createTextNode(".rte-markdown-mode{display:block;box-sizing:border-box;width:100%;min-height:240px;margin:0;padding:12px 14px;border:1px solid #cbd5e1;border-radius:8px;font:14px/1.6 ui-monospace,SFMono-Regular,Consolas,monospace;color:#0f172a;background:#fff;resize:vertical;}.rte-markdown-note{margin:0 0 6px;font:13px/1.4 system-ui,sans-serif;color:#475569;}.rte-markdown-split.has-preview{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;}@media (max-width:640px){.rte-markdown-split.has-preview{grid-template-columns:minmax(0,1fr);}}.rte-markdown-preview{box-sizing:border-box;min-height:240px;max-height:70vh;overflow:auto;padding:12px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#f8fafc;color:#0f172a;font:15px/1.6 system-ui,sans-serif;overflow-wrap:anywhere;}.rte-markdown-preview img{max-width:100%;height:auto;}.rte-markdown-preview table{border-collapse:collapse;}.rte-markdown-preview th,.rte-markdown-preview td{border:1px solid #cbd5e1;padding:4px 8px;}.rte-markdown-bar{margin:0 0 6px;}.rte-markdown-preview-toggle{padding:2px 10px;min-height:24px;border:1px solid #94a3b8;border-radius:6px;background:#fff;color:#0f172a;font:12px/1.4 system-ui,sans-serif;cursor:pointer;}.rte-markdown-preview-toggle:focus-visible{outline:2px solid #1d4ed8;outline-offset:2px;}")),(e.head||e.documentElement).appendChild(r)}}};function E(){try{var o=t.getEditable();if(o){var n=o.querySelector("h1,h2,h3"),a=n?n.textContent:o.textContent||"";a=(a||"").trim().split(`
2
+ `)[0].slice(0,60);var p=x(a);if(p)return p+".md"}}catch{}return"document.md"}function x(o){return o?(o=String(o).replace(/\.md$/i,""),o=o.replace(/[\\/:*?"<>|\u0000-\u001f]+/g," ").replace(/\s+/g," ").trim(),o=o.replace(/[ .]+$/,""),o):""}function _(o){try{if(navigator.clipboard&&navigator.clipboard.writeText)return navigator.clipboard.writeText(o).then(function(){return!0},function(){return b(o)})}catch{}return Promise.resolve(b(o))}function b(o){try{var n=document,a=n.createElement("textarea");a.value=o,a.style.position="fixed",a.style.top="-1000px",a.style.opacity="0",n.body.appendChild(a),a.focus(),a.select();var p=!1;try{p=n.execCommand("copy")}catch{p=!1}return n.body.removeChild(a),p}catch{return!1}}function T(o,n){try{var a=new Blob([o],{type:"text/markdown;charset=utf-8"}),p=(window.URL||window.webkitURL).createObjectURL(a),u=document.createElement("a");return u.href=p,u.download=n,u.style.display="none",document.body.appendChild(u),u.click(),setTimeout(function(){try{document.body.removeChild(u)}catch{}try{(window.URL||window.webkitURL).revokeObjectURL(p)}catch{}},0),!0}catch{return!1}}}
@@ -25,6 +25,12 @@ function RTE_Plugin_MathDialog() {
25
25
 
26
26
  obj.PluginName = "MathDialog";
27
27
 
28
+ // 2026-10-18 the words read config.text_ keys (language packs), English as the fallback; {0} fills a template.
29
+ // tools/i18n/plugin-panels-language.mjs
30
+ function pText(key, fallback, arg) {
31
+ var s = (config && config["text_" + key]) || fallback;
32
+ return arg === undefined ? s : s.split("{0}").join(String(arg));
33
+ }
28
34
  obj.InitConfig = function (argconfig) { config = argconfig; };
29
35
 
30
36
  obj.InitEditor = function (argeditor) {
@@ -105,7 +111,7 @@ function RTE_Plugin_MathDialog() {
105
111
 
106
112
  var renderer = getRenderer(win);
107
113
  if (!renderer) {
108
- rendererNote.innerText = "No KaTeX/MathJax detected on the page — the equation is stored as markup and will render wherever a math renderer is loaded.";
114
+ rendererNote.innerText = pText("ma_norenderer", "No KaTeX/MathJax detected on the page \u2014 the equation is stored as markup and will render wherever a math renderer is loaded.");
109
115
  }
110
116
 
111
117
  function updatePreview() {
@@ -113,7 +119,7 @@ function RTE_Plugin_MathDialog() {
113
119
  if (!tex.trim()) { preview.textContent = ""; return; }
114
120
  if (renderer && renderer.kind === "katex") {
115
121
  try { renderer.katex.render(tex, preview, { throwOnError: false, displayMode: false }); }
116
- catch (e) { preview.textContent = "⚠ " + (e && e.message ? e.message : "render error"); }
122
+ catch (e) { preview.textContent = "\u26a0 " + (e && e.message ? e.message : "render error"); }
117
123
  } else if (renderer && renderer.kind === "mathjax") {
118
124
  preview.textContent = "\\(" + tex + "\\)";
119
125
  try { renderer.MathJax.typesetPromise([preview]); } catch (e) { /* ignore */ }
@@ -126,9 +132,9 @@ function RTE_Plugin_MathDialog() {
126
132
 
127
133
  var footer = append(wrap, "div", "display:flex;justify-content:flex-end;gap:8px;margin-top:14px");
128
134
  var cancel = append(footer, "button", "padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer", "");
129
- cancel.type = "button"; cancel.textContent = "Cancel"; cancel.onclick = close;
135
+ cancel.type = "button"; cancel.textContent = pText("cancel", "Cancel"); cancel.onclick = close;
130
136
  var ok = append(footer, "button", "padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer", "");
131
- ok.type = "button"; ok.textContent = existing ? "Update" : "Insert";
137
+ ok.type = "button"; ok.textContent = existing ? pText("update", "Update") : pText("insert", "Insert");
132
138
 
133
139
  ok.onclick = function () {
134
140
  var tex = ta.value.trim();
@@ -144,7 +150,7 @@ function RTE_Plugin_MathDialog() {
144
150
  }
145
151
  var safeTex = String(tex).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
146
152
  var safeText = String("$" + tex + "$").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
147
- editor.insertHTML('<span class="rte-math-inline" data-tex="' + safeTex + '">' + safeText + "</span>​");
153
+ editor.insertHTML('<span class="rte-math-inline" data-tex="' + safeTex + '">' + safeText + "</span>\u200b");
148
154
  close();
149
155
  if (editor.renderMath) editor.renderMath();
150
156
  editor.focus();
@@ -1 +1 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_mathdialog=RTE_Plugin_MathDialog,RTE_DefaultConfig.mathDialogSamples=RTE_DefaultConfig.mathDialogSamples||["x^2 + y^2 = z^2","\\frac{a}{b}","\\sqrt{x}","\\sum_{i=1}^{n} i","\\int_0^1 x\\,dx","\\alpha\\beta\\gamma"];function RTE_Plugin_MathDialog(){var c=this,m,t;c.PluginName="MathDialog",c.InitConfig=function(e){m=e},c.InitEditor=function(e){t=e,t.attachEvent("exec_command_insertmath",function(a){a.returnValue=!0,c.OpenMathDialog()})};function i(e,a,n,p){var u=e.ownerDocument.createElement(a);return n&&(u.style.cssText=n),p&&(u.className=p),e.appendChild(u),u}function b(){try{var e=t.getSelection();if(!e||e.rangeCount===0)return null;for(var a=e.getRangeAt(0).startContainer,n=t.getEditable();a&&a!==n;){if(a.nodeType===1&&a.classList&&a.classList.contains("rte-math-inline"))return a;a=a.parentNode}}catch{}return null}function T(e){var a=e.katex||e.parent&&e.parent.katex;if(a&&typeof a.render=="function")return{kind:"katex",katex:a};var n=e.MathJax||e.parent&&e.parent.MathJax;return n&&n.typesetPromise?{kind:"mathjax",MathJax:n}:null}c.OpenMathDialog=function(){var e=b(),a=e&&e.getAttribute("data-tex")||"",n=t.createDialog(t.getLangText&&t.getLangText("insertmathtitle")||"Insert / edit equation","rte-dialog-math"),p=typeof n.close=="function"?function(){n.close()}:function(){t.closeCurrentPopup()},u=n.ownerDocument.defaultView||window,d=i(n,"div","padding:14px;min-width:420px;font:13px -apple-system,Segoe UI,sans-serif");i(d,"div","font-weight:600;margin-bottom:4px","").innerText=t.getLangText&&t.getLangText("insertmathlabel")||"TeX / LaTeX";var l=i(d,"textarea","width:100%;box-sizing:border-box;min-height:72px;padding:8px 10px;border:1px solid #cbd5e1;border-radius:8px;font:13px ui-monospace,Consolas,monospace;resize:vertical");l.value=a,l.placeholder="e.g. x^2 + y^2 = z^2";var w=i(d,"div","display:flex;flex-wrap:wrap;gap:6px;margin:8px 0");(m.mathDialogSamples||[]).forEach(function(r){var o=i(w,"button","font:11px ui-monospace,monospace;padding:3px 8px;border:1px solid #e2e8f0;border-radius:6px;background:#f8fafc;cursor:pointer","");o.type="button",o.textContent=r,o.onclick=function(){l.value=r,s(),l.focus()}}),i(d,"div","font-weight:600;margin:10px 0 4px","").innerText=t.getLangText&&t.getLangText("insertmathpreview")||"Preview";var f=i(d,"div","min-height:48px;padding:10px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#fff;overflow:auto;text-align:center"),k=i(d,"div","font-size:11px;color:#94a3b8;margin-top:4px",""),x=T(u);x||(k.innerText="No KaTeX/MathJax detected on the page \u2014 the equation is stored as markup and will render wherever a math renderer is loaded.");function s(){var r=l.value;if(!r.trim()){f.textContent="";return}if(x&&x.kind==="katex")try{x.katex.render(r,f,{throwOnError:!1,displayMode:!1})}catch(o){f.textContent="\u26A0 "+(o&&o.message?o.message:"render error")}else if(x&&x.kind==="mathjax"){f.textContent="\\("+r+"\\)";try{x.MathJax.typesetPromise([f])}catch{}}else f.textContent="$"+r+"$"}l.oninput=s,setTimeout(function(){l.focus(),s()},0);var v=i(d,"div","display:flex;justify-content:flex-end;gap:8px;margin-top:14px"),g=i(v,"button","padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer","");g.type="button",g.textContent="Cancel",g.onclick=p;var h=i(v,"button","padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer","");h.type="button",h.textContent=e?"Update":"Insert",h.onclick=function(){var r=l.value.trim();if(!r){p();return}if(e){e.setAttribute("data-tex",r),e.textContent="$"+r+"$",p(),t.renderMath&&t.renderMath(),t.focus();return}var o=String(r).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"),C=("$"+r+"$").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");t.insertHTML('<span class="rte-math-inline" data-tex="'+o+'">'+C+"</span>\u200B"),p(),t.renderMath&&t.renderMath(),t.focus()}}}
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_mathdialog=RTE_Plugin_MathDialog,RTE_DefaultConfig.mathDialogSamples=RTE_DefaultConfig.mathDialogSamples||["x^2 + y^2 = z^2","\\frac{a}{b}","\\sqrt{x}","\\sum_{i=1}^{n} i","\\int_0^1 x\\,dx","\\alpha\\beta\\gamma"];function RTE_Plugin_MathDialog(){var f=this,s,a;f.PluginName="MathDialog";function g(e,t,n){var o=s&&s["text_"+e]||t;return n===void 0?o:o.split("{0}").join(String(n))}f.InitConfig=function(e){s=e},f.InitEditor=function(e){a=e,a.attachEvent("exec_command_insertmath",function(t){t.returnValue=!0,f.OpenMathDialog()})};function i(e,t,n,o){var x=e.ownerDocument.createElement(t);return n&&(x.style.cssText=n),o&&(x.className=o),e.appendChild(x),x}function T(){try{var e=a.getSelection();if(!e||e.rangeCount===0)return null;for(var t=e.getRangeAt(0).startContainer,n=a.getEditable();t&&t!==n;){if(t.nodeType===1&&t.classList&&t.classList.contains("rte-math-inline"))return t;t=t.parentNode}}catch{}return null}function w(e){var t=e.katex||e.parent&&e.parent.katex;if(t&&typeof t.render=="function")return{kind:"katex",katex:t};var n=e.MathJax||e.parent&&e.parent.MathJax;return n&&n.typesetPromise?{kind:"mathjax",MathJax:n}:null}f.OpenMathDialog=function(){var e=T(),t=e&&e.getAttribute("data-tex")||"",n=a.createDialog(a.getLangText&&a.getLangText("insertmathtitle")||"Insert / edit equation","rte-dialog-math"),o=typeof n.close=="function"?function(){n.close()}:function(){a.closeCurrentPopup()},x=n.ownerDocument.defaultView||window,l=i(n,"div","padding:14px;min-width:420px;font:13px -apple-system,Segoe UI,sans-serif");i(l,"div","font-weight:600;margin-bottom:4px","").innerText=a.getLangText&&a.getLangText("insertmathlabel")||"TeX / LaTeX";var d=i(l,"textarea","width:100%;box-sizing:border-box;min-height:72px;padding:8px 10px;border:1px solid #cbd5e1;border-radius:8px;font:13px ui-monospace,Consolas,monospace;resize:vertical");d.value=t,d.placeholder="e.g. x^2 + y^2 = z^2";var k=i(l,"div","display:flex;flex-wrap:wrap;gap:6px;margin:8px 0");(s.mathDialogSamples||[]).forEach(function(r){var p=i(k,"button","font:11px ui-monospace,monospace;padding:3px 8px;border:1px solid #e2e8f0;border-radius:6px;background:#f8fafc;cursor:pointer","");p.type="button",p.textContent=r,p.onclick=function(){d.value=r,h(),d.focus()}}),i(l,"div","font-weight:600;margin:10px 0 4px","").innerText=a.getLangText&&a.getLangText("insertmathpreview")||"Preview";var c=i(l,"div","min-height:48px;padding:10px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#fff;overflow:auto;text-align:center"),C=i(l,"div","font-size:11px;color:#94a3b8;margin-top:4px",""),u=w(x);u||(C.innerText=g("ma_norenderer","No KaTeX/MathJax detected on the page \u2014 the equation is stored as markup and will render wherever a math renderer is loaded."));function h(){var r=d.value;if(!r.trim()){c.textContent="";return}if(u&&u.kind==="katex")try{u.katex.render(r,c,{throwOnError:!1,displayMode:!1})}catch(p){c.textContent="\u26A0 "+(p&&p.message?p.message:"render error")}else if(u&&u.kind==="mathjax"){c.textContent="\\("+r+"\\)";try{u.MathJax.typesetPromise([c])}catch{}}else c.textContent="$"+r+"$"}d.oninput=h,setTimeout(function(){d.focus(),h()},0);var b=i(l,"div","display:flex;justify-content:flex-end;gap:8px;margin-top:14px"),m=i(b,"button","padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer","");m.type="button",m.textContent=g("cancel","Cancel"),m.onclick=o;var v=i(b,"button","padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer","");v.type="button",v.textContent=e?g("update","Update"):g("insert","Insert"),v.onclick=function(){var r=d.value.trim();if(!r){o();return}if(e){e.setAttribute("data-tex",r),e.textContent="$"+r+"$",o(),a.renderMath&&a.renderMath(),a.focus();return}var p=String(r).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"),y=("$"+r+"$").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");a.insertHTML('<span class="rte-math-inline" data-tex="'+p+'">'+y+"</span>\u200B"),o(),a.renderMath&&a.renderMath(),a.focus()}}}
@@ -22,6 +22,12 @@ function RTE_Plugin_Mention() {
22
22
 
23
23
  obj.PluginName = "Mention";
24
24
 
25
+ // 2026-10-18 the words read config.text_ keys (language packs), English as the fallback; {0} fills a template.
26
+ // tools/i18n/plugin-panels-language.mjs
27
+ function pText(key, fallback, arg) {
28
+ var s = (config && config["text_" + key]) || fallback;
29
+ return arg === undefined ? s : s.split("{0}").join(String(arg));
30
+ }
25
31
  obj.InitConfig = function (argconfig) {
26
32
  config = argconfig;
27
33
  if (config.mentionEnabled === false) return;
@@ -66,28 +72,55 @@ function RTE_Plugin_Mention() {
66
72
 
67
73
  injectStyles();
68
74
 
69
- var editdoc = editor.getDocument();
70
- editdoc.addEventListener("keydown", onEditDocKeyDown, true);
71
- editdoc.addEventListener("input", onEditDocInput, true);
72
- editdoc.addEventListener("compositionstart", function () { composing = true; });
73
- editdoc.addEventListener("compositionend", function () { composing = false; });
74
- editdoc.addEventListener("mousedown", function (e) {
75
+ // 2026-10-03 Bound through editor.bindDocumentEvent, so the listeners follow the live document:
76
+ // shell plugins move the iframe during the init loop, and listeners added to editdoc here stayed
77
+ // on the dead document (this feature never fired). tools/keyboard/plugin-listeners.mjs
78
+ var on = function (type, fn, capture) {
79
+ if (editor.bindDocumentEvent) editor.bindDocumentEvent(type, fn, capture);
80
+ else editor.getDocument().addEventListener(type, fn, capture);
81
+ };
82
+ on("keydown", onEditDocKeyDown, true);
83
+ on("input", onEditDocInput, true);
84
+ on("compositionstart", function () { composing = true; });
85
+ on("compositionend", function () { composing = false; });
86
+ on("mousedown", function (e) {
75
87
  // Don't close when the user is clicking on a mention span (for selection/delete).
76
88
  if (e.target && e.target.closest && e.target.closest("." + config.mentionInsertClass)) return;
77
89
  closePopup();
78
90
  }, true);
79
- editdoc.addEventListener("blur", function () { setTimeout(closePopup, 150); }, true);
91
+ on("blur", function () { setTimeout(closePopup, 150); }, true);
80
92
 
81
93
  window.addEventListener("scroll", onHostScrollOrResize, true);
82
94
  window.addEventListener("resize", onHostScrollOrResize, true);
83
95
  };
84
96
 
97
+ // 2026-10-19 The docs, the migration guide and the demos all register with search(query, done) or an
98
+ // async search(query) returning the list - but only source was accepted, so those triggers were
99
+ // silently dropped and @ did nothing (richtexteditor.com/demos/mentions included). search is now
100
+ // accepted in both forms, and a definition with neither is reported. tools/mentions/mention-search-api.mjs
101
+ function adaptSearch(search) {
102
+ return function (query, ctx) {
103
+ return new Promise(function (resolve, reject) {
104
+ var settled = false;
105
+ var done = function (results) { if (!settled) { settled = true; resolve(results); } };
106
+ var ret;
107
+ try { ret = search(query, done, ctx); } catch (err) { reject(err); return; }
108
+ if (ret !== undefined) Promise.resolve(ret).then(function (r) { if (r !== undefined) done(r); }, reject);
109
+ });
110
+ };
111
+ }
112
+
85
113
  function registerTrigger(def) {
86
- if (!def || !def.trigger || typeof def.source !== "function") return;
114
+ if (!def || !def.trigger) return;
115
+ var source = typeof def.source === "function" ? def.source : (typeof def.search === "function" ? adaptSearch(def.search) : null);
116
+ if (!source) {
117
+ if (window.console && console.warn) console.warn("RichTextEditor mentions: trigger \"" + def.trigger + "\" was not registered - pass search(query, done) or source(query).");
118
+ return;
119
+ }
87
120
  var existingIdx = findTriggerIndex(def.trigger);
88
121
  var normalized = {
89
122
  trigger: def.trigger,
90
- source: def.source,
123
+ source: source,
91
124
  renderItem: def.renderItem || null,
92
125
  renderInsert: def.renderInsert || null,
93
126
  insertClass: def.insertClass || config.mentionInsertClass,
@@ -283,7 +316,14 @@ function RTE_Plugin_Mention() {
283
316
  function renderPopup() {
284
317
  popupHost = editor.iframe.ownerDocument;
285
318
  popupEl = popupHost.createElement("div");
286
- popupEl.className = "rte-mention-popup";
319
+ // 2026-10-17 appended to the page body, outside the editor, so rte-dark could not reach it: mirrored (and
320
+ // rte-auto-dark under a dark system setting). tools/mentions/mention-popup-dark.mjs
321
+ var mDark = false;
322
+ try {
323
+ var mk = editor.container && editor.container.classList;
324
+ mDark = !!mk && (mk.contains("rte-dark") || (mk.contains("rte-auto-dark") && !mk.contains("rte-light") && !!(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches)));
325
+ } catch (x) { mDark = false; }
326
+ popupEl.className = "rte-mention-popup" + (mDark ? " rte-mention-popup-dark" : "");
287
327
  popupEl.setAttribute("role", "listbox");
288
328
  popupEl.setAttribute("aria-label", activeTrigger.label);
289
329
  popupHost.body.appendChild(popupEl);
@@ -294,7 +334,7 @@ function RTE_Plugin_Mention() {
294
334
  popupEl.innerHTML = "";
295
335
  var loader = popupHost.createElement("div");
296
336
  loader.className = "rte-mention-loading";
297
- loader.textContent = "Searching\u2026";
337
+ loader.textContent = pText("mn_searching", "Searching\u2026");
298
338
  popupEl.appendChild(loader);
299
339
  statusEl = loader;
300
340
  }
@@ -307,7 +347,7 @@ function RTE_Plugin_Mention() {
307
347
  if (!items.length) {
308
348
  var empty = popupHost.createElement("div");
309
349
  empty.className = "rte-mention-empty";
310
- empty.textContent = "No matches";
350
+ empty.textContent = pText("mn_nomatches", "No matches");
311
351
  popupEl.appendChild(empty);
312
352
  return;
313
353
  }
@@ -321,7 +361,13 @@ function RTE_Plugin_Mention() {
321
361
  btn.setAttribute("aria-selected", index === activeIndex ? "true" : "false");
322
362
  btn.setAttribute("data-index", index);
323
363
 
324
- if (activeTrigger.renderItem) {
364
+ if (activeTrigger.renderItem && activeTrigger.renderItem.length < 2) {
365
+ // renderItem(user) returning text or a node, as the docs write it
366
+ var shown = activeTrigger.renderItem(item);
367
+ if (shown && shown.nodeType) btn.appendChild(shown);
368
+ else if (shown != null && shown !== "") btn.textContent = String(shown);
369
+ else renderDefaultItem(btn, item);
370
+ } else if (activeTrigger.renderItem) {
325
371
  activeTrigger.renderItem(btn, item);
326
372
  } else {
327
373
  renderDefaultItem(btn, item);
@@ -442,15 +488,23 @@ function RTE_Plugin_Mention() {
442
488
  function insertMention(triggerDef, item) {
443
489
  var editdoc = editor.getDocument();
444
490
  var span;
445
- if (triggerDef.renderInsert) {
491
+ var chip = function (text) {
492
+ var el = editdoc.createElement("span");
493
+ el.className = triggerDef.insertClass;
494
+ el.setAttribute("contenteditable", "false");
495
+ el.setAttribute("data-rte-mention-id", item.id != null ? item.id : "");
496
+ el.setAttribute("data-rte-mention-trigger", triggerDef.trigger);
497
+ el.textContent = text;
498
+ return el;
499
+ };
500
+ if (triggerDef.renderInsert && triggerDef.renderInsert.length < 2) {
501
+ // renderInsert(user) returning the chip's text (or a node), as the docs write it
502
+ var out = triggerDef.renderInsert(item);
503
+ span = out && out.nodeType ? out : chip(out != null && out !== "" ? String(out) : triggerDef.trigger + itemLabel(item));
504
+ } else if (triggerDef.renderInsert) {
446
505
  span = triggerDef.renderInsert(editdoc, item);
447
506
  } else {
448
- span = editdoc.createElement("span");
449
- span.className = triggerDef.insertClass;
450
- span.setAttribute("contenteditable", "false");
451
- span.setAttribute("data-rte-mention-id", item.id != null ? item.id : "");
452
- span.setAttribute("data-rte-mention-trigger", triggerDef.trigger);
453
- span.textContent = triggerDef.trigger + itemLabel(item);
507
+ span = chip(triggerDef.trigger + itemLabel(item));
454
508
  }
455
509
  if (!span) return;
456
510
 
@@ -479,8 +533,10 @@ function RTE_Plugin_Mention() {
479
533
  var r = rects && rects.length ? rects[rects.length - 1] : null;
480
534
  if (!r) r = trigger.range.getBoundingClientRect();
481
535
 
482
- var left = ir.left + (r.left || 0) + window.pageXOffset;
483
- var top = ir.top + (r.bottom || r.top || 0) + window.pageYOffset + 4;
536
+ // the caret rect is in iframe pixels, scaled on screen inside a transform:scale() ancestor
537
+ var sk = iframe.offsetWidth && ir.width > 0 ? ir.width / iframe.offsetWidth : 1;
538
+ var left = ir.left + (r.left || 0) * sk + window.pageXOffset;
539
+ var top = ir.top + (r.bottom || r.top || 0) * sk + window.pageYOffset + 4;
484
540
 
485
541
  popupEl.style.position = "absolute";
486
542
  popupEl.style.left = left + "px";
@@ -488,8 +544,8 @@ function RTE_Plugin_Mention() {
488
544
 
489
545
  var vh = window.innerHeight || document.documentElement.clientHeight;
490
546
  var popupRect = popupEl.getBoundingClientRect();
491
- if (popupRect.bottom > vh - 8 && (ir.top + (r.top || 0)) > popupRect.height + 16) {
492
- popupEl.style.top = (ir.top + (r.top || 0) + window.pageYOffset - popupRect.height - 4) + "px";
547
+ if (popupRect.bottom > vh - 8 && (ir.top + (r.top || 0) * sk) > popupRect.height + 16) {
548
+ popupEl.style.top = (ir.top + (r.top || 0) * sk + window.pageYOffset - popupRect.height - 4) + "px";
493
549
  }
494
550
  }
495
551
 
@@ -516,7 +572,14 @@ function RTE_Plugin_Mention() {
516
572
  ".rte-mention-item-active .rte-mention-subtitle{color:#315277}",
517
573
  ".rte-mention-loading,.rte-mention-empty{padding:14px 16px;color:#52657e;font-size:12px;font-weight:700;text-align:center}",
518
574
  ".rte-mention{display:inline-block;padding:1px 7px;border-radius:999px;background:#eef4ff;color:#0f3f9f;font-weight:650;cursor:default;border:1px solid rgba(37,99,235,.16)}",
519
- ".rte-mention:hover{background:#e4edff}"
575
+ ".rte-mention:hover{background:#e4edff}",
576
+ ".rte-mention-popup.rte-mention-popup-dark{background:linear-gradient(180deg,#1e293b,#0f172a);border-color:#334155;color:#e2e8f0;box-shadow:0 18px 40px rgba(0,0,0,.5)}",
577
+ ".rte-mention-popup-dark .rte-mention-item:hover,.rte-mention-popup-dark .rte-mention-item-active{background:#1e3a8a;color:#ffffff}",
578
+ ".rte-mention-popup-dark .rte-mention-avatar{background:#334155;color:#e2e8f0}",
579
+ ".rte-mention-popup-dark .rte-mention-item-active .rte-mention-avatar{background:#0f172a;color:#bfdbfe}",
580
+ ".rte-mention-popup-dark .rte-mention-subtitle{color:#94a3b8}",
581
+ ".rte-mention-popup-dark .rte-mention-item-active .rte-mention-subtitle{color:#bfdbfe}",
582
+ ".rte-mention-popup-dark .rte-mention-loading,.rte-mention-popup-dark .rte-mention-empty{color:#94a3b8}"
520
583
  ].join("\n");
521
584
  host.head.appendChild(style);
522
585
  // A <style> ELEMENT is governed by style-src: under a strict policy the browser
@@ -1,3 +1,3 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_mention=RTE_Plugin_Mention;function RTE_Plugin_Mention(){var w=this,l,s,p=null,i=null,C=null,h=[],v=null,m=null,f=[],c=0,y=!1,E=0,b=null;w.PluginName="Mention",w.InitConfig=function(e){l=e,l.mentionEnabled!==!1&&(l.mentionTrigger=l.mentionTrigger||"@",l.mentionDebounceMs=l.mentionDebounceMs==null?150:l.mentionDebounceMs,l.mentionMaxItems=l.mentionMaxItems||8,l.mentionStaticList=l.mentionStaticList||null,l.mentionSource=l.mentionSource||null,l.mentionInsertClass=l.mentionInsertClass||"rte-mention",l.mentionTriggers=l.mentionTriggers||null)},w.InitEditor=function(e){if(s=e,l.mentionEnabled!==!1){if(s.mentions={register:A,remove:M,list:function(){return h.slice()},close:d,isOpen:function(){return!!i}},(l.mentionSource||l.mentionStaticList)&&A({trigger:l.mentionTrigger,source:l.mentionSource||function(r){return P(l.mentionStaticList,r)}}),Array.isArray(l.mentionTriggers))for(var t=0;t<l.mentionTriggers.length;t++)A(l.mentionTriggers[t]);G();var n=s.getDocument();n.addEventListener("keydown",z,!0),n.addEventListener("input",H,!0),n.addEventListener("compositionstart",function(){y=!0}),n.addEventListener("compositionend",function(){y=!1}),n.addEventListener("mousedown",function(r){r.target&&r.target.closest&&r.target.closest("."+l.mentionInsertClass)||d()},!0),n.addEventListener("blur",function(){setTimeout(d,150)},!0),window.addEventListener("scroll",O,!0),window.addEventListener("resize",O,!0)}};function A(e){if(!(!e||!e.trigger||typeof e.source!="function")){var t=T(e.trigger),n={trigger:e.trigger,source:e.source,renderItem:e.renderItem||null,renderInsert:e.renderInsert||null,insertClass:e.insertClass||l.mentionInsertClass,label:e.label||"mentions "+e.trigger};t>=0?h[t]=n:h.push(n)}}function M(e){var t=T(e);t>=0&&h.splice(t,1)}function T(e){for(var t=0;t<h.length;t++)if(h[t].trigger===e)return t;return-1}function x(e){return e&&(e.label||e.name||e.id)||""}function I(e){return e&&(e.subtitle||e.email)||""}function P(e,t){if(!Array.isArray(e))return[];if(!t)return e.slice(0,50);var n=t.toLowerCase();return e.filter(function(r){var o=(x(r)+" "+I(r)+" "+(r.id||"")).toLowerCase();return o.indexOf(n)!==-1})}function z(e){if(!y){if(i)switch(e.key){case"ArrowDown":e.preventDefault(),e.stopPropagation(),k(1);return;case"ArrowUp":e.preventDefault(),e.stopPropagation(),k(-1);return;case"Enter":case"Tab":if(f.length){e.preventDefault(),e.stopPropagation(),S();return}d();return;case"Escape":case"Esc":e.preventDefault(),e.stopPropagation(),d();return}if(!e.ctrlKey&&!e.metaKey&&!e.altKey){var t=T(e.key);if(t>=0&&q()){var n=h[t];setTimeout(function(){j(n)},0)}}}}function H(){i&&U()}function q(){var e=s.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed)return!1;for(var t=e.getRangeAt(0),n=t.startContainer,r=t.startOffset,o=s.getEditable(),a=n.nodeType===1?n:n.parentNode;a&&a!==o;){var g=a.nodeName;if(g==="CODE"||g==="PRE"||a.classList&&a.classList.contains(l.mentionInsertClass))return!1;a=a.parentNode}if(n.nodeType===3){if(r===0)return!0;var u=n.nodeValue.charAt(r-1);return/\s/.test(u)}return!0}function j(e){d();var t=s.getSelection();if(!(!t||t.rangeCount===0)){var n=t.getRangeAt(0).cloneRange();v=e,m={range:n,startNode:n.startContainer,startOffset:n.startOffset,triggerCharCount:1,query:""},_(),L(),R("")}}function d(){b&&(clearTimeout(b),b=null),i&&i.parentNode&&i.parentNode.removeChild(i),i=null,C=null,v=null,m=null,f=[],c=0}function U(){if(m){var e=s.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed){d();return}var t=e.getRangeAt(0),n=t.startContainer;if(n!==m.startNode){d();return}var r=t.startOffset;if(r<m.startOffset){d();return}var o=(n.nodeType===3?n.nodeValue:"")||"",a=o.substring(m.startOffset,r);if(/\s/.test(a)){d();return}m.query=a,R(a),L()}}function R(e){if(!v)return;var t=++E;b&&(clearTimeout(b),b=null);var n=e.length===0?0:l.mentionDebounceMs;function r(){B();var o;try{o=v.source(e,{trigger:v.trigger})}catch(a){console.warn("Mention source threw:",a),o=[]}Promise.resolve(o).then(function(a){t!==E||!i||(f=Array.isArray(a)?a.slice(0,l.mentionMaxItems):[],c=0,N())},function(a){t!==E||!i||(console.warn("Mention source failed:",a),f=[],N())})}n>0?b=setTimeout(r,n):r()}function _(){p=s.iframe.ownerDocument,i=p.createElement("div"),i.className="rte-mention-popup",i.setAttribute("role","listbox"),i.setAttribute("aria-label",v.label),p.body.appendChild(i)}function B(){if(i){i.innerHTML="";var e=p.createElement("div");e.className="rte-mention-loading",e.textContent="Searching\u2026",i.appendChild(e),C=e}}function N(){if(i){if(i.innerHTML="",C=null,!f.length){var e=p.createElement("div");e.className="rte-mention-empty",e.textContent="No matches",i.appendChild(e);return}for(var t=0;t<f.length;t++)(function(n,r){var o=p.createElement("button");o.type="button",o.className="rte-mention-item"+(r===c?" rte-mention-item-active":""),o.setAttribute("role","option"),o.setAttribute("aria-selected",r===c?"true":"false"),o.setAttribute("data-index",r),v.renderItem?v.renderItem(o,n):K(o,n),o.addEventListener("mousedown",function(a){a.preventDefault(),a.stopPropagation(),c=r,S()}),o.addEventListener("click",function(a){i&&(a.preventDefault(),a.stopPropagation(),c=r,S())}),o.addEventListener("mouseenter",function(){c!==r&&(c=r,D())}),i.appendChild(o)})(f[t],t)}}function K(e,t){var n=p.createElement("span");if(n.className="rte-mention-avatar",t.avatarUrl){var r=p.createElement("img");r.src=t.avatarUrl,r.alt="",n.appendChild(r)}else n.textContent=V(x(t)||"?");e.appendChild(n);var o=p.createElement("span");o.className="rte-mention-body";var a=p.createElement("span");a.className="rte-mention-label",a.textContent=x(t),o.appendChild(a);var g=I(t);if(g){var u=p.createElement("span");u.className="rte-mention-subtitle",u.textContent=g,o.appendChild(u)}e.appendChild(o)}function V(e){var t=String(e).trim().split(/\s+/);return t[0]?t.length===1?t[0].charAt(0).toUpperCase():(t[0].charAt(0)+t[t.length-1].charAt(0)).toUpperCase():"?"}function D(){if(i){for(var e=i.querySelectorAll(".rte-mention-item"),t=0;t<e.length;t++){var n=+e[t].getAttribute("data-index"),r=n===c;e[t].classList.toggle("rte-mention-item-active",r),e[t].setAttribute("aria-selected",r?"true":"false")}Y()}}function Y(){if(i){var e=i.querySelector(".rte-mention-item-active");if(e){var t=e.offsetTop,n=t+e.offsetHeight;t<i.scrollTop?i.scrollTop=t:n>i.scrollTop+i.clientHeight&&(i.scrollTop=n-i.clientHeight)}}}function k(e){f.length&&(c=(c+e+f.length)%f.length,D())}function S(){if(!f.length){d();return}var e=f[c],t=m,n=v;d(),!(!e||!t||!n)&&(X(t),F(n,e))}function X(e){var t=e.startNode;if(t){var n=e.startOffset-(e.triggerCharCount||0);n<0&&(n=0);var r=s.getSelection();if(!(!r||r.rangeCount===0)){var o=r.getRangeAt(0),a=o.startContainer,g=o.startOffset,u=s.getDocument().createRange();u.setStart(t,n),u.setEnd(a,g);try{u.deleteContents()}catch{return}r.removeAllRanges(),r.addRange(u)}}}function F(e,t){var n=s.getDocument(),r;if(e.renderInsert?r=e.renderInsert(n,t):(r=n.createElement("span"),r.className=e.insertClass,r.setAttribute("contenteditable","false"),r.setAttribute("data-rte-mention-id",t.id!=null?t.id:""),r.setAttribute("data-rte-mention-trigger",e.trigger),r.textContent=e.trigger+x(t)),!!r){var o=s.getSelection();if(!(!o||o.rangeCount===0)){var a=o.getRangeAt(0);a.insertNode(r);var g=n.createTextNode("\xA0");r.parentNode.insertBefore(g,r.nextSibling);var u=n.createRange();u.setStartAfter(g),u.collapse(!0),o.removeAllRanges(),o.addRange(u)}}}function L(){if(!(!i||!m)){var e=s.iframe,t=e.getBoundingClientRect(),n=m.range.getClientRects(),r=n&&n.length?n[n.length-1]:null;r||(r=m.range.getBoundingClientRect());var o=t.left+(r.left||0)+window.pageXOffset,a=t.top+(r.bottom||r.top||0)+window.pageYOffset+4;i.style.position="absolute",i.style.left=o+"px",i.style.top=a+"px";var g=window.innerHeight||document.documentElement.clientHeight,u=i.getBoundingClientRect();u.bottom>g-8&&t.top+(r.top||0)>u.height+16&&(i.style.top=t.top+(r.top||0)+window.pageYOffset-u.height-4+"px")}}function O(){i&&L()}function G(){var e=s&&s.iframe&&s.iframe.ownerDocument||document;if(!e.querySelector("style[data-rte-mention]")){var t=e.createElement("style");t.setAttribute("data-rte-mention","1"),t.textContent=["/* 2026-07-12 mention picker precision */",".rte-mention-popup{position:absolute;z-index:2147483000;min-width:240px;max-width:min(340px,calc(100vw - 24px));max-height:min(320px,60vh);overflow-y:auto;padding:5px;background:linear-gradient(180deg,rgba(255,255,255,.98),rgba(248,251,255,.96));border:1px solid rgba(148,163,184,.22);box-shadow:0 14px 32px rgba(29,78,216,.12),0 2px 8px rgba(15,23,42,.08);border-radius:8px;font-family:Aptos,'Segoe UI',sans-serif;font-size:13px;color:#172033;scrollbar-width:thin}",".rte-mention-item{display:flex;align-items:center;gap:9px;width:100%;min-height:40px;padding:6px 8px;border:0;background:transparent;text-align:left;cursor:pointer;color:inherit;font:inherit;border-radius:7px}",".rte-mention-item:hover,.rte-mention-item-active{background:#eef4ff;color:#0f3f9f}",".rte-mention-avatar{flex:0 0 30px;width:30px;height:30px;border-radius:8px;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;background:#e7eefb;color:#315277;font-size:11px;font-weight:800;letter-spacing:.02em;box-shadow:inset 0 0 0 1px rgba(148,163,184,.18)}",".rte-mention-avatar img{width:100%;height:100%;object-fit:cover}",".rte-mention-item-active .rte-mention-avatar{background:#ffffff;color:#0f3f9f}",".rte-mention-body{display:flex;flex-direction:column;min-width:0;flex:1}",".rte-mention-label{font-weight:750;font-size:13px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}",".rte-mention-subtitle{font-size:11px;color:#64748b;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}",".rte-mention-item-active .rte-mention-subtitle{color:#315277}",".rte-mention-loading,.rte-mention-empty{padding:14px 16px;color:#52657e;font-size:12px;font-weight:700;text-align:center}",".rte-mention{display:inline-block;padding:1px 7px;border-radius:999px;background:#eef4ff;color:#0f3f9f;font-weight:650;cursor:default;border:1px solid rgba(37,99,235,.16)}",".rte-mention:hover{background:#e4edff}"].join(`
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_mention=RTE_Plugin_Mention;function RTE_Plugin_Mention(){var C=this,l,s,v=null,a=null,T=null,b=[],d=null,h=null,p=[],g=0,E=!1,A=0,x=null;C.PluginName="Mention";function N(e,t,n){var r=l&&l["text_"+e]||t;return n===void 0?r:r.split("{0}").join(String(n))}C.InitConfig=function(e){l=e,l.mentionEnabled!==!1&&(l.mentionTrigger=l.mentionTrigger||"@",l.mentionDebounceMs=l.mentionDebounceMs==null?150:l.mentionDebounceMs,l.mentionMaxItems=l.mentionMaxItems||8,l.mentionStaticList=l.mentionStaticList||null,l.mentionSource=l.mentionSource||null,l.mentionInsertClass=l.mentionInsertClass||"rte-mention",l.mentionTriggers=l.mentionTriggers||null)},C.InitEditor=function(e){if(s=e,l.mentionEnabled!==!1){if(s.mentions={register:S,remove:j,list:function(){return b.slice()},close:m,isOpen:function(){return!!a}},(l.mentionSource||l.mentionStaticList)&&S({trigger:l.mentionTrigger,source:l.mentionSource||function(r){return U(l.mentionStaticList,r)}}),Array.isArray(l.mentionTriggers))for(var t=0;t<l.mentionTriggers.length;t++)S(l.mentionTriggers[t]);$();var n=function(r,i,o){s.bindDocumentEvent?s.bindDocumentEvent(r,i,o):s.getDocument().addEventListener(r,i,o)};n("keydown",B,!0),n("input",K,!0),n("compositionstart",function(){E=!0}),n("compositionend",function(){E=!1}),n("mousedown",function(r){r.target&&r.target.closest&&r.target.closest("."+l.mentionInsertClass)||m()},!0),n("blur",function(){setTimeout(m,150)},!0),window.addEventListener("scroll",H,!0),window.addEventListener("resize",H,!0)}};function _(e){return function(t,n){return new Promise(function(r,i){var o=!1,u=function(f){o||(o=!0,r(f))},c;try{c=e(t,u,n)}catch(f){i(f);return}c!==void 0&&Promise.resolve(c).then(function(f){f!==void 0&&u(f)},i)})}}function S(e){if(!(!e||!e.trigger)){var t=typeof e.source=="function"?e.source:typeof e.search=="function"?_(e.search):null;if(!t){window.console&&console.warn&&console.warn('RichTextEditor mentions: trigger "'+e.trigger+'" was not registered - pass search(query, done) or source(query).');return}var n=k(e.trigger),r={trigger:e.trigger,source:t,renderItem:e.renderItem||null,renderInsert:e.renderInsert||null,insertClass:e.insertClass||l.mentionInsertClass,label:e.label||"mentions "+e.trigger};n>=0?b[n]=r:b.push(r)}}function j(e){var t=k(e);t>=0&&b.splice(t,1)}function k(e){for(var t=0;t<b.length;t++)if(b[t].trigger===e)return t;return-1}function y(e){return e&&(e.label||e.name||e.id)||""}function D(e){return e&&(e.subtitle||e.email)||""}function U(e,t){if(!Array.isArray(e))return[];if(!t)return e.slice(0,50);var n=t.toLowerCase();return e.filter(function(r){var i=(y(r)+" "+D(r)+" "+(r.id||"")).toLowerCase();return i.indexOf(n)!==-1})}function B(e){if(!E){if(a)switch(e.key){case"ArrowDown":e.preventDefault(),e.stopPropagation(),z(1);return;case"ArrowUp":e.preventDefault(),e.stopPropagation(),z(-1);return;case"Enter":case"Tab":if(p.length){e.preventDefault(),e.stopPropagation(),I();return}m();return;case"Escape":case"Esc":e.preventDefault(),e.stopPropagation(),m();return}if(!e.ctrlKey&&!e.metaKey&&!e.altKey){var t=k(e.key);if(t>=0&&V()){var n=b[t];setTimeout(function(){W(n)},0)}}}}function K(){a&&Y()}function V(){var e=s.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed)return!1;for(var t=e.getRangeAt(0),n=t.startContainer,r=t.startOffset,i=s.getEditable(),o=n.nodeType===1?n:n.parentNode;o&&o!==i;){var u=o.nodeName;if(u==="CODE"||u==="PRE"||o.classList&&o.classList.contains(l.mentionInsertClass))return!1;o=o.parentNode}if(n.nodeType===3){if(r===0)return!0;var c=n.nodeValue.charAt(r-1);return/\s/.test(c)}return!0}function W(e){m();var t=s.getSelection();if(!(!t||t.rangeCount===0)){var n=t.getRangeAt(0).cloneRange();d=e,h={range:n,startNode:n.startContainer,startOffset:n.startOffset,triggerCharCount:1,query:""},X(),R(),O("")}}function m(){x&&(clearTimeout(x),x=null),a&&a.parentNode&&a.parentNode.removeChild(a),a=null,T=null,d=null,h=null,p=[],g=0}function Y(){if(h){var e=s.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed){m();return}var t=e.getRangeAt(0),n=t.startContainer;if(n!==h.startNode){m();return}var r=t.startOffset;if(r<h.startOffset){m();return}var i=(n.nodeType===3?n.nodeValue:"")||"",o=i.substring(h.startOffset,r);if(/\s/.test(o)){m();return}h.query=o,O(o),R()}}function O(e){if(!d)return;var t=++A;x&&(clearTimeout(x),x=null);var n=e.length===0?0:l.mentionDebounceMs;function r(){F();var i;try{i=d.source(e,{trigger:d.trigger})}catch(o){console.warn("Mention source threw:",o),i=[]}Promise.resolve(i).then(function(o){t!==A||!a||(p=Array.isArray(o)?o.slice(0,l.mentionMaxItems):[],g=0,M())},function(o){t!==A||!a||(console.warn("Mention source failed:",o),p=[],M())})}n>0?x=setTimeout(r,n):r()}function X(){v=s.iframe.ownerDocument,a=v.createElement("div");var e=!1;try{var t=s.container&&s.container.classList;e=!!t&&(t.contains("rte-dark")||t.contains("rte-auto-dark")&&!t.contains("rte-light")&&!!(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches))}catch{e=!1}a.className="rte-mention-popup"+(e?" rte-mention-popup-dark":""),a.setAttribute("role","listbox"),a.setAttribute("aria-label",d.label),v.body.appendChild(a)}function F(){if(a){a.innerHTML="";var e=v.createElement("div");e.className="rte-mention-loading",e.textContent=N("mn_searching","Searching\u2026"),a.appendChild(e),T=e}}function M(){if(a){if(a.innerHTML="",T=null,!p.length){var e=v.createElement("div");e.className="rte-mention-empty",e.textContent=N("mn_nomatches","No matches"),a.appendChild(e);return}for(var t=0;t<p.length;t++)(function(n,r){var i=v.createElement("button");if(i.type="button",i.className="rte-mention-item"+(r===g?" rte-mention-item-active":""),i.setAttribute("role","option"),i.setAttribute("aria-selected",r===g?"true":"false"),i.setAttribute("data-index",r),d.renderItem&&d.renderItem.length<2){var o=d.renderItem(n);o&&o.nodeType?i.appendChild(o):o!=null&&o!==""?i.textContent=String(o):P(i,n)}else d.renderItem?d.renderItem(i,n):P(i,n);i.addEventListener("mousedown",function(u){u.preventDefault(),u.stopPropagation(),g=r,I()}),i.addEventListener("click",function(u){a&&(u.preventDefault(),u.stopPropagation(),g=r,I())}),i.addEventListener("mouseenter",function(){g!==r&&(g=r,q())}),a.appendChild(i)})(p[t],t)}}function P(e,t){var n=v.createElement("span");if(n.className="rte-mention-avatar",t.avatarUrl){var r=v.createElement("img");r.src=t.avatarUrl,r.alt="",n.appendChild(r)}else n.textContent=G(y(t)||"?");e.appendChild(n);var i=v.createElement("span");i.className="rte-mention-body";var o=v.createElement("span");o.className="rte-mention-label",o.textContent=y(t),i.appendChild(o);var u=D(t);if(u){var c=v.createElement("span");c.className="rte-mention-subtitle",c.textContent=u,i.appendChild(c)}e.appendChild(i)}function G(e){var t=String(e).trim().split(/\s+/);return t[0]?t.length===1?t[0].charAt(0).toUpperCase():(t[0].charAt(0)+t[t.length-1].charAt(0)).toUpperCase():"?"}function q(){if(a){for(var e=a.querySelectorAll(".rte-mention-item"),t=0;t<e.length;t++){var n=+e[t].getAttribute("data-index"),r=n===g;e[t].classList.toggle("rte-mention-item-active",r),e[t].setAttribute("aria-selected",r?"true":"false")}J()}}function J(){if(a){var e=a.querySelector(".rte-mention-item-active");if(e){var t=e.offsetTop,n=t+e.offsetHeight;t<a.scrollTop?a.scrollTop=t:n>a.scrollTop+a.clientHeight&&(a.scrollTop=n-a.clientHeight)}}}function z(e){p.length&&(g=(g+e+p.length)%p.length,q())}function I(){if(!p.length){m();return}var e=p[g],t=h,n=d;m(),!(!e||!t||!n)&&(Q(t),Z(n,e))}function Q(e){var t=e.startNode;if(t){var n=e.startOffset-(e.triggerCharCount||0);n<0&&(n=0);var r=s.getSelection();if(!(!r||r.rangeCount===0)){var i=r.getRangeAt(0),o=i.startContainer,u=i.startOffset,c=s.getDocument().createRange();c.setStart(t,n),c.setEnd(o,u);try{c.deleteContents()}catch{return}r.removeAllRanges(),r.addRange(c)}}}function Z(e,t){var n=s.getDocument(),r,i=function(ee){var w=n.createElement("span");return w.className=e.insertClass,w.setAttribute("contenteditable","false"),w.setAttribute("data-rte-mention-id",t.id!=null?t.id:""),w.setAttribute("data-rte-mention-trigger",e.trigger),w.textContent=ee,w};if(e.renderInsert&&e.renderInsert.length<2){var o=e.renderInsert(t);r=o&&o.nodeType?o:i(o!=null&&o!==""?String(o):e.trigger+y(t))}else e.renderInsert?r=e.renderInsert(n,t):r=i(e.trigger+y(t));if(r){var u=s.getSelection();if(!(!u||u.rangeCount===0)){var c=u.getRangeAt(0);c.insertNode(r);var f=n.createTextNode("\xA0");r.parentNode.insertBefore(f,r.nextSibling);var L=n.createRange();L.setStartAfter(f),L.collapse(!0),u.removeAllRanges(),u.addRange(L)}}}function R(){if(!(!a||!h)){var e=s.iframe,t=e.getBoundingClientRect(),n=h.range.getClientRects(),r=n&&n.length?n[n.length-1]:null;r||(r=h.range.getBoundingClientRect());var i=e.offsetWidth&&t.width>0?t.width/e.offsetWidth:1,o=t.left+(r.left||0)*i+window.pageXOffset,u=t.top+(r.bottom||r.top||0)*i+window.pageYOffset+4;a.style.position="absolute",a.style.left=o+"px",a.style.top=u+"px";var c=window.innerHeight||document.documentElement.clientHeight,f=a.getBoundingClientRect();f.bottom>c-8&&t.top+(r.top||0)*i>f.height+16&&(a.style.top=t.top+(r.top||0)*i+window.pageYOffset-f.height-4+"px")}}function H(){a&&R()}function $(){var e=s&&s.iframe&&s.iframe.ownerDocument||document;if(!e.querySelector("style[data-rte-mention]")){var t=e.createElement("style");t.setAttribute("data-rte-mention","1"),t.textContent=["/* 2026-07-12 mention picker precision */",".rte-mention-popup{position:absolute;z-index:2147483000;min-width:240px;max-width:min(340px,calc(100vw - 24px));max-height:min(320px,60vh);overflow-y:auto;padding:5px;background:linear-gradient(180deg,rgba(255,255,255,.98),rgba(248,251,255,.96));border:1px solid rgba(148,163,184,.22);box-shadow:0 14px 32px rgba(29,78,216,.12),0 2px 8px rgba(15,23,42,.08);border-radius:8px;font-family:Aptos,'Segoe UI',sans-serif;font-size:13px;color:#172033;scrollbar-width:thin}",".rte-mention-item{display:flex;align-items:center;gap:9px;width:100%;min-height:40px;padding:6px 8px;border:0;background:transparent;text-align:left;cursor:pointer;color:inherit;font:inherit;border-radius:7px}",".rte-mention-item:hover,.rte-mention-item-active{background:#eef4ff;color:#0f3f9f}",".rte-mention-avatar{flex:0 0 30px;width:30px;height:30px;border-radius:8px;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;background:#e7eefb;color:#315277;font-size:11px;font-weight:800;letter-spacing:.02em;box-shadow:inset 0 0 0 1px rgba(148,163,184,.18)}",".rte-mention-avatar img{width:100%;height:100%;object-fit:cover}",".rte-mention-item-active .rte-mention-avatar{background:#ffffff;color:#0f3f9f}",".rte-mention-body{display:flex;flex-direction:column;min-width:0;flex:1}",".rte-mention-label{font-weight:750;font-size:13px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}",".rte-mention-subtitle{font-size:11px;color:#64748b;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}",".rte-mention-item-active .rte-mention-subtitle{color:#315277}",".rte-mention-loading,.rte-mention-empty{padding:14px 16px;color:#52657e;font-size:12px;font-weight:700;text-align:center}",".rte-mention{display:inline-block;padding:1px 7px;border-radius:999px;background:#eef4ff;color:#0f3f9f;font-weight:650;cursor:default;border:1px solid rgba(37,99,235,.16)}",".rte-mention:hover{background:#e4edff}",".rte-mention-popup.rte-mention-popup-dark{background:linear-gradient(180deg,#1e293b,#0f172a);border-color:#334155;color:#e2e8f0;box-shadow:0 18px 40px rgba(0,0,0,.5)}",".rte-mention-popup-dark .rte-mention-item:hover,.rte-mention-popup-dark .rte-mention-item-active{background:#1e3a8a;color:#ffffff}",".rte-mention-popup-dark .rte-mention-avatar{background:#334155;color:#e2e8f0}",".rte-mention-popup-dark .rte-mention-item-active .rte-mention-avatar{background:#0f172a;color:#bfdbfe}",".rte-mention-popup-dark .rte-mention-subtitle{color:#94a3b8}",".rte-mention-popup-dark .rte-mention-item-active .rte-mention-subtitle{color:#bfdbfe}",".rte-mention-popup-dark .rte-mention-loading,.rte-mention-popup-dark .rte-mention-empty{color:#94a3b8}"].join(`
2
2
  `),e.head.appendChild(t),s&&typeof s.ensureStyleSheetLive=="function"&&s.ensureStyleSheetLive(e,t,"rte-mentionplugin-style",t.textContent);var n=s.getDocument();if(n&&n.head&&!n.querySelector("style[data-rte-mention-inline]")){var r=n.createElement("style");r.setAttribute("data-rte-mention-inline","1"),r.textContent=[".rte-mention{display:inline-block;padding:1px 7px;border-radius:999px;background:#eef4ff;color:#0f3f9f;font-weight:650;cursor:default;border:1px solid rgba(37,99,235,.16);user-select:all}",".rte-mention:hover{background:#e4edff}"].join(`
3
3
  `),n.head.appendChild(r),s&&typeof s.ensureStyleSheetLive=="function"&&s.ensureStyleSheetLive(n,r,"rte-mentionplugin-iStyle",r.textContent)}}}}
@@ -30,6 +30,12 @@ function RTE_Plugin_MermaidDiagram() {
30
30
 
31
31
  obj.PluginName = "MermaidDiagram";
32
32
 
33
+ // 2026-10-18 the words read config.text_ keys (language packs), English as the fallback; {0} fills a template.
34
+ // tools/i18n/plugin-panels-language.mjs
35
+ function pText(key, fallback, arg) {
36
+ var s = (config && config["text_" + key]) || fallback;
37
+ return arg === undefined ? s : s.split("{0}").join(String(arg));
38
+ }
33
39
  obj.InitConfig = function (argconfig) { config = argconfig; };
34
40
 
35
41
  obj.InitEditor = function (argeditor) {
@@ -245,7 +251,7 @@ function RTE_Plugin_MermaidDiagram() {
245
251
  "min-height:80px;padding:10px 12px;border:1px solid #e2e8f0;border-radius:8px;background:#fff;overflow:auto;text-align:center");
246
252
  var note = append(wrap, "div", "font-size:11px;color:#94a3b8;margin-top:4px");
247
253
  if (typeof config.diagramResolver !== "function" && !getMermaid(win)) {
248
- note.innerText = "No Mermaid renderer detected on the page — the diagram is stored as source and will render wherever Mermaid (or config.diagramResolver) is available.";
254
+ note.innerText = pText("dg_norenderer", "No Mermaid renderer detected on the page \u2014 the diagram is stored as source and will render wherever Mermaid (or config.diagramResolver) is available.");
249
255
  }
250
256
 
251
257
  var previewTimer = null;
@@ -266,9 +272,9 @@ function RTE_Plugin_MermaidDiagram() {
266
272
 
267
273
  var footer = append(wrap, "div", "display:flex;justify-content:flex-end;gap:8px;margin-top:14px");
268
274
  var cancel = append(footer, "button", "padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer");
269
- cancel.type = "button"; cancel.textContent = "Cancel"; cancel.onclick = close;
275
+ cancel.type = "button"; cancel.textContent = pText("cancel", "Cancel"); cancel.onclick = close;
270
276
  var ok = append(footer, "button", "padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer");
271
- ok.type = "button"; ok.textContent = existing ? "Update" : "Insert";
277
+ ok.type = "button"; ok.textContent = existing ? pText("update", "Update") : pText("insert", "Insert");
272
278
 
273
279
  ok.onclick = function () {
274
280
  var src = ta.value.trim();