@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
|
@@ -24,6 +24,13 @@ function RTE_Plugin_EmailToolkit() {
|
|
|
24
24
|
obj.PluginName = "EmailToolkit";
|
|
25
25
|
|
|
26
26
|
obj.InitConfig = function (argconfig) { config = argconfig; };
|
|
27
|
+
// 2026-10-18 the words read config.text_ keys (language packs), English as the fallback; {0} / {1} fill a template.
|
|
28
|
+
// tools/i18n/plugin-bars-language.mjs
|
|
29
|
+
function pText(key, fallback) {
|
|
30
|
+
var s = (config && config["text_" + key]) || fallback;
|
|
31
|
+
for (var i = 2; i < arguments.length; i++) s = s.split("{" + (i - 2) + "}").join(String(arguments[i]));
|
|
32
|
+
return s;
|
|
33
|
+
}
|
|
27
34
|
|
|
28
35
|
obj.InitEditor = function (argeditor) {
|
|
29
36
|
editor = argeditor;
|
|
@@ -113,12 +120,19 @@ function RTE_Plugin_EmailToolkit() {
|
|
|
113
120
|
var editable = editor.getEditable();
|
|
114
121
|
var editdoc = editor.getDocument();
|
|
115
122
|
var win = (editdoc && editdoc.defaultView) || window;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
// 2026-10-03 Built inside editor.runInSavedView: the inlining needs the LIVE DOM (computed
|
|
124
|
+
// styles), and the live DOM carries other plugins' on-screen state - with merge-field preview
|
|
125
|
+
// on, the e-mail got the SAMPLE data ("Dear Ada Lovelace") instead of the template's fields.
|
|
126
|
+
// tools/markdown/plugin-chrome-exports.mjs
|
|
127
|
+
var build = function () {
|
|
128
|
+
var container = editdoc.createElement("div");
|
|
129
|
+
for (var i = 0; i < editable.childNodes.length; i++) {
|
|
130
|
+
var c = cloneInlined(editable.childNodes[i], win);
|
|
131
|
+
if (c) container.appendChild(c);
|
|
132
|
+
}
|
|
133
|
+
return container.innerHTML;
|
|
134
|
+
};
|
|
135
|
+
var inner = typeof editor.runInSavedView === "function" ? editor.runInSavedView(build) : build();
|
|
122
136
|
var wrap = options.wrap !== false;
|
|
123
137
|
if (!wrap) return inner;
|
|
124
138
|
var width = options.width || config.emailWrapWidth || 640;
|
|
@@ -136,30 +150,30 @@ function RTE_Plugin_EmailToolkit() {
|
|
|
136
150
|
var close = typeof dlg.close === "function" ? function () { dlg.close(); } : function () { editor.closeCurrentPopup(); };
|
|
137
151
|
var wrap = append(dlg, "div", "", "rte-email-export");
|
|
138
152
|
append(wrap, "div", "", "rte-email-export-copy").innerText =
|
|
139
|
-
"Inline-styled HTML for email clients (class/style blocks resolved to inline styles). Copy and paste into your email tool.";
|
|
153
|
+
pText("em_copy", "Inline-styled HTML for email clients (class/style blocks resolved to inline styles). Copy and paste into your email tool.");
|
|
140
154
|
var ta = append(wrap, "textarea", "", "rte-email-export-code");
|
|
141
155
|
ta.value = html;
|
|
142
156
|
ta.readOnly = true;
|
|
143
|
-
ta.setAttribute("aria-label", "Inline-styled email HTML");
|
|
157
|
+
ta.setAttribute("aria-label", pText("em_code", "Inline-styled email HTML"));
|
|
144
158
|
var status = append(wrap, "div", "", "rte-email-export-status");
|
|
145
159
|
status.setAttribute("role", "status");
|
|
146
160
|
status.setAttribute("aria-live", "polite");
|
|
147
|
-
status.textContent = "Ready to copy "
|
|
161
|
+
status.textContent = pText("em_ready", "Ready to copy {0} characters.", html.length);
|
|
148
162
|
var foot = append(wrap, "div", "", "rte-email-export-footer");
|
|
149
163
|
var copyBtn = append(foot, "button", "", "rte-email-export-button rte-email-export-button-primary");
|
|
150
|
-
copyBtn.type = "button"; copyBtn.textContent = "Copy";
|
|
164
|
+
copyBtn.type = "button"; copyBtn.textContent = pText("copy", "Copy");
|
|
151
165
|
copyBtn.onclick = function () {
|
|
152
166
|
ta.select();
|
|
153
167
|
try {
|
|
154
168
|
if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(ta.value); }
|
|
155
169
|
else { dlg.ownerDocument.execCommand("copy"); }
|
|
156
|
-
copyBtn.textContent = "Copied";
|
|
157
|
-
status.textContent = "Copied email HTML to the clipboard.";
|
|
158
|
-
setTimeout(function () { copyBtn.textContent = "Copy"; status.textContent = "Ready to copy "
|
|
170
|
+
copyBtn.textContent = pText("em_copied", "Copied");
|
|
171
|
+
status.textContent = pText("em_copieddone", "Copied email HTML to the clipboard.");
|
|
172
|
+
setTimeout(function () { copyBtn.textContent = pText("copy", "Copy"); status.textContent = pText("em_ready", "Ready to copy {0} characters.", html.length); }, 1400);
|
|
159
173
|
} catch (e) { /* ignore */ }
|
|
160
174
|
};
|
|
161
175
|
var closeBtn = append(foot, "button", "", "rte-email-export-button");
|
|
162
|
-
closeBtn.type = "button"; closeBtn.textContent = "Close"; closeBtn.onclick = close;
|
|
176
|
+
closeBtn.type = "button"; closeBtn.textContent = pText("close", "Close"); closeBtn.onclick = close;
|
|
163
177
|
setTimeout(function () { ta.focus(); }, 0);
|
|
164
178
|
};
|
|
165
179
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_emailtoolkit=RTE_Plugin_EmailToolkit,RTE_DefaultConfig.emailInlineProperties=RTE_DefaultConfig.emailInlineProperties||["color","background-color","font-family","font-size","font-weight","font-style","text-decoration","text-align","line-height","margin-top","margin-bottom","margin-left","margin-right","padding-top","padding-bottom","padding-left","padding-right","border","border-radius","vertical-align","list-style-type","width"],RTE_DefaultConfig.emailWrapWidth=RTE_DefaultConfig.emailWrapWidth||640;function RTE_Plugin_EmailToolkit(){var f=this,
|
|
1
|
+
window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_emailtoolkit=RTE_Plugin_EmailToolkit,RTE_DefaultConfig.emailInlineProperties=RTE_DefaultConfig.emailInlineProperties||["color","background-color","font-family","font-size","font-weight","font-style","text-decoration","text-align","line-height","margin-top","margin-bottom","margin-left","margin-right","padding-top","padding-bottom","padding-left","padding-right","border","border-radius","vertical-align","list-style-type","width"],RTE_DefaultConfig.emailWrapWidth=RTE_DefaultConfig.emailWrapWidth||640;function RTE_Plugin_EmailToolkit(){var f=this,p,u;f.PluginName="EmailToolkit",f.InitConfig=function(e){p=e};function c(e,n){for(var t=p&&p["text_"+e]||n,i=2;i<arguments.length;i++)t=t.split("{"+(i-2)+"}").join(String(arguments[i]));return t}f.InitEditor=function(e){u=e,u.getEmailHTML=function(n){return f.BuildEmailHTML(n||{})},u.attachEvent("exec_command_emailexport",function(n){n.returnValue=!0,f.OpenEmailExport()})};function s(e,n,t,i){var r=e.ownerDocument.createElement(n);return t&&(r.style.cssText=t),i&&(r.className=i),e.appendChild(r),r}function y(e,n){if(!n)return!0;var t=n.trim().toLowerCase();return t==="normal"||t==="auto"||t==="none"||t==="0px"||t==="0"?!(e==="list-style-type"&&t==="none"):e==="background-color"&&(t==="rgba(0, 0, 0, 0)"||t==="transparent")?!0:e==="color"&&t==="rgb(0, 0, 0)"?!1:e==="text-decoration"&&t.indexOf("none")===0||e==="border"&&(t.indexOf("0px")===0||t.indexOf("none")!==-1&&t.indexOf("0px")!==-1)||e==="vertical-align"&&t==="baseline"||e==="font-weight"&&t==="400"||e==="font-style"&&t==="normal"||e==="text-align"&&(t==="start"||t==="left")}var x={UL:1,OL:1,LI:1};function b(e,n){for(var t=n.getComputedStyle(e),i=p.emailInlineProperties||[],r=[],o=0;o<i.length;o++){var l=i[o],a;try{a=t.getPropertyValue(l)}catch{a=""}a==null||a===""||y(l,a)||l==="width"&&e.nodeName!=="TABLE"&&e.nodeName!=="IMG"&&e.nodeName!=="TD"&&e.nodeName!=="TH"||l==="list-style-type"&&!x[e.nodeName]||r.push(l+":"+a)}return r.join(";")}var h={SCRIPT:1,STYLE:1,LINK:1,META:1};function g(e,n){if(e.nodeType===3)return e.ownerDocument.createTextNode(e.data);if(e.nodeType!==1||h[e.nodeName])return null;for(var t=e.ownerDocument,i=t.createElement(e.nodeName),r=0;r<e.attributes.length;r++){var o=e.attributes[r],l=o.name.toLowerCase();l==="class"||l==="id"||l==="contenteditable"||l==="style"||l.indexOf("data-rte-")===0||i.setAttribute(o.name,o.value)}var a=b(e,n);a&&i.setAttribute("style",a);for(var d=0;d<e.childNodes.length;d++){var m=g(e.childNodes[d],n);m&&i.appendChild(m)}return i}f.BuildEmailHTML=function(e){var n=u.getEditable(),t=u.getDocument(),i=t&&t.defaultView||window,r=function(){for(var d=t.createElement("div"),m=0;m<n.childNodes.length;m++){var v=g(n.childNodes[m],i);v&&d.appendChild(v)}return d.innerHTML},o=typeof u.runInSavedView=="function"?u.runInSavedView(r):r(),l=e.wrap!==!1;if(!l)return o;var a=e.width||p.emailWrapWidth||640;return'<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse"><tr><td align="center" style="padding:0"><table role="presentation" width="'+a+'" cellpadding="0" cellspacing="0" style="border-collapse:collapse;max-width:'+a+'px;width:100%"><tr><td style="padding:16px;font-family:Arial,Helvetica,sans-serif">'+o+"</td></tr></table></td></tr></table>"},f.OpenEmailExport=function(){var e=f.BuildEmailHTML({}),n=u.createDialog(u.getLangText&&u.getLangText("emailexporttitle")||"Export email HTML","rte-dialog-email"),t=typeof n.close=="function"?function(){n.close()}:function(){u.closeCurrentPopup()},i=s(n,"div","","rte-email-export");s(i,"div","","rte-email-export-copy").innerText=c("em_copy","Inline-styled HTML for email clients (class/style blocks resolved to inline styles). Copy and paste into your email tool.");var r=s(i,"textarea","","rte-email-export-code");r.value=e,r.readOnly=!0,r.setAttribute("aria-label",c("em_code","Inline-styled email HTML"));var o=s(i,"div","","rte-email-export-status");o.setAttribute("role","status"),o.setAttribute("aria-live","polite"),o.textContent=c("em_ready","Ready to copy {0} characters.",e.length);var l=s(i,"div","","rte-email-export-footer"),a=s(l,"button","","rte-email-export-button rte-email-export-button-primary");a.type="button",a.textContent=c("copy","Copy"),a.onclick=function(){r.select();try{navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r.value):n.ownerDocument.execCommand("copy"),a.textContent=c("em_copied","Copied"),o.textContent=c("em_copieddone","Copied email HTML to the clipboard."),setTimeout(function(){a.textContent=c("copy","Copy"),o.textContent=c("em_ready","Ready to copy {0} characters.",e.length)},1400)}catch{}};var d=s(l,"button","","rte-email-export-button");d.type="button",d.textContent=c("close","Close"),d.onclick=t,setTimeout(function(){r.focus()},0)}}
|
|
@@ -12,61 +12,61 @@ RTE_DefaultConfig.plugin_emojiautocomplete = RTE_Plugin_EmojiAutocomplete;
|
|
|
12
12
|
RTE_DefaultConfig.emojiAutocompleteEnabled = (typeof RTE_DefaultConfig.emojiAutocompleteEnabled === "undefined")
|
|
13
13
|
? true : RTE_DefaultConfig.emojiAutocompleteEnabled;
|
|
14
14
|
RTE_DefaultConfig.emojiShortcodes = RTE_DefaultConfig.emojiShortcodes || {
|
|
15
|
-
smile: "
|
|
16
|
-
sweat_smile: "
|
|
17
|
-
kissing_heart: "
|
|
18
|
-
neutral_face: "
|
|
19
|
-
grimacing: "
|
|
20
|
-
face_with_thermometer: "
|
|
21
|
-
exploding_head: "
|
|
22
|
-
worried: "
|
|
23
|
-
fearful: "
|
|
24
|
-
disappointed: "
|
|
25
|
-
cursing_face: "
|
|
26
|
-
ghost: "
|
|
27
|
-
speak_no_evil: "
|
|
28
|
-
heart: "
|
|
29
|
-
purple_heart: "
|
|
30
|
-
heartpulse: "
|
|
31
|
-
"+1": "
|
|
32
|
-
facepunch: "
|
|
33
|
-
muscle: "
|
|
34
|
-
crossed_fingers: "
|
|
35
|
-
fire: "
|
|
36
|
-
dizzy: "
|
|
37
|
-
rainbow: "
|
|
38
|
-
tada: "
|
|
39
|
-
gem: "
|
|
40
|
-
"100": "
|
|
41
|
-
warning: "
|
|
42
|
-
mag: "
|
|
43
|
-
coffee: "
|
|
44
|
-
hamburger: "
|
|
45
|
-
apple: "
|
|
46
|
-
dog: "
|
|
47
|
-
tiger: "
|
|
48
|
-
penguin: "
|
|
49
|
-
book: "
|
|
50
|
-
chart: "
|
|
51
|
-
paperclip: "
|
|
52
|
-
bomb: "
|
|
53
|
-
credit_card: "
|
|
54
|
-
microscope: "
|
|
55
|
-
computer: "
|
|
56
|
-
seedling: "
|
|
57
|
-
four_leaf_clover: "
|
|
58
|
-
musical_note: "
|
|
59
|
-
soccer: "
|
|
60
|
-
dart: "
|
|
61
|
-
sos: "
|
|
62
|
-
arrow_up: "
|
|
63
|
-
bangbang: "
|
|
15
|
+
smile: "\ud83d\ude04", smiley: "\ud83d\ude03", grin: "\ud83d\ude01", laughing: "\ud83d\ude06", satisfied: "\ud83d\ude06", joy: "\ud83d\ude02", rofl: "\ud83e\udd23",
|
|
16
|
+
sweat_smile: "\ud83d\ude05", wink: "\ud83d\ude09", blush: "\ud83d\ude0a", innocent: "\ud83d\ude07", heart_eyes: "\ud83d\ude0d", star_struck: "\ud83e\udd29",
|
|
17
|
+
kissing_heart: "\ud83d\ude18", yum: "\ud83d\ude0b", stuck_out_tongue: "\ud83d\ude1b", zany: "\ud83e\udd2a", thinking: "\ud83e\udd14", shush: "\ud83e\udd2b",
|
|
18
|
+
neutral_face: "\ud83d\ude10", expressionless: "\ud83d\ude11", no_mouth: "\ud83d\ude36", smirk: "\ud83d\ude0f", unamused: "\ud83d\ude12", roll_eyes: "\ud83d\ude44",
|
|
19
|
+
grimacing: "\ud83d\ude2c", relieved: "\ud83d\ude0c", pensive: "\ud83d\ude14", sleepy: "\ud83d\ude2a", sleeping: "\ud83d\ude34", mask: "\ud83d\ude37",
|
|
20
|
+
face_with_thermometer: "\ud83e\udd12", nauseated_face: "\ud83e\udd22", sneezing_face: "\ud83e\udd27", dizzy_face: "\ud83d\ude35",
|
|
21
|
+
exploding_head: "\ud83e\udd2f", cowboy: "\ud83e\udd20", sunglasses: "\ud83d\ude0e", nerd: "\ud83e\udd13", monocle: "\ud83e\uddd0", confused: "\ud83d\ude15",
|
|
22
|
+
worried: "\ud83d\ude1f", slightly_frowning_face: "\ud83d\ude41", open_mouth: "\ud83d\ude2e", astonished: "\ud83d\ude32", flushed: "\ud83d\ude33",
|
|
23
|
+
fearful: "\ud83d\ude28", cold_sweat: "\ud83d\ude30", cry: "\ud83d\ude22", sob: "\ud83d\ude2d", scream: "\ud83d\ude31", confounded: "\ud83d\ude16", persevere: "\ud83d\ude23",
|
|
24
|
+
disappointed: "\ud83d\ude1e", sweat: "\ud83d\ude13", weary: "\ud83d\ude29", tired_face: "\ud83d\ude2b", triumph: "\ud83d\ude24", rage: "\ud83d\ude21", angry: "\ud83d\ude20",
|
|
25
|
+
cursing_face: "\ud83e\udd2c", smiling_imp: "\ud83d\ude08", imp: "\ud83d\udc7f", skull: "\ud83d\udc80", poop: "\ud83d\udca9", hankey: "\ud83d\udca9", clown: "\ud83e\udd21",
|
|
26
|
+
ghost: "\ud83d\udc7b", alien: "\ud83d\udc7d", robot: "\ud83e\udd16", heart_eyes_cat: "\ud83d\ude3b", see_no_evil: "\ud83d\ude48", hear_no_evil: "\ud83d\ude49",
|
|
27
|
+
speak_no_evil: "\ud83d\ude4a",
|
|
28
|
+
heart: "\u2764\ufe0f", orange_heart: "\ud83e\udde1", yellow_heart: "\ud83d\udc9b", green_heart: "\ud83d\udc9a", blue_heart: "\ud83d\udc99",
|
|
29
|
+
purple_heart: "\ud83d\udc9c", black_heart: "\ud83d\udda4", broken_heart: "\ud83d\udc94", two_hearts: "\ud83d\udc95", sparkling_heart: "\ud83d\udc96",
|
|
30
|
+
heartpulse: "\ud83d\udc97", cupid: "\ud83d\udc98", gift_heart: "\ud83d\udc9d", revolving_hearts: "\ud83d\udc9e", kiss: "\ud83d\udc8b",
|
|
31
|
+
"+1": "\ud83d\udc4d", thumbsup: "\ud83d\udc4d", "-1": "\ud83d\udc4e", thumbsdown: "\ud83d\udc4e", ok_hand: "\ud83d\udc4c", punch: "\ud83d\udc4a", fist: "\u270a",
|
|
32
|
+
facepunch: "\ud83d\udc4a", wave: "\ud83d\udc4b", raised_hand: "\u270b", raised_hands: "\ud83d\ude4c", pray: "\ud83d\ude4f", clap: "\ud83d\udc4f",
|
|
33
|
+
muscle: "\ud83d\udcaa", point_up: "\u261d\ufe0f", point_down: "\ud83d\udc47", point_left: "\ud83d\udc48", point_right: "\ud83d\udc49", v: "\u270c\ufe0f",
|
|
34
|
+
crossed_fingers: "\ud83e\udd1e", handshake: "\ud83e\udd1d", writing_hand: "\u270d\ufe0f", selfie: "\ud83e\udd33", nail_care: "\ud83d\udc85", eyes: "\ud83d\udc40",
|
|
35
|
+
fire: "\ud83d\udd25", star: "\u2b50", star2: "\ud83c\udf1f", sparkles: "\u2728", zap: "\u26a1", boom: "\ud83d\udca5", collision: "\ud83d\udca5",
|
|
36
|
+
dizzy: "\ud83d\udcab", sweat_drops: "\ud83d\udca6", droplet: "\ud83d\udca7", snowflake: "\u2744\ufe0f", sunny: "\u2600\ufe0f", cloud: "\u2601\ufe0f",
|
|
37
|
+
rainbow: "\ud83c\udf08", umbrella: "\u2614", ocean: "\ud83c\udf0a", sun_with_face: "\ud83c\udf1e", full_moon: "\ud83c\udf15", crescent_moon: "\ud83c\udf19",
|
|
38
|
+
tada: "\ud83c\udf89", confetti_ball: "\ud83c\udf8a", balloon: "\ud83c\udf88", gift: "\ud83c\udf81", trophy: "\ud83c\udfc6", medal: "\ud83c\udfc5", crown: "\ud83d\udc51",
|
|
39
|
+
gem: "\ud83d\udc8e", rocket: "\ud83d\ude80", airplane: "\u2708\ufe0f", car: "\ud83d\ude97", rotating_light: "\ud83d\udea8",
|
|
40
|
+
"100": "\ud83d\udcaf", white_check_mark: "\u2705", heavy_check_mark: "\u2714\ufe0f", ballot_box_with_check: "\u2611\ufe0f", x: "\u274c",
|
|
41
|
+
warning: "\u26a0\ufe0f", no_entry: "\u26d4", question: "\u2753", exclamation: "\u2757", bulb: "\ud83d\udca1", lock: "\ud83d\udd12", key: "\ud83d\udd11",
|
|
42
|
+
mag: "\ud83d\udd0d", bell: "\ud83d\udd14", recycle: "\u267b\ufe0f", heavy_plus_sign: "\u2795", heavy_minus_sign: "\u2796",
|
|
43
|
+
coffee: "\u2615", tea: "\ud83c\udf75", beer: "\ud83c\udf7a", beers: "\ud83c\udf7b", wine_glass: "\ud83c\udf77", cocktail: "\ud83c\udf78", pizza: "\ud83c\udf55",
|
|
44
|
+
hamburger: "\ud83c\udf54", fries: "\ud83c\udf5f", taco: "\ud83c\udf2e", cake: "\ud83c\udf82", birthday: "\ud83c\udf82", cookie: "\ud83c\udf6a", doughnut: "\ud83c\udf69",
|
|
45
|
+
apple: "\ud83c\udf4e", banana: "\ud83c\udf4c", strawberry: "\ud83c\udf53", avocado: "\ud83e\udd51", bread: "\ud83c\udf5e", cheese: "\ud83e\uddc0",
|
|
46
|
+
dog: "\ud83d\udc36", cat: "\ud83d\udc31", mouse: "\ud83d\udc2d", rabbit: "\ud83d\udc30", bear: "\ud83d\udc3b", panda_face: "\ud83d\udc3c", koala: "\ud83d\udc28",
|
|
47
|
+
tiger: "\ud83d\udc2f", lion: "\ud83e\udd81", cow: "\ud83d\udc2e", pig: "\ud83d\udc37", frog: "\ud83d\udc38", monkey_face: "\ud83d\udc35", chicken: "\ud83d\udc14",
|
|
48
|
+
penguin: "\ud83d\udc27", bird: "\ud83d\udc26", unicorn: "\ud83e\udd84", bee: "\ud83d\udc1d", bug: "\ud83d\udc1b", butterfly: "\ud83e\udd8b", snail: "\ud83d\udc0c",
|
|
49
|
+
book: "\ud83d\udcd6", books: "\ud83d\udcda", memo: "\ud83d\udcdd", pencil: "\ud83d\udcdd", email: "\u2709\ufe0f", envelope: "\u2709\ufe0f", calendar: "\ud83d\udcc5",
|
|
50
|
+
chart: "\ud83d\udcca", bar_chart: "\ud83d\udcca", chart_with_upwards_trend: "\ud83d\udcc8", clipboard: "\ud83d\udccb", pushpin: "\ud83d\udccc",
|
|
51
|
+
paperclip: "\ud83d\udcce", scissors: "\u2702\ufe0f", hammer: "\ud83d\udd28", wrench: "\ud83d\udd27", gear: "\u2699\ufe0f", nut_and_bolt: "\ud83d\udd29",
|
|
52
|
+
bomb: "\ud83d\udca3", hourglass: "\u231b", watch: "\u231a", alarm_clock: "\u23f0", moneybag: "\ud83d\udcb0", dollar: "\ud83d\udcb5",
|
|
53
|
+
credit_card: "\ud83d\udcb3", chart_increasing: "\ud83d\udcc8", link: "\ud83d\udd17", mag_right: "\ud83d\udd0e", telescope: "\ud83d\udd2d",
|
|
54
|
+
microscope: "\ud83d\udd2c", syringe: "\ud83d\udc89", pill: "\ud83d\udc8a", phone: "\ud83d\udcde", telephone: "\ud83d\udcde", iphone: "\ud83d\udcf1",
|
|
55
|
+
computer: "\ud83d\udcbb", keyboard: "\u2328\ufe0f", printer: "\ud83d\udda8\ufe0f", camera: "\ud83d\udcf7", movie_camera: "\ud83c\udfa5", tv: "\ud83d\udcfa",
|
|
56
|
+
seedling: "\ud83c\udf31", evergreen_tree: "\ud83c\udf32", deciduous_tree: "\ud83c\udf33", palm_tree: "\ud83c\udf34", cactus: "\ud83c\udf35",
|
|
57
|
+
four_leaf_clover: "\ud83c\udf40", rose: "\ud83c\udf39", sunflower: "\ud83c\udf3b", tulip: "\ud83c\udf37", blossom: "\ud83c\udf3c", herb: "\ud83c\udf3f",
|
|
58
|
+
musical_note: "\ud83c\udfb5", notes: "\ud83c\udfb6", microphone: "\ud83c\udfa4", headphones: "\ud83c\udfa7", guitar: "\ud83c\udfb8", trumpet: "\ud83c\udfba",
|
|
59
|
+
soccer: "\u26bd", basketball: "\ud83c\udfc0", football: "\ud83c\udfc8", baseball: "\u26be", tennis: "\ud83c\udfbe", "8ball": "\ud83c\udfb1",
|
|
60
|
+
dart: "\ud83c\udfaf", video_game: "\ud83c\udfae", game_die: "\ud83c\udfb2", trophy2: "\ud83c\udfc6",
|
|
61
|
+
sos: "\ud83c\udd98", new: "\ud83c\udd95", ok: "\ud83c\udd97", up: "\ud83c\udd99", cool: "\ud83c\udd92", free: "\ud83c\udd93",
|
|
62
|
+
arrow_up: "\u2b06\ufe0f", arrow_down: "\u2b07\ufe0f", arrow_left: "\u2b05\ufe0f", arrow_right: "\u27a1\ufe0f", arrow_forward: "\u25b6\ufe0f",
|
|
63
|
+
bangbang: "\u203c\ufe0f", interrobang: "\u2049\ufe0f", grey_question: "\u2754", grey_exclamation: "\u2755"
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
function RTE_Plugin_EmojiAutocomplete() {
|
|
67
67
|
var obj = this;
|
|
68
68
|
var config, editor, editable, editdoc;
|
|
69
|
-
var pop = null, items = [], sel = 0, queryStart = -1, queryNode = null;
|
|
69
|
+
var pop = null, items = [], sel = 0, queryStart = -1, queryNode = null, lastFix = null;
|
|
70
70
|
|
|
71
71
|
obj.PluginName = "EmojiAutocomplete";
|
|
72
72
|
|
|
@@ -77,10 +77,19 @@ function RTE_Plugin_EmojiAutocomplete() {
|
|
|
77
77
|
editable = editor.getEditable();
|
|
78
78
|
editdoc = editor.getDocument();
|
|
79
79
|
if (!editable || !editdoc) return;
|
|
80
|
-
|
|
80
|
+
// 2026-10-03 Bound through editor.bindDocumentEvent, so the listeners follow the live document:
|
|
81
|
+
// shell plugins move the iframe during the init loop, and listeners added to editdoc here stayed
|
|
82
|
+
// on the dead document (this feature never fired). tools/keyboard/plugin-listeners.mjs
|
|
83
|
+
var on = function (type, fn, capture) {
|
|
84
|
+
if (editor.bindDocumentEvent) editor.bindDocumentEvent(type, fn, capture);
|
|
85
|
+
else editor.getDocument().addEventListener(type, fn, capture);
|
|
86
|
+
};
|
|
87
|
+
on("input", onInput, false);
|
|
81
88
|
// keydown in capture so we intercept nav keys before the editor does.
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
on("keydown", onKeyDown, true);
|
|
90
|
+
on("blur", function () { setTimeout(closePopup, 150); }, true);
|
|
91
|
+
// the references held above go stale with the document
|
|
92
|
+
editor.attachEvent("documentreplaced", function () { editable = editor.getEditable(); editdoc = editor.getDocument(); });
|
|
84
93
|
};
|
|
85
94
|
|
|
86
95
|
function map() { return config.emojiShortcodes || {}; }
|
|
@@ -150,11 +159,19 @@ function RTE_Plugin_EmojiAutocomplete() {
|
|
|
150
159
|
pop = hostDoc.createElement("div");
|
|
151
160
|
pop.className = "rte-emoji-pop";
|
|
152
161
|
pop.setAttribute("role", "listbox");
|
|
153
|
-
pop.setAttribute("aria-label", "Emoji suggestions");
|
|
162
|
+
pop.setAttribute("aria-label", ((typeof config !== "undefined" && config && config.text_emoji_suggest) || "Emoji suggestions"));
|
|
154
163
|
pop.style.cssText = "position:fixed;z-index:2147483600;";
|
|
155
164
|
hostDoc.body.appendChild(pop);
|
|
156
165
|
}
|
|
157
|
-
|
|
166
|
+
// 2026-10-17 appended to the page body, outside the editor, so rte-dark could not reach it: mirrored (and
|
|
167
|
+
// rte-auto-dark under a dark system setting). tools/emoji/emoji-autocomplete-dark.mjs
|
|
168
|
+
var popDark = false;
|
|
169
|
+
try {
|
|
170
|
+
var hk = editor.container && editor.container.classList;
|
|
171
|
+
popDark = !!hk && (hk.contains("rte-dark") || (hk.contains("rte-auto-dark") && !hk.contains("rte-light") && !!(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches)));
|
|
172
|
+
} catch (x) { popDark = false; }
|
|
173
|
+
pop.className = "rte-emoji-pop" + (popDark ? " rte-emoji-pop-dark" : "");
|
|
174
|
+
pop.innerHTML = __RTE_TT("");
|
|
158
175
|
items.forEach(function (it, i) {
|
|
159
176
|
var row = hostDoc.createElement("div");
|
|
160
177
|
row.className = "rte-emoji-pop-row" + (i === sel ? " is-active" : "");
|
|
@@ -175,8 +192,12 @@ function RTE_Plugin_EmojiAutocomplete() {
|
|
|
175
192
|
// position near the caret (iframe rect + caret rect)
|
|
176
193
|
try {
|
|
177
194
|
var cr = range.getBoundingClientRect();
|
|
178
|
-
var
|
|
179
|
-
var
|
|
195
|
+
var fe = editdoc.defaultView && editdoc.defaultView.frameElement;
|
|
196
|
+
var fr = fe ? fe.getBoundingClientRect() : { left: 0, top: 0, width: 0 };
|
|
197
|
+
// the caret rect is in iframe pixels, which are scaled on screen inside a
|
|
198
|
+
// transform:scale() ancestor; the popup lives in the host body (viewport pixels)
|
|
199
|
+
var k = fe && fe.offsetWidth && fr.width > 0 ? fr.width / fe.offsetWidth : 1;
|
|
200
|
+
var x = fr.left + cr.left * k, y = fr.top + cr.bottom * k + 4;
|
|
180
201
|
var vw = hostDoc.documentElement.clientWidth, vh = hostDoc.documentElement.clientHeight;
|
|
181
202
|
pop.style.left = Math.max(4, Math.min(x, vw - 290)) + "px";
|
|
182
203
|
pop.style.top = Math.max(4, Math.min(y, vh - 20)) + "px";
|
|
@@ -194,6 +215,15 @@ function RTE_Plugin_EmojiAutocomplete() {
|
|
|
194
215
|
}
|
|
195
216
|
|
|
196
217
|
function onKeyDown(e) {
|
|
218
|
+
// 2026-10-03 Ctrl/Cmd+Z straight after a conversion gives the typed shortcode back (":smile:"),
|
|
219
|
+
// as autocorrect does for its corrections - the editor's own undo would also take back the
|
|
220
|
+
// typing it was grouped with. Any other key forgets the conversion.
|
|
221
|
+
// tools/keyboard/emoji-autocomplete.mjs
|
|
222
|
+
if (lastFix) {
|
|
223
|
+
var isUndo = (e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey && (e.code === "KeyZ" || e.key === "z" || e.key === "Z");
|
|
224
|
+
if (isUndo && undoLastFix()) { e.preventDefault(); e.stopPropagation(); return; }
|
|
225
|
+
if (!/^(Control|Meta|Shift|Alt|CapsLock)$/.test(e.key)) lastFix = null;
|
|
226
|
+
}
|
|
197
227
|
if (!pop || pop.style.display === "none" || !items.length) return;
|
|
198
228
|
switch (e.key) {
|
|
199
229
|
case "ArrowDown": e.preventDefault(); e.stopPropagation(); sel = (sel + 1) % items.length; highlightRows(); break;
|
|
@@ -204,6 +234,29 @@ function RTE_Plugin_EmojiAutocomplete() {
|
|
|
204
234
|
}
|
|
205
235
|
}
|
|
206
236
|
|
|
237
|
+
// Put the typed shortcode back over the emoji the last conversion wrote - only while the caret is
|
|
238
|
+
// still right behind that emoji and the emoji is untouched.
|
|
239
|
+
function undoLastFix() {
|
|
240
|
+
var f = lastFix;
|
|
241
|
+
lastFix = null;
|
|
242
|
+
if (!f || !f.node.parentNode || f.node.data !== f.emo) return false;
|
|
243
|
+
var s = editor.getSelection();
|
|
244
|
+
if (!s || !s.rangeCount || !s.isCollapsed) return false;
|
|
245
|
+
var r = s.getRangeAt(0), here = r.startContainer, off = r.startOffset;
|
|
246
|
+
var behind = (here === f.node && off === f.node.data.length) ||
|
|
247
|
+
(here.nodeType === 3 && off === 0 && here.previousSibling === f.node) ||
|
|
248
|
+
(here === f.node.parentNode && here.childNodes[off - 1] === f.node);
|
|
249
|
+
if (!behind) return false;
|
|
250
|
+
f.node.data = f.typed;
|
|
251
|
+
var c = editor.getDocument().createRange();
|
|
252
|
+
c.setStart(f.node, f.typed.length);
|
|
253
|
+
c.collapse(true);
|
|
254
|
+
s.removeAllRanges();
|
|
255
|
+
s.addRange(c);
|
|
256
|
+
if (typeof editor.fireChange === "function") { try { editor.fireChange(); } catch (e) { /* ignore */ } }
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
207
260
|
function commit() {
|
|
208
261
|
if (!items.length || !queryNode || queryStart < 0) { closePopup(); return; }
|
|
209
262
|
var it = items[sel] || items[0];
|
|
@@ -225,6 +278,7 @@ function RTE_Plugin_EmojiAutocomplete() {
|
|
|
225
278
|
var tailNode = tail ? editdoc.createTextNode(tail) : null;
|
|
226
279
|
if (tailNode) frag.appendChild(tailNode);
|
|
227
280
|
parent.replaceChild(frag, node);
|
|
281
|
+
lastFix = { node: emoNode, emo: text, typed: data.slice(start, end) };
|
|
228
282
|
var rr = editdoc.createRange();
|
|
229
283
|
if (tailNode) rr.setStart(tailNode, 0); else rr.setStartAfter(emoNode);
|
|
230
284
|
rr.collapse(true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_emojiautocomplete=RTE_Plugin_EmojiAutocomplete,RTE_DefaultConfig.emojiAutocompleteEnabled=typeof RTE_DefaultConfig.emojiAutocompleteEnabled>"u"?!0:RTE_DefaultConfig.emojiAutocompleteEnabled,RTE_DefaultConfig.emojiShortcodes=RTE_DefaultConfig.emojiShortcodes||{smile:"\u{1F604}",smiley:"\u{1F603}",grin:"\u{1F601}",laughing:"\u{1F606}",satisfied:"\u{1F606}",joy:"\u{1F602}",rofl:"\u{1F923}",sweat_smile:"\u{1F605}",wink:"\u{1F609}",blush:"\u{1F60A}",innocent:"\u{1F607}",heart_eyes:"\u{1F60D}",star_struck:"\u{1F929}",kissing_heart:"\u{1F618}",yum:"\u{1F60B}",stuck_out_tongue:"\u{1F61B}",zany:"\u{1F92A}",thinking:"\u{1F914}",shush:"\u{1F92B}",neutral_face:"\u{1F610}",expressionless:"\u{1F611}",no_mouth:"\u{1F636}",smirk:"\u{1F60F}",unamused:"\u{1F612}",roll_eyes:"\u{1F644}",grimacing:"\u{1F62C}",relieved:"\u{1F60C}",pensive:"\u{1F614}",sleepy:"\u{1F62A}",sleeping:"\u{1F634}",mask:"\u{1F637}",face_with_thermometer:"\u{1F912}",nauseated_face:"\u{1F922}",sneezing_face:"\u{1F927}",dizzy_face:"\u{1F635}",exploding_head:"\u{1F92F}",cowboy:"\u{1F920}",sunglasses:"\u{1F60E}",nerd:"\u{1F913}",monocle:"\u{1F9D0}",confused:"\u{1F615}",worried:"\u{1F61F}",slightly_frowning_face:"\u{1F641}",open_mouth:"\u{1F62E}",astonished:"\u{1F632}",flushed:"\u{1F633}",fearful:"\u{1F628}",cold_sweat:"\u{1F630}",cry:"\u{1F622}",sob:"\u{1F62D}",scream:"\u{1F631}",confounded:"\u{1F616}",persevere:"\u{1F623}",disappointed:"\u{1F61E}",sweat:"\u{1F613}",weary:"\u{1F629}",tired_face:"\u{1F62B}",triumph:"\u{1F624}",rage:"\u{1F621}",angry:"\u{1F620}",cursing_face:"\u{1F92C}",smiling_imp:"\u{1F608}",imp:"\u{1F47F}",skull:"\u{1F480}",poop:"\u{1F4A9}",hankey:"\u{1F4A9}",clown:"\u{1F921}",ghost:"\u{1F47B}",alien:"\u{1F47D}",robot:"\u{1F916}",heart_eyes_cat:"\u{1F63B}",see_no_evil:"\u{1F648}",hear_no_evil:"\u{1F649}",speak_no_evil:"\u{1F64A}",heart:"\u2764\uFE0F",orange_heart:"\u{1F9E1}",yellow_heart:"\u{1F49B}",green_heart:"\u{1F49A}",blue_heart:"\u{1F499}",purple_heart:"\u{1F49C}",black_heart:"\u{1F5A4}",broken_heart:"\u{1F494}",two_hearts:"\u{1F495}",sparkling_heart:"\u{1F496}",heartpulse:"\u{1F497}",cupid:"\u{1F498}",gift_heart:"\u{1F49D}",revolving_hearts:"\u{1F49E}",kiss:"\u{1F48B}","+1":"\u{1F44D}",thumbsup:"\u{1F44D}","-1":"\u{1F44E}",thumbsdown:"\u{1F44E}",ok_hand:"\u{1F44C}",punch:"\u{1F44A}",fist:"\u270A",facepunch:"\u{1F44A}",wave:"\u{1F44B}",raised_hand:"\u270B",raised_hands:"\u{1F64C}",pray:"\u{1F64F}",clap:"\u{1F44F}",muscle:"\u{1F4AA}",point_up:"\u261D\uFE0F",point_down:"\u{1F447}",point_left:"\u{1F448}",point_right:"\u{1F449}",v:"\u270C\uFE0F",crossed_fingers:"\u{1F91E}",handshake:"\u{1F91D}",writing_hand:"\u270D\uFE0F",selfie:"\u{1F933}",nail_care:"\u{1F485}",eyes:"\u{1F440}",fire:"\u{1F525}",star:"\u2B50",star2:"\u{1F31F}",sparkles:"\u2728",zap:"\u26A1",boom:"\u{1F4A5}",collision:"\u{1F4A5}",dizzy:"\u{1F4AB}",sweat_drops:"\u{1F4A6}",droplet:"\u{1F4A7}",snowflake:"\u2744\uFE0F",sunny:"\u2600\uFE0F",cloud:"\u2601\uFE0F",rainbow:"\u{1F308}",umbrella:"\u2614",ocean:"\u{1F30A}",sun_with_face:"\u{1F31E}",full_moon:"\u{1F315}",crescent_moon:"\u{1F319}",tada:"\u{1F389}",confetti_ball:"\u{1F38A}",balloon:"\u{1F388}",gift:"\u{1F381}",trophy:"\u{1F3C6}",medal:"\u{1F3C5}",crown:"\u{1F451}",gem:"\u{1F48E}",rocket:"\u{1F680}",airplane:"\u2708\uFE0F",car:"\u{1F697}",rotating_light:"\u{1F6A8}",100:"\u{1F4AF}",white_check_mark:"\u2705",heavy_check_mark:"\u2714\uFE0F",ballot_box_with_check:"\u2611\uFE0F",x:"\u274C",warning:"\u26A0\uFE0F",no_entry:"\u26D4",question:"\u2753",exclamation:"\u2757",bulb:"\u{1F4A1}",lock:"\u{1F512}",key:"\u{1F511}",mag:"\u{1F50D}",bell:"\u{1F514}",recycle:"\u267B\uFE0F",heavy_plus_sign:"\u2795",heavy_minus_sign:"\u2796",coffee:"\u2615",tea:"\u{1F375}",beer:"\u{1F37A}",beers:"\u{1F37B}",wine_glass:"\u{1F377}",cocktail:"\u{1F378}",pizza:"\u{1F355}",hamburger:"\u{1F354}",fries:"\u{1F35F}",taco:"\u{1F32E}",cake:"\u{1F382}",birthday:"\u{1F382}",cookie:"\u{1F36A}",doughnut:"\u{1F369}",apple:"\u{1F34E}",banana:"\u{1F34C}",strawberry:"\u{1F353}",avocado:"\u{1F951}",bread:"\u{1F35E}",cheese:"\u{1F9C0}",dog:"\u{1F436}",cat:"\u{1F431}",mouse:"\u{1F42D}",rabbit:"\u{1F430}",bear:"\u{1F43B}",panda_face:"\u{1F43C}",koala:"\u{1F428}",tiger:"\u{1F42F}",lion:"\u{1F981}",cow:"\u{1F42E}",pig:"\u{1F437}",frog:"\u{1F438}",monkey_face:"\u{1F435}",chicken:"\u{1F414}",penguin:"\u{1F427}",bird:"\u{1F426}",unicorn:"\u{1F984}",bee:"\u{1F41D}",bug:"\u{1F41B}",butterfly:"\u{1F98B}",snail:"\u{1F40C}",book:"\u{1F4D6}",books:"\u{1F4DA}",memo:"\u{1F4DD}",pencil:"\u{1F4DD}",email:"\u2709\uFE0F",envelope:"\u2709\uFE0F",calendar:"\u{1F4C5}",chart:"\u{1F4CA}",bar_chart:"\u{1F4CA}",chart_with_upwards_trend:"\u{1F4C8}",clipboard:"\u{1F4CB}",pushpin:"\u{1F4CC}",paperclip:"\u{1F4CE}",scissors:"\u2702\uFE0F",hammer:"\u{1F528}",wrench:"\u{1F527}",gear:"\u2699\uFE0F",nut_and_bolt:"\u{1F529}",bomb:"\u{1F4A3}",hourglass:"\u231B",watch:"\u231A",alarm_clock:"\u23F0",moneybag:"\u{1F4B0}",dollar:"\u{1F4B5}",credit_card:"\u{1F4B3}",chart_increasing:"\u{1F4C8}",link:"\u{1F517}",mag_right:"\u{1F50E}",telescope:"\u{1F52D}",microscope:"\u{1F52C}",syringe:"\u{1F489}",pill:"\u{1F48A}",phone:"\u{1F4DE}",telephone:"\u{1F4DE}",iphone:"\u{1F4F1}",computer:"\u{1F4BB}",keyboard:"\u2328\uFE0F",printer:"\u{1F5A8}\uFE0F",camera:"\u{1F4F7}",movie_camera:"\u{1F3A5}",tv:"\u{1F4FA}",seedling:"\u{1F331}",evergreen_tree:"\u{1F332}",deciduous_tree:"\u{1F333}",palm_tree:"\u{1F334}",cactus:"\u{1F335}",four_leaf_clover:"\u{1F340}",rose:"\u{1F339}",sunflower:"\u{1F33B}",tulip:"\u{1F337}",blossom:"\u{1F33C}",herb:"\u{1F33F}",musical_note:"\u{1F3B5}",notes:"\u{1F3B6}",microphone:"\u{1F3A4}",headphones:"\u{1F3A7}",guitar:"\u{1F3B8}",trumpet:"\u{1F3BA}",soccer:"\u26BD",basketball:"\u{1F3C0}",football:"\u{1F3C8}",baseball:"\u26BE",tennis:"\u{1F3BE}","8ball":"\u{1F3B1}",dart:"\u{1F3AF}",video_game:"\u{1F3AE}",game_die:"\u{1F3B2}",trophy2:"\u{1F3C6}",sos:"\u{1F198}",new:"\u{1F195}",ok:"\u{1F197}",up:"\u{1F199}",cool:"\u{1F192}",free:"\u{1F193}",arrow_up:"\u2B06\uFE0F",arrow_down:"\u2B07\uFE0F",arrow_left:"\u2B05\uFE0F",arrow_right:"\u27A1\uFE0F",arrow_forward:"\u25B6\uFE0F",bangbang:"\u203C\uFE0F",interrobang:"\u2049\uFE0F",grey_question:"\u2754",grey_exclamation:"\u2755"};function RTE_Plugin_EmojiAutocomplete(){var y=this,k,b,E,i,n=null,f=[],l=0,w=-1,v=null;y.PluginName="EmojiAutocomplete",y.InitConfig=function(e){k=e},y.InitEditor=function(e){b=e,E=b.getEditable(),i=b.getDocument(),!(!E||!i)&&(i.addEventListener("input",j,!1),i.addEventListener("keydown",P,!0),i.addEventListener("blur",function(){setTimeout(m,150)},!0))};function D(){return k.emojiShortcodes||{}}function R(){var e=b.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed)return null;var t=e.getRangeAt(0);if(t.startContainer.nodeType!==3)return null;for(var a=t.startContainer.parentNode;a&&a!==E;){if(a.nodeName==="CODE"||a.nodeName==="PRE")return null;a=a.parentNode}return t}function j(){if(k.emojiAutocompleteEnabled){var e=R();if(!e){m();return}var t=e.startContainer,a=e.startOffset,h=t.data.slice(0,a),u=/(^|[^a-z0-9_])(:[a-z0-9_+\-]{1,30}:)$/i.exec(h);if(u){var _=u[2].slice(1,-1).toLowerCase(),p=D()[_];if(p){A(t,a-u[2].length,a,p),m();return}}var c=/(^|[^a-z0-9_])(:)([a-z0-9_+\-]{1,30})$/i.exec(h);if(c){var o=c[3].toLowerCase();v=t,w=a-o.length-1,z(o,e)}else m()}}function z(e,t){for(var a=D(),h=Object.keys(a),u=[],_=[],p=0;p<h.length;p++){var c=h[p];c.indexOf(e)===0?u.push(c):c.indexOf(e)!==-1&&_.push(c)}for(var o=u.concat(_),g={},r=[],s=0;s<o.length&&r.length<8;s++){var d=a[o[s]];g[d]||(g[d]=1,r.push({code:o[s],emo:d}))}if(!r.length){m();return}f=r,l=0,N(t)}function N(e){var t=document;n||(n=t.createElement("div"),n.className="rte-emoji-pop",n.setAttribute("role","listbox"),n.setAttribute("aria-label","Emoji suggestions"),n.style.cssText="position:fixed;z-index:2147483600;",t.body.appendChild(n)),n.innerHTML="",f.forEach(function(o,g){var r=t.createElement("div");r.className="rte-emoji-pop-row"+(g===l?" is-active":""),r.setAttribute("role","option"),r.setAttribute("aria-selected",g===l?"true":"false");var s=t.createElement("span");s.className="rte-emoji-pop-glyph",s.textContent=o.emo;var d=t.createElement("span");d.className="rte-emoji-pop-code",d.textContent=":"+o.code+":",r.appendChild(s),r.appendChild(d),r.onmousedown=function(x){x.preventDefault(),l=g,T()},r.onmouseenter=function(){l=g,C()},n.appendChild(r)});try{var a=e.getBoundingClientRect(),h=i.defaultView&&i.defaultView.frameElement?i.defaultView.frameElement.getBoundingClientRect():{left:0,top:0},u=h.left+a.left,_=h.top+a.bottom+4,p=t.documentElement.clientWidth,c=t.documentElement.clientHeight;n.style.left=Math.max(4,Math.min(u,p-290))+"px",n.style.top=Math.max(4,Math.min(_,c-20))+"px",n.style.display="block"}catch{}}function C(){if(n)for(var e=n.childNodes,t=0;t<e.length;t++)e[t].classList.toggle("is-active",t===l),e[t].setAttribute("aria-selected",t===l?"true":"false")}function P(e){if(!(!n||n.style.display==="none"||!f.length))switch(e.key){case"ArrowDown":e.preventDefault(),e.stopPropagation(),l=(l+1)%f.length,C();break;case"ArrowUp":e.preventDefault(),e.stopPropagation(),l=(l-1+f.length)%f.length,C();break;case"Enter":case"Tab":e.preventDefault(),e.stopPropagation(),T();break;case"Escape":e.preventDefault(),e.stopPropagation(),m();break}}function T(){if(!f.length||!v||w<0){m();return}var e=f[l]||f[0],t=R();if(!t||t.startContainer!==v){m();return}A(v,w,t.startOffset,e.emo),m()}function A(e,t,a,h){try{var u=e.data,_=u.slice(0,t),p=u.slice(a),c=e.parentNode;if(!c)return;var o=i.createDocumentFragment();_&&o.appendChild(i.createTextNode(_));var g=i.createTextNode(h);o.appendChild(g);var r=p?i.createTextNode(p):null;r&&o.appendChild(r),c.replaceChild(o,e);var s=i.createRange();r?s.setStart(r,0):s.setStartAfter(g),s.collapse(!0);var d=b.getSelection();if(d&&(d.removeAllRanges(),d.addRange(s)),typeof b.fireChange=="function")try{b.fireChange()}catch{}}catch{}}function m(){n&&(n.style.display="none"),f=[],l=0,w=-1,v=null}}
|
|
1
|
+
window.RTE_DefaultConfig||(window.RTE_DefaultConfig={}),RTE_DefaultConfig.plugin_emojiautocomplete=RTE_Plugin_EmojiAutocomplete,RTE_DefaultConfig.emojiAutocompleteEnabled=typeof RTE_DefaultConfig.emojiAutocompleteEnabled>"u"?!0:RTE_DefaultConfig.emojiAutocompleteEnabled,RTE_DefaultConfig.emojiShortcodes=RTE_DefaultConfig.emojiShortcodes||{smile:"\u{1F604}",smiley:"\u{1F603}",grin:"\u{1F601}",laughing:"\u{1F606}",satisfied:"\u{1F606}",joy:"\u{1F602}",rofl:"\u{1F923}",sweat_smile:"\u{1F605}",wink:"\u{1F609}",blush:"\u{1F60A}",innocent:"\u{1F607}",heart_eyes:"\u{1F60D}",star_struck:"\u{1F929}",kissing_heart:"\u{1F618}",yum:"\u{1F60B}",stuck_out_tongue:"\u{1F61B}",zany:"\u{1F92A}",thinking:"\u{1F914}",shush:"\u{1F92B}",neutral_face:"\u{1F610}",expressionless:"\u{1F611}",no_mouth:"\u{1F636}",smirk:"\u{1F60F}",unamused:"\u{1F612}",roll_eyes:"\u{1F644}",grimacing:"\u{1F62C}",relieved:"\u{1F60C}",pensive:"\u{1F614}",sleepy:"\u{1F62A}",sleeping:"\u{1F634}",mask:"\u{1F637}",face_with_thermometer:"\u{1F912}",nauseated_face:"\u{1F922}",sneezing_face:"\u{1F927}",dizzy_face:"\u{1F635}",exploding_head:"\u{1F92F}",cowboy:"\u{1F920}",sunglasses:"\u{1F60E}",nerd:"\u{1F913}",monocle:"\u{1F9D0}",confused:"\u{1F615}",worried:"\u{1F61F}",slightly_frowning_face:"\u{1F641}",open_mouth:"\u{1F62E}",astonished:"\u{1F632}",flushed:"\u{1F633}",fearful:"\u{1F628}",cold_sweat:"\u{1F630}",cry:"\u{1F622}",sob:"\u{1F62D}",scream:"\u{1F631}",confounded:"\u{1F616}",persevere:"\u{1F623}",disappointed:"\u{1F61E}",sweat:"\u{1F613}",weary:"\u{1F629}",tired_face:"\u{1F62B}",triumph:"\u{1F624}",rage:"\u{1F621}",angry:"\u{1F620}",cursing_face:"\u{1F92C}",smiling_imp:"\u{1F608}",imp:"\u{1F47F}",skull:"\u{1F480}",poop:"\u{1F4A9}",hankey:"\u{1F4A9}",clown:"\u{1F921}",ghost:"\u{1F47B}",alien:"\u{1F47D}",robot:"\u{1F916}",heart_eyes_cat:"\u{1F63B}",see_no_evil:"\u{1F648}",hear_no_evil:"\u{1F649}",speak_no_evil:"\u{1F64A}",heart:"\u2764\uFE0F",orange_heart:"\u{1F9E1}",yellow_heart:"\u{1F49B}",green_heart:"\u{1F49A}",blue_heart:"\u{1F499}",purple_heart:"\u{1F49C}",black_heart:"\u{1F5A4}",broken_heart:"\u{1F494}",two_hearts:"\u{1F495}",sparkling_heart:"\u{1F496}",heartpulse:"\u{1F497}",cupid:"\u{1F498}",gift_heart:"\u{1F49D}",revolving_hearts:"\u{1F49E}",kiss:"\u{1F48B}","+1":"\u{1F44D}",thumbsup:"\u{1F44D}","-1":"\u{1F44E}",thumbsdown:"\u{1F44E}",ok_hand:"\u{1F44C}",punch:"\u{1F44A}",fist:"\u270A",facepunch:"\u{1F44A}",wave:"\u{1F44B}",raised_hand:"\u270B",raised_hands:"\u{1F64C}",pray:"\u{1F64F}",clap:"\u{1F44F}",muscle:"\u{1F4AA}",point_up:"\u261D\uFE0F",point_down:"\u{1F447}",point_left:"\u{1F448}",point_right:"\u{1F449}",v:"\u270C\uFE0F",crossed_fingers:"\u{1F91E}",handshake:"\u{1F91D}",writing_hand:"\u270D\uFE0F",selfie:"\u{1F933}",nail_care:"\u{1F485}",eyes:"\u{1F440}",fire:"\u{1F525}",star:"\u2B50",star2:"\u{1F31F}",sparkles:"\u2728",zap:"\u26A1",boom:"\u{1F4A5}",collision:"\u{1F4A5}",dizzy:"\u{1F4AB}",sweat_drops:"\u{1F4A6}",droplet:"\u{1F4A7}",snowflake:"\u2744\uFE0F",sunny:"\u2600\uFE0F",cloud:"\u2601\uFE0F",rainbow:"\u{1F308}",umbrella:"\u2614",ocean:"\u{1F30A}",sun_with_face:"\u{1F31E}",full_moon:"\u{1F315}",crescent_moon:"\u{1F319}",tada:"\u{1F389}",confetti_ball:"\u{1F38A}",balloon:"\u{1F388}",gift:"\u{1F381}",trophy:"\u{1F3C6}",medal:"\u{1F3C5}",crown:"\u{1F451}",gem:"\u{1F48E}",rocket:"\u{1F680}",airplane:"\u2708\uFE0F",car:"\u{1F697}",rotating_light:"\u{1F6A8}",100:"\u{1F4AF}",white_check_mark:"\u2705",heavy_check_mark:"\u2714\uFE0F",ballot_box_with_check:"\u2611\uFE0F",x:"\u274C",warning:"\u26A0\uFE0F",no_entry:"\u26D4",question:"\u2753",exclamation:"\u2757",bulb:"\u{1F4A1}",lock:"\u{1F512}",key:"\u{1F511}",mag:"\u{1F50D}",bell:"\u{1F514}",recycle:"\u267B\uFE0F",heavy_plus_sign:"\u2795",heavy_minus_sign:"\u2796",coffee:"\u2615",tea:"\u{1F375}",beer:"\u{1F37A}",beers:"\u{1F37B}",wine_glass:"\u{1F377}",cocktail:"\u{1F378}",pizza:"\u{1F355}",hamburger:"\u{1F354}",fries:"\u{1F35F}",taco:"\u{1F32E}",cake:"\u{1F382}",birthday:"\u{1F382}",cookie:"\u{1F36A}",doughnut:"\u{1F369}",apple:"\u{1F34E}",banana:"\u{1F34C}",strawberry:"\u{1F353}",avocado:"\u{1F951}",bread:"\u{1F35E}",cheese:"\u{1F9C0}",dog:"\u{1F436}",cat:"\u{1F431}",mouse:"\u{1F42D}",rabbit:"\u{1F430}",bear:"\u{1F43B}",panda_face:"\u{1F43C}",koala:"\u{1F428}",tiger:"\u{1F42F}",lion:"\u{1F981}",cow:"\u{1F42E}",pig:"\u{1F437}",frog:"\u{1F438}",monkey_face:"\u{1F435}",chicken:"\u{1F414}",penguin:"\u{1F427}",bird:"\u{1F426}",unicorn:"\u{1F984}",bee:"\u{1F41D}",bug:"\u{1F41B}",butterfly:"\u{1F98B}",snail:"\u{1F40C}",book:"\u{1F4D6}",books:"\u{1F4DA}",memo:"\u{1F4DD}",pencil:"\u{1F4DD}",email:"\u2709\uFE0F",envelope:"\u2709\uFE0F",calendar:"\u{1F4C5}",chart:"\u{1F4CA}",bar_chart:"\u{1F4CA}",chart_with_upwards_trend:"\u{1F4C8}",clipboard:"\u{1F4CB}",pushpin:"\u{1F4CC}",paperclip:"\u{1F4CE}",scissors:"\u2702\uFE0F",hammer:"\u{1F528}",wrench:"\u{1F527}",gear:"\u2699\uFE0F",nut_and_bolt:"\u{1F529}",bomb:"\u{1F4A3}",hourglass:"\u231B",watch:"\u231A",alarm_clock:"\u23F0",moneybag:"\u{1F4B0}",dollar:"\u{1F4B5}",credit_card:"\u{1F4B3}",chart_increasing:"\u{1F4C8}",link:"\u{1F517}",mag_right:"\u{1F50E}",telescope:"\u{1F52D}",microscope:"\u{1F52C}",syringe:"\u{1F489}",pill:"\u{1F48A}",phone:"\u{1F4DE}",telephone:"\u{1F4DE}",iphone:"\u{1F4F1}",computer:"\u{1F4BB}",keyboard:"\u2328\uFE0F",printer:"\u{1F5A8}\uFE0F",camera:"\u{1F4F7}",movie_camera:"\u{1F3A5}",tv:"\u{1F4FA}",seedling:"\u{1F331}",evergreen_tree:"\u{1F332}",deciduous_tree:"\u{1F333}",palm_tree:"\u{1F334}",cactus:"\u{1F335}",four_leaf_clover:"\u{1F340}",rose:"\u{1F339}",sunflower:"\u{1F33B}",tulip:"\u{1F337}",blossom:"\u{1F33C}",herb:"\u{1F33F}",musical_note:"\u{1F3B5}",notes:"\u{1F3B6}",microphone:"\u{1F3A4}",headphones:"\u{1F3A7}",guitar:"\u{1F3B8}",trumpet:"\u{1F3BA}",soccer:"\u26BD",basketball:"\u{1F3C0}",football:"\u{1F3C8}",baseball:"\u26BE",tennis:"\u{1F3BE}","8ball":"\u{1F3B1}",dart:"\u{1F3AF}",video_game:"\u{1F3AE}",game_die:"\u{1F3B2}",trophy2:"\u{1F3C6}",sos:"\u{1F198}",new:"\u{1F195}",ok:"\u{1F197}",up:"\u{1F199}",cool:"\u{1F192}",free:"\u{1F193}",arrow_up:"\u2B06\uFE0F",arrow_down:"\u2B07\uFE0F",arrow_left:"\u2B05\uFE0F",arrow_right:"\u27A1\uFE0F",arrow_forward:"\u25B6\uFE0F",bangbang:"\u203C\uFE0F",interrobang:"\u2049\uFE0F",grey_question:"\u2754",grey_exclamation:"\u2755"};function RTE_Plugin_EmojiAutocomplete(){var D=this,y,c,E,g,n=null,m=[],f=0,x=-1,k=null,C=null;D.PluginName="EmojiAutocomplete",D.InitConfig=function(d){y=d},D.InitEditor=function(d){if(c=d,E=c.getEditable(),g=c.getDocument(),!(!E||!g)){var e=function(u,t,a){c.bindDocumentEvent?c.bindDocumentEvent(u,t,a):c.getDocument().addEventListener(u,t,a)};e("input",P,!1),e("keydown",O,!0),e("blur",function(){setTimeout(b,150)},!0),c.attachEvent("documentreplaced",function(){E=c.getEditable(),g=c.getDocument()})}};function j(){return y.emojiShortcodes||{}}function z(){var d=c.getSelection();if(!d||d.rangeCount===0||!d.isCollapsed)return null;var e=d.getRangeAt(0);if(e.startContainer.nodeType!==3)return null;for(var u=e.startContainer.parentNode;u&&u!==E;){if(u.nodeName==="CODE"||u.nodeName==="PRE")return null;u=u.parentNode}return e}function P(){if(y.emojiAutocompleteEnabled){var d=z();if(!d){b();return}var e=d.startContainer,u=d.startOffset,t=e.data.slice(0,u),a=/(^|[^a-z0-9_])(:[a-z0-9_+\-]{1,30}:)$/i.exec(t);if(a){var r=a[2].slice(1,-1).toLowerCase(),o=j()[r];if(o){S(e,u-a[2].length,u,o),b();return}}var i=/(^|[^a-z0-9_])(:)([a-z0-9_+\-]{1,30})$/i.exec(t);if(i){var l=i[3].toLowerCase();k=e,x=u-l.length-1,M(l,d)}else b()}}function M(d,e){for(var u=j(),t=Object.keys(u),a=[],r=[],o=0;o<t.length;o++){var i=t[o];i.indexOf(d)===0?a.push(i):i.indexOf(d)!==-1&&r.push(i)}for(var l=a.concat(r),_={},p=[],h=0;h<l.length&&p.length<8;h++){var s=u[l[h]];_[s]||(_[s]=1,p.push({code:l[h],emo:s}))}if(!p.length){b();return}m=p,f=0,L(e)}function L(d){var e=document;n||(n=e.createElement("div"),n.className="rte-emoji-pop",n.setAttribute("role","listbox"),n.setAttribute("aria-label",typeof y<"u"&&y&&y.text_emoji_suggest||"Emoji suggestions"),n.style.cssText="position:fixed;z-index:2147483600;",e.body.appendChild(n));var u=!1;try{var t=c.container&&c.container.classList;u=!!t&&(t.contains("rte-dark")||t.contains("rte-auto-dark")&&!t.contains("rte-light")&&!!(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches))}catch{u=!1}n.className="rte-emoji-pop"+(u?" rte-emoji-pop-dark":""),n.innerHTML=__RTE_TT(""),m.forEach(function(s,w){var v=e.createElement("div");v.className="rte-emoji-pop-row"+(w===f?" is-active":""),v.setAttribute("role","option"),v.setAttribute("aria-selected",w===f?"true":"false");var T=e.createElement("span");T.className="rte-emoji-pop-glyph",T.textContent=s.emo;var A=e.createElement("span");A.className="rte-emoji-pop-code",A.textContent=":"+s.code+":",v.appendChild(T),v.appendChild(A),v.onmousedown=function(F){F.preventDefault(),f=w,N()},v.onmouseenter=function(){f=w,R()},n.appendChild(v)});try{var a=d.getBoundingClientRect(),r=g.defaultView&&g.defaultView.frameElement,o=r?r.getBoundingClientRect():{left:0,top:0,width:0},i=r&&r.offsetWidth&&o.width>0?o.width/r.offsetWidth:1,l=o.left+a.left*i,_=o.top+a.bottom*i+4,p=e.documentElement.clientWidth,h=e.documentElement.clientHeight;n.style.left=Math.max(4,Math.min(l,p-290))+"px",n.style.top=Math.max(4,Math.min(_,h-20))+"px",n.style.display="block"}catch{}}function R(){if(n)for(var d=n.childNodes,e=0;e<d.length;e++)d[e].classList.toggle("is-active",e===f),d[e].setAttribute("aria-selected",e===f?"true":"false")}function O(d){if(C){var e=(d.ctrlKey||d.metaKey)&&!d.shiftKey&&!d.altKey&&(d.code==="KeyZ"||d.key==="z"||d.key==="Z");if(e&&K()){d.preventDefault(),d.stopPropagation();return}/^(Control|Meta|Shift|Alt|CapsLock)$/.test(d.key)||(C=null)}if(!(!n||n.style.display==="none"||!m.length))switch(d.key){case"ArrowDown":d.preventDefault(),d.stopPropagation(),f=(f+1)%m.length,R();break;case"ArrowUp":d.preventDefault(),d.stopPropagation(),f=(f-1+m.length)%m.length,R();break;case"Enter":case"Tab":d.preventDefault(),d.stopPropagation(),N();break;case"Escape":d.preventDefault(),d.stopPropagation(),b();break}}function K(){var d=C;if(C=null,!d||!d.node.parentNode||d.node.data!==d.emo)return!1;var e=c.getSelection();if(!e||!e.rangeCount||!e.isCollapsed)return!1;var u=e.getRangeAt(0),t=u.startContainer,a=u.startOffset,r=t===d.node&&a===d.node.data.length||t.nodeType===3&&a===0&&t.previousSibling===d.node||t===d.node.parentNode&&t.childNodes[a-1]===d.node;if(!r)return!1;d.node.data=d.typed;var o=c.getDocument().createRange();if(o.setStart(d.node,d.typed.length),o.collapse(!0),e.removeAllRanges(),e.addRange(o),typeof c.fireChange=="function")try{c.fireChange()}catch{}return!0}function N(){if(!m.length||!k||x<0){b();return}var d=m[f]||m[0],e=z();if(!e||e.startContainer!==k){b();return}S(k,x,e.startOffset,d.emo),b()}function S(d,e,u,t){try{var a=d.data,r=a.slice(0,e),o=a.slice(u),i=d.parentNode;if(!i)return;var l=g.createDocumentFragment();r&&l.appendChild(g.createTextNode(r));var _=g.createTextNode(t);l.appendChild(_);var p=o?g.createTextNode(o):null;p&&l.appendChild(p),i.replaceChild(l,d),C={node:_,emo:t,typed:a.slice(e,u)};var h=g.createRange();p?h.setStart(p,0):h.setStartAfter(_),h.collapse(!0);var s=c.getSelection();if(s&&(s.removeAllRanges(),s.addRange(h)),typeof c.fireChange=="function")try{c.fireChange()}catch{}}catch{}}function b(){n&&(n.style.display="none"),m=[],f=0,x=-1,k=null}}
|
|
@@ -91,6 +91,16 @@ function RTE_Plugin_Footnotes() {
|
|
|
91
91
|
editable.addEventListener("keyup", queueSync);
|
|
92
92
|
editable.addEventListener("cut", queueSync);
|
|
93
93
|
editable.addEventListener("paste", queueSync);
|
|
94
|
+
// 2026-10-13 A marker can arrive after the events above ran: an asynchronous paste or drop inserts it on a later
|
|
95
|
+
// tick, after the sync those events queued had already run, and a fast or synthetic paste had no keystroke after
|
|
96
|
+
// it. The observer resyncs after any change to the document outside the notes section. tools/footnotes/footnote-marker-arrives.mjs
|
|
97
|
+
try {
|
|
98
|
+
if (syncObserver) syncObserver.disconnect();
|
|
99
|
+
syncObserver = new MutationObserver(function () {
|
|
100
|
+
if (!syncRunning) queueSync();
|
|
101
|
+
});
|
|
102
|
+
syncObserver.observe(editable, { childList: true, subtree: true, characterData: true });
|
|
103
|
+
} catch (e) { /* no observer: the events above still resync */ }
|
|
94
104
|
editable.addEventListener("drop", queueSync);
|
|
95
105
|
// Clicking a marker jumps to its note, and clicking the backlink returns.
|
|
96
106
|
editable.addEventListener("click", function (e) {
|
|
@@ -109,10 +119,21 @@ function RTE_Plugin_Footnotes() {
|
|
|
109
119
|
// Coalesce bursts of edits into one renumber. setTimeout, not rAF: the
|
|
110
120
|
// editor may live in a background tab or a hidden iframe, where rAF never
|
|
111
121
|
// fires and the numbering would silently stop updating.
|
|
122
|
+
// 2026-10-13 runSync is the only place the queued renumber runs. The observer's own records from the sync are
|
|
123
|
+
// dropped, so the renumber does not queue itself again.
|
|
124
|
+
var syncObserver = null, syncRunning = false;
|
|
125
|
+
function runSync() {
|
|
126
|
+
syncRunning = true;
|
|
127
|
+
try { syncFootnotes(); }
|
|
128
|
+
finally {
|
|
129
|
+
if (syncObserver) { try { syncObserver.takeRecords(); } catch (e) { } }
|
|
130
|
+
syncRunning = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
112
133
|
function queueSync() {
|
|
113
134
|
if (syncQueued) return;
|
|
114
135
|
syncQueued = true;
|
|
115
|
-
setTimeout(function () { syncQueued = false;
|
|
136
|
+
setTimeout(function () { syncQueued = false; runSync(); }, 0);
|
|
116
137
|
}
|
|
117
138
|
|
|
118
139
|
function closestClass(node, cls, root) {
|
|
@@ -210,7 +231,7 @@ function RTE_Plugin_Footnotes() {
|
|
|
210
231
|
back.setAttribute("data-fn-id", id);
|
|
211
232
|
back.setAttribute("href", "#fnref-" + id);
|
|
212
233
|
back.setAttribute("contenteditable", "false");
|
|
213
|
-
back.setAttribute("title", "Back to reference");
|
|
234
|
+
back.setAttribute("title", ((typeof config !== "undefined" && config && config.text_fn_backref) || "Back to reference"));
|
|
214
235
|
back.textContent = "\u21a9";
|
|
215
236
|
li.appendChild(back);
|
|
216
237
|
note.appendChild(li);
|
|
@@ -265,6 +286,7 @@ function RTE_Plugin_Footnotes() {
|
|
|
265
286
|
if (!list.length) {
|
|
266
287
|
// Last marker went away: drop the section rather than leaving an
|
|
267
288
|
// empty "Footnotes" heading in the saved HTML.
|
|
289
|
+
if (sec) keepNotes(sec.querySelectorAll("li.rte-fn-note"));
|
|
268
290
|
if (sec && sec.parentNode) sec.parentNode.removeChild(sec);
|
|
269
291
|
return [];
|
|
270
292
|
}
|
|
@@ -280,7 +302,9 @@ function RTE_Plugin_Footnotes() {
|
|
|
280
302
|
var id = ref.getAttribute("data-fn-id");
|
|
281
303
|
// A copy/paste of a marker duplicates its id; re-key the duplicate so
|
|
282
304
|
// the two markers do not fight over one note.
|
|
305
|
+
var dupOf = null;
|
|
283
306
|
if (seen[id]) {
|
|
307
|
+
dupOf = id;
|
|
284
308
|
var fresh = newId();
|
|
285
309
|
ref.setAttribute("data-fn-id", fresh);
|
|
286
310
|
ref.setAttribute("id", "fnref-" + fresh);
|
|
@@ -296,14 +320,7 @@ function RTE_Plugin_Footnotes() {
|
|
|
296
320
|
if (ref.getAttribute("id") !== "fnref-" + id) ref.setAttribute("id", "fnref-" + id);
|
|
297
321
|
|
|
298
322
|
var note = ol.querySelector('li.rte-fn-note[data-fn-id="' + cssEscape(id) + '"]');
|
|
299
|
-
if (!note)
|
|
300
|
-
// Marker with no note — a paste from elsewhere, or a note the
|
|
301
|
-
// user deleted by hand. Give it an empty note to write into.
|
|
302
|
-
note = doc.createElement("li");
|
|
303
|
-
note.className = "rte-fn-note";
|
|
304
|
-
note.setAttribute("data-fn-id", id);
|
|
305
|
-
note.setAttribute("id", "fn-" + id);
|
|
306
|
-
}
|
|
323
|
+
if (!note) note = noteFor(doc, ol, id, dupOf);
|
|
307
324
|
note.setAttribute("data-fn-number", num);
|
|
308
325
|
// Append in marker order — this both inserts new notes and re-sorts
|
|
309
326
|
// existing ones to match a reordered document.
|
|
@@ -314,7 +331,7 @@ function RTE_Plugin_Footnotes() {
|
|
|
314
331
|
// Drop notes whose marker is gone.
|
|
315
332
|
var notes = Array.prototype.slice.call(ol.querySelectorAll("li.rte-fn-note"));
|
|
316
333
|
for (var j = 0; j < notes.length; j++) {
|
|
317
|
-
if (!seen[notes[j].getAttribute("data-fn-id")]) ol.removeChild(notes[j]);
|
|
334
|
+
if (!seen[notes[j].getAttribute("data-fn-id")]) { keepNotes([notes[j]]); ol.removeChild(notes[j]); }
|
|
318
335
|
}
|
|
319
336
|
|
|
320
337
|
if (ol.getAttribute("data-numbering") !== config.footnotesNumbering) {
|
|
@@ -323,6 +340,43 @@ function RTE_Plugin_Footnotes() {
|
|
|
323
340
|
return out;
|
|
324
341
|
}
|
|
325
342
|
|
|
343
|
+
// 2026-10-03 A note is KEPT when its marker goes, so a marker that comes back - cut + paste, a
|
|
344
|
+
// drag - gets its text back; and a copied marker gets a copy of its note, as in Word. The pass
|
|
345
|
+
// deleted the note and gave the returning marker an EMPTY one: cutting "Beta.[2]" and pasting
|
|
346
|
+
// it earlier renumbered correctly but lost "note B" for good. Kept for the editor's lifetime,
|
|
347
|
+
// keyed by footnote id. tools/footnotes/footnotes-move.mjs
|
|
348
|
+
var keptNotes = {};
|
|
349
|
+
function keepNotes(list) {
|
|
350
|
+
for (var i = 0; i < list.length; i++) {
|
|
351
|
+
var id = list[i].getAttribute("data-fn-id");
|
|
352
|
+
if (id) keptNotes[id] = list[i];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function noteFor(doc, ol, id, dupOf) {
|
|
356
|
+
var note = keptNotes[id];
|
|
357
|
+
if (note) {
|
|
358
|
+
delete keptNotes[id];
|
|
359
|
+
return note;
|
|
360
|
+
}
|
|
361
|
+
var src = dupOf ? (ol.querySelector('li.rte-fn-note[data-fn-id="' + cssEscape(dupOf) + '"]') || keptNotes[dupOf]) : null;
|
|
362
|
+
if (src) {
|
|
363
|
+
note = src.cloneNode(true);
|
|
364
|
+
var backs = note.querySelectorAll("a.rte-fn-back");
|
|
365
|
+
for (var i = 0; i < backs.length; i++) {
|
|
366
|
+
backs[i].setAttribute("data-fn-id", id);
|
|
367
|
+
backs[i].setAttribute("href", "#fnref-" + id);
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
// Marker with no note anywhere - a paste from another document, or a note the user
|
|
371
|
+
// deleted by hand. Give it an empty note to write into.
|
|
372
|
+
note = doc.createElement("li");
|
|
373
|
+
note.className = "rte-fn-note";
|
|
374
|
+
}
|
|
375
|
+
note.setAttribute("data-fn-id", id);
|
|
376
|
+
note.setAttribute("id", "fn-" + id);
|
|
377
|
+
return note;
|
|
378
|
+
}
|
|
379
|
+
|
|
326
380
|
// Read the WHOLE <li> minus the backlink rather than one designated child.
|
|
327
381
|
// The user can type anywhere in the note, and documents saved by an earlier
|
|
328
382
|
// revision still carry a .rte-fn-text wrapper, so anything that trusts a
|