@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
@@ -73,20 +73,20 @@ function RTE_Plugin_Autocorrect() {
73
73
 
74
74
  // Multi-character sequences replaced the moment they are completed.
75
75
  var SEQUENCES = [
76
- { from: "...", to: "…" }, // ellipsis
77
- { from: "-->", to: "⟶" }, // long right arrow
78
- { from: "->", to: "→" },
79
- { from: "<-", to: "←" },
80
- { from: "<=", to: "≤" },
81
- { from: ">=", to: "≥" },
82
- { from: "!=", to: "≠" },
83
- { from: "(c)", to: "©" },
84
- { from: "(r)", to: "®" },
85
- { from: "(tm)", to: "™" },
86
- { from: "1/2", to: "½" },
87
- { from: "1/4", to: "¼" },
88
- { from: "3/4", to: "¾" },
89
- { from: "+-", to: "±" }
76
+ { from: "...", to: "\u2026" }, // ellipsis
77
+ { from: "-->", to: "\u27f6" }, // long right arrow
78
+ { from: "->", to: "\u2192" },
79
+ { from: "<-", to: "\u2190" },
80
+ { from: "<=", to: "\u2264" },
81
+ { from: ">=", to: "\u2265" },
82
+ { from: "!=", to: "\u2260" },
83
+ { from: "(c)", to: "\xa9" },
84
+ { from: "(r)", to: "\xae" },
85
+ { from: "(tm)", to: "\u2122" },
86
+ { from: "1/2", to: "\xbd" },
87
+ { from: "1/4", to: "\xbc" },
88
+ { from: "3/4", to: "\xbe" },
89
+ { from: "+-", to: "\xb1" }
90
90
  ];
91
91
 
92
92
  obj.PluginName = "Autocorrect";
@@ -186,7 +186,10 @@ function RTE_Plugin_Autocorrect() {
186
186
  // ---- the Backspace escape hatch --------------------------------------
187
187
 
188
188
  function onKeyDown(e) {
189
- if (e.key !== "Backspace" || !lastFix) return;
189
+ // Ctrl/Cmd+Z straight after a correction reverts just the correction (Word, CKEditor),
190
+ // where the editor's own undo would also throw away the typing it was grouped with.
191
+ var isUndo = (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey && (e.code === "KeyZ" || e.key === "z" || e.key === "Z");
192
+ if ((e.key !== "Backspace" && !isUndo) || !lastFix) return;
190
193
  var c = caret();
191
194
  if (!c || c.node !== lastFix.node) { lastFix = null; return; }
192
195
  // Only when the caret is still exactly where the correction left it —
@@ -217,7 +220,7 @@ function RTE_Plugin_Autocorrect() {
217
220
  }
218
221
 
219
222
  function isBoundary(ch) {
220
- return ch === " " || ch === " " || ".,;:!?)]}\"'’”".indexOf(ch) >= 0;
223
+ return ch === " " || ch === "\xa0" || ".,;:!?)]}\"'\u2019\u201d".indexOf(ch) >= 0;
221
224
  }
222
225
 
223
226
  // Substitutions that resolve as soon as the triggering character lands.
@@ -229,8 +232,8 @@ function RTE_Plugin_Autocorrect() {
229
232
  // whitespace or an opening bracket it opens, otherwise it closes.
230
233
  if (ch === '"' || ch === "'") {
231
234
  var prev = at >= 2 ? text.charAt(at - 2) : "";
232
- var opening = !prev || /[\s(\[{—–\-]/.test(prev);
233
- var repl = ch === '"' ? (opening ? "“" : "”") : (opening ? "‘" : "’");
235
+ var opening = !prev || /[\s(\[{\u2014\u2013\-]/.test(prev);
236
+ var repl = ch === '"' ? (opening ? "\u201c" : "\u201d") : (opening ? "\u2018" : "\u2019");
234
237
  return replaceRange(c, at - 1, at, repl, ch);
235
238
  }
236
239
 
@@ -240,9 +243,9 @@ function RTE_Plugin_Autocorrect() {
240
243
  // start of a line and a "--flag" are left alone.
241
244
  if (ch === "-" && at >= 2 && text.charAt(at - 2) === "-") {
242
245
  var before = at >= 3 ? text.charAt(at - 3) : "";
243
- var ok = /[\w\)\]"'’]/.test(before);
244
- if (!ok && /\s/.test(before)) ok = /[\w\)\]"'’]\s*$/.test(text.slice(0, at - 3));
245
- if (ok) return replaceRange(c, at - 2, at, "—", "--");
246
+ var ok = /[\w\)\]"'\u2019]/.test(before);
247
+ if (!ok && /\s/.test(before)) ok = /[\w\)\]"'\u2019]\s*$/.test(text.slice(0, at - 3));
248
+ if (ok) return replaceRange(c, at - 2, at, "\u2014", "--");
246
249
  }
247
250
 
248
251
  for (var i = 0; i < SEQUENCES.length; i++) {
@@ -263,9 +266,17 @@ function RTE_Plugin_Autocorrect() {
263
266
  var text = c.node.nodeValue;
264
267
  var end = c.offset - 1; // the boundary char we just typed
265
268
  var start = end;
266
- while (start > 0 && /[A-Za-z'’]/.test(text.charAt(start - 1))) start--;
269
+ while (start > 0 && /[A-Za-z'\u2019]/.test(text.charAt(start - 1))) start--;
267
270
  if (start === end) return;
268
271
  var word = text.substring(start, end);
272
+ // a single letter followed by "." is the start of "i.e." / "e.g." - the "." is typed before
273
+ // the rest of the abbreviation exists, so leave it (it became "I.e.")
274
+ if (ch === "." && word.length === 1) return;
275
+ // 2026-10-03 A dotted abbreviation ("i.e.", "e.g.") keeps its case: "i.e." became "I.e.".
276
+ // tools/autolink/autolink.mjs
277
+ var tokEnd = end;
278
+ while (tokEnd < text.length && !/\s/.test(text.charAt(tokEnd))) tokEnd++;
279
+ if (/^[a-z]\.[a-z]\.?$/i.test(text.substring(start, tokEnd))) return;
269
280
 
270
281
  // Spelling THEN capitalisation, applied in sequence to the same word.
271
282
  // Treating them as alternatives means "teh cat" opening a sentence comes
@@ -277,9 +288,11 @@ function RTE_Plugin_Autocorrect() {
277
288
  // The table stores plain apostrophes so it stays easy to extend, but
278
289
  // typing ' produces a curly one — emit the same character here or
279
290
  // "don't" ends up with a different apostrophe than "it's".
280
- if (config.autocorrectTypography !== false) fixed = fixed.replace(/'/g, "’");
291
+ if (config.autocorrectTypography !== false) fixed = fixed.replace(/'/g, "\u2019");
281
292
  }
282
- if (config.autocorrectCapitalize !== false && startsSentence(text, start, c.node)) {
293
+ // A word inside a web address or email ("www.", "me@x.org", "https://a.example.org/path")
294
+ // is never a sentence start: capitalising it corrupts the link built from that text.
295
+ if (config.autocorrectCapitalize !== false && !inAddress(text, start, end) && startsSentence(text, start, c.node)) {
283
296
  var first = fixed.charAt(0);
284
297
  if (first !== first.toUpperCase()) fixed = first.toUpperCase() + fixed.substring(1);
285
298
  }
@@ -296,12 +309,34 @@ function RTE_Plugin_Autocorrect() {
296
309
  return fixed;
297
310
  }
298
311
 
312
+ function inAddress(text, start, end) {
313
+ var s = start;
314
+ while (s > 0 && !/\s/.test(text.charAt(s - 1))) s--;
315
+ // 2026-10-03 Read the WHOLE token (to the next space) and ignore an opening bracket or quote:
316
+ // "(https://x" was read as "(https:" - no slash yet - and capitalised to "(Https://".
317
+ // tools/autolink/autolink.mjs
318
+ var e2 = end;
319
+ while (e2 < text.length && !/\s/.test(text.charAt(e2))) e2++;
320
+ var token = text.substring(s, Math.max(e2, end + 1)).toLowerCase().replace(/^[(\[{<'"\u2018\u201c]+/, "");
321
+ return /^www\./.test(token) || /^[a-z][a-z0-9+.-]*:/.test(token) || /[\/@]/.test(token);
322
+ }
323
+
299
324
  function startsSentence(text, start, node) {
325
+ var spaced = false;
300
326
  for (var i = start - 1; i >= 0; i--) {
301
327
  var ch = text.charAt(i);
302
- if (/\s/.test(ch)) continue;
303
- if (ch === '"' || ch === "'" || ch === "“" || ch === "‘" || ch === "(") continue;
304
- return ".!?".indexOf(ch) >= 0;
328
+ if (/\s/.test(ch)) { spaced = true; continue; }
329
+ if (ch === '"' || ch === "'" || ch === "\u201c" || ch === "\u2018" || ch === "(") continue;
330
+ // ".!?" ends a sentence only when space follows it: "example.com" and "e.g" have none.
331
+ // 2026-10-03 ...and the full stop of an abbreviation never does (Word, Google Docs):
332
+ // "e.g. Apples", "etc. And" were capitalised. tools/autolink/autolink.mjs
333
+ if (spaced && ch === ".") {
334
+ var ws = i;
335
+ while (ws > 0 && !/\s/.test(text.charAt(ws - 1))) ws--;
336
+ var prevTok = text.substring(ws, i + 1).toLowerCase().replace(/^[("'\u2018\u201c]+/, "");
337
+ if (/^(e\.g|i\.e|etc|vs|cf|approx|incl|viz|al|resp|esp|ca)\.$/.test(prevTok)) return false;
338
+ }
339
+ return spaced && ".!?".indexOf(ch) >= 0;
305
340
  }
306
341
  // Nothing before it in this node: only a sentence start if nothing
307
342
  // precedes the node in its block either.
@@ -344,10 +379,10 @@ function RTE_Plugin_Autocorrect() {
344
379
  for (var i = 0; i < SEQUENCES.length; i++) {
345
380
  out = out.split(SEQUENCES[i].from).join(SEQUENCES[i].to);
346
381
  }
347
- out = out.replace(/(^|[\s(\[{])"/g, "$1“").replace(/"/g, "”");
348
- out = out.replace(/(^|[\s(\[{])'/g, "$1‘").replace(/'/g, "’");
349
- out = out.replace(/(\w)--(\w)/g, "$1—$2");
350
- out = out.replace(/(\w)\s--\s(\w)/g, "$1 — $2");
382
+ out = out.replace(/(^|[\s(\[{])"/g, "$1\u201c").replace(/"/g, "\u201d");
383
+ out = out.replace(/(^|[\s(\[{])'/g, "$1\u2018").replace(/'/g, "\u2019");
384
+ out = out.replace(/(\w)--(\w)/g, "$1\u2014$2");
385
+ out = out.replace(/(\w)\s--\s(\w)/g, "$1 \u2014 $2");
351
386
  return out;
352
387
  }
353
388
  }
@@ -1 +1 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_autocorrect=RTE_Plugin_Autocorrect,typeof RTE_DefaultConfig.autocorrectEnabled>"u"&&(RTE_DefaultConfig.autocorrectEnabled=!0),typeof RTE_DefaultConfig.autocorrectCapitalize>"u"&&(RTE_DefaultConfig.autocorrectCapitalize=!0),typeof RTE_DefaultConfig.autocorrectTypography>"u"&&(RTE_DefaultConfig.autocorrectTypography=!0),typeof RTE_DefaultConfig.autocorrectSpelling>"u"&&(RTE_DefaultConfig.autocorrectSpelling=!0),typeof RTE_DefaultConfig.autocorrectReplacements>"u"&&(RTE_DefaultConfig.autocorrectReplacements=null);function RTE_Plugin_Autocorrect(){var w=this,s,c,R=null,p=!0,u=null,C={teh:"the",adn:"and",taht:"that",thier:"their",freind:"friend",recieve:"receive",recieved:"received",seperate:"separate",seperated:"separated",occured:"occurred",occuring:"occurring",definately:"definitely",accomodate:"accommodate",acommodate:"accommodate",wich:"which",becuase:"because",beacuse:"because",becasue:"because",arguement:"argument",existance:"existence",maintainance:"maintenance",neccessary:"necessary",necessery:"necessary",occassion:"occasion",publically:"publicly",reccommend:"recommend",refered:"referred",relevent:"relevant",succesful:"successful",successfull:"successful",untill:"until",wierd:"weird",acheive:"achieve",beleive:"believe",concious:"conscious",embarass:"embarrass",goverment:"government",independant:"independent",occurence:"occurrence",perseverence:"perseverance",priviledge:"privilege",supercede:"supersede",threshhold:"threshold",tommorow:"tomorrow",tomorow:"tomorrow",truely:"truly",alot:"a lot",infront:"in front",inspite:"in spite",dont:"don't",doesnt:"doesn't",didnt:"didn't",cant:"can't",isnt:"isn't",wasnt:"wasn't",arent:"aren't",werent:"weren't",havent:"haven't",hasnt:"hasn't",hadnt:"hadn't",couldnt:"couldn't",shouldnt:"shouldn't",wouldnt:"wouldn't",youre:"you're",theyre:"they're",wouldve:"would've",couldve:"could've",shouldve:"should've",i:"I",im:"I'm",ive:"I've",id:"I'd"},g=[{from:"...",to:"\u2026"},{from:"-->",to:"\u27F6"},{from:"->",to:"\u2192"},{from:"<-",to:"\u2190"},{from:"<=",to:"\u2264"},{from:">=",to:"\u2265"},{from:"!=",to:"\u2260"},{from:"(c)",to:"\xA9"},{from:"(r)",to:"\xAE"},{from:"(tm)",to:"\u2122"},{from:"1/2",to:"\xBD"},{from:"1/4",to:"\xBC"},{from:"3/4",to:"\xBE"},{from:"+-",to:"\xB1"}];w.PluginName="Autocorrect",w.InitConfig=function(t){s=t,p=s.autocorrectEnabled!==!1},w.InitEditor=function(t){c=t,m();try{c.attachEvent("ready",m)}catch{}try{c.attachEvent("aftersethtml",m)}catch{}setTimeout(m,0),c.setAutocorrectEnabled=function(e){return p=!!e,p},c.isAutocorrectEnabled=function(){return p},c.addAutocorrectRule=function(e,r){return e?(E()[String(e).toLowerCase()]=String(r),!0):!1},c.getAutocorrectRules=function(){var e=E(),r={};for(var n in e)e.hasOwnProperty(n)&&(r[n]=e[n]);return r},c.applyTypography=function(e){return N(String(e))}};var v=null;function E(){if(v)return v;v={};for(var t in C)C.hasOwnProperty(t)&&(v[t]=C[t]);var e=s.autocorrectReplacements;if(e)for(var r in e)e.hasOwnProperty(r)&&(v[String(r).toLowerCase()]=e[r]);return v}function m(){var t=T();if(!(!t||t===R)){R=t;var e=b();e&&(e.addEventListener("input",P),e.addEventListener("keydown",x,!0))}}function T(){try{return c.getDocument()}catch{return null}}function b(){try{return c.getEditable()}catch{return null}}function _(t){for(var e=b(),r=t&&t.nodeType===3?t.parentNode:t;r&&r!==e;){var n=r.nodeName;if(n==="CODE"||n==="PRE"||n==="KBD"||n==="SAMP"||n==="VAR"||r.getAttribute&&r.getAttribute("data-rte-no-autocorrect")!==null&&r.getAttribute("data-rte-no-autocorrect")!=="false")return!0;r=r.parentNode}return!1}function D(){try{var t=c.getSelection();if(!t||t.rangeCount===0)return null;var e=t.getRangeAt(0);return!e.collapsed||!e.startContainer||e.startContainer.nodeType!==3?null:{node:e.startContainer,offset:e.startOffset}}catch{return null}}function S(t,e){try{var r=T(),n=r.createRange(),a=t.nodeValue.length;n.setStart(t,Math.max(0,Math.min(e,a))),n.collapse(!0);var i=c.getSelection();i.removeAllRanges(),i.addRange(n)}catch{}}function x(t){if(!(t.key!=="Backspace"||!u)){var e=D();if(!e||e.node!==u.node){u=null;return}if(e.offset!==u.caretAfter){u=null;return}var r=e.node.nodeValue;e.node.nodeValue=r.slice(0,u.start)+u.typed+r.slice(u.start+u.fixed.length),S(e.node,u.start+u.typed.length+(u.tail||0)),u=null,t.preventDefault(),t.stopPropagation()}}function P(t){if(p){var e=t&&typeof t.data=="string"?t.data:null;if(e){var r=D();r&&(_(r.node)||s.autocorrectTypography!==!1&&O(r,e)||I(e)&&L(r,e))}}}function I(t){return t===" "||t==="\xA0"||`.,;:!?)]}"'\u2019\u201D`.indexOf(t)>=0}function O(t,e){var r=t.node.nodeValue,n=t.offset;if(e==='"'||e==="'"){var a=n>=2?r.charAt(n-2):"",i=!a||/[\s(\[{—–\-]/.test(a),o=e==='"'?i?"\u201C":"\u201D":i?"\u2018":"\u2019";return y(t,n-1,n,o,e)}if(e==="-"&&n>=2&&r.charAt(n-2)==="-"){var l=n>=3?r.charAt(n-3):"",f=/[\w\)\]"'’]/.test(l);if(!f&&/\s/.test(l)&&(f=/[\w\)\]"'’]\s*$/.test(r.slice(0,n-3))),f)return y(t,n-2,n,"\u2014","--")}for(var A=0;A<g.length;A++){var d=g[A];if(d.from.charAt(d.from.length-1)===e){var h=n-d.from.length;if(!(h<0)&&r.substring(h,n).toLowerCase()===d.from&&!(/^\d/.test(d.from)&&h>0&&/[\w.]/.test(r.charAt(h-1))))return y(t,h,n,d.to,d.from)}}return!1}function L(t,e){for(var r=t.node.nodeValue,n=t.offset-1,a=n;a>0&&/[A-Za-z'’]/.test(r.charAt(a-1));)a--;if(a!==n){var i=r.substring(a,n),o=i;if(s.autocorrectSpelling!==!1){var l=E()[o.toLowerCase()];l&&(o=U(o,l)),s.autocorrectTypography!==!1&&(o=o.replace(/'/g,"\u2019"))}if(s.autocorrectCapitalize!==!1&&V(r,a,t.node)){var f=o.charAt(0);f!==f.toUpperCase()&&(o=f.toUpperCase()+o.substring(1))}o!==i&&y(t,a,n,o,i)}}function U(t,e){return t===t.toUpperCase()&&t.length>1?e.toUpperCase():t.charAt(0)===t.charAt(0).toUpperCase()?e.charAt(0).toUpperCase()+e.substring(1):e}function V(t,e,r){for(var n=e-1;n>=0;n--){var a=t.charAt(n);if(!/\s/.test(a)&&!(a==='"'||a==="'"||a==="\u201C"||a==="\u2018"||a==="("))return".!?".indexOf(a)>=0}return!$(r)}function $(t){for(var e=b(),r=t;r&&r!==e;){for(var n=r.previousSibling;n;){if((n.textContent||"").trim())return!0;n=n.previousSibling}if(r=r.parentNode,r&&/^(P|LI|TD|TH|H[1-6]|BLOCKQUOTE|DIV)$/.test(r.nodeName))return!1}return!1}function y(t,e,r,n,a){var i=t.node,o=i.nodeValue,l=t.offset-r;i.nodeValue=o.slice(0,e)+n+o.slice(r);var f=e+n.length+l;return S(i,f),u={node:i,start:e,typed:a,fixed:n,caretAfter:f,tail:l},!0}function N(t){for(var e=t,r=0;r<g.length;r++)e=e.split(g[r].from).join(g[r].to);return e=e.replace(/(^|[\s(\[{])"/g,"$1\u201C").replace(/"/g,"\u201D"),e=e.replace(/(^|[\s(\[{])'/g,"$1\u2018").replace(/'/g,"\u2019"),e=e.replace(/(\w)--(\w)/g,"$1\u2014$2"),e=e.replace(/(\w)\s--\s(\w)/g,"$1 \u2014 $2"),e}}
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_autocorrect=RTE_Plugin_Autocorrect,typeof RTE_DefaultConfig.autocorrectEnabled>"u"&&(RTE_DefaultConfig.autocorrectEnabled=!0),typeof RTE_DefaultConfig.autocorrectCapitalize>"u"&&(RTE_DefaultConfig.autocorrectCapitalize=!0),typeof RTE_DefaultConfig.autocorrectTypography>"u"&&(RTE_DefaultConfig.autocorrectTypography=!0),typeof RTE_DefaultConfig.autocorrectSpelling>"u"&&(RTE_DefaultConfig.autocorrectSpelling=!0),typeof RTE_DefaultConfig.autocorrectReplacements>"u"&&(RTE_DefaultConfig.autocorrectReplacements=null);function RTE_Plugin_Autocorrect(){var C=this,s,f,R=null,g=!0,c=null,b={teh:"the",adn:"and",taht:"that",thier:"their",freind:"friend",recieve:"receive",recieved:"received",seperate:"separate",seperated:"separated",occured:"occurred",occuring:"occurring",definately:"definitely",accomodate:"accommodate",acommodate:"accommodate",wich:"which",becuase:"because",beacuse:"because",becasue:"because",arguement:"argument",existance:"existence",maintainance:"maintenance",neccessary:"necessary",necessery:"necessary",occassion:"occasion",publically:"publicly",reccommend:"recommend",refered:"referred",relevent:"relevant",succesful:"successful",successfull:"successful",untill:"until",wierd:"weird",acheive:"achieve",beleive:"believe",concious:"conscious",embarass:"embarrass",goverment:"government",independant:"independent",occurence:"occurrence",perseverence:"perseverance",priviledge:"privilege",supercede:"supersede",threshhold:"threshold",tommorow:"tomorrow",tomorow:"tomorrow",truely:"truly",alot:"a lot",infront:"in front",inspite:"in spite",dont:"don't",doesnt:"doesn't",didnt:"didn't",cant:"can't",isnt:"isn't",wasnt:"wasn't",arent:"aren't",werent:"weren't",havent:"haven't",hasnt:"hasn't",hadnt:"hadn't",couldnt:"couldn't",shouldnt:"shouldn't",wouldnt:"wouldn't",youre:"you're",theyre:"they're",wouldve:"would've",couldve:"could've",shouldve:"should've",i:"I",im:"I'm",ive:"I've",id:"I'd"},h=[{from:"...",to:"\u2026"},{from:"-->",to:"\u27F6"},{from:"->",to:"\u2192"},{from:"<-",to:"\u2190"},{from:"<=",to:"\u2264"},{from:">=",to:"\u2265"},{from:"!=",to:"\u2260"},{from:"(c)",to:"\xA9"},{from:"(r)",to:"\xAE"},{from:"(tm)",to:"\u2122"},{from:"1/2",to:"\xBD"},{from:"1/4",to:"\xBC"},{from:"3/4",to:"\xBE"},{from:"+-",to:"\xB1"}];C.PluginName="Autocorrect",C.InitConfig=function(e){s=e,g=s.autocorrectEnabled!==!1},C.InitEditor=function(e){f=e,y();try{f.attachEvent("ready",y)}catch{}try{f.attachEvent("aftersethtml",y)}catch{}setTimeout(y,0),f.setAutocorrectEnabled=function(t){return g=!!t,g},f.isAutocorrectEnabled=function(){return g},f.addAutocorrectRule=function(t,r){return t?(A()[String(t).toLowerCase()]=String(r),!0):!1},f.getAutocorrectRules=function(){var t=A(),r={};for(var n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);return r},f.applyTypography=function(t){return K(String(t))}};var p=null;function A(){if(p)return p;p={};for(var e in b)b.hasOwnProperty(e)&&(p[e]=b[e]);var t=s.autocorrectReplacements;if(t)for(var r in t)t.hasOwnProperty(r)&&(p[String(r).toLowerCase()]=t[r]);return p}function y(){var e=T();if(!(!e||e===R)){R=e;var t=E();t&&(t.addEventListener("input",L),t.addEventListener("keydown",_,!0))}}function T(){try{return f.getDocument()}catch{return null}}function E(){try{return f.getEditable()}catch{return null}}function S(e){for(var t=E(),r=e&&e.nodeType===3?e.parentNode:e;r&&r!==t;){var n=r.nodeName;if(n==="CODE"||n==="PRE"||n==="KBD"||n==="SAMP"||n==="VAR"||r.getAttribute&&r.getAttribute("data-rte-no-autocorrect")!==null&&r.getAttribute("data-rte-no-autocorrect")!=="false")return!0;r=r.parentNode}return!1}function D(){try{var e=f.getSelection();if(!e||e.rangeCount===0)return null;var t=e.getRangeAt(0);return!t.collapsed||!t.startContainer||t.startContainer.nodeType!==3?null:{node:t.startContainer,offset:t.startOffset}}catch{return null}}function x(e,t){try{var r=T(),n=r.createRange(),o=e.nodeValue.length;n.setStart(e,Math.max(0,Math.min(t,o))),n.collapse(!0);var a=f.getSelection();a.removeAllRanges(),a.addRange(n)}catch{}}function _(e){var t=(e.ctrlKey||e.metaKey)&&!e.shiftKey&&!e.altKey&&(e.code==="KeyZ"||e.key==="z"||e.key==="Z");if(!(e.key!=="Backspace"&&!t||!c)){var r=D();if(!r||r.node!==c.node){c=null;return}if(r.offset!==c.caretAfter){c=null;return}var n=r.node.nodeValue;r.node.nodeValue=n.slice(0,c.start)+c.typed+n.slice(c.start+c.fixed.length),x(r.node,c.start+c.typed.length+(c.tail||0)),c=null,e.preventDefault(),e.stopPropagation()}}function L(e){if(g){var t=e&&typeof e.data=="string"?e.data:null;if(t){var r=D();r&&(S(r.node)||s.autocorrectTypography!==!1&&z(r,t)||P(t)&&I(r,t))}}}function P(e){return e===" "||e==="\xA0"||`.,;:!?)]}"'\u2019\u201D`.indexOf(e)>=0}function z(e,t){var r=e.node.nodeValue,n=e.offset;if(t==='"'||t==="'"){var o=n>=2?r.charAt(n-2):"",a=!o||/[\s(\[{\u2014\u2013\-]/.test(o),i=t==='"'?a?"\u201C":"\u201D":a?"\u2018":"\u2019";return w(e,n-1,n,i,t)}if(t==="-"&&n>=2&&r.charAt(n-2)==="-"){var u=n>=3?r.charAt(n-3):"",l=/[\w\)\]"'\u2019]/.test(u);if(!l&&/\s/.test(u)&&(l=/[\w\)\]"'\u2019]\s*$/.test(r.slice(0,n-3))),l)return w(e,n-2,n,"\u2014","--")}for(var d=0;d<h.length;d++){var v=h[d];if(v.from.charAt(v.from.length-1)===t){var m=n-v.from.length;if(!(m<0)&&r.substring(m,n).toLowerCase()===v.from&&!(/^\d/.test(v.from)&&m>0&&/[\w.]/.test(r.charAt(m-1))))return w(e,m,n,v.to,v.from)}}return!1}function I(e,t){for(var r=e.node.nodeValue,n=e.offset-1,o=n;o>0&&/[A-Za-z'\u2019]/.test(r.charAt(o-1));)o--;if(o!==n){var a=r.substring(o,n);if(!(t==="."&&a.length===1)){for(var i=n;i<r.length&&!/\s/.test(r.charAt(i));)i++;if(!/^[a-z]\.[a-z]\.?$/i.test(r.substring(o,i))){var u=a;if(s.autocorrectSpelling!==!1){var l=A()[u.toLowerCase()];l&&(u=O(u,l)),s.autocorrectTypography!==!1&&(u=u.replace(/'/g,"\u2019"))}if(s.autocorrectCapitalize!==!1&&!U(r,o,n)&&$(r,o,e.node)){var d=u.charAt(0);d!==d.toUpperCase()&&(u=d.toUpperCase()+u.substring(1))}u!==a&&w(e,o,n,u,a)}}}}function O(e,t){return e===e.toUpperCase()&&e.length>1?t.toUpperCase():e.charAt(0)===e.charAt(0).toUpperCase()?t.charAt(0).toUpperCase()+t.substring(1):t}function U(e,t,r){for(var n=t;n>0&&!/\s/.test(e.charAt(n-1));)n--;for(var o=r;o<e.length&&!/\s/.test(e.charAt(o));)o++;var a=e.substring(n,Math.max(o,r+1)).toLowerCase().replace(/^[(\[{<'"\u2018\u201c]+/,"");return/^www\./.test(a)||/^[a-z][a-z0-9+.-]*:/.test(a)||/[\/@]/.test(a)}function $(e,t,r){for(var n=!1,o=t-1;o>=0;o--){var a=e.charAt(o);if(/\s/.test(a)){n=!0;continue}if(!(a==='"'||a==="'"||a==="\u201C"||a==="\u2018"||a==="(")){if(n&&a==="."){for(var i=o;i>0&&!/\s/.test(e.charAt(i-1));)i--;var u=e.substring(i,o+1).toLowerCase().replace(/^[("'\u2018\u201c]+/,"");if(/^(e\.g|i\.e|etc|vs|cf|approx|incl|viz|al|resp|esp|ca)\.$/.test(u))return!1}return n&&".!?".indexOf(a)>=0}}return!V(r)}function V(e){for(var t=E(),r=e;r&&r!==t;){for(var n=r.previousSibling;n;){if((n.textContent||"").trim())return!0;n=n.previousSibling}if(r=r.parentNode,r&&/^(P|LI|TD|TH|H[1-6]|BLOCKQUOTE|DIV)$/.test(r.nodeName))return!1}return!1}function w(e,t,r,n,o){var a=e.node,i=a.nodeValue,u=e.offset-r;a.nodeValue=i.slice(0,t)+n+i.slice(r);var l=t+n.length+u;return x(a,l),c={node:a,start:t,typed:o,fixed:n,caretAfter:l,tail:u},!0}function K(e){for(var t=e,r=0;r<h.length;r++)t=t.split(h[r].from).join(h[r].to);return t=t.replace(/(^|[\s(\[{])"/g,"$1\u201C").replace(/"/g,"\u201D"),t=t.replace(/(^|[\s(\[{])'/g,"$1\u2018").replace(/'/g,"\u2019"),t=t.replace(/(\w)--(\w)/g,"$1\u2014$2"),t=t.replace(/(\w)\s--\s(\w)/g,"$1 \u2014 $2"),t}}
@@ -71,6 +71,23 @@ function RTE_Plugin_AutoEmbed() {
71
71
  if (m) return "https://player.vimeo.com/video/" + m[1];
72
72
  m = /^https?:\/\/player\.vimeo\.com\/video\/(\d{6,12})/i.exec(url);
73
73
  if (m) return "https://player.vimeo.com/video/" + m[1];
74
+ // 2026-10-13 more providers, each id checked against its own pattern before it is placed in the embed address.
75
+ m = /^https?:\/\/(?:www\.)?dailymotion\.com\/video\/([A-Za-z0-9]{4,20})(?:[/?#]|$)/i.exec(url);
76
+ if (m) return "https://www.dailymotion.com/embed/video/" + m[1];
77
+ m = /^https?:\/\/dai\.ly\/([A-Za-z0-9]{4,20})(?:[/?#]|$)/i.exec(url);
78
+ if (m) return "https://www.dailymotion.com/embed/video/" + m[1];
79
+ m = /^https?:\/\/(?:www\.)?loom\.com\/share\/([a-f0-9]{32})(?:[/?#]|$)/i.exec(url);
80
+ if (m) return "https://www.loom.com/embed/" + m[1];
81
+ m = /^https?:\/\/(?:www\.)?codepen\.io\/([A-Za-z0-9_-]{1,40})\/pen\/([A-Za-z0-9]{4,20})(?:[/?#]|$)/i.exec(url);
82
+ if (m) return "https://codepen.io/" + m[1] + "/embed/" + m[2] + "?default-tab=result";
83
+ m = /^https?:\/\/(?:www\.)?ted\.com\/talks\/([a-z0-9_]{3,80})(?:[/?#]|$)/i.exec(url);
84
+ if (m) return "https://embed.ted.com/talks/" + m[1];
85
+ // 2026-10-15 Youku and Coub, which Plate also embeds. Tweets are not here: they need X's widget script, an
86
+ // external call. tools/embeds/embed-providers.mjs
87
+ m = /^https?:\/\/v\.youku\.com\/v_show\/id_(X[A-Za-z0-9]{6,30}={0,2})\.html(?:[?#]|$)/i.exec(url);
88
+ if (m) return "https://player.youku.com/embed/" + m[1];
89
+ m = /^https?:\/\/(?:www\.)?coub\.com\/view\/([a-z0-9]{3,12})(?:[/?#]|$)/i.exec(url);
90
+ if (m) return "https://coub.com/embed/" + m[1];
74
91
  return null;
75
92
  }
76
93
  function resolve(url) {
@@ -1 +1 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_autoembed=RTE_Plugin_AutoEmbed,RTE_DefaultConfig.autoEmbedEnabled=typeof RTE_DefaultConfig.autoEmbedEnabled>"u"?!0:RTE_DefaultConfig.autoEmbedEnabled,RTE_DefaultConfig.autoEmbedResolver=RTE_DefaultConfig.autoEmbedResolver||null;function RTE_Plugin_AutoEmbed(){var s=this,f,i,D;s.PluginName="AutoEmbed",s.InitConfig=function(e){f=e};var p=null;function o(){try{var e=i.getDocument();if(!e||e===p)return;e.addEventListener("paste",C,!0),p=e}catch{}}s.InitEditor=function(e){i=e,o();try{i.attachEvent("ready",o)}catch{}try{i.attachEvent("aftersethtml",o)}catch{}setTimeout(o,0),setTimeout(o,200),i.embedUrl=function(t){var r=v(String(t||"").trim());return r?(R(r),!0):!1}};function w(e){var t;return t=/^https?:\/\/(?:www\.)?youtube\.com\/watch\?(?:[^#]*&)?v=([A-Za-z0-9_-]{6,20})/i.exec(e),t||(t=/^https?:\/\/youtu\.be\/([A-Za-z0-9_-]{6,20})/i.exec(e),t)||(t=/^https?:\/\/(?:www\.)?youtube\.com\/shorts\/([A-Za-z0-9_-]{6,20})/i.exec(e),t)?"https://www.youtube.com/embed/"+t[1]:(t=/^https?:\/\/(?:www\.)?vimeo\.com\/(\d{6,12})(?:[/?#]|$)/i.exec(e),t||(t=/^https?:\/\/player\.vimeo\.com\/video\/(\d{6,12})/i.exec(e),t)?"https://player.vimeo.com/video/"+t[1]:null)}function v(e){var t=w(e);if(t)return t;if(typeof f.autoEmbedResolver=="function")try{var r=f.autoEmbedResolver(e);if(typeof r=="string"&&/^https:\/\//i.test(r))return r}catch{}return null}function E(){try{var e=i.getSelection();return e&&e.rangeCount>0&&e.isCollapsed}catch{return!1}}function C(e){if(!(!f.autoEmbedEnabled||!E())){var t=e.clipboardData||window.clipboardData;if(t){var r;try{r=t.getData("text/plain")}catch{return}if(r&&(r=r.trim(),!(/\s/.test(r)||!/^https?:\/\/\S+$/i.test(r)))){var a=v(r);if(a){var u=0;(function n(){x(r,a)||++u<12&&setTimeout(n,25)})()}}}}}function x(e,t){try{var r=i.getEditable();if(!r)return!1;for(var a=r.querySelectorAll("p,div,li,h1,h2,h3,h4,h5,h6"),u=a.length-1;u>=0;u--){var n=a[u];if(!(n.classList&&n.classList.contains("rte-embed"))&&!(n.querySelector&&(n.querySelector(".rte-embed")||n.querySelector("ul,ol,table")))&&(n.textContent||"").trim()===e){var d=i.getDocument();g(d);var l=d.createElement("div");l.innerHTML=b(t)+"<p><br></p>";var c=n.parentNode;if(!c)return;for(var S=l.firstChild,T=l.lastChild;l.firstChild;)c.insertBefore(l.firstChild,n);c.removeChild(n);try{var m=d.createRange();m.setStart(T,0),m.collapse(!0);var h=i.getSelection();h&&(h.removeAllRanges(),h.addRange(m))}catch{}try{typeof i.fireChange=="function"&&i.fireChange()}catch{}return!0}}}catch{}return!1}function b(e){var t=String(e).replace(/"/g,"&quot;");return'<div class="rte-embed" contenteditable="false" data-embed="'+t+'" style="display:block;margin:12px 0;max-width:720px;"><div class="rte-embed-frame" style="position:relative;width:100%;height:0;padding-bottom:56.25%;overflow:hidden;border-radius:10px;background:#000;"><iframe src="'+t+'" loading="lazy" allowfullscreen referrerpolicy="strict-origin-when-cross-origin" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;"></iframe></div></div>'}function g(e){if(!(!e||e.getElementById("rte-autoembed-styles"))){var t=".rte-embed{display:block;margin:12px 0;max-width:720px;}.rte-embed .rte-embed-frame{position:relative;width:100%;height:0;padding-bottom:56.25%;overflow:hidden;border-radius:10px;background:#000;}.rte-embed .rte-embed-frame iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;}",r=e.createElement("style");r.id="rte-autoembed-styles",r.appendChild(e.createTextNode(t)),(e.head||e.getElementsByTagName("head")[0]||e.documentElement).appendChild(r),i&&typeof i.ensureStyleSheetLive=="function"&&i.ensureStyleSheetLive(e,r,"rte-autoembed-styles",r.textContent)}}function R(e){g(i.getDocument());try{i.insertHTML(b(e)+"<p><br></p>")}catch{}try{typeof i.fireChange=="function"&&i.fireChange()}catch{}}}
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_autoembed=RTE_Plugin_AutoEmbed,RTE_DefaultConfig.autoEmbedEnabled=typeof RTE_DefaultConfig.autoEmbedEnabled>"u"?!0:RTE_DefaultConfig.autoEmbedEnabled,RTE_DefaultConfig.autoEmbedResolver=RTE_DefaultConfig.autoEmbedResolver||null;function RTE_Plugin_AutoEmbed(){var d=this,s,r,T;d.PluginName="AutoEmbed",d.InitConfig=function(t){s=t};var p=null;function o(){try{var t=r.getDocument();if(!t||t===p)return;t.addEventListener("paste",x,!0),p=t}catch{}}d.InitEditor=function(t){r=t,o();try{r.attachEvent("ready",o)}catch{}try{r.attachEvent("aftersethtml",o)}catch{}setTimeout(o,0),setTimeout(o,200),r.embedUrl=function(e){var i=b(String(e||"").trim());return i?(_(i),!0):!1}};function g(t){var e;return e=/^https?:\/\/(?:www\.)?youtube\.com\/watch\?(?:[^#]*&)?v=([A-Za-z0-9_-]{6,20})/i.exec(t),e||(e=/^https?:\/\/youtu\.be\/([A-Za-z0-9_-]{6,20})/i.exec(t),e)||(e=/^https?:\/\/(?:www\.)?youtube\.com\/shorts\/([A-Za-z0-9_-]{6,20})/i.exec(t),e)?"https://www.youtube.com/embed/"+e[1]:(e=/^https?:\/\/(?:www\.)?vimeo\.com\/(\d{6,12})(?:[/?#]|$)/i.exec(t),e||(e=/^https?:\/\/player\.vimeo\.com\/video\/(\d{6,12})/i.exec(t),e)?"https://player.vimeo.com/video/"+e[1]:(e=/^https?:\/\/(?:www\.)?dailymotion\.com\/video\/([A-Za-z0-9]{4,20})(?:[/?#]|$)/i.exec(t),e||(e=/^https?:\/\/dai\.ly\/([A-Za-z0-9]{4,20})(?:[/?#]|$)/i.exec(t),e)?"https://www.dailymotion.com/embed/video/"+e[1]:(e=/^https?:\/\/(?:www\.)?loom\.com\/share\/([a-f0-9]{32})(?:[/?#]|$)/i.exec(t),e?"https://www.loom.com/embed/"+e[1]:(e=/^https?:\/\/(?:www\.)?codepen\.io\/([A-Za-z0-9_-]{1,40})\/pen\/([A-Za-z0-9]{4,20})(?:[/?#]|$)/i.exec(t),e?"https://codepen.io/"+e[1]+"/embed/"+e[2]+"?default-tab=result":(e=/^https?:\/\/(?:www\.)?ted\.com\/talks\/([a-z0-9_]{3,80})(?:[/?#]|$)/i.exec(t),e?"https://embed.ted.com/talks/"+e[1]:(e=/^https?:\/\/v\.youku\.com\/v_show\/id_(X[A-Za-z0-9]{6,30}={0,2})\.html(?:[?#]|$)/i.exec(t),e?"https://player.youku.com/embed/"+e[1]:(e=/^https?:\/\/(?:www\.)?coub\.com\/view\/([a-z0-9]{3,12})(?:[/?#]|$)/i.exec(t),e?"https://coub.com/embed/"+e[1]:null)))))))}function b(t){var e=g(t);if(e)return e;if(typeof s.autoEmbedResolver=="function")try{var i=s.autoEmbedResolver(t);if(typeof i=="string"&&/^https:\/\//i.test(i))return i}catch{}return null}function E(){try{var t=r.getSelection();return t&&t.rangeCount>0&&t.isCollapsed}catch{return!1}}function x(t){if(!(!s.autoEmbedEnabled||!E())){var e=t.clipboardData||window.clipboardData;if(e){var i;try{i=e.getData("text/plain")}catch{return}if(i&&(i=i.trim(),!(/\s/.test(i)||!/^https?:\/\/\S+$/i.test(i)))){var n=b(i);if(n){var u=0;(function a(){C(i,n)||++u<12&&setTimeout(a,25)})()}}}}}function C(t,e){try{var i=r.getEditable();if(!i)return!1;for(var n=i.querySelectorAll("p,div,li,h1,h2,h3,h4,h5,h6"),u=n.length-1;u>=0;u--){var a=n[u];if(!(a.classList&&a.classList.contains("rte-embed"))&&!(a.querySelector&&(a.querySelector(".rte-embed")||a.querySelector("ul,ol,table")))&&(a.textContent||"").trim()===t){var c=r.getDocument();v(c);var l=c.createElement("div");l.innerHTML=w(e)+"<p><br></p>";var f=a.parentNode;if(!f)return;for(var D=l.firstChild,R=l.lastChild;l.firstChild;)f.insertBefore(l.firstChild,a);f.removeChild(a);try{var m=c.createRange();m.setStart(R,0),m.collapse(!0);var h=r.getSelection();h&&(h.removeAllRanges(),h.addRange(m))}catch{}try{typeof r.fireChange=="function"&&r.fireChange()}catch{}return!0}}}catch{}return!1}function w(t){var e=String(t).replace(/"/g,"&quot;");return'<div class="rte-embed" contenteditable="false" data-embed="'+e+'" style="display:block;margin:12px 0;max-width:720px;"><div class="rte-embed-frame" style="position:relative;width:100%;height:0;padding-bottom:56.25%;overflow:hidden;border-radius:10px;background:#000;"><iframe src="'+e+'" loading="lazy" allowfullscreen referrerpolicy="strict-origin-when-cross-origin" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;"></iframe></div></div>'}function v(t){if(!(!t||t.getElementById("rte-autoembed-styles"))){var e=".rte-embed{display:block;margin:12px 0;max-width:720px;}.rte-embed .rte-embed-frame{position:relative;width:100%;height:0;padding-bottom:56.25%;overflow:hidden;border-radius:10px;background:#000;}.rte-embed .rte-embed-frame iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;}",i=t.createElement("style");i.id="rte-autoembed-styles",i.appendChild(t.createTextNode(e)),(t.head||t.getElementsByTagName("head")[0]||t.documentElement).appendChild(i),r&&typeof r.ensureStyleSheetLive=="function"&&r.ensureStyleSheetLive(t,i,"rte-autoembed-styles",i.textContent)}}function _(t){v(r.getDocument());try{r.insertHTML(w(t)+"<p><br></p>")}catch{}try{typeof r.fireChange=="function"&&r.fireChange()}catch{}}}
@@ -9,11 +9,11 @@ RTE_DefaultConfig.plugin_blocktypes = RTE_Plugin_BlockTypes;
9
9
 
10
10
  // Callout variants: id -> { label, icon }. Customizable via config.calloutTypes.
11
11
  RTE_DefaultConfig.calloutTypes = RTE_DefaultConfig.calloutTypes || [
12
- { id: "info", label: "Info", icon: "ℹ️" }, // ℹ️
13
- { id: "success", label: "Success", icon: "✅" }, // ✅
14
- { id: "warning", label: "Warning", icon: "⚠️" }, // ⚠️
15
- { id: "danger", label: "Danger", icon: "⛔" }, // ⛔
16
- { id: "note", label: "Note", icon: "📝" } // 📝
12
+ { id: "info", label: "Info", icon: "\u2139\ufe0f" }, // ℹ️
13
+ { id: "success", label: "Success", icon: "\u2705" }, // ✅
14
+ { id: "warning", label: "Warning", icon: "\u26a0\ufe0f" }, // ⚠️
15
+ { id: "danger", label: "Danger", icon: "\u26d4" }, // ⛔
16
+ { id: "note", label: "Note", icon: "\ud83d\udcdd" } // 📝
17
17
  ];
18
18
  RTE_DefaultConfig.calloutDefaultType = RTE_DefaultConfig.calloutDefaultType || "info";
19
19
  RTE_DefaultConfig.columnsDefaultCount = RTE_DefaultConfig.columnsDefaultCount || 2;
@@ -57,7 +57,7 @@ function RTE_Plugin_BlockTypes() {
57
57
  for (var i = 0; i < types.length; i++) {
58
58
  if (types[i].id === id) return types[i];
59
59
  }
60
- return types[0] || { id: "info", label: "Info", icon: "ℹ️" };
60
+ return types[0] || { id: "info", label: "Info", icon: "\u2139\ufe0f" };
61
61
  }
62
62
 
63
63
  // --- Insertion -------------------------------------------------------
@@ -110,17 +110,26 @@ function RTE_Plugin_BlockTypes() {
110
110
  // the blocks rendered unstyled (transparent callouts, block-display
111
111
  // columns instead of flex).
112
112
  injectStyles();
113
+ // 2026-10-03 The caret goes into the block JUST inserted, with its first placeholder
114
+ // selected so typing replaces it. It went to the start of the placeholder ("Hi thereCallout
115
+ // text"), and to the LAST element of the class in the document: the last column, and - with
116
+ // a callout inserted above an existing one - into the OLD callout, so what the user typed
117
+ // changed content that was already there. The new block is the first element of the class
118
+ // that was not there before. tools/blocks/block-types-insert.mjs
119
+ var before = [];
120
+ try { before = Array.prototype.slice.call(editor.getEditable().getElementsByClassName(focusClass)); } catch (e) { before = []; }
113
121
  editor.insertHTML(html);
114
122
  try {
115
123
  var editdoc = editor.getDocument();
116
124
  var editable = editor.getEditable();
117
125
  var targets = editable.getElementsByClassName(focusClass);
118
- if (targets && targets.length) {
119
- var target = targets[targets.length - 1]; // the one we just inserted
126
+ var target = null;
127
+ for (var i = 0; i < targets.length && !target; i++)
128
+ if (before.indexOf(targets[i]) === -1) target = targets[i];
129
+ if (target) {
120
130
  var caretNode = target.querySelector("p") || target;
121
131
  var range = editdoc.createRange();
122
132
  range.selectNodeContents(caretNode);
123
- range.collapse(true);
124
133
  var sel = editor.getSelection();
125
134
  sel.removeAllRanges();
126
135
  sel.addRange(range);
@@ -1,2 +1,2 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_blocktypes=RTE_Plugin_BlockTypes,RTE_DefaultConfig.calloutTypes=RTE_DefaultConfig.calloutTypes||[{id:"info",label:"Info",icon:"\u2139\uFE0F"},{id:"success",label:"Success",icon:"\u2705"},{id:"warning",label:"Warning",icon:"\u26A0\uFE0F"},{id:"danger",label:"Danger",icon:"\u26D4"},{id:"note",label:"Note",icon:"\u{1F4DD}"}],RTE_DefaultConfig.calloutDefaultType=RTE_DefaultConfig.calloutDefaultType||"info",RTE_DefaultConfig.columnsDefaultCount=RTE_DefaultConfig.columnsDefaultCount||2;function RTE_Plugin_BlockTypes(){var r=this,i,l;r.PluginName="BlockTypes",r.InitConfig=function(t){i=t},r.InitEditor=function(t){l=t,l.attachEvent("exec_command_insertcallout",function(e,a,o){e.returnValue=!0,r.InsertCallout(o)}),l.attachEvent("exec_command_insertcolumns",function(e,a,o){e.returnValue=!0,r.InsertColumns(o)}),l.attachEvent("exec_command_inserttoggle",function(e){e.returnValue=!0,r.InsertToggle()}),d()};function c(t){return String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function p(t){for(var e=i.calloutTypes||[],a=0;a<e.length;a++)if(e[a].id===t)return e[a];return e[0]||{id:"info",label:"Info",icon:"\u2139\uFE0F"}}r.InsertCallout=function(t){var e=p(t||i.calloutDefaultType),a=l.getLangText&&l.getLangText("calloutplaceholder")||"Callout text",o='<div class="rte-callout rte-callout-'+c(e.id)+'" data-rte-block="callout" data-rte-callout-type="'+c(e.id)+'"><div class="rte-callout-icon" contenteditable="false" data-rte-callout-icon="1">'+e.icon+'</div><div class="rte-callout-body"><p>'+c(a)+"</p></div></div><p><br></p>";u(o,"rte-callout-body")},r.InsertColumns=function(t){t=parseInt(t,10)||i.columnsDefaultCount||2,t<2&&(t=2),t>4&&(t=4);for(var e="",a=l.getLangText&&l.getLangText("columnplaceholder")||"Column",o=0;o<t;o++)e+='<div class="rte-column"><p>'+c(a)+" "+(o+1)+"</p></div>";var n='<div class="rte-columns rte-columns-'+t+'" data-rte-block="columns" data-rte-columns="'+t+'">'+e+"</div><p><br></p>";u(n,"rte-column")},r.InsertToggle=function(){var t=l.getLangText&&l.getLangText("toggleplaceholder")||"Toggle title",e=l.getLangText&&l.getLangText("togglebodyplaceholder")||"Hidden content",a='<details class="rte-toggle" data-rte-block="toggle" open><summary class="rte-toggle-summary">'+c(t)+'</summary><div class="rte-toggle-body"><p>'+c(e)+"</p></div></details><p><br></p>";u(a,"rte-toggle-summary")};function u(t,e){d(),l.insertHTML(t);try{var a=l.getDocument(),o=l.getEditable(),n=o.getElementsByClassName(e);if(n&&n.length){var s=n[n.length-1],m=s.querySelector("p")||s,g=a.createRange();g.selectNodeContents(m),g.collapse(!0);var f=l.getSelection();f.removeAllRanges(),f.addRange(g)}}catch{}l.focus()}function d(){var t=[".rte-callout{display:flex;gap:10px;align-items:flex-start;margin:12px 0;padding:12px 14px;border-radius:8px;border:1px solid rgba(15,23,42,.12);border-left-width:4px;background:#f8fafc}",".rte-callout-icon{flex:0 0 auto;font-size:18px;line-height:1.4;user-select:none}",".rte-callout-body{flex:1;min-width:0}",".rte-callout-body > :first-child{margin-top:0}",".rte-callout-body > :last-child{margin-bottom:0}",".rte-callout-info{border-left-color:#2563eb;background:#eff6ff}",".rte-callout-success{border-left-color:#16a34a;background:#f0fdf4}",".rte-callout-warning{border-left-color:#d97706;background:#fffbeb}",".rte-callout-danger{border-left-color:#dc2626;background:#fef2f2}",".rte-callout-note{border-left-color:#7c3aed;background:#faf5ff}",".rte-columns{display:flex;gap:16px;margin:12px 0;align-items:stretch}",".rte-column{flex:1 1 0;min-width:0;padding:8px 10px;border:1px dashed rgba(15,23,42,.15);border-radius:6px}",".rte-column > :first-child{margin-top:0}",".rte-column > :last-child{margin-bottom:0}",".rte-toggle{margin:12px 0;border:1px solid rgba(15,23,42,.12);border-radius:8px;padding:6px 12px;background:#fafbff}",".rte-toggle > summary{cursor:pointer;font-weight:600;outline:none;list-style:revert;padding:4px 0}",".rte-toggle-body{padding:4px 0 4px 16px}",".rte-toggle-body > :first-child{margin-top:0}",".rte-toggle-body > :last-child{margin-bottom:0}","@media (max-width:640px){.rte-columns{flex-direction:column}}"].join(`
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_blocktypes=RTE_Plugin_BlockTypes,RTE_DefaultConfig.calloutTypes=RTE_DefaultConfig.calloutTypes||[{id:"info",label:"Info",icon:"\u2139\uFE0F"},{id:"success",label:"Success",icon:"\u2705"},{id:"warning",label:"Warning",icon:"\u26A0\uFE0F"},{id:"danger",label:"Danger",icon:"\u26D4"},{id:"note",label:"Note",icon:"\u{1F4DD}"}],RTE_DefaultConfig.calloutDefaultType=RTE_DefaultConfig.calloutDefaultType||"info",RTE_DefaultConfig.columnsDefaultCount=RTE_DefaultConfig.columnsDefaultCount||2;function RTE_Plugin_BlockTypes(){var r=this,i,l;r.PluginName="BlockTypes",r.InitConfig=function(t){i=t},r.InitEditor=function(t){l=t,l.attachEvent("exec_command_insertcallout",function(e,a,o){e.returnValue=!0,r.InsertCallout(o)}),l.attachEvent("exec_command_insertcolumns",function(e,a,o){e.returnValue=!0,r.InsertColumns(o)}),l.attachEvent("exec_command_inserttoggle",function(e){e.returnValue=!0,r.InsertToggle()}),s()};function n(t){return String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function b(t){for(var e=i.calloutTypes||[],a=0;a<e.length;a++)if(e[a].id===t)return e[a];return e[0]||{id:"info",label:"Info",icon:"\u2139\uFE0F"}}r.InsertCallout=function(t){var e=b(t||i.calloutDefaultType),a=l.getLangText&&l.getLangText("calloutplaceholder")||"Callout text",o='<div class="rte-callout rte-callout-'+n(e.id)+'" data-rte-block="callout" data-rte-callout-type="'+n(e.id)+'"><div class="rte-callout-icon" contenteditable="false" data-rte-callout-icon="1">'+e.icon+'</div><div class="rte-callout-body"><p>'+n(a)+"</p></div></div><p><br></p>";g(o,"rte-callout-body")},r.InsertColumns=function(t){t=parseInt(t,10)||i.columnsDefaultCount||2,t<2&&(t=2),t>4&&(t=4);for(var e="",a=l.getLangText&&l.getLangText("columnplaceholder")||"Column",o=0;o<t;o++)e+='<div class="rte-column"><p>'+n(a)+" "+(o+1)+"</p></div>";var u='<div class="rte-columns rte-columns-'+t+'" data-rte-block="columns" data-rte-columns="'+t+'">'+e+"</div><p><br></p>";g(u,"rte-column")},r.InsertToggle=function(){var t=l.getLangText&&l.getLangText("toggleplaceholder")||"Toggle title",e=l.getLangText&&l.getLangText("togglebodyplaceholder")||"Hidden content",a='<details class="rte-toggle" data-rte-block="toggle" open><summary class="rte-toggle-summary">'+n(t)+'</summary><div class="rte-toggle-body"><p>'+n(e)+"</p></div></details><p><br></p>";g(a,"rte-toggle-summary")};function g(t,e){s();var a=[];try{a=Array.prototype.slice.call(l.getEditable().getElementsByClassName(e))}catch{a=[]}l.insertHTML(t);try{for(var o=l.getDocument(),u=l.getEditable(),f=u.getElementsByClassName(e),c=null,d=0;d<f.length&&!c;d++)a.indexOf(f[d])===-1&&(c=f[d]);if(c){var y=c.querySelector("p")||c,p=o.createRange();p.selectNodeContents(y);var m=l.getSelection();m.removeAllRanges(),m.addRange(p)}}catch{}l.focus()}function s(){var t=[".rte-callout{display:flex;gap:10px;align-items:flex-start;margin:12px 0;padding:12px 14px;border-radius:8px;border:1px solid rgba(15,23,42,.12);border-left-width:4px;background:#f8fafc}",".rte-callout-icon{flex:0 0 auto;font-size:18px;line-height:1.4;user-select:none}",".rte-callout-body{flex:1;min-width:0}",".rte-callout-body > :first-child{margin-top:0}",".rte-callout-body > :last-child{margin-bottom:0}",".rte-callout-info{border-left-color:#2563eb;background:#eff6ff}",".rte-callout-success{border-left-color:#16a34a;background:#f0fdf4}",".rte-callout-warning{border-left-color:#d97706;background:#fffbeb}",".rte-callout-danger{border-left-color:#dc2626;background:#fef2f2}",".rte-callout-note{border-left-color:#7c3aed;background:#faf5ff}",".rte-columns{display:flex;gap:16px;margin:12px 0;align-items:stretch}",".rte-column{flex:1 1 0;min-width:0;padding:8px 10px;border:1px dashed rgba(15,23,42,.15);border-radius:6px}",".rte-column > :first-child{margin-top:0}",".rte-column > :last-child{margin-bottom:0}",".rte-toggle{margin:12px 0;border:1px solid rgba(15,23,42,.12);border-radius:8px;padding:6px 12px;background:#fafbff}",".rte-toggle > summary{cursor:pointer;font-weight:600;outline:none;list-style:revert;padding:4px 0}",".rte-toggle-body{padding:4px 0 4px 16px}",".rte-toggle-body > :first-child{margin-top:0}",".rte-toggle-body > :last-child{margin-bottom:0}","@media (max-width:640px){.rte-columns{flex-direction:column}}"].join(`
2
2
  `);try{var e=l.getDocument();if(!e)return;var a=e.head||e.getElementsByTagName&&e.getElementsByTagName("head")[0]||e.documentElement;if(a&&!e.querySelector("style[data-rte-blocktypes]")){var o=e.createElement("style");o.setAttribute("data-rte-blocktypes","1"),o.textContent=t,a.appendChild(o),l&&typeof l.ensureStyleSheetLive=="function"&&l.ensureStyleSheetLive(e,o,"rte-blocktypes-st",o.textContent)}}catch{}}}
@@ -37,6 +37,13 @@ function RTE_Plugin_BookmarkCard() {
37
37
  obj.PluginName = "BookmarkCard";
38
38
 
39
39
  obj.InitConfig = function (argconfig) { config = argconfig; };
40
+ // 2026-10-18 the words read config.text_ keys (language packs), English as the fallback; {0} / {1} fill a template.
41
+ // tools/i18n/plugin-bars-language.mjs
42
+ function pText(key, fallback) {
43
+ var s = (config && config["text_" + key]) || fallback;
44
+ for (var i = 2; i < arguments.length; i++) s = s.split("{" + (i - 2) + "}").join(String(arguments[i]));
45
+ return s;
46
+ }
40
47
 
41
48
  obj.InitEditor = function (argeditor) {
42
49
  editor = argeditor;
@@ -175,22 +182,22 @@ function RTE_Plugin_BookmarkCard() {
175
182
  input.type = "url"; input.placeholder = "https://example.com/article";
176
183
 
177
184
  var status = append(wrap, "div", "font-size:11px;color:#94a3b8;margin-top:6px;min-height:14px");
178
- if (!config.bookmarkResolver) status.innerText = "No metadata resolver configured — a basic card (favicon + domain) will be inserted. Wire config.bookmarkResolver for rich previews.";
185
+ if (!config.bookmarkResolver) status.innerText = pText("bm_noresolver", "No metadata resolver configured \u2014 a basic card (favicon + domain) will be inserted. Wire config.bookmarkResolver for rich previews.");
179
186
 
180
187
  var footer = append(wrap, "div", "display:flex;justify-content:flex-end;gap:8px;margin-top:14px");
181
188
  var cancel = append(footer, "button", "padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer");
182
- cancel.type = "button"; cancel.textContent = "Cancel"; cancel.onclick = close;
189
+ cancel.type = "button"; cancel.textContent = pText("cancel", "Cancel"); cancel.onclick = close;
183
190
  var ok = append(footer, "button", "padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer");
184
- ok.type = "button"; ok.textContent = "Insert";
191
+ ok.type = "button"; ok.textContent = pText("insert", "Insert");
185
192
 
186
193
  setTimeout(function () { input.focus(); }, 0);
187
194
  input.onkeydown = function (e) { if (e.key === "Enter") { e.preventDefault(); ok.click(); } };
188
195
 
189
196
  ok.onclick = function () {
190
197
  var url = normalizeUrl(input.value);
191
- if (!url) { status.style.color = "#dc2626"; status.innerText = "Enter a valid http(s) URL."; return; }
198
+ if (!url) { status.style.color = "#dc2626"; status.innerText = pText("bminvalid", "Enter a valid http(s) URL."); return; }
192
199
  if (config.bookmarkResolver && typeof config.bookmarkResolver === "function") {
193
- ok.disabled = true; status.style.color = "#94a3b8"; status.innerText = "Fetching preview…";
200
+ ok.disabled = true; status.style.color = "#94a3b8"; status.innerText = pText("bmfetching", "Fetching preview\u2026");
194
201
  var done = false;
195
202
  function finish(meta) { if (done) return; done = true; meta = meta || {}; meta.url = url; close(); insertCard(meta); }
196
203
  try {
@@ -1,2 +1,2 @@
1
- window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_bookmarkcard=RTE_Plugin_BookmarkCard,RTE_DefaultConfig.bookmarkResolver=RTE_DefaultConfig.bookmarkResolver||null,RTE_DefaultConfig.bookmarkFaviconService=typeof RTE_DefaultConfig.bookmarkFaviconService>"u"?"":RTE_DefaultConfig.bookmarkFaviconService;function RTE_Plugin_BookmarkCard(){var b=this,l,o;b.PluginName="BookmarkCard",b.InitConfig=function(e){l=e},b.InitEditor=function(e){o=e,o.attachEvent("exec_command_insertbookmark",function(r){r.returnValue=!0,b.OpenBookmarkDialog()});try{var t=o.getEditable();t&&(t.addEventListener("click",E,!0),t.addEventListener("keydown",R,!0))}catch{}h()};function c(e,t,r,a){var i=e.ownerDocument.createElement(t);return r&&(i.style.cssText=r),a&&(i.className=a),e.appendChild(i),i}function f(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function w(e){var t=String(e||"").trim();if(!t||/^(javascript|data|vbscript|file):/i.test(t))return null;if(!/^https?:\/\//i.test(t))if(/^[a-z0-9.-]+\.[a-z]{2,}([\/?#].*)?$/i.test(t))t="https://"+t;else return null;try{if(typeof URL=="function"){var r=new URL(t);return r.protocol!=="http:"&&r.protocol!=="https:"?null:r.href}}catch{return null}return t}function C(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return e.replace(/^https?:\/\//i,"").split("/")[0].replace(/^www\./,"")}}function g(e,t){for(;e&&e!==t;){if(e.nodeType===1&&e.classList&&e.classList.contains("rte-bookmark-card"))return e;e=e.parentNode}return null}function v(e){if(!(!e||!e.parentNode)){e.parentNode.removeChild(e);try{typeof o.fireChange=="function"&&o.fireChange()}catch{}try{o.focus()}catch{}}}function E(e){for(var t=e.target,r=o.getEditable();t&&t!==r;){if(t.nodeType===1&&t.getAttribute&&t.getAttribute("data-rte-bookmark-remove")==="1"){e.preventDefault(),e.stopPropagation(),v(g(t,r));return}t=t.parentNode}}function R(e){if((e.key==="Enter"||e.key===" ")&&e.target&&e.target.getAttribute&&e.target.getAttribute("data-rte-bookmark-remove")==="1"){e.preventDefault(),e.stopPropagation(),v(g(e.target,o.getEditable()));return}if(!(e.key!=="Delete"&&e.key!=="Backspace")){var t=null;try{var r=o.getSelection();r&&r.rangeCount&&(t=g(r.getRangeAt(0).startContainer,o.getEditable()))}catch{t=null}t&&(e.preventDefault(),v(t))}}function T(e){var t=e.url,r=C(t),a=e.title||r,i=e.description||"",d=e.favicon||(l.bookmarkFaviconService?l.bookmarkFaviconService+encodeURIComponent(r):""),u=e.image||"",n='<a class="rte-bookmark-card" data-rte-block="bookmark" href="'+f(t)+'" target="_blank" rel="noopener noreferrer" contenteditable="false">';return n+='<span class="rte-bookmark-remove" data-rte-bookmark-remove="1" role="button" tabindex="0" aria-label="Remove bookmark" title="Remove bookmark">x</span>',n+='<span class="rte-bookmark-main">',n+='<span class="rte-bookmark-title">'+f(a)+"</span>",i&&(n+='<span class="rte-bookmark-desc">'+f(i)+"</span>"),n+='<span class="rte-bookmark-url">',d&&(n+='<img class="rte-bookmark-favicon" src="'+f(d)+'" alt="" width="16" height="16">'),n+="<span>"+f(r)+"</span></span>",n+="</span>",u&&(n+=`<span class="rte-bookmark-thumb" style="background-image:url('`+f(u).replace(/'/g,"%27")+`')"></span>`),n+="</a><p><br></p>",n}function x(e){h(),o.insertHTML(T(e)),o.focus()}b.OpenBookmarkDialog=function(){var e=o.createDialog(o.getLangText&&o.getLangText("insertbookmarktitle")||"Insert bookmark","rte-dialog-bookmark"),t=typeof e.close=="function"?function(){e.close()}:function(){o.closeCurrentPopup()},r=c(e,"div","padding:14px;min-width:420px;font:13px -apple-system,Segoe UI,sans-serif");c(r,"div","font-weight:600;margin-bottom:4px").innerText=o.getLangText&&o.getLangText("insertbookmarklabel")||"Link URL";var a=c(r,"input","width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid #cbd5e1;border-radius:8px;font:13px ui-monospace,monospace");a.type="url",a.placeholder="https://example.com/article";var i=c(r,"div","font-size:11px;color:#94a3b8;margin-top:6px;min-height:14px");l.bookmarkResolver||(i.innerText="No metadata resolver configured \u2014 a basic card (favicon + domain) will be inserted. Wire config.bookmarkResolver for rich previews.");var d=c(r,"div","display:flex;justify-content:flex-end;gap:8px;margin-top:14px"),u=c(d,"button","padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer");u.type="button",u.textContent="Cancel",u.onclick=t;var n=c(d,"button","padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer");n.type="button",n.textContent="Insert",setTimeout(function(){a.focus()},0),a.onkeydown=function(s){s.key==="Enter"&&(s.preventDefault(),n.click())},n.onclick=function(){var s=w(a.value);if(!s){i.style.color="#dc2626",i.innerText="Enter a valid http(s) URL.";return}if(l.bookmarkResolver&&typeof l.bookmarkResolver=="function"){let k=function(p){y||(y=!0,p=p||{},p.url=s,t(),x(p))};var D=k;n.disabled=!0,i.style.color="#94a3b8",i.innerText="Fetching preview\u2026";var y=!1;try{var m=l.bookmarkResolver(s);m&&typeof m.then=="function"?(m.then(function(p){k(p||{})},function(){k({})}),setTimeout(function(){k({})},8e3)):k(m||{})}catch{k({})}}else t(),x({url:s})}};function h(){var e=[".rte-bookmark-card{position:relative;display:flex;align-items:stretch;justify-content:space-between;gap:12px;margin:12px 0;border:1px solid rgba(15,23,42,.14);border-radius:10px;overflow:hidden;text-decoration:none;color:inherit;background:#fff;max-width:640px;transition:box-shadow 160ms,border-color 160ms}",".rte-bookmark-card:hover{border-color:rgba(37,99,235,.5);box-shadow:0 6px 18px rgba(15,23,42,.10)}",".rte-bookmark-remove{position:absolute;top:7px;right:7px;width:22px;height:22px;border:1px solid rgba(15,23,42,.14);border-radius:999px;background:rgba(255,255,255,.96);color:#334155;display:flex;align-items:center;justify-content:center;font:700 13px/1 -apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;box-shadow:0 4px 12px rgba(15,23,42,.12);opacity:0;transition:opacity 120ms,border-color 120ms,color 120ms;z-index:2}",".rte-bookmark-card:hover .rte-bookmark-remove,.rte-bookmark-card:focus .rte-bookmark-remove{opacity:1}",".rte-bookmark-remove:hover{border-color:rgba(220,38,38,.38);color:#b91c1c}",".rte-bookmark-main{flex:1;min-width:0;padding:12px 14px;display:flex;flex-direction:column;gap:4px}",".rte-bookmark-title{font-weight:600;font-size:14px;line-height:1.3;color:#0f172a;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}",".rte-bookmark-desc{font-size:12px;color:#64748b;line-height:1.4;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}",".rte-bookmark-url{display:flex;align-items:center;gap:6px;font-size:11px;color:#94a3b8;margin-top:2px}",".rte-bookmark-favicon{width:16px;height:16px;border-radius:3px;flex:0 0 16px}",".rte-bookmark-thumb{flex:0 0 120px;background-size:cover;background-position:center;background-color:#f1f5f9}","@media (max-width:480px){.rte-bookmark-thumb{display:none}}"].join(`
2
- `);try{var t=o.getDocument();if(!t)return;var r=t.head||t.getElementsByTagName&&t.getElementsByTagName("head")[0]||t.documentElement;if(r&&!t.querySelector("style[data-rte-bookmarkcard]")){var a=t.createElement("style");a.setAttribute("data-rte-bookmarkcard","1"),a.textContent=e,r.appendChild(a),o&&typeof o.ensureStyleSheetLive=="function"&&o.ensureStyleSheetLive(t,a,"rte-bookmarkcard-st",a.textContent)}}catch{}}}
1
+ window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_bookmarkcard=RTE_Plugin_BookmarkCard,RTE_DefaultConfig.bookmarkResolver=RTE_DefaultConfig.bookmarkResolver||null,RTE_DefaultConfig.bookmarkFaviconService=typeof RTE_DefaultConfig.bookmarkFaviconService>"u"?"":RTE_DefaultConfig.bookmarkFaviconService;function RTE_Plugin_BookmarkCard(){var b=this,l,a;b.PluginName="BookmarkCard",b.InitConfig=function(e){l=e};function d(e,t){for(var r=l&&l["text_"+e]||t,o=2;o<arguments.length;o++)r=r.split("{"+(o-2)+"}").join(String(arguments[o]));return r}b.InitEditor=function(e){a=e,a.attachEvent("exec_command_insertbookmark",function(r){r.returnValue=!0,b.OpenBookmarkDialog()});try{var t=a.getEditable();t&&(t.addEventListener("click",R,!0),t.addEventListener("keydown",T,!0))}catch{}y()};function c(e,t,r,o){var i=e.ownerDocument.createElement(t);return r&&(i.style.cssText=r),o&&(i.className=o),e.appendChild(i),i}function f(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function C(e){var t=String(e||"").trim();if(!t||/^(javascript|data|vbscript|file):/i.test(t))return null;if(!/^https?:\/\//i.test(t))if(/^[a-z0-9.-]+\.[a-z]{2,}([\/?#].*)?$/i.test(t))t="https://"+t;else return null;try{if(typeof URL=="function"){var r=new URL(t);return r.protocol!=="http:"&&r.protocol!=="https:"?null:r.href}}catch{return null}return t}function E(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return e.replace(/^https?:\/\//i,"").split("/")[0].replace(/^www\./,"")}}function v(e,t){for(;e&&e!==t;){if(e.nodeType===1&&e.classList&&e.classList.contains("rte-bookmark-card"))return e;e=e.parentNode}return null}function x(e){if(!(!e||!e.parentNode)){e.parentNode.removeChild(e);try{typeof a.fireChange=="function"&&a.fireChange()}catch{}try{a.focus()}catch{}}}function R(e){for(var t=e.target,r=a.getEditable();t&&t!==r;){if(t.nodeType===1&&t.getAttribute&&t.getAttribute("data-rte-bookmark-remove")==="1"){e.preventDefault(),e.stopPropagation(),x(v(t,r));return}t=t.parentNode}}function T(e){if((e.key==="Enter"||e.key===" ")&&e.target&&e.target.getAttribute&&e.target.getAttribute("data-rte-bookmark-remove")==="1"){e.preventDefault(),e.stopPropagation(),x(v(e.target,a.getEditable()));return}if(!(e.key!=="Delete"&&e.key!=="Backspace")){var t=null;try{var r=a.getSelection();r&&r.rangeCount&&(t=v(r.getRangeAt(0).startContainer,a.getEditable()))}catch{t=null}t&&(e.preventDefault(),x(t))}}function D(e){var t=e.url,r=E(t),o=e.title||r,i=e.description||"",m=e.favicon||(l.bookmarkFaviconService?l.bookmarkFaviconService+encodeURIComponent(r):""),u=e.image||"",n='<a class="rte-bookmark-card" data-rte-block="bookmark" href="'+f(t)+'" target="_blank" rel="noopener noreferrer" contenteditable="false">';return n+='<span class="rte-bookmark-remove" data-rte-bookmark-remove="1" role="button" tabindex="0" aria-label="Remove bookmark" title="Remove bookmark">x</span>',n+='<span class="rte-bookmark-main">',n+='<span class="rte-bookmark-title">'+f(o)+"</span>",i&&(n+='<span class="rte-bookmark-desc">'+f(i)+"</span>"),n+='<span class="rte-bookmark-url">',m&&(n+='<img class="rte-bookmark-favicon" src="'+f(m)+'" alt="" width="16" height="16">'),n+="<span>"+f(r)+"</span></span>",n+="</span>",u&&(n+=`<span class="rte-bookmark-thumb" style="background-image:url('`+f(u).replace(/'/g,"%27")+`')"></span>`),n+="</a><p><br></p>",n}function h(e){y(),a.insertHTML(D(e)),a.focus()}b.OpenBookmarkDialog=function(){var e=a.createDialog(a.getLangText&&a.getLangText("insertbookmarktitle")||"Insert bookmark","rte-dialog-bookmark"),t=typeof e.close=="function"?function(){e.close()}:function(){a.closeCurrentPopup()},r=c(e,"div","padding:14px;min-width:420px;font:13px -apple-system,Segoe UI,sans-serif");c(r,"div","font-weight:600;margin-bottom:4px").innerText=a.getLangText&&a.getLangText("insertbookmarklabel")||"Link URL";var o=c(r,"input","width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid #cbd5e1;border-radius:8px;font:13px ui-monospace,monospace");o.type="url",o.placeholder="https://example.com/article";var i=c(r,"div","font-size:11px;color:#94a3b8;margin-top:6px;min-height:14px");l.bookmarkResolver||(i.innerText=d("bm_noresolver","No metadata resolver configured \u2014 a basic card (favicon + domain) will be inserted. Wire config.bookmarkResolver for rich previews."));var m=c(r,"div","display:flex;justify-content:flex-end;gap:8px;margin-top:14px"),u=c(m,"button","padding:6px 14px;border:1px solid #cbd5e1;border-radius:8px;background:#fff;cursor:pointer");u.type="button",u.textContent=d("cancel","Cancel"),u.onclick=t;var n=c(m,"button","padding:6px 14px;border:1px solid #1d67ba;border-radius:8px;background:#1d67ba;color:#fff;cursor:pointer");n.type="button",n.textContent=d("insert","Insert"),setTimeout(function(){o.focus()},0),o.onkeydown=function(s){s.key==="Enter"&&(s.preventDefault(),n.click())},n.onclick=function(){var s=C(o.value);if(!s){i.style.color="#dc2626",i.innerText=d("bminvalid","Enter a valid http(s) URL.");return}if(l.bookmarkResolver&&typeof l.bookmarkResolver=="function"){let k=function(p){w||(w=!0,p=p||{},p.url=s,t(),h(p))};var S=k;n.disabled=!0,i.style.color="#94a3b8",i.innerText=d("bmfetching","Fetching preview\u2026");var w=!1;try{var g=l.bookmarkResolver(s);g&&typeof g.then=="function"?(g.then(function(p){k(p||{})},function(){k({})}),setTimeout(function(){k({})},8e3)):k(g||{})}catch{k({})}}else t(),h({url:s})}};function y(){var e=[".rte-bookmark-card{position:relative;display:flex;align-items:stretch;justify-content:space-between;gap:12px;margin:12px 0;border:1px solid rgba(15,23,42,.14);border-radius:10px;overflow:hidden;text-decoration:none;color:inherit;background:#fff;max-width:640px;transition:box-shadow 160ms,border-color 160ms}",".rte-bookmark-card:hover{border-color:rgba(37,99,235,.5);box-shadow:0 6px 18px rgba(15,23,42,.10)}",".rte-bookmark-remove{position:absolute;top:7px;right:7px;width:22px;height:22px;border:1px solid rgba(15,23,42,.14);border-radius:999px;background:rgba(255,255,255,.96);color:#334155;display:flex;align-items:center;justify-content:center;font:700 13px/1 -apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;box-shadow:0 4px 12px rgba(15,23,42,.12);opacity:0;transition:opacity 120ms,border-color 120ms,color 120ms;z-index:2}",".rte-bookmark-card:hover .rte-bookmark-remove,.rte-bookmark-card:focus .rte-bookmark-remove{opacity:1}",".rte-bookmark-remove:hover{border-color:rgba(220,38,38,.38);color:#b91c1c}",".rte-bookmark-main{flex:1;min-width:0;padding:12px 14px;display:flex;flex-direction:column;gap:4px}",".rte-bookmark-title{font-weight:600;font-size:14px;line-height:1.3;color:#0f172a;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}",".rte-bookmark-desc{font-size:12px;color:#64748b;line-height:1.4;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}",".rte-bookmark-url{display:flex;align-items:center;gap:6px;font-size:11px;color:#94a3b8;margin-top:2px}",".rte-bookmark-favicon{width:16px;height:16px;border-radius:3px;flex:0 0 16px}",".rte-bookmark-thumb{flex:0 0 120px;background-size:cover;background-position:center;background-color:#f1f5f9}","@media (max-width:480px){.rte-bookmark-thumb{display:none}}"].join(`
2
+ `);try{var t=a.getDocument();if(!t)return;var r=t.head||t.getElementsByTagName&&t.getElementsByTagName("head")[0]||t.documentElement;if(r&&!t.querySelector("style[data-rte-bookmarkcard]")){var o=t.createElement("style");o.setAttribute("data-rte-bookmarkcard","1"),o.textContent=e,r.appendChild(o),a&&typeof a.ensureStyleSheetLive=="function"&&a.ensureStyleSheetLive(t,o,"rte-bookmarkcard-st",o.textContent)}}catch{}}}
@@ -48,6 +48,18 @@ function RTE_Plugin_ChangeCase() {
48
48
  editor.getChangeCaseModes = function () {
49
49
  return ["upper", "lower", "title", "sentence", "toggle"];
50
50
  };
51
+
52
+ // 2026-10-17 Shift+F3 cycles the selection's case as Word does: lowercase -> Title Case -> UPPERCASE -> lowercase,
53
+ // the next step chosen from the text as it is now. tools/keyboard/format-case-keys.mjs
54
+ (editor.bindDocumentEvent ? function (fn) { editor.bindDocumentEvent("keydown", fn, true); } : function (fn) { editor.getDocument().addEventListener("keydown", fn, true); })(function (e) {
55
+ if (e.key !== "F3" || !e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) return;
56
+ var text = "";
57
+ try { text = String(editor.getSelection().toString() || ""); } catch (x) { text = ""; }
58
+ if (!/\S/.test(text)) return;
59
+ e.preventDefault();
60
+ var next = text === text.toUpperCase() ? "lower" : text === transform(text, "title") ? "upper" : "title";
61
+ obj.Apply(next);
62
+ });
51
63
  };
52
64
 
53
65
  function getDoc() { try { return editor.getDocument(); } catch (e) { return null; } }
@@ -194,29 +206,30 @@ function RTE_Plugin_ChangeCase() {
194
206
  var sel;
195
207
  try { sel = editor.getSelection(); } catch (e) { return false; }
196
208
  if (!doc || !sel || sel.rangeCount === 0) return false;
209
+ // 2026-10-14 Suggesting mode: a case change rewrites text and is not tracked yet, so the track hook refuses it.
210
+ // tools/review/suggesting-structure-audit.mjs
211
+ if (editor.__trackHook && editor.__trackHook("refuse", { message: "Suggesting is on, so the case was not changed. Turn suggesting off to change it." }) === true) return false;
212
+
213
+ // 2026-10-03 A cell selection (cells marked by a drag, Shift+click or Shift+Arrow) changes
214
+ // EVERY selected cell, as Google Docs does; the caret's word was all that changed before - and
215
+ // a drag leaves the caret on none. tools/tables/cell-selection-keys.mjs
216
+ var marked = doc.querySelectorAll("[__rte_selected_cell]");
217
+ if (marked.length > 1) {
218
+ var anyCell = false;
219
+ for (var mc = 0; mc < marked.length; mc++) {
220
+ var cr = doc.createRange();
221
+ cr.selectNodeContents(marked[mc]);
222
+ if (applyToRange(cr, doc, mode)) anyCell = true;
223
+ }
224
+ if (anyCell) fireChange();
225
+ return anyCell;
226
+ }
197
227
 
198
228
  var range = sel.getRangeAt(0);
199
229
  if (range.collapsed && !expandToWord(range)) return false;
200
230
 
201
- var nodes = textNodesInRange(range, doc);
202
- if (!nodes.length) return false;
203
-
204
- // Join -> transform -> write back, so context-sensitive modes see the
205
- // whole selection rather than one <strong>'s worth of it.
206
- var joined = "";
207
- for (var i = 0; i < nodes.length; i++) joined += nodes[i].nodeValue;
208
- var result = transform(joined, mode);
209
- if (result === joined) return false;
210
- // Defensive: every mode is length-preserving, but if a future mode is
211
- // not, bail rather than corrupt the document by mis-slicing.
212
- if (result.length !== joined.length) return false;
213
-
214
- var at = 0;
215
- for (var j = 0; j < nodes.length; j++) {
216
- var len = nodes[j].nodeValue.length;
217
- nodes[j].nodeValue = result.substr(at, len);
218
- at += len;
219
- }
231
+ var nodes = applyToRange(range, doc, mode);
232
+ if (!nodes) return false;
220
233
 
221
234
  // Restore the selection over the transformed run.
222
235
  try {
@@ -231,6 +244,46 @@ function RTE_Plugin_ChangeCase() {
231
244
  return true;
232
245
  };
233
246
 
247
+ // Transforms the text in range; returns its text nodes, or null when nothing changed.
248
+ function applyToRange(range, doc, mode) {
249
+ var nodes = textNodesInRange(range, doc);
250
+ if (!nodes.length) return null;
251
+
252
+ // Join -> transform -> write back, so context-sensitive modes see the
253
+ // whole selection rather than one <strong>'s worth of it.
254
+ var joined = "";
255
+ for (var i = 0; i < nodes.length; i++) joined += nodes[i].nodeValue;
256
+ // 2026-10-02 Case mapping is NOT always length-preserving: German "\u00df" uppercases to "SS",
257
+ // ligatures like "\ufb01" to "FI". The old guard then refused the WHOLE change, so a selection
258
+ // containing one sharp s could never be uppercased. The modes are decided on a proxy where
259
+ // every such character is a plain x / X (length-preserving), then each ORIGINAL character
260
+ // gets the case its proxy received, written back node by node so lengths may change.
261
+ // tools/formatting/change-case.mjs
262
+ var proxy = "";
263
+ for (var pi = 0; pi < joined.length; pi++) {
264
+ var ch0 = joined.charAt(pi);
265
+ proxy += (ch0.toUpperCase().length !== 1 || ch0.toLowerCase().length !== 1) ? (ch0 === ch0.toLowerCase() ? "x" : "X") : ch0;
266
+ }
267
+ var decided = transform(proxy, mode);
268
+ if (decided.length !== proxy.length) return null;
269
+ var pieces = [], changed = false;
270
+ for (var qi = 0; qi < joined.length; qi++) {
271
+ var orig = joined.charAt(qi), was = proxy.charAt(qi), now = decided.charAt(qi), out = orig;
272
+ if (now !== was) out = (now === was.toUpperCase()) ? orig.toUpperCase() : orig.toLowerCase();
273
+ if (out !== orig) changed = true;
274
+ pieces.push(out);
275
+ }
276
+ if (!changed) return null;
277
+
278
+ var at = 0;
279
+ for (var j = 0; j < nodes.length; j++) {
280
+ var len = nodes[j].nodeValue.length;
281
+ nodes[j].nodeValue = pieces.slice(at, at + len).join("");
282
+ at += len;
283
+ }
284
+ return nodes;
285
+ }
286
+
234
287
  function fireChange() {
235
288
  try { if (typeof editor.updateDesign === "function") editor.updateDesign(); } catch (e) {}
236
289
  try { if (typeof editor.fireChange === "function") editor.fireChange(); } catch (e) {}