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