@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.
- package/README.md +173 -10
- package/angular/build-manifest.json +23 -0
- package/angular/index.d.ts +71 -76
- package/angular/index.mjs +2 -0
- package/angular/package.json +4 -0
- package/headless/index.d.ts +3 -1
- package/headless/index.js +72 -16
- package/index.d.ts +33 -54
- package/integrations/initialization-scope.js +27 -0
- package/integrations/native-mount.js +30 -0
- package/integrations/shared.d.ts +23 -1
- package/integrations/shared.js +58 -22
- package/package.json +25 -3
- package/react/index.js +118 -37
- package/react/index.mjs +29 -0
- package/richtexteditor/all_plugins.js +7113 -1111
- package/richtexteditor/all_plugins.min.js +62 -59
- package/richtexteditor/lang/emoji/LICENSE-CLDR.txt +41 -0
- package/richtexteditor/lang/emoji/rte-emoji-de.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-es.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-fr.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-it.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ja.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ko.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-nl.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-pt-pt.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-pt.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ru.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-zh-Hans.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-zh-Hant.js +3 -0
- package/richtexteditor/lang/rte-lang-af.js +1 -0
- package/richtexteditor/lang/rte-lang-ar.js +1 -0
- package/richtexteditor/lang/rte-lang-bg.js +1 -0
- package/richtexteditor/lang/rte-lang-bn.js +1 -0
- package/richtexteditor/lang/rte-lang-bs.js +1 -0
- package/richtexteditor/lang/rte-lang-ca.js +1 -0
- package/richtexteditor/lang/rte-lang-cs.js +1 -0
- package/richtexteditor/lang/rte-lang-cy.js +1 -0
- package/richtexteditor/lang/rte-lang-da.js +1 -0
- package/richtexteditor/lang/rte-lang-de.js +1017 -2
- package/richtexteditor/lang/rte-lang-el.js +1 -0
- package/richtexteditor/lang/rte-lang-en.js +1 -0
- package/richtexteditor/lang/rte-lang-es.js +1023 -2
- package/richtexteditor/lang/rte-lang-et.js +1 -0
- package/richtexteditor/lang/rte-lang-fa.js +1 -0
- package/richtexteditor/lang/rte-lang-fi.js +1 -0
- package/richtexteditor/lang/rte-lang-fil.js +1 -0
- package/richtexteditor/lang/rte-lang-fj.js +1 -0
- package/richtexteditor/lang/rte-lang-fr.js +1023 -2
- package/richtexteditor/lang/rte-lang-ga.js +1 -0
- package/richtexteditor/lang/rte-lang-gu.js +1 -0
- package/richtexteditor/lang/rte-lang-he.js +1 -0
- package/richtexteditor/lang/rte-lang-hi.js +1 -0
- package/richtexteditor/lang/rte-lang-hr.js +1 -0
- package/richtexteditor/lang/rte-lang-ht.js +1 -0
- package/richtexteditor/lang/rte-lang-hu.js +1 -0
- package/richtexteditor/lang/rte-lang-id.js +1 -0
- package/richtexteditor/lang/rte-lang-is.js +1 -0
- package/richtexteditor/lang/rte-lang-it.js +1023 -2
- package/richtexteditor/lang/rte-lang-ja.js +1023 -2
- package/richtexteditor/lang/rte-lang-kn.js +1 -0
- package/richtexteditor/lang/rte-lang-ko.js +1023 -2
- package/richtexteditor/lang/rte-lang-lt.js +1 -0
- package/richtexteditor/lang/rte-lang-lv.js +1 -0
- package/richtexteditor/lang/rte-lang-mg.js +1 -0
- package/richtexteditor/lang/rte-lang-mi.js +1 -0
- package/richtexteditor/lang/rte-lang-ml.js +1 -0
- package/richtexteditor/lang/rte-lang-mr.js +1 -0
- package/richtexteditor/lang/rte-lang-ms.js +1 -0
- package/richtexteditor/lang/rte-lang-mt.js +1 -0
- package/richtexteditor/lang/rte-lang-mww.js +1 -0
- package/richtexteditor/lang/rte-lang-nb.js +1 -0
- package/richtexteditor/lang/rte-lang-nl.js +1023 -2
- package/richtexteditor/lang/rte-lang-otq.js +1 -0
- package/richtexteditor/lang/rte-lang-pa.js +1 -0
- package/richtexteditor/lang/rte-lang-pl.js +1 -0
- package/richtexteditor/lang/rte-lang-pt-pt.js +1023 -2
- package/richtexteditor/lang/rte-lang-pt.js +1023 -2
- package/richtexteditor/lang/rte-lang-ro.js +1 -0
- package/richtexteditor/lang/rte-lang-ru.js +1023 -2
- package/richtexteditor/lang/rte-lang-sk.js +1 -0
- package/richtexteditor/lang/rte-lang-sl.js +1 -0
- package/richtexteditor/lang/rte-lang-sm.js +1 -0
- package/richtexteditor/lang/rte-lang-sr-Cyrl.js +1 -0
- package/richtexteditor/lang/rte-lang-sr-Latn.js +1 -0
- package/richtexteditor/lang/rte-lang-sv.js +1 -0
- package/richtexteditor/lang/rte-lang-sw.js +1 -0
- package/richtexteditor/lang/rte-lang-ta.js +1 -0
- package/richtexteditor/lang/rte-lang-te.js +1 -0
- package/richtexteditor/lang/rte-lang-th.js +1 -0
- package/richtexteditor/lang/rte-lang-tlh-Latn.js +1 -0
- package/richtexteditor/lang/rte-lang-tlh-Piqd.js +1 -0
- package/richtexteditor/lang/rte-lang-to.js +1 -0
- package/richtexteditor/lang/rte-lang-tr.js +1 -0
- package/richtexteditor/lang/rte-lang-ty.js +1 -0
- package/richtexteditor/lang/rte-lang-uk.js +1 -0
- package/richtexteditor/lang/rte-lang-ur.js +1 -0
- package/richtexteditor/lang/rte-lang-vi.js +1 -0
- package/richtexteditor/lang/rte-lang-yua.js +1 -0
- package/richtexteditor/lang/rte-lang-zh-Hans.js +1017 -2
- package/richtexteditor/lang/rte-lang-zh-Hant.js +1017 -2
- package/richtexteditor/plugins/a11yenhance.js +2 -1
- package/richtexteditor/plugins/a11yenhance.min.js +1 -1
- package/richtexteditor/plugins/accessibilitychecker.js +252 -60
- package/richtexteditor/plugins/accessibilitychecker.min.js +1 -1
- package/richtexteditor/plugins/aitoolkit.js +966 -303
- package/richtexteditor/plugins/aitoolkit.min.js +7 -7
- package/richtexteditor/plugins/all_plugins.js +7113 -1111
- package/richtexteditor/plugins/all_plugins.min.js +62 -59
- package/richtexteditor/plugins/autocorrect.js +66 -31
- package/richtexteditor/plugins/autocorrect.min.js +1 -1
- package/richtexteditor/plugins/autoembed.js +17 -0
- package/richtexteditor/plugins/autoembed.min.js +1 -1
- package/richtexteditor/plugins/blocktypes.js +18 -9
- package/richtexteditor/plugins/blocktypes.min.js +1 -1
- package/richtexteditor/plugins/bookmarkcard.js +12 -5
- package/richtexteditor/plugins/bookmarkcard.min.js +2 -2
- package/richtexteditor/plugins/changecase.js +72 -19
- package/richtexteditor/plugins/changecase.min.js +1 -1
- package/richtexteditor/plugins/charlimit.js +62 -2
- package/richtexteditor/plugins/charlimit.min.js +2 -2
- package/richtexteditor/plugins/comments.js +458 -59
- package/richtexteditor/plugins/comments.min.js +4 -3
- package/richtexteditor/plugins/contentminimap.js +25 -6
- package/richtexteditor/plugins/contentminimap.min.js +1 -1
- package/richtexteditor/plugins/crossreference.js +1 -1
- package/richtexteditor/plugins/crossreference.min.js +1 -1
- package/richtexteditor/plugins/dialoga11y.js +26 -4
- package/richtexteditor/plugins/dialoga11y.min.js +1 -1
- package/richtexteditor/plugins/dictation.js +1 -1
- package/richtexteditor/plugins/documentimport.js +220 -51
- package/richtexteditor/plugins/documentimport.min.js +4 -4
- package/richtexteditor/plugins/documentoutline.js +88 -38
- package/richtexteditor/plugins/documentoutline.min.js +1 -1
- package/richtexteditor/plugins/docxexport.js +204 -32
- package/richtexteditor/plugins/docxexport.min.js +2 -2
- package/richtexteditor/plugins/draghandle.js +267 -3
- package/richtexteditor/plugins/draghandle.min.js +1 -1
- package/richtexteditor/plugins/emailtoolkit.js +28 -14
- package/richtexteditor/plugins/emailtoolkit.min.js +1 -1
- package/richtexteditor/plugins/emojiautocomplete.js +110 -56
- package/richtexteditor/plugins/emojiautocomplete.min.js +1 -1
- package/richtexteditor/plugins/footnotes.js +65 -11
- package/richtexteditor/plugins/footnotes.min.js +1 -1
- package/richtexteditor/plugins/formatpainter.js +10 -0
- package/richtexteditor/plugins/formatpainter.min.js +1 -1
- package/richtexteditor/plugins/formattingmarks.js +53 -8
- package/richtexteditor/plugins/formattingmarks.min.js +1 -1
- package/richtexteditor/plugins/gapcursor.js +60 -0
- package/richtexteditor/plugins/gapcursor.min.js +1 -1
- package/richtexteditor/plugins/ghostcomplete.js +1 -1
- package/richtexteditor/plugins/html2pdf.js +1 -1
- package/richtexteditor/plugins/html2pdf.min.js +1 -1
- package/richtexteditor/plugins/imageeditor.js +12 -6
- package/richtexteditor/plugins/imageeditor.min.js +1 -1
- package/richtexteditor/plugins/importstyles.js +1 -1
- package/richtexteditor/plugins/inlinecode.js +25 -0
- package/richtexteditor/plugins/inlinecode.min.js +1 -1
- package/richtexteditor/plugins/insertcode.js +21 -3
- package/richtexteditor/plugins/insertcode.min.js +4 -4
- package/richtexteditor/plugins/insertemoji.js +112 -15
- package/richtexteditor/plugins/insertemoji.min.js +1 -1
- package/richtexteditor/plugins/insertgallery.js +42 -36
- package/richtexteditor/plugins/insertgallery.min.js +1 -1
- package/richtexteditor/plugins/inserttemplate.js +33 -17
- package/richtexteditor/plugins/inserttemplate.min.js +1 -1
- package/richtexteditor/plugins/keyboarda11y.js +66 -3
- package/richtexteditor/plugins/keyboarda11y.min.js +1 -1
- package/richtexteditor/plugins/layouttable.js +20 -0
- package/richtexteditor/plugins/layouttable.min.js +1 -1
- package/richtexteditor/plugins/linkchecker.js +29 -9
- package/richtexteditor/plugins/linkchecker.min.js +1 -1
- package/richtexteditor/plugins/localdraft.js +51 -7
- package/richtexteditor/plugins/localdraft.min.js +1 -1
- package/richtexteditor/plugins/markdownexport.js +159 -0
- package/richtexteditor/plugins/markdownexport.min.js +2 -2
- package/richtexteditor/plugins/mathdialog.js +11 -5
- package/richtexteditor/plugins/mathdialog.min.js +1 -1
- package/richtexteditor/plugins/mentionplugin.js +88 -25
- package/richtexteditor/plugins/mentionplugin.min.js +1 -1
- package/richtexteditor/plugins/mermaiddiagram.js +9 -3
- package/richtexteditor/plugins/mermaiddiagram.min.js +2 -2
- package/richtexteditor/plugins/multilevellist.js +4 -0
- package/richtexteditor/plugins/multilevellist.min.js +1 -1
- package/richtexteditor/plugins/pdfexport.js +235 -35
- package/richtexteditor/plugins/pdfexport.min.js +12 -12
- package/richtexteditor/plugins/permanentpen.js +3 -3
- package/richtexteditor/plugins/permanentpen.min.js +1 -1
- package/richtexteditor/plugins/readabilitystats.js +25 -11
- package/richtexteditor/plugins/readabilitystats.min.js +1 -1
- package/richtexteditor/plugins/readaloud.js +29 -15
- package/richtexteditor/plugins/readaloud.min.js +1 -1
- package/richtexteditor/plugins/restrictedediting.js +166 -0
- package/richtexteditor/plugins/restrictedediting.min.js +2 -2
- package/richtexteditor/plugins/revisionhistory.js +169 -37
- package/richtexteditor/plugins/revisionhistory.min.js +3 -3
- package/richtexteditor/plugins/rubyannotation.js +19 -9
- package/richtexteditor/plugins/rubyannotation.min.js +1 -1
- package/richtexteditor/plugins/sanitizer.js +86 -4
- package/richtexteditor/plugins/sanitizer.min.js +1 -1
- package/richtexteditor/plugins/slashcommand.js +30 -16
- package/richtexteditor/plugins/slashcommand.min.js +2 -2
- package/richtexteditor/plugins/smartchips.js +36 -22
- package/richtexteditor/plugins/smartchips.min.js +2 -2
- package/richtexteditor/plugins/spellcheck.js +17 -8
- package/richtexteditor/plugins/spellcheck.min.js +2 -2
- package/richtexteditor/plugins/stateinspector.js +19 -9
- package/richtexteditor/plugins/stateinspector.min.js +2 -2
- package/richtexteditor/plugins/structured-content-bridge.js +56 -24
- package/richtexteditor/plugins/structured-content-bridge.min.js +7 -7
- package/richtexteditor/plugins/tableofcontents.js +5 -2
- package/richtexteditor/plugins/tableofcontents.min.js +1 -1
- package/richtexteditor/plugins/tabletools.js +388 -3
- package/richtexteditor/plugins/tabletools.min.js +1 -1
- package/richtexteditor/plugins/textdirection.js +18 -5
- package/richtexteditor/plugins/textdirection.min.js +1 -1
- package/richtexteditor/plugins/textpartlanguage.js +161 -32
- package/richtexteditor/plugins/textpartlanguage.min.js +1 -1
- package/richtexteditor/plugins/todolist.js +90 -6
- package/richtexteditor/plugins/todolist.min.js +1 -1
- package/richtexteditor/plugins/trackedchanges.js +1812 -25
- package/richtexteditor/plugins/trackedchanges.min.js +5 -3
- package/richtexteditor/plugins/wordexport.js +2 -2
- package/richtexteditor/plugins/yjscollab.js +9 -4
- package/richtexteditor/plugins/yjscollab.min.js +1 -1
- package/richtexteditor/plugins/zz_richtextbox_dialog_style.js +22 -13
- package/richtexteditor/plugins/zz_richtextbox_dialog_style.min.js +1 -1
- package/richtexteditor/rte-config.js +131 -50
- package/richtexteditor/rte-headless.js +19 -4
- package/richtexteditor/rte-webcomponent.js +89 -16
- package/richtexteditor/rte.js +133 -52
- package/richtexteditor/runtime/colorpicker_more_ns.htm +93 -16
- package/scripts/build-angular.mjs +97 -0
- package/svelte/index.d.ts +2 -1
- package/svelte/index.js +80 -9
- package/vue/index.js +130 -34
- package/angular/component.ts +0 -297
- 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: "
|
|
77
|
-
{ from: "-->", to: "
|
|
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
|
-
|
|
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 === "
|
|
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(\[{
|
|
233
|
-
var repl = ch === '"' ? (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\)\]"'
|
|
244
|
-
if (!ok && /\s/.test(before)) ok = /[\w\)\]"'
|
|
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'
|
|
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
|
-
|
|
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 === "
|
|
304
|
-
|
|
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
|
|
348
|
-
out = out.replace(/(^|[\s(\[{])'/g, "$1
|
|
349
|
-
out = out.replace(/(\w)--(\w)/g, "$1
|
|
350
|
-
out = out.replace(/(\w)\s--\s(\w)/g, "$1
|
|
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
|
|
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
|
|
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,""");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
|
-
|
|
119
|
-
|
|
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()}),
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}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
|
|
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,
|
|
2
|
-
`);try{var t=
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}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 =
|
|
202
|
-
if (!nodes
|
|
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) {}
|