@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
|
@@ -22,7 +22,10 @@ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
|
|
|
22
22
|
var scripts = document.getElementsByTagName("script");
|
|
23
23
|
for (var j = scripts.length - 1; j >= 0; j--) {
|
|
24
24
|
var src = scripts[j].getAttribute("src") || "";
|
|
25
|
-
|
|
25
|
+
// 2026-10-17 the .min names too: a page loading all_plugins.min.js matched nothing and fell back to the fixed
|
|
26
|
+
// /richtexteditor path - the drive root over file://, so the AI stylesheet never loaded from a download opened
|
|
27
|
+
// from disk. tools/ai/aitoolkit-css-location.mjs
|
|
28
|
+
if (/(?:^|\/)(?:aitoolkit|all_plugins)(?:\.min)?\.js(?:[?#].*)?$/i.test(src)) {
|
|
26
29
|
ourScript = scripts[j];
|
|
27
30
|
break;
|
|
28
31
|
}
|
|
@@ -33,11 +36,13 @@ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
|
|
|
33
36
|
// paying for it. The readable .css is still shipped and still the one to edit
|
|
34
37
|
// or override; this only changes what gets fetched by default.
|
|
35
38
|
function resolve(name) {
|
|
36
|
-
return srcAttr
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
if (srcAttr) return srcAttr.replace(/[?#].*$/, "").replace(/[^/]+$/, name);
|
|
40
|
+
// no plugin script of ours (bundled into an app script): the folder rte.js was loaded from, then the old default
|
|
41
|
+
var base = (typeof RichTextEditor !== "undefined" && RichTextEditor.__scriptBase) ||
|
|
42
|
+
(window.RTE_DefaultConfig && window.RTE_DefaultConfig.url_base) || "/richtexteditor";
|
|
43
|
+
return base + "/plugins/" + name;
|
|
39
44
|
}
|
|
40
|
-
function bust(href) { return href.indexOf("?") < 0 ? href + "?v=
|
|
45
|
+
function bust(href) { return href.indexOf("?") < 0 ? href + "?v=20261018a" : href; }
|
|
41
46
|
|
|
42
47
|
var link = document.createElement("link");
|
|
43
48
|
link.rel = "stylesheet";
|
|
@@ -94,6 +99,15 @@ function RTE_Plugin_AIToolkit() {
|
|
|
94
99
|
var obj = this;
|
|
95
100
|
var config;
|
|
96
101
|
var editor;
|
|
102
|
+
// 2026-10-25 UI words outside InitConfig (inline review chips, review shortcuts, Ask AI result / plan, the legacy
|
|
103
|
+
// review layout) read config.text_ keys with English as the fallback; {0} and {1} take the values.
|
|
104
|
+
// tools/i18n/ai-review-chips-language.mjs
|
|
105
|
+
function uiT(key, fallback, a, b) {
|
|
106
|
+
var s = (config && config["text_" + key]) || fallback;
|
|
107
|
+
if (a !== undefined) s = s.split("{0}").join(String(a));
|
|
108
|
+
if (b !== undefined) s = s.split("{1}").join(String(b));
|
|
109
|
+
return s;
|
|
110
|
+
}
|
|
97
111
|
|
|
98
112
|
obj.PluginName = "AIToolkit";
|
|
99
113
|
|
|
@@ -127,26 +141,26 @@ function RTE_Plugin_AIToolkit() {
|
|
|
127
141
|
// in a later pass. Customer overrides via `aiToolkitActions` keep
|
|
128
142
|
// any legacy long-form labels untouched.
|
|
129
143
|
config.aiToolkitActions = config.aiToolkitActions || [
|
|
130
|
-
{ id: "chat-panel", section: "Start", icon: "chat", title: "Chat", description: "Ask follow-up questions about this document.", target: "chat-panel" },
|
|
131
|
-
{ id: "open-dialog", section: "Start", icon: "open_dialog", title: "Draft", description: "Generate, rewrite, translate, or summarize before applying.", target: "dialog" },
|
|
132
|
-
{ id: "review-panel", section: "Start", icon: "review", title: "Review", description: "Accept or reject prepared AI edits.", target: "review-panel" },
|
|
133
|
-
{ id: "proofread", section: "Quick edit", icon: "proofread", title: "Proofread", description: "Check grammar, spacing, and clarity.", resolverMode: "proofread", target: "selection-preview" },
|
|
134
|
-
{ id: "rewrite", section: "Quick edit", icon: "rewrite", title: "Rewrite", description: "Improve clarity without changing intent.", resolverMode: "rewrite", target: "selection-preview" },
|
|
135
|
-
{ id: "translate", section: "Quick edit", icon: "translate", title: "Translate", description: "Choose a language and preview the result.", resolverMode: "translate", target: "dialog", autoRun: false },
|
|
136
|
-
{ id: "justify", section: "Quick edit", icon: "justify", title: "Explain", description: "Rewrite and show why it changed.", resolverMode: "justify", target: "dialog", autoRun: false },
|
|
137
|
-
{ id: "comment", section: "Insert", icon: "comment", title: "Add note", description: "Insert a short comment near the selection.", resolverMode: "comment", target: "comment" },
|
|
138
|
-
{ id: "paragraph", section: "Insert", icon: "paragraph", title: "Add paragraph", description: "Draft a supporting paragraph below.", resolverMode: "paragraph", target: "insert" }
|
|
144
|
+
{ id: "chat-panel", section: aiT("aia_sec_start", "Start"), icon: "chat", title: aiT("aia_chat_panel_t", "Chat"), description: aiT("aia_chat_panel_d", "Ask follow-up questions about this document."), target: "chat-panel" },
|
|
145
|
+
{ id: "open-dialog", section: aiT("aia_sec_start", "Start"), icon: "open_dialog", title: aiT("aia_open_dialog_t", "Draft"), description: aiT("aia_open_dialog_d", "Generate, rewrite, translate, or summarize before applying."), target: "dialog" },
|
|
146
|
+
{ id: "review-panel", section: aiT("aia_sec_start", "Start"), icon: "review", title: aiT("aia_review_panel_t", "Review"), description: aiT("aia_review_panel_d", "Accept or reject prepared AI edits."), target: "review-panel" },
|
|
147
|
+
{ id: "proofread", section: aiT("aia_sec_quick", "Quick edit"), icon: "proofread", title: aiT("aia_proofread_t", "Proofread"), description: aiT("aia_proofread_d", "Check grammar, spacing, and clarity."), resolverMode: "proofread", target: "selection-preview" },
|
|
148
|
+
{ id: "rewrite", section: aiT("aia_sec_quick", "Quick edit"), icon: "rewrite", title: aiT("aia_rewrite_t", "Rewrite"), description: aiT("aia_rewrite_d", "Improve clarity without changing intent."), resolverMode: "rewrite", target: "selection-preview" },
|
|
149
|
+
{ id: "translate", section: aiT("aia_sec_quick", "Quick edit"), icon: "translate", title: aiT("aia_translate_t", "Translate"), description: aiT("aia_translate_d", "Choose a language and preview the result."), resolverMode: "translate", target: "dialog", autoRun: false },
|
|
150
|
+
{ id: "justify", section: aiT("aia_sec_quick", "Quick edit"), icon: "justify", title: aiT("aia_justify_t", "Explain"), description: aiT("aia_justify_d", "Rewrite and show why it changed."), resolverMode: "justify", target: "dialog", autoRun: false },
|
|
151
|
+
{ id: "comment", section: aiT("aia_sec_insert", "Insert"), icon: "comment", title: aiT("aia_comment_t", "Add note"), description: aiT("aia_comment_d", "Insert a short comment near the selection."), resolverMode: "comment", target: "comment" },
|
|
152
|
+
{ id: "paragraph", section: aiT("aia_sec_insert", "Insert"), icon: "paragraph", title: aiT("aia_paragraph_t", "Add paragraph"), description: aiT("aia_paragraph_d", "Draft a supporting paragraph below."), resolverMode: "paragraph", target: "insert" }
|
|
139
153
|
];
|
|
140
154
|
// 2026-05-09 (v20260509j): single-verb default chip labels matching
|
|
141
155
|
// the toolbar dropdown idiom — chips render on one line at the
|
|
142
156
|
// default 390px chat panel width. Customer overrides via
|
|
143
157
|
// aiToolkitChatPrompts keep their own labels untouched.
|
|
144
158
|
config.aiToolkitChatPrompts = config.aiToolkitChatPrompts || [
|
|
145
|
-
{ id: "summarize", label: "Summarize", prompt: "Summarize the current content and suggest the clearest next edit." },
|
|
146
|
-
{ id: "proofread", label: "Proofread", prompt: "Proofread the current content and prepare a cleaner version I can review." },
|
|
147
|
-
{ id: "translate", label: "Translate", prompt: "Translate the current content into Spanish and prepare a reviewable version." },
|
|
148
|
-
{ id: "headings", label: "Headings", prompt: "Suggest better section titles and subheadings for this content." },
|
|
149
|
-
{ id: "expand", label: "Expand", prompt: "Add a short supporting paragraph that strengthens this content." }
|
|
159
|
+
{ id: "summarize", label: aiT("aip_summarize", "Summarize"), prompt: "Summarize the current content and suggest the clearest next edit." },
|
|
160
|
+
{ id: "proofread", label: aiT("aip_proofread", "Proofread"), prompt: "Proofread the current content and prepare a cleaner version I can review." },
|
|
161
|
+
{ id: "translate", label: aiT("aip_translate", "Translate"), prompt: "Translate the current content into Spanish and prepare a reviewable version." },
|
|
162
|
+
{ id: "headings", label: aiT("aip_headings", "Headings"), prompt: "Suggest better section titles and subheadings for this content." },
|
|
163
|
+
{ id: "expand", label: aiT("aip_expand", "Expand"), prompt: "Add a short supporting paragraph that strengthens this content." }
|
|
150
164
|
];
|
|
151
165
|
// 2026-05-20 (v20260520c): descriptions trimmed to ~5-8 words so
|
|
152
166
|
// each fits the one-line mode caption without wrapping at the 480px
|
|
@@ -165,23 +179,29 @@ function RTE_Plugin_AIToolkit() {
|
|
|
165
179
|
// on narrow viewports. Same brevity Notion AI inline composer subtitles
|
|
166
180
|
// ship — "Improve writing", "Make shorter" — single 2-4 word verb
|
|
167
181
|
// phrases.
|
|
182
|
+
// 2026-10-18 the Ask AI dialog's words read config.text_ keys where they are SHOWN (English as the fallback);
|
|
183
|
+
// labels that also feed logic (Document / Selection) are translated at the display sites only.
|
|
184
|
+
// tools/i18n/ask-ai-language.mjs
|
|
185
|
+
function aiT(key, fallback, arg) { var s = (config && config["text_" + key]) || fallback; return arg === undefined ? s : s.split("{0}").join(String(arg)); }
|
|
186
|
+
obj.__aiT = aiT;
|
|
168
187
|
config.aiToolkitDialogModes = config.aiToolkitDialogModes || [
|
|
169
|
-
{ id: "proofread", title: "Proofread", description: "Fix grammar & clarity." },
|
|
170
|
-
{ id: "rewrite", title: "Rewrite", description: "Rewrite for clarity." },
|
|
171
|
-
{ id: "translate", title: "Translate", description: "Translate to a language." },
|
|
172
|
-
{ id: "justify", title: "Explain rewrite", description: "Rewrite and explain why." },
|
|
173
|
-
{ id: "shorten", title: "Shorten", description: "Compress to be shorter." },
|
|
174
|
-
{ id: "expand", title: "Expand", description: "Add supporting detail." },
|
|
175
|
-
{ id: "summarize", title: "Summarize", description: "Summarize the source." }
|
|
188
|
+
{ id: "proofread", title: aiT("aim_proofread_t", "Proofread"), description: aiT("aim_proofread_d", "Fix grammar & clarity.") },
|
|
189
|
+
{ id: "rewrite", title: aiT("aim_rewrite_t", "Rewrite"), description: aiT("aim_rewrite_d", "Rewrite for clarity.") },
|
|
190
|
+
{ id: "translate", title: aiT("aim_translate_t", "Translate"), description: aiT("aim_translate_d", "Translate to a language.") },
|
|
191
|
+
{ id: "justify", title: aiT("aim_justify_t", "Explain rewrite"), description: aiT("aim_justify_d", "Rewrite and explain why.") },
|
|
192
|
+
{ id: "shorten", title: aiT("aim_shorten_t", "Shorten"), description: aiT("aim_shorten_d", "Compress to be shorter.") },
|
|
193
|
+
{ id: "expand", title: aiT("aim_expand_t", "Expand"), description: aiT("aim_expand_d", "Add supporting detail.") },
|
|
194
|
+
{ id: "summarize", title: aiT("aim_summarize_t", "Summarize"), description: aiT("aim_summarize_d", "Summarize the source.") }
|
|
176
195
|
];
|
|
177
196
|
config.aiToolkitResolver = config.aiToolkitResolver || null;
|
|
197
|
+
// 2026-10-13 image generation: the host's provider call, bring your own key. null = not configured.
|
|
198
|
+
config.aiToolkitImageResolver = config.aiToolkitImageResolver || null;
|
|
178
199
|
config.aiToolkitOperationHandlers = config.aiToolkitOperationHandlers || {};
|
|
179
200
|
config.aiToolkitPersistenceKey = config.aiToolkitPersistenceKey || "";
|
|
180
201
|
config.aiToolkitReviewSyncInterval = config.aiToolkitReviewSyncInterval || 15000;
|
|
181
202
|
config.aiToolkitSuggestionLedgerUrl = config.aiToolkitSuggestionLedgerUrl || "";
|
|
182
203
|
config.aiToolkitReviewLogUrl = config.aiToolkitReviewLogUrl || "";
|
|
183
204
|
config.aiToolkitAutoToolbarButtons = config.aiToolkitAutoToolbarButtons !== false;
|
|
184
|
-
config.aiToolkitUiVersion = config.aiToolkitUiVersion || "v20260520k";
|
|
185
205
|
|
|
186
206
|
appendToolbarCommand("toolbar_default", "#{aiassist}");
|
|
187
207
|
appendToolbarCommand("toolbar_basic", "#{aiassist}");
|
|
@@ -200,10 +220,129 @@ function RTE_Plugin_AIToolkit() {
|
|
|
200
220
|
|
|
201
221
|
obj.InitEditor = function (argeditor) {
|
|
202
222
|
editor = argeditor;
|
|
223
|
+
|
|
224
|
+
// 2026-10-13 Image generation (tools/ai/image-generation.mjs). The host supplies the provider call through
|
|
225
|
+
// config.aiToolkitImageResolver, so the editor makes no outbound request of its own. What comes back is checked
|
|
226
|
+
// before anything is inserted: an image data URL (png, jpeg, webp or gif) or an https address, at most 6 million
|
|
227
|
+
// characters.
|
|
228
|
+
var IMAGE_SRC_MAX = 6000000;
|
|
229
|
+
function checkGeneratedImageSrc(src) {
|
|
230
|
+
var s = typeof src === "string" ? src.replace(/^\s+|\s+$/g, "") : "";
|
|
231
|
+
if (!s) throw new Error("The image generator returned no image.");
|
|
232
|
+
if (s.length > IMAGE_SRC_MAX) throw new Error("The generated image is too large to insert.");
|
|
233
|
+
if (/^data:image\/(png|jpe?g|webp|gif);base64,[A-Za-z0-9+\/=]+$/i.test(s)) return s;
|
|
234
|
+
if (/^https:\/\/[^\s"'<>]+$/i.test(s)) return s;
|
|
235
|
+
throw new Error("The image generator returned something that is not an image address.");
|
|
236
|
+
}
|
|
237
|
+
function generateImage(prompt) {
|
|
238
|
+
var text = String(prompt || "").replace(/^\s+|\s+$/g, "");
|
|
239
|
+
if (!text) return Promise.reject(new Error("Describe the image first."));
|
|
240
|
+
var resolver = config.aiToolkitImageResolver;
|
|
241
|
+
if (typeof resolver !== "function") {
|
|
242
|
+
return Promise.reject(new Error("No image generator is configured (config.aiToolkitImageResolver)."));
|
|
243
|
+
}
|
|
244
|
+
return Promise.resolve().then(function () { return resolver(text); }).then(checkGeneratedImageSrc);
|
|
245
|
+
}
|
|
246
|
+
function insertGeneratedImage(src, alt) {
|
|
247
|
+
editor.insertHTML('<img src="' + escapeAttribute(src) + '" alt="' + escapeAttribute(alt || "") + '">');
|
|
248
|
+
try { if (typeof editor.fireChange === "function") editor.fireChange(); } catch (e) { /* ignore */ }
|
|
249
|
+
}
|
|
250
|
+
var imageComposer = null;
|
|
251
|
+
function closeImageComposer() {
|
|
252
|
+
// 2026-10-14 Focus inside the card (Escape, Cancel) goes back to the editor when it closes, so a
|
|
253
|
+
// keyboard user does not land on the page body (WCAG 2.4.3). tools/ai/image-generator-focus.mjs
|
|
254
|
+
var hadFocus = false;
|
|
255
|
+
try { hadFocus = !!(imageComposer && imageComposer.contains(imageComposer.ownerDocument.activeElement)); } catch (e) { /* ignore */ }
|
|
256
|
+
if (imageComposer && imageComposer.parentNode) imageComposer.parentNode.removeChild(imageComposer);
|
|
257
|
+
imageComposer = null;
|
|
258
|
+
if (hadFocus) { try { editor.focus(); } catch (e) { /* ignore */ } }
|
|
259
|
+
}
|
|
260
|
+
// A small prompt card over the editor. Generate inserts the image at the caret and closes the card; Cancel and
|
|
261
|
+
// Escape close it without inserting anything.
|
|
262
|
+
function openImageComposer() {
|
|
263
|
+
closeImageComposer();
|
|
264
|
+
var frame = editor.iframe;
|
|
265
|
+
if (!frame || !frame.ownerDocument) return;
|
|
266
|
+
var host = frame.ownerDocument;
|
|
267
|
+
var box = host.createElement("div");
|
|
268
|
+
box.className = "rte-image-gen";
|
|
269
|
+
box.setAttribute("role", "dialog");
|
|
270
|
+
box.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aig_title", "Generate an image") : "Generate an image"));
|
|
271
|
+
var bs = box.style;
|
|
272
|
+
bs.position = "fixed"; bs.zIndex = "2147483000"; bs.width = "320px"; bs.padding = "12px";
|
|
273
|
+
bs.background = "#fff"; bs.border = "1px solid rgba(0,0,0,.15)"; bs.borderRadius = "8px";
|
|
274
|
+
bs.boxShadow = "0 8px 24px rgba(15,23,42,.18)"; bs.font = "13px/1.4 system-ui, sans-serif"; bs.color = "#1f2937";
|
|
275
|
+
var fr = frame.getBoundingClientRect();
|
|
276
|
+
bs.left = Math.round(fr.left + 16) + "px";
|
|
277
|
+
bs.top = Math.round(fr.top + 16) + "px";
|
|
278
|
+
var label = host.createElement("label");
|
|
279
|
+
label.textContent = (obj.__aiT ? obj.__aiT("aig_describe", "Describe the image") : "Describe the image");
|
|
280
|
+
label.style.display = "block";
|
|
281
|
+
label.style.marginBottom = "6px";
|
|
282
|
+
var area = host.createElement("textarea");
|
|
283
|
+
area.rows = 3;
|
|
284
|
+
area.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aig_describe", "Describe the image") : "Describe the image"));
|
|
285
|
+
area.style.width = "100%"; area.style.boxSizing = "border-box"; area.style.font = "inherit";
|
|
286
|
+
var status = host.createElement("div");
|
|
287
|
+
status.className = "rte-image-gen-status";
|
|
288
|
+
status.setAttribute("aria-live", "polite");
|
|
289
|
+
status.style.minHeight = "18px"; status.style.margin = "6px 0"; status.style.color = "#b91c1c";
|
|
290
|
+
var row = host.createElement("div");
|
|
291
|
+
row.style.textAlign = "right";
|
|
292
|
+
var cancel = host.createElement("button");
|
|
293
|
+
cancel.type = "button";
|
|
294
|
+
cancel.className = "rte-image-gen-cancel";
|
|
295
|
+
cancel.textContent = (obj.__aiT ? obj.__aiT("aig_cancel", "Cancel") : "Cancel");
|
|
296
|
+
cancel.style.marginRight = "6px";
|
|
297
|
+
var go = host.createElement("button");
|
|
298
|
+
go.type = "button";
|
|
299
|
+
go.className = "rte-image-gen-go";
|
|
300
|
+
go.textContent = (obj.__aiT ? obj.__aiT("aig_generate", "Generate") : "Generate");
|
|
301
|
+
go.style.background = "#1d67ba"; go.style.color = "#fff"; go.style.border = "0";
|
|
302
|
+
go.style.borderRadius = "4px"; go.style.padding = "4px 12px";
|
|
303
|
+
go.addEventListener("click", function () {
|
|
304
|
+
var text = area.value.replace(/^\s+|\s+$/g, "");
|
|
305
|
+
if (!text) { status.textContent = (obj.__aiT ? obj.__aiT("aig_describefirst", "Describe the image first.") : "Describe the image first."); return; }
|
|
306
|
+
go.disabled = true;
|
|
307
|
+
status.style.color = "#475569";
|
|
308
|
+
status.textContent = (obj.__aiT ? obj.__aiT("aig_generating", "Generating...") : "Generating...");
|
|
309
|
+
generateImage(text).then(function (src) {
|
|
310
|
+
insertGeneratedImage(src, text);
|
|
311
|
+
closeImageComposer();
|
|
312
|
+
// the Generate button was disabled while it ran, which moved focus out of the card: return it here
|
|
313
|
+
try { editor.focus(); } catch (e) { /* ignore */ }
|
|
314
|
+
}, function (err) {
|
|
315
|
+
go.disabled = false;
|
|
316
|
+
status.style.color = "#b91c1c";
|
|
317
|
+
status.textContent = (err && err.message) || (obj.__aiT ? obj.__aiT("aig_failed", "The image could not be generated.") : "The image could not be generated.");
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
cancel.addEventListener("click", closeImageComposer);
|
|
321
|
+
box.addEventListener("keydown", function (e) {
|
|
322
|
+
if (e.key === "Escape" || e.key === "Esc") { e.preventDefault(); closeImageComposer(); }
|
|
323
|
+
});
|
|
324
|
+
row.appendChild(cancel);
|
|
325
|
+
row.appendChild(go);
|
|
326
|
+
box.appendChild(label);
|
|
327
|
+
box.appendChild(area);
|
|
328
|
+
box.appendChild(status);
|
|
329
|
+
box.appendChild(row);
|
|
330
|
+
host.body.appendChild(box);
|
|
331
|
+
imageComposer = box;
|
|
332
|
+
try { area.focus(); } catch (e) { /* focus is best effort */ }
|
|
333
|
+
}
|
|
334
|
+
editor.generateImage = function (prompt) {
|
|
335
|
+
return generateImage(prompt).then(function (src) { insertGeneratedImage(src, prompt); return true; });
|
|
336
|
+
};
|
|
337
|
+
editor.openImageGenerator = function () { openImageComposer(); };
|
|
338
|
+
|
|
203
339
|
editor.aiToolkit = {
|
|
340
|
+
generateImage: generateImage,
|
|
341
|
+
setImageResolver: function (fn) { config.aiToolkitImageResolver = typeof fn === "function" ? fn : null; },
|
|
204
342
|
normalizeText: normalizeText,
|
|
205
343
|
ensureSentence: ensureSentence,
|
|
206
344
|
buildDemoResult: buildDemoResult,
|
|
345
|
+
isDemoMode: isDemoMode,
|
|
207
346
|
getTranslateLanguages: getTranslateLanguages,
|
|
208
347
|
getTranslateLanguageLabel: getTranslateLanguageLabel,
|
|
209
348
|
getOperationContract: getOperationContract,
|
|
@@ -690,6 +829,21 @@ function RTE_Plugin_AIToolkit() {
|
|
|
690
829
|
config[key] = current ? current + token : token;
|
|
691
830
|
}
|
|
692
831
|
|
|
832
|
+
// 2026-10-15 with no resolver the toolkit answers from built-in samples, and nothing said so: an evaluating
|
|
833
|
+
// customer reported the AI feature as "not working". The dialog and the chat panel now carry a notice while
|
|
834
|
+
// no resolver is set. tools/ai/demo-mode-notice.mjs
|
|
835
|
+
function isDemoMode() {
|
|
836
|
+
return typeof config.aiToolkitResolver !== "function";
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
function appendDemoNotice(parent) {
|
|
840
|
+
if (!isDemoMode()) return null;
|
|
841
|
+
var notice = append(parent, "div", "", "rte-ai-demo-notice",
|
|
842
|
+
config.text_aitoolkitdemonotice || "Demo mode: these are built-in sample results, not a real AI model. Connect an AI provider with the aiToolkitResolver setting to get real suggestions.");
|
|
843
|
+
notice.setAttribute("role", "note");
|
|
844
|
+
return notice;
|
|
845
|
+
}
|
|
846
|
+
|
|
693
847
|
function append(parent, tagName, cssText, className, text) {
|
|
694
848
|
var node = parent.ownerDocument.createElement(tagName);
|
|
695
849
|
if (cssText) {
|
|
@@ -1100,7 +1254,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1100
1254
|
if (mode === "insert" && editor && editor.insertHTML) {
|
|
1101
1255
|
editor.insertHTML(html);
|
|
1102
1256
|
} else if (editor && editor.setHTMLCode) {
|
|
1103
|
-
|
|
1257
|
+
// undoable: Ctrl+Z gives back exactly the document this replaced
|
|
1258
|
+
// (tools/import/replace-undo-plugins.mjs)
|
|
1259
|
+
editor.setHTMLCode(html, { undoable: true });
|
|
1104
1260
|
}
|
|
1105
1261
|
return html;
|
|
1106
1262
|
}).catch(function (err) {
|
|
@@ -1137,6 +1293,385 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1137
1293
|
.trim();
|
|
1138
1294
|
}
|
|
1139
1295
|
|
|
1296
|
+
// 2026-10-18 Spoken labels are phrases joined into sentences. A phrase that already ended one ("... is ready.")
|
|
1297
|
+
// gave "ready.. Document thread"; after such a phrase the next follows with a space. tools/ai/aria-double-period.mjs
|
|
1298
|
+
function joinSentences(parts) {
|
|
1299
|
+
var out = "";
|
|
1300
|
+
for (var i = 0; i < parts.length; i++) {
|
|
1301
|
+
var s = String(parts[i] == null ? "" : parts[i]).replace(/[ \t\r\n]+$/, "");
|
|
1302
|
+
if (!s) continue;
|
|
1303
|
+
out += !out ? s : (/[.?!\u2026\u3002\uff01\uff1f]$/.test(out) ? " " : ". ") + s;
|
|
1304
|
+
}
|
|
1305
|
+
return out;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// 2026-10-18 The inline AI suggestion card and the AI chat compose most of their words - shown and announced -
|
|
1309
|
+
// from many small builders. With a language pack loaded, this catalog translates them where they are displayed:
|
|
1310
|
+
// a whole string, else sentence by sentence, with patterns for the counts ("Queue 1 of 2"). Text a person wrote
|
|
1311
|
+
// (the card's Current / Suggested compare, the chat's messages) is never touched; anything not catalogued stays
|
|
1312
|
+
// as it is; an English page does nothing here. tools/i18n/ai-card-chat-language.mjs
|
|
1313
|
+
var AIQ_EXACT = [
|
|
1314
|
+
["air_accept", "Accept"],
|
|
1315
|
+
["air_reject", "Reject"],
|
|
1316
|
+
["air_current", "Current"],
|
|
1317
|
+
["air_suggested", "Suggested"],
|
|
1318
|
+
["air_why", "Why"],
|
|
1319
|
+
["air_scope_sel", "Selection"],
|
|
1320
|
+
["air_scope_doc", "Document"],
|
|
1321
|
+
["air_type_proofread", "Proofread"],
|
|
1322
|
+
["air_type_rewrite", "Rewrite"],
|
|
1323
|
+
["air_type_translate", "Translate"],
|
|
1324
|
+
["air_type_comment", "Comment"],
|
|
1325
|
+
["air_type_paragraph", "Paragraph"],
|
|
1326
|
+
["air_type_summarize", "Summarize"],
|
|
1327
|
+
["air_type_expand", "Expand"],
|
|
1328
|
+
["air_type_shorten", "Shorten"],
|
|
1329
|
+
["aip_headings", "Headings"],
|
|
1330
|
+
["aichat", "AI Chat"],
|
|
1331
|
+
["aic_newchat", "Start a fresh chat"],
|
|
1332
|
+
["aic_closechat", "Close AI chat"],
|
|
1333
|
+
["aic_close", "Close"],
|
|
1334
|
+
["aic_usesel", "Use selection"],
|
|
1335
|
+
["aic_usedoc", "Use document"],
|
|
1336
|
+
["aic_copymsg", "Copy message text"],
|
|
1337
|
+
["aic_copy", "Copy"],
|
|
1338
|
+
["aic_regen", "Regenerate response"],
|
|
1339
|
+
["aid_regenerate", "Regenerate"],
|
|
1340
|
+
["aic_actions", "AI chat actions"],
|
|
1341
|
+
["aic_send", "Send"],
|
|
1342
|
+
["aic_starttitle", "Start with AI Chat"],
|
|
1343
|
+
["aic_pill_doc", "Document context"],
|
|
1344
|
+
["aic_pill_sel", "Selection context"],
|
|
1345
|
+
["aic_compose_doc", "Compose next AI request for the current document"],
|
|
1346
|
+
["aic_compose_sel", "Compose next AI request for the current selection"],
|
|
1347
|
+
["aic_emptytitle_doc", "Type a prompt or load a starter for the current document first"],
|
|
1348
|
+
["aic_emptytitle_sel", "Type a prompt or load a starter for the current selection first"],
|
|
1349
|
+
["aic_empty_doc", "Ask anything about the current document"],
|
|
1350
|
+
["aic_empty_sel", "Ask anything about the current selection"],
|
|
1351
|
+
["air_focusaria", "Focus the current AI review item"],
|
|
1352
|
+
["aiq_preview", "AI suggestion preview"],
|
|
1353
|
+
["aiq_proposed", "Proposed edit"],
|
|
1354
|
+
["aiq_curandsug", "Current and suggested text"],
|
|
1355
|
+
["aiq_curtext", "Current text"],
|
|
1356
|
+
["aiq_sugtext", "Suggested text"],
|
|
1357
|
+
["aiq_ready", "Ready to review"],
|
|
1358
|
+
["aiq_curfocus", "Current focus"],
|
|
1359
|
+
["aiq_seldraft", "Selection draft"],
|
|
1360
|
+
["aiq_docdraft", "Document draft"],
|
|
1361
|
+
["aiq_prepdraft", "Prepared draft"],
|
|
1362
|
+
["aiq_customdraft", "Custom draft"],
|
|
1363
|
+
["aiq_draftready", "Draft ready"],
|
|
1364
|
+
["aiq_glance", "Change at a glance"],
|
|
1365
|
+
["aiq_surface", "Surface edit"],
|
|
1366
|
+
["aiq_textrewrite", "Text rewrite"],
|
|
1367
|
+
["aiq_textchange", "Text change"],
|
|
1368
|
+
["aiq_langchange", "Language change"],
|
|
1369
|
+
["aiq_reviewchange", "Reviewable change"],
|
|
1370
|
+
["aiq_acceptedchange", "Accepted change"],
|
|
1371
|
+
["aiq_rejectedchange", "Rejected change"],
|
|
1372
|
+
["aiq_lowimpact", "Low impact"],
|
|
1373
|
+
["aiq_medimpact", "Medium impact"],
|
|
1374
|
+
["aiq_highimpact", "High impact"],
|
|
1375
|
+
["aiq_whatnext", "What happens next"],
|
|
1376
|
+
["aiq_qcomplete", "Queue complete"],
|
|
1377
|
+
["aiq_qopened", "Queue opened"],
|
|
1378
|
+
["aiq_qhandoff", "Queue handoff"],
|
|
1379
|
+
["aiq_qstate", "Queue state"],
|
|
1380
|
+
["aiq_recready", "Recovery ready"],
|
|
1381
|
+
["aiq_recavail", "Recovery available"],
|
|
1382
|
+
["aiq_finalitem", "Accepting or rejecting this final pending item finishes the current review run"],
|
|
1383
|
+
["aiq_moveson", "Accepting or rejecting this item moves review straight to the next pending suggestion"],
|
|
1384
|
+
["aiq_nolater", "No later pending items remain in this queue"],
|
|
1385
|
+
["aiq_thenrec", "Then recovery and next queues appear"],
|
|
1386
|
+
["aiq_thencomplete", "Then queue complete"],
|
|
1387
|
+
["aiq_undolast", "Undo the last decision or open another queue"],
|
|
1388
|
+
["aiq_afterfinal", "After reviewing the final pending item, recovery and next queues appear"],
|
|
1389
|
+
["aiq_afterdec", "After this decision"],
|
|
1390
|
+
["aiq_handoff", "Action handoff"],
|
|
1391
|
+
["aiq_decidelane", "Decide lane"],
|
|
1392
|
+
["aiq_curlane", "Current lane"],
|
|
1393
|
+
["aiq_curactionlane", "Current action lane"],
|
|
1394
|
+
["aiq_kblane", "Keyboard lane"],
|
|
1395
|
+
["aiq_curenter", "Current Enter target"],
|
|
1396
|
+
["aiq_spaceact", "Enter or Space activates this action"],
|
|
1397
|
+
["aiq_acceptfinish", "Accept & finish"],
|
|
1398
|
+
["aiq_rejectfinish", "Reject & finish"],
|
|
1399
|
+
["aiq_acceptnext", "Accept & next"],
|
|
1400
|
+
["aiq_rejectnext", "Reject & next"],
|
|
1401
|
+
["aiq_accfinishdesc", "Accept & finish this AI change and finish the current review queue"],
|
|
1402
|
+
["aiq_rejfinishdesc", "Reject & finish this AI change and finish the current review queue"],
|
|
1403
|
+
["aiq_open", "Open"],
|
|
1404
|
+
["aiq_review", "Review"],
|
|
1405
|
+
["aiq_move", "Move"],
|
|
1406
|
+
["aiq_previous", "Previous"],
|
|
1407
|
+
["aiq_next", "Next"],
|
|
1408
|
+
["aiq_decide", "Decide"],
|
|
1409
|
+
["aiq_recover", "Recover"],
|
|
1410
|
+
["aiq_actions", "AI suggestion actions"],
|
|
1411
|
+
["aiq_openactions", "Open actions"],
|
|
1412
|
+
["aiq_moveactions", "Move actions"],
|
|
1413
|
+
["aiq_decideactions", "Decide actions"],
|
|
1414
|
+
["aiq_recoveractions", "Recover actions"],
|
|
1415
|
+
["aiq_whysug", "Why this suggestion"],
|
|
1416
|
+
["aiq_upnext", "Up next"],
|
|
1417
|
+
["aiq_upnextcur", "Up next becomes current"],
|
|
1418
|
+
["aiq_follows", "This follows after the current decision"],
|
|
1419
|
+
["aiq_nextitem", "Next item"],
|
|
1420
|
+
["aiq_reviewnow", "Review this item now"],
|
|
1421
|
+
["aiq_reopen", "Reopen this suggestion in the current review lane"],
|
|
1422
|
+
["aiq_jump", "Jump earlier or later in this queue before deciding"],
|
|
1423
|
+
["aiq_previtem", "Previous AI review item"],
|
|
1424
|
+
["aiq_nextitemai", "Next AI review item"],
|
|
1425
|
+
["aiq_noprev", "No previous AI review item in the current queue"],
|
|
1426
|
+
["aiq_nonext", "No next AI review item in the current queue"],
|
|
1427
|
+
["aiq_shortcuts", "Inline AI review shortcuts"],
|
|
1428
|
+
["aiq_kbguide", "Keyboard guide"],
|
|
1429
|
+
["aiq_move_l", "move"],
|
|
1430
|
+
["aiq_jump_l", "jump"],
|
|
1431
|
+
["aiq_enter", "Enter"],
|
|
1432
|
+
["aiq_custom", "Custom"],
|
|
1433
|
+
["aiq_reason_proof", "Normalizes spacing, punctuation, and capitalization while keeping the original meaning intact"],
|
|
1434
|
+
["aiq_reason_rewrite", "Tightens the wording by removing filler phrases so the point comes through faster"],
|
|
1435
|
+
["aiq_c_ready", "Ready"],
|
|
1436
|
+
["aiq_c_docfocus", "Document focus"],
|
|
1437
|
+
["aiq_c_selfocus", "Selection focus"],
|
|
1438
|
+
["aiq_c_inplace", "Ask, rewrite, or review the current document in place"],
|
|
1439
|
+
["aiq_c_docthread", "Document thread"],
|
|
1440
|
+
["aiq_c_selthread", "Selection thread"],
|
|
1441
|
+
["aiq_c_newask", "Ready for a new ask"],
|
|
1442
|
+
["aiq_c_latest", "Latest reply is ready"],
|
|
1443
|
+
["aiq_c_context", "Context"],
|
|
1444
|
+
["aiq_c_docactive", "Document active"],
|
|
1445
|
+
["aiq_c_selactive", "Selection active"],
|
|
1446
|
+
["aiq_c_nosel", "No current selection"],
|
|
1447
|
+
["aiq_c_selready", "Selection ready"],
|
|
1448
|
+
["aiq_c_wholedoc", "Using the whole document as the active source"],
|
|
1449
|
+
["aiq_c_narrow", "Select text any time to narrow the ask"],
|
|
1450
|
+
["aiq_c_snapshot", "Document snapshot"],
|
|
1451
|
+
["aiq_c_scopeswitch", "Context scope switch"],
|
|
1452
|
+
["aiq_c_unavail", "Unavailable until text is selected"],
|
|
1453
|
+
["aiq_c_activescope", "Active scope"],
|
|
1454
|
+
["aiq_c_usingwhole", "AI Chat is using the whole document"],
|
|
1455
|
+
["aiq_c_quickstarts", "Quick starts"],
|
|
1456
|
+
["aiq_c_readychoose", "Ready to choose"],
|
|
1457
|
+
["aiq_c_choosestarter", "Choose a starter for the current document or keep typing your own prompt in Compose"],
|
|
1458
|
+
["aiq_c_starterbtns", "Starter buttons for the current document"],
|
|
1459
|
+
["aiq_c_loadsstarter", "Loads this starter into Compose for the current document"],
|
|
1460
|
+
["aiq_c_summarystarter", "Summary starter"],
|
|
1461
|
+
["aiq_c_reviewstarter", "Review starter"],
|
|
1462
|
+
["aiq_c_langstarter", "Language starter"],
|
|
1463
|
+
["aiq_c_structstarter", "Structure starter"],
|
|
1464
|
+
["aiq_c_expandstarter", "Expand starter"],
|
|
1465
|
+
["aiq_c_starterready", "Starter ready"],
|
|
1466
|
+
["aiq_c_p_summarize", "Summarize the current content and suggest the clearest next edit"],
|
|
1467
|
+
["aiq_c_p_proofread", "Proofread the current content and prepare a cleaner version I can review"],
|
|
1468
|
+
["aiq_c_p_translate", "Translate the current content into Spanish and prepare a reviewable version"],
|
|
1469
|
+
["aiq_c_p_headings", "Suggest better section titles and subheadings for this content"],
|
|
1470
|
+
["aiq_c_p_expand", "Add a short supporting paragraph that strengthens this content"],
|
|
1471
|
+
["aiq_c_conversation", "Conversation"],
|
|
1472
|
+
["aiq_c_firstex", "First exchange"],
|
|
1473
|
+
["aiq_c_waitfirst", "Waiting for first ask"],
|
|
1474
|
+
["aiq_c_firstanswer", "Your first answer, draft, or reviewable change for the current document will appear here"],
|
|
1475
|
+
["aiq_c_askexplore", "Ask and explore"],
|
|
1476
|
+
["aiq_c_getanswers", "Get answers, summaries, headings, or rewrite direction grounded in the current context"],
|
|
1477
|
+
["aiq_c_prepedits", "Prepare reviewable edits"],
|
|
1478
|
+
["aiq_c_previewinline", "Preview inline changes, apply structured plans, or turn responses into review-ready suggestions"],
|
|
1479
|
+
["aiq_c_usestarters", "Use starters or type your own"],
|
|
1480
|
+
["aiq_c_choosecurated", "Choose one of the curated quick starts above or write a custom prompt in the composer below"],
|
|
1481
|
+
["aiq_c_compose", "Compose"],
|
|
1482
|
+
["aiq_c_readyask", "Ready to ask about the current document"],
|
|
1483
|
+
["aiq_c_entersends", "Enter sends"],
|
|
1484
|
+
["aiq_c_composeactions", "Compose actions"],
|
|
1485
|
+
["aiq_c_openask", "Open Ask AI"],
|
|
1486
|
+
["aiq_c_senddisabled", "Send disabled"],
|
|
1487
|
+
["aiq_c_responseready", "AI response ready"],
|
|
1488
|
+
["aiq_c_replyready", "Reply ready"],
|
|
1489
|
+
["aiq_c_textchange", "This is a text change"],
|
|
1490
|
+
["aiq_c_exchange", "AI chat exchange"],
|
|
1491
|
+
["aiq_c_customex", "Custom exchange"],
|
|
1492
|
+
["aiq_c_request", "Request"],
|
|
1493
|
+
["aiq_c_curexchange", "Current exchange"],
|
|
1494
|
+
["aiq_c_you", "You"],
|
|
1495
|
+
["aiq_c_prompt", "Prompt"],
|
|
1496
|
+
["aiq_c_promptsent", "Prompt sent"],
|
|
1497
|
+
["aiq_c_waitingai", "Waiting on AI for the current document context"],
|
|
1498
|
+
["aiq_c_whatyouasked", "What you asked"],
|
|
1499
|
+
["aiq_c_usingdoc", "Using current document"],
|
|
1500
|
+
["aiq_c_response", "Response"],
|
|
1501
|
+
["aiq_c_answer", "Answer"],
|
|
1502
|
+
["aiq_c_answerready", "Answer ready"],
|
|
1503
|
+
["aiq_c_readanswer", "Read the answer grounded in the current document context"],
|
|
1504
|
+
["aiq_c_copyonly", "Copy only"],
|
|
1505
|
+
["aiq_c_copyonlygroup", "Copy only group"],
|
|
1506
|
+
["aiq_c_copyprep", "Copy this prepared reply without changing the document"],
|
|
1507
|
+
["aiq_c_copyprepai", "Copy this prepared AI reply without changing the document"],
|
|
1508
|
+
["aiq_c_copytext", "Copy text"],
|
|
1509
|
+
["aiq_c_actions", "Actions"],
|
|
1510
|
+
["aiq_c_ai", "AI"]
|
|
1511
|
+
];
|
|
1512
|
+
var AIQ_PATTERNS = [
|
|
1513
|
+
["aiq_p_queue", new RegExp("^Queue (\\d+) of (\\d+)$")],
|
|
1514
|
+
["aiq_p_step", new RegExp("^(\\d+) steps?$")],
|
|
1515
|
+
["aiq_p_keeps", new RegExp("^Keeps (\\d+) words? across (\\d+) sentences?$")],
|
|
1516
|
+
["aiq_p_queuein", new RegExp("^It is queue (\\d+) of (\\d+) in this view$")],
|
|
1517
|
+
["aiq_p_enterfocuses", new RegExp("^Enter focuses (.+)$")],
|
|
1518
|
+
["aiq_p_entercolon", new RegExp("^Enter: (.+)$")],
|
|
1519
|
+
["aiq_p_focus", new RegExp("^[Ff]ocus (.+)$")],
|
|
1520
|
+
["aiq_p_reviewopens", new RegExp("^Review opens on (.+)$")],
|
|
1521
|
+
["aiq_p_openfocus", new RegExp("^Open this AI suggestion in review and focus (.+)$")],
|
|
1522
|
+
["aiq_p_auses", new RegExp("^A uses (.+)$")],
|
|
1523
|
+
["aiq_p_ruses", new RegExp("^R uses (.+)$")],
|
|
1524
|
+
["aiq_p_exchanges", new RegExp("^(\\d+) exchanges?$")],
|
|
1525
|
+
["aiq_p_messages", new RegExp("^(\\d+) messages?$")],
|
|
1526
|
+
["aiq_p_words", new RegExp("^(\\d+) words?$")],
|
|
1527
|
+
["aid_chars", new RegExp("^(\\d+) chars?$")],
|
|
1528
|
+
["aiq_p_paragraphs", new RegExp("^(\\d+) paragraphs?$")],
|
|
1529
|
+
["aic_pill_starters", new RegExp("^(\\d+) starters?$")],
|
|
1530
|
+
["aic_pill_words", new RegExp("^(\\d+) words in scope$")],
|
|
1531
|
+
["aiq_p_exchangen", new RegExp("^Exchange (\\d+)$")],
|
|
1532
|
+
["aiq_p_turn", new RegExp("^Turn (\\d+)$")],
|
|
1533
|
+
["aiq_p_convdoc", new RegExp("^(\\d+) exchanges?, (\\d+) messages? in this conversation for the current document$")],
|
|
1534
|
+
["aiq_p_convsel", new RegExp("^(\\d+) exchanges?, (\\d+) messages? in this conversation for the current selection$")],
|
|
1535
|
+
["aiq_p_threaddoc", new RegExp("^(\\d+) exchanges?, (\\d+) messages? in this document thread$")],
|
|
1536
|
+
["aiq_p_threadsel", new RegExp("^(\\d+) exchanges?, (\\d+) messages? in this selection thread$")],
|
|
1537
|
+
["aiq_p_responding", new RegExp("^Responding to (.+) request$")],
|
|
1538
|
+
["aiq_p_actions", new RegExp("^Actions: (.+)$")]
|
|
1539
|
+
];
|
|
1540
|
+
var aiqIndex = null;
|
|
1541
|
+
function aiqLocale() {
|
|
1542
|
+
var l = config && config.text_uilocale;
|
|
1543
|
+
return l && !/^en(-|$)/i.test(l) ? l : "";
|
|
1544
|
+
}
|
|
1545
|
+
function aiqCjk() { return /^(zh|ja)/i.test(aiqLocale()); }
|
|
1546
|
+
function aiqExact(s) {
|
|
1547
|
+
if (!aiqIndex) {
|
|
1548
|
+
aiqIndex = {};
|
|
1549
|
+
for (var i = 0; i < AIQ_EXACT.length; i++) {
|
|
1550
|
+
var en = AIQ_EXACT[i][1];
|
|
1551
|
+
if (!aiqIndex["=" + en]) aiqIndex["=" + en] = AIQ_EXACT[i][0];
|
|
1552
|
+
if (!aiqIndex["~" + en.toLowerCase()]) aiqIndex["~" + en.toLowerCase()] = AIQ_EXACT[i][0];
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
var key = aiqIndex["=" + s] || aiqIndex["~" + s.toLowerCase()];
|
|
1556
|
+
return (key && config["text_" + key]) || null;
|
|
1557
|
+
}
|
|
1558
|
+
// a phrase without its closing stop: the catalog, then the patterns (a word capture must translate too)
|
|
1559
|
+
function aiqCore(s) {
|
|
1560
|
+
var v = aiqExact(s);
|
|
1561
|
+
if (v) return v;
|
|
1562
|
+
for (var i = 0; i < AIQ_PATTERNS.length; i++) {
|
|
1563
|
+
var m = AIQ_PATTERNS[i][1].exec(s);
|
|
1564
|
+
if (!m) continue;
|
|
1565
|
+
var tpl = config["text_" + AIQ_PATTERNS[i][0]];
|
|
1566
|
+
if (!tpl) return null;
|
|
1567
|
+
var out = tpl;
|
|
1568
|
+
for (var j = 1; j < m.length; j++) {
|
|
1569
|
+
var cap = m[j], tr = /^[0-9]+$/.test(cap) ? cap : aiqCore(cap);
|
|
1570
|
+
if (tr == null) return null;
|
|
1571
|
+
out = out.split("{" + (j - 1) + "}").join(tr);
|
|
1572
|
+
}
|
|
1573
|
+
return out;
|
|
1574
|
+
}
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
function aiqPiece(piece) {
|
|
1578
|
+
var body = piece, punct = "";
|
|
1579
|
+
var last = body.charAt(body.length - 1);
|
|
1580
|
+
if (last === "." || last === ":") { punct = last; body = body.substring(0, body.length - 1); }
|
|
1581
|
+
var v = aiqCore(body);
|
|
1582
|
+
if (v == null) return null;
|
|
1583
|
+
if (punct) {
|
|
1584
|
+
var end = v.charAt(v.length - 1);
|
|
1585
|
+
var closed = ".:!?".indexOf(end) >= 0 || end === String.fromCharCode(0x3002) || end === String.fromCharCode(0xff1a);
|
|
1586
|
+
if (!closed) v += aiqCjk() ? String.fromCharCode(punct === ":" ? 0xff1a : 0x3002) : punct;
|
|
1587
|
+
}
|
|
1588
|
+
return v;
|
|
1589
|
+
}
|
|
1590
|
+
function aiqText(text) {
|
|
1591
|
+
var t = String(text == null ? "" : text).replace(/^\s+|\s+$/g, "");
|
|
1592
|
+
if (!t || !/[A-Za-z]/.test(t)) return null;
|
|
1593
|
+
var whole = aiqPiece(t);
|
|
1594
|
+
if (whole != null) return whole;
|
|
1595
|
+
var dash = t.indexOf(" - ");
|
|
1596
|
+
if (dash > 0) {
|
|
1597
|
+
var a = aiqText(t.substring(0, dash)), b = aiqText(t.substring(dash + 3));
|
|
1598
|
+
if (a != null || b != null) return (a != null ? a : t.substring(0, dash)) + " - " + (b != null ? b : t.substring(dash + 3));
|
|
1599
|
+
}
|
|
1600
|
+
var pieces = t.match(/[^.:!?]+[.:!?]*/g);
|
|
1601
|
+
if (!pieces || pieces.length < 2) return null;
|
|
1602
|
+
var out = "", prevTranslated = false, changed = false;
|
|
1603
|
+
for (var i = 0; i < pieces.length; i++) {
|
|
1604
|
+
var p = pieces[i].replace(/^\s+|\s+$/g, "");
|
|
1605
|
+
if (!p) continue;
|
|
1606
|
+
var tr = aiqPiece(p);
|
|
1607
|
+
if (tr != null) changed = true;
|
|
1608
|
+
var local = tr != null || !/[A-Za-z]/.test(p);
|
|
1609
|
+
var cur = tr != null ? tr : p;
|
|
1610
|
+
out += !out ? cur : ((local && prevTranslated && aiqCjk()) ? "" : " ") + cur;
|
|
1611
|
+
prevTranslated = local;
|
|
1612
|
+
}
|
|
1613
|
+
return changed ? out : null;
|
|
1614
|
+
}
|
|
1615
|
+
var aiqCjkStop = null, aiqCjkGap = null;
|
|
1616
|
+
function aiqFinish(s) {
|
|
1617
|
+
if (s == null || !aiqCjk()) return s;
|
|
1618
|
+
if (!aiqCjkStop) {
|
|
1619
|
+
var cjk = String.fromCharCode(0x4e00) + "-" + String.fromCharCode(0x9fff) + String.fromCharCode(0x3040) + "-" + String.fromCharCode(0x30ff) + String.fromCharCode(0x201d) + String.fromCharCode(0x300d);
|
|
1620
|
+
aiqCjkStop = new RegExp("([" + cjk + "])\\.", "g");
|
|
1621
|
+
aiqCjkGap = new RegExp("([" + String.fromCharCode(0x3002) + String.fromCharCode(0xff1a) + "])\\s+(?=[^A-Za-z0-9\\s])", "g");
|
|
1622
|
+
}
|
|
1623
|
+
return s.replace(aiqCjkStop, "$1" + String.fromCharCode(0x3002)).replace(aiqCjkGap, "$1");
|
|
1624
|
+
}
|
|
1625
|
+
var AIQ_SKIP = ".rte-ai-inline-preview-compare-text, .rte-ai-chat-message-text, .rte-ai-chat-message-request-body, textarea, input, script, style, svg";
|
|
1626
|
+
function aiqLocalize(root) {
|
|
1627
|
+
if (!root || !aiqLocale()) return;
|
|
1628
|
+
var stack = [root];
|
|
1629
|
+
while (stack.length) {
|
|
1630
|
+
var el = stack.pop();
|
|
1631
|
+
if (el.nodeType !== 1) continue;
|
|
1632
|
+
if (el !== root && el.matches && el.matches(AIQ_SKIP)) continue;
|
|
1633
|
+
for (var a = 0; a < 3; a++) {
|
|
1634
|
+
var name = a === 0 ? "aria-label" : (a === 1 ? "title" : "placeholder");
|
|
1635
|
+
var val = el.getAttribute(name);
|
|
1636
|
+
if (val) { var tv = aiqFinish(aiqText(val) || val); if (tv !== val) el.setAttribute(name, tv); }
|
|
1637
|
+
}
|
|
1638
|
+
for (var c = el.firstChild; c; c = c.nextSibling) {
|
|
1639
|
+
if (c.nodeType === 1) stack.push(c);
|
|
1640
|
+
else if (c.nodeType === 3 && /[A-Za-z.]/.test(c.data)) {
|
|
1641
|
+
var tt = aiqFinish(aiqText(c.data) || c.data.replace(/^\s+|\s+$/g, ""));
|
|
1642
|
+
if (tt) {
|
|
1643
|
+
var lead = /^\s*/.exec(c.data)[0], trail = /\s*$/.exec(c.data)[0];
|
|
1644
|
+
if (lead + tt + trail !== c.data) c.data = lead + tt + trail;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
// keep a root localized as the toolkit rebuilds it (idempotent: a translated string has nothing left to match)
|
|
1651
|
+
function aiqWatch(root, select) {
|
|
1652
|
+
if (!root || !aiqLocale() || root.__aiqWatched) return;
|
|
1653
|
+
root.__aiqWatched = true;
|
|
1654
|
+
var run = function () {
|
|
1655
|
+
if (!select) { aiqLocalize(root); return; }
|
|
1656
|
+
var list = root.querySelectorAll(select);
|
|
1657
|
+
for (var i = 0; i < list.length; i++) aiqLocalize(list[i]);
|
|
1658
|
+
};
|
|
1659
|
+
run();
|
|
1660
|
+
var win = root.ownerDocument && root.ownerDocument.defaultView;
|
|
1661
|
+
var MO = win && win.MutationObserver;
|
|
1662
|
+
if (!MO) return;
|
|
1663
|
+
var pending = false;
|
|
1664
|
+
new MO(function () {
|
|
1665
|
+
if (pending) return;
|
|
1666
|
+
pending = true;
|
|
1667
|
+
win.setTimeout(function () { pending = false; run(); }, 0);
|
|
1668
|
+
}).observe(root, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["aria-label", "title", "placeholder"] });
|
|
1669
|
+
}
|
|
1670
|
+
function aiqWatchCards() {
|
|
1671
|
+
var editable = editor.getEditable ? editor.getEditable() : null;
|
|
1672
|
+
if (editable) aiqWatch(editable, ".rte-ai-inline-preview");
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1140
1675
|
function ensureSentence(text) {
|
|
1141
1676
|
var clean = normalizeText(text);
|
|
1142
1677
|
if (!clean) {
|
|
@@ -1157,6 +1692,24 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1157
1692
|
return normalizeText(language || "").toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
1158
1693
|
}
|
|
1159
1694
|
|
|
1695
|
+
// 2026-10-18 the Translate-to list names the built-in languages in the page's language (Intl.DisplayNames in the
|
|
1696
|
+
// pack's locale, text_uilocale) at the display site only; values and the language a request names are unchanged,
|
|
1697
|
+
// and an application's own label is kept. tools/i18n/ai-translate-languages.mjs
|
|
1698
|
+
var TRANSLATE_BUILTIN = { spanish: ["es", "Spanish"], french: ["fr", "French"], german: ["de", "German"], italian: ["it", "Italian"], portuguese: ["pt", "Portuguese"], japanese: ["ja", "Japanese"] };
|
|
1699
|
+
function getTranslateLanguageDisplay(entry) {
|
|
1700
|
+
var label = entry.label || entry.value;
|
|
1701
|
+
var builtIn = TRANSLATE_BUILTIN[normalizeLanguageValue(entry.value)];
|
|
1702
|
+
var locale = config && config.text_uilocale;
|
|
1703
|
+
if (!builtIn || label !== builtIn[1] || !locale || /^en(-|$)/i.test(locale)) return label;
|
|
1704
|
+
try {
|
|
1705
|
+
if (typeof Intl !== "undefined" && Intl.DisplayNames) {
|
|
1706
|
+
var n = new Intl.DisplayNames([locale], { type: "language" }).of(builtIn[0]);
|
|
1707
|
+
if (n && n !== builtIn[0]) return n;
|
|
1708
|
+
}
|
|
1709
|
+
} catch (e) { /* the English label */ }
|
|
1710
|
+
return label;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1160
1713
|
function getTranslateLanguageLabel(language) {
|
|
1161
1714
|
var normalized = normalizeLanguageValue(language);
|
|
1162
1715
|
var languages = getTranslateLanguages();
|
|
@@ -1187,27 +1740,27 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1187
1740
|
function getSuggestionTypeLabel(type) {
|
|
1188
1741
|
switch (getSuggestionTypeValue(type)) {
|
|
1189
1742
|
case "proofread":
|
|
1190
|
-
return "Proofread";
|
|
1743
|
+
return (obj.__aiT ? obj.__aiT("air_type_proofread", "Proofread") : "Proofread");
|
|
1191
1744
|
case "rewrite":
|
|
1192
|
-
return "Rewrite";
|
|
1745
|
+
return (obj.__aiT ? obj.__aiT("air_type_rewrite", "Rewrite") : "Rewrite");
|
|
1193
1746
|
case "translate":
|
|
1194
|
-
return "Translate";
|
|
1747
|
+
return (obj.__aiT ? obj.__aiT("air_type_translate", "Translate") : "Translate");
|
|
1195
1748
|
case "justify":
|
|
1196
|
-
return "Justify";
|
|
1749
|
+
return (obj.__aiT ? obj.__aiT("air_type_justify", "Justify") : "Justify");
|
|
1197
1750
|
case "summarize":
|
|
1198
|
-
return "Summarize";
|
|
1751
|
+
return (obj.__aiT ? obj.__aiT("air_type_summarize", "Summarize") : "Summarize");
|
|
1199
1752
|
case "shorten":
|
|
1200
|
-
return "Shorten";
|
|
1753
|
+
return (obj.__aiT ? obj.__aiT("air_type_shorten", "Shorten") : "Shorten");
|
|
1201
1754
|
case "expand":
|
|
1202
|
-
return "Expand";
|
|
1755
|
+
return (obj.__aiT ? obj.__aiT("air_type_expand", "Expand") : "Expand");
|
|
1203
1756
|
case "comment":
|
|
1204
|
-
return "Comment";
|
|
1757
|
+
return (obj.__aiT ? obj.__aiT("air_type_comment", "Comment") : "Comment");
|
|
1205
1758
|
case "paragraph":
|
|
1206
|
-
return "Paragraph";
|
|
1759
|
+
return (obj.__aiT ? obj.__aiT("air_type_paragraph", "Paragraph") : "Paragraph");
|
|
1207
1760
|
case "chat":
|
|
1208
|
-
return "Chat";
|
|
1761
|
+
return (obj.__aiT ? obj.__aiT("air_type_chat", "Chat") : "Chat");
|
|
1209
1762
|
default:
|
|
1210
|
-
return "Other";
|
|
1763
|
+
return (obj.__aiT ? obj.__aiT("air_type_other", "Other") : "Other");
|
|
1211
1764
|
}
|
|
1212
1765
|
}
|
|
1213
1766
|
|
|
@@ -1358,7 +1911,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1358
1911
|
if (options.redoNextLabel) {
|
|
1359
1912
|
parts.push(options.redoNextLabel);
|
|
1360
1913
|
}
|
|
1361
|
-
return parts
|
|
1914
|
+
return joinSentences(parts);
|
|
1362
1915
|
}
|
|
1363
1916
|
|
|
1364
1917
|
function buildSuggestionSourceLabel(type, snapshot, language, scope) {
|
|
@@ -1383,11 +1936,11 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1383
1936
|
var languageValue = getTranslateLanguageValue(language);
|
|
1384
1937
|
var languageLabel = getTranslateLanguageLabel(languageValue);
|
|
1385
1938
|
var leadMap = {
|
|
1386
|
-
spanish: "Version en
|
|
1387
|
-
french: "Version
|
|
1939
|
+
spanish: "Version en espa\xf1ol",
|
|
1940
|
+
french: "Version fran\xe7aise",
|
|
1388
1941
|
german: "Deutsche Fassung",
|
|
1389
1942
|
italian: "Versione italiana",
|
|
1390
|
-
portuguese: "
|
|
1943
|
+
portuguese: "Vers\xe3o em portugu\xeas",
|
|
1391
1944
|
japanese: "Japanese draft"
|
|
1392
1945
|
};
|
|
1393
1946
|
var lead = leadMap[languageValue] || (languageLabel + " version");
|
|
@@ -1402,20 +1955,29 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1402
1955
|
}
|
|
1403
1956
|
|
|
1404
1957
|
var words = clean.split(/\s+/);
|
|
1958
|
+
// 2026-10-18 an in-place edit ends like the selection it replaces: one that stops before the end of its
|
|
1959
|
+
// paragraph gains no closing stop, one that starts mid-sentence keeps its first letter. Proofreading "Hello world"
|
|
1960
|
+
// in "Hello world, this is a test." gave "Hello world., this is a test.". tools/ai/demo-proofread-fragment.mjs
|
|
1961
|
+
function finishEdit(text) {
|
|
1962
|
+
var s = normalizeText(text);
|
|
1963
|
+
if (!s) return s;
|
|
1964
|
+
if (!options.midStart) s = s.charAt(0).toUpperCase() + s.substring(1);
|
|
1965
|
+
if (!options.midEnd && !/[.!?]$/.test(s)) s += ".";
|
|
1966
|
+
return s;
|
|
1967
|
+
}
|
|
1405
1968
|
switch (mode) {
|
|
1406
1969
|
case "proofread":
|
|
1407
1970
|
var proofed = clean
|
|
1408
1971
|
.replace(/\s{2,}/g, " ")
|
|
1409
1972
|
.replace(/\s+([,.;:!?])/g, "$1")
|
|
1410
1973
|
.replace(/([,.;:!?])([^\s"'\)\]])/g, "$1 $2")
|
|
1411
|
-
.replace(/\.{2,}(?!\.)/g, ".")
|
|
1412
|
-
|
|
1413
|
-
return ensureSentence(proofed);
|
|
1974
|
+
.replace(/\.{2,}(?!\.)/g, ".");
|
|
1975
|
+
return finishEdit(proofed);
|
|
1414
1976
|
case "rewrite":
|
|
1415
|
-
return
|
|
1416
|
-
.replace(/\bvery\s
|
|
1417
|
-
.replace(/\breally\s
|
|
1418
|
-
.replace(/\bjust\s
|
|
1977
|
+
return finishEdit(clean
|
|
1978
|
+
.replace(/\bvery\b\s*/gi, "")
|
|
1979
|
+
.replace(/\breally\b\s*/gi, "")
|
|
1980
|
+
.replace(/\bjust\b\s*/gi, "")
|
|
1419
1981
|
.replace(/\bin order to\b/gi, "to")
|
|
1420
1982
|
.replace(/\bdue to the fact that\b/gi, "because")
|
|
1421
1983
|
.replace(/\s{2,}/g, " "));
|
|
@@ -1445,7 +2007,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1445
2007
|
if (!clean) {
|
|
1446
2008
|
return "Additional paragraph: This section adds a concise supporting explanation so the reader gets more context without losing momentum.";
|
|
1447
2009
|
}
|
|
1448
|
-
return ensureSentence("Additional paragraph: This section adds a concise supporting explanation that reinforces " + clean.split(/\s+/).slice(0, 10).join(" ") + " for the reader.");
|
|
2010
|
+
return ensureSentence("Additional paragraph: This section adds a concise supporting explanation that reinforces " + clean.split(/\s+/).slice(0, 10).join(" ").replace(/[.!?;:,]+$/, "") + " for the reader.");
|
|
1449
2011
|
}
|
|
1450
2012
|
|
|
1451
2013
|
function truncateText(text, maxLength) {
|
|
@@ -1457,7 +2019,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1457
2019
|
}
|
|
1458
2020
|
|
|
1459
2021
|
function buildChatAnswer(prompt, source) {
|
|
1460
|
-
|
|
2022
|
+
// 2026-10-18 the quoted text loses its own closing stop, or the reply read "this is a test.. Ask me" and
|
|
2023
|
+
// "test., I would". tools/ai/aria-double-period.mjs
|
|
2024
|
+
var focus = String(truncateText(source, 160) || "").replace(/[ \t\r\n.!?;:,]+$/, "") || "the current document";
|
|
1461
2025
|
if (/\b(headings?|titles?)\b/.test(prompt)) {
|
|
1462
2026
|
return "You could tighten the structure by using shorter headings that mirror the main claims in " + focus + ". Ask me to draft heading options and I can turn them into reviewable suggestions.";
|
|
1463
2027
|
}
|
|
@@ -1996,7 +2560,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
1996
2560
|
if (unavailableReason) {
|
|
1997
2561
|
parts.push(unavailableReason);
|
|
1998
2562
|
}
|
|
1999
|
-
button.setAttribute("aria-label", parts
|
|
2563
|
+
button.setAttribute("aria-label", joinSentences(parts));
|
|
2000
2564
|
button.title = detail
|
|
2001
2565
|
? (label || "Action") + " - " + detail + (unavailableReason ? " " + unavailableReason : "")
|
|
2002
2566
|
: (label || "Action") + (unavailableReason ? " - " + unavailableReason : "");
|
|
@@ -2011,13 +2575,34 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2011
2575
|
}, action, request);
|
|
2012
2576
|
}
|
|
2013
2577
|
|
|
2578
|
+
// Whether a selection starts mid-sentence (text before it in its block that does not end a sentence) and ends
|
|
2579
|
+
// before its block does (text after it). Only for a selection; a document-wide request is a whole text.
|
|
2580
|
+
function selectionSentenceContext(request) {
|
|
2581
|
+
var out = { midStart: false, midEnd: false };
|
|
2582
|
+
try {
|
|
2583
|
+
var snap = request && request.snapshot;
|
|
2584
|
+
var r = snap && snap.hasSelection && request.scope !== "document" ? snap.range : null;
|
|
2585
|
+
if (!r) return out;
|
|
2586
|
+
var doc = r.startContainer.ownerDocument;
|
|
2587
|
+
var blockOf = function (n) {
|
|
2588
|
+
var el = n && n.nodeType === 1 ? n : (n && n.parentNode);
|
|
2589
|
+
while (el && el.nodeType === 1 && !/^(P|LI|TD|TH|H[1-6]|DIV|BLOCKQUOTE|PRE|BODY)$/.test(el.nodeName)) el = el.parentNode;
|
|
2590
|
+
return el && el.nodeType === 1 ? el : null;
|
|
2591
|
+
};
|
|
2592
|
+
var b1 = blockOf(r.startContainer), b2 = blockOf(r.endContainer);
|
|
2593
|
+
if (b1) { var pre = doc.createRange(); pre.selectNodeContents(b1); pre.setEnd(r.startContainer, r.startOffset); var before = pre.toString(); out.midStart = /\S/.test(before) && !/[.!?]["'\u201d)\]]*\s*$/.test(before); }
|
|
2594
|
+
if (b2) { var post = doc.createRange(); post.selectNodeContents(b2); post.setStart(r.endContainer, r.endOffset); out.midEnd = /\S/.test(post.toString()); }
|
|
2595
|
+
} catch (e) { /* a whole text */ }
|
|
2596
|
+
return out;
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2014
2599
|
function defaultResolveAction(request) {
|
|
2015
2600
|
switch (request.mode) {
|
|
2016
2601
|
case "proofread":
|
|
2017
2602
|
var proofReason = "Normalizes spacing, punctuation, and capitalization while keeping the original meaning intact.";
|
|
2018
2603
|
return {
|
|
2019
2604
|
operations: [
|
|
2020
|
-
buildLegacyOperation(request.action && request.action.target ? request.action.target : "selection-preview", buildDemoResult("proofread", request.source), { reason: proofReason }, request, request.action)
|
|
2605
|
+
buildLegacyOperation(request.action && request.action.target ? request.action.target : "selection-preview", buildDemoResult("proofread", request.source, selectionSentenceContext(request)), { reason: proofReason }, request, request.action)
|
|
2021
2606
|
],
|
|
2022
2607
|
reason: proofReason
|
|
2023
2608
|
};
|
|
@@ -2025,7 +2610,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2025
2610
|
var rewriteReason = "Tightens the wording by removing filler phrases so the point comes through faster.";
|
|
2026
2611
|
return {
|
|
2027
2612
|
operations: [
|
|
2028
|
-
buildLegacyOperation(request.action && request.action.target ? request.action.target : "selection-preview", buildDemoResult("rewrite", request.source), { reason: rewriteReason }, request, request.action)
|
|
2613
|
+
buildLegacyOperation(request.action && request.action.target ? request.action.target : "selection-preview", buildDemoResult("rewrite", request.source, selectionSentenceContext(request)), { reason: rewriteReason }, request, request.action)
|
|
2029
2614
|
],
|
|
2030
2615
|
reason: rewriteReason
|
|
2031
2616
|
};
|
|
@@ -2048,7 +2633,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2048
2633
|
operations: [
|
|
2049
2634
|
{
|
|
2050
2635
|
type: "preview-suggestion",
|
|
2051
|
-
text: buildDemoResult("rewrite", request.source),
|
|
2636
|
+
text: buildDemoResult("rewrite", request.source, selectionSentenceContext(request)),
|
|
2052
2637
|
reason: "This rewrite reduces filler language, clarifies the main point, and makes the sentence easier to review before accepting."
|
|
2053
2638
|
}
|
|
2054
2639
|
],
|
|
@@ -2534,6 +3119,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2534
3119
|
scope: suggestion.snapshot && suggestion.snapshot.hasSelection ? "selection" : "document",
|
|
2535
3120
|
text: suggestion.text || "",
|
|
2536
3121
|
blockPath: suggestion.blockPath || "",
|
|
3122
|
+
mentions: cleanLedgerMentions(suggestion.mentions),
|
|
3123
|
+
reactions: cleanLedgerReactions(suggestion.reactions),
|
|
2537
3124
|
replies: Array.isArray(suggestion.replies) ? suggestion.replies : []
|
|
2538
3125
|
};
|
|
2539
3126
|
}
|
|
@@ -2548,7 +3135,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2548
3135
|
if (!html) return "";
|
|
2549
3136
|
html = String(html);
|
|
2550
3137
|
if (typeof editor.sanitizeHtml === "function") html = editor.sanitizeHtml(html);
|
|
2551
|
-
var doc = new DOMParser().parseFromString("<body>" + html + "</body>", "text/html");
|
|
3138
|
+
var doc = new DOMParser().parseFromString(__RTE_TT("<body>" + html + "</body>"), "text/html");
|
|
2552
3139
|
var styled = doc.body.querySelectorAll("[style]");
|
|
2553
3140
|
for (var i = 0; i < styled.length; i++) {
|
|
2554
3141
|
var st = styled[i].style;
|
|
@@ -2560,6 +3147,33 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2560
3147
|
}
|
|
2561
3148
|
return doc.body.innerHTML;
|
|
2562
3149
|
}
|
|
3150
|
+
// 2026-10-12 comment mentions: the { id, name } pairs a comment names, kept with the comment in the shared store.
|
|
3151
|
+
function cleanLedgerMentions(list) {
|
|
3152
|
+
var out = [];
|
|
3153
|
+
if (!Array.isArray(list)) return out;
|
|
3154
|
+
for (var i = 0; i < list.length; i++) {
|
|
3155
|
+
var m = list[i];
|
|
3156
|
+
if (m && m.id != null && m.name) out.push({ id: String(m.id), name: String(m.name) });
|
|
3157
|
+
}
|
|
3158
|
+
return out;
|
|
3159
|
+
}
|
|
3160
|
+
// 2026-10-15 comment reactions: [{ emoji, users: [id] }], kept with the comment like mentions.
|
|
3161
|
+
function cleanLedgerReactions(list) {
|
|
3162
|
+
var out = [];
|
|
3163
|
+
if (!Array.isArray(list)) return out;
|
|
3164
|
+
for (var i = 0; i < list.length && out.length < 20; i++) {
|
|
3165
|
+
var r = list[i];
|
|
3166
|
+
if (!r || typeof r.emoji !== "string" || !r.emoji || r.emoji.length > 8 || !Array.isArray(r.users)) continue;
|
|
3167
|
+
var users = [];
|
|
3168
|
+
for (var j = 0; j < r.users.length; j++) {
|
|
3169
|
+
var u = r.users[j] == null ? "" : String(r.users[j]);
|
|
3170
|
+
if (u && users.indexOf(u) < 0) users.push(u);
|
|
3171
|
+
}
|
|
3172
|
+
if (users.length) out.push({ emoji: r.emoji, users: users });
|
|
3173
|
+
}
|
|
3174
|
+
return out;
|
|
3175
|
+
}
|
|
3176
|
+
|
|
2563
3177
|
|
|
2564
3178
|
function normalizeLedgerEntry(raw) {
|
|
2565
3179
|
if (!raw || !raw.id) return null;
|
|
@@ -2592,6 +3206,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2592
3206
|
sourceLabel: raw.sourceLabel || "",
|
|
2593
3207
|
snapshot: raw.snapshot || { hasSelection: raw.scope === "selection" },
|
|
2594
3208
|
text: raw.text || "",
|
|
3209
|
+
mentions: cleanLedgerMentions(raw.mentions),
|
|
3210
|
+
reactions: cleanLedgerReactions(raw.reactions),
|
|
2595
3211
|
blockPath: raw.blockPath || "",
|
|
2596
3212
|
replies: Array.isArray(raw.replies) ? raw.replies : []
|
|
2597
3213
|
};
|
|
@@ -2634,6 +3250,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2634
3250
|
hasSelection: raw.scope === "selection"
|
|
2635
3251
|
},
|
|
2636
3252
|
text: raw.text || "",
|
|
3253
|
+
mentions: cleanLedgerMentions(raw.mentions),
|
|
3254
|
+
reactions: cleanLedgerReactions(raw.reactions),
|
|
2637
3255
|
blockPath: raw.blockPath || "",
|
|
2638
3256
|
replies: Array.isArray(raw.replies) ? raw.replies : []
|
|
2639
3257
|
};
|
|
@@ -2689,6 +3307,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2689
3307
|
createdAt: suggestion.createdAt || 0,
|
|
2690
3308
|
decidedAt: suggestion.decidedAt || 0,
|
|
2691
3309
|
sourceLabel: suggestion.sourceLabel || "",
|
|
3310
|
+
mentions: cleanLedgerMentions(suggestion.mentions),
|
|
3311
|
+
reactions: cleanLedgerReactions(suggestion.reactions),
|
|
2692
3312
|
snapshot: {
|
|
2693
3313
|
hasSelection: !!(suggestion.snapshot && suggestion.snapshot.hasSelection)
|
|
2694
3314
|
}
|
|
@@ -2988,7 +3608,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2988
3608
|
|
|
2989
3609
|
if (suggestion.status === "pending") {
|
|
2990
3610
|
if (resolvedWrapper) {
|
|
2991
|
-
resolvedWrapper.outerHTML = createInlinePreviewHtml(suggestion);
|
|
3611
|
+
resolvedWrapper.outerHTML = __RTE_TT(createInlinePreviewHtml(suggestion));
|
|
2992
3612
|
updated = true;
|
|
2993
3613
|
}
|
|
2994
3614
|
continue;
|
|
@@ -2997,7 +3617,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
2997
3617
|
if (suggestion.status === "accepted" || suggestion.status === "rejected" || suggestion.status === "stale") {
|
|
2998
3618
|
var resolvedHtml = getResolvedSuggestionHtml(suggestion, suggestion.status);
|
|
2999
3619
|
if (previewWrapper) {
|
|
3000
|
-
previewWrapper.outerHTML = resolvedHtml;
|
|
3620
|
+
previewWrapper.outerHTML = __RTE_TT(resolvedHtml);
|
|
3001
3621
|
updated = true;
|
|
3002
3622
|
}
|
|
3003
3623
|
else if (resolvedWrapper && (
|
|
@@ -3006,7 +3626,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
3006
3626
|
? (suggestion.resultHtml || textToInlineHtml(suggestion.resultText || ""))
|
|
3007
3627
|
: (suggestion.originalHtml || textToInlineHtml(suggestion.originalText || "")))
|
|
3008
3628
|
)) {
|
|
3009
|
-
resolvedWrapper.outerHTML = resolvedHtml;
|
|
3629
|
+
resolvedWrapper.outerHTML = __RTE_TT(resolvedHtml);
|
|
3010
3630
|
updated = true;
|
|
3011
3631
|
}
|
|
3012
3632
|
}
|
|
@@ -3792,7 +4412,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
3792
4412
|
}
|
|
3793
4413
|
|
|
3794
4414
|
remoteChip.textContent = sharedUpdateCount > 1 ? sharedUpdateCount + " shared updates" : "Shared update";
|
|
3795
|
-
remoteChip.setAttribute("aria-label", "Shared AI review updates");
|
|
4415
|
+
remoteChip.setAttribute("aria-label", uiT("aiu_sharedupdates", "Shared AI review updates"));
|
|
3796
4416
|
|
|
3797
4417
|
var referenceNode = anchorNode && anchorNode.parentNode === wrapper ? anchorNode : (wrapper.querySelector ? wrapper.querySelector(".rte-ai-inline-preview-actions") : null);
|
|
3798
4418
|
if (referenceNode && referenceNode.parentNode === wrapper) {
|
|
@@ -3988,7 +4608,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
3988
4608
|
wrappers[i].appendChild(openedChip);
|
|
3989
4609
|
}
|
|
3990
4610
|
}
|
|
3991
|
-
openedChip.textContent = "Queue opened";
|
|
4611
|
+
openedChip.textContent = uiT("aiu_queueopened", "Queue opened");
|
|
3992
4612
|
openedChip.setAttribute("aria-label", "AI review queue opened");
|
|
3993
4613
|
}
|
|
3994
4614
|
else if (openedChip && openedChip.parentNode) {
|
|
@@ -4019,7 +4639,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4019
4639
|
wrappers[i].appendChild(focusChip);
|
|
4020
4640
|
}
|
|
4021
4641
|
}
|
|
4022
|
-
focusChip.textContent = "Focus "
|
|
4642
|
+
focusChip.textContent = uiT("aiu_focus", "Focus {0}", aiqText(queueFocusLabel) || queueFocusLabel);
|
|
4023
4643
|
focusChip.setAttribute("aria-label", "Queue opens on " + queueFocusLabel);
|
|
4024
4644
|
}
|
|
4025
4645
|
else if (focusChip && focusChip.parentNode) {
|
|
@@ -4105,9 +4725,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4105
4725
|
actionsNodeForSharedState.appendChild(sharedSeenButton);
|
|
4106
4726
|
}
|
|
4107
4727
|
}
|
|
4108
|
-
sharedSeenButton.textContent = "Got it";
|
|
4109
|
-
sharedSeenButton.setAttribute("aria-label", "Clear shared AI review update notice");
|
|
4110
|
-
sharedSeenButton.title = "Clear shared AI review update notice";
|
|
4728
|
+
sharedSeenButton.textContent = uiT("aiu_gotit", "Got it");
|
|
4729
|
+
sharedSeenButton.setAttribute("aria-label", uiT("aiu_clearshared", "Clear shared AI review update notice"));
|
|
4730
|
+
sharedSeenButton.title = uiT("aiu_clearshared", "Clear shared AI review update notice");
|
|
4111
4731
|
applyInlineReviewButtonShortcutState(sharedSeenButton, "Clear shared AI review update notice", inlineButtonShortcutOptions);
|
|
4112
4732
|
}
|
|
4113
4733
|
else if (sharedSeenButton && sharedSeenButton.parentNode) {
|
|
@@ -4163,8 +4783,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4163
4783
|
}
|
|
4164
4784
|
}
|
|
4165
4785
|
}
|
|
4166
|
-
queueChip.textContent = "
|
|
4167
|
-
queueChip.setAttribute("aria-label", "Current AI review queue position");
|
|
4786
|
+
queueChip.textContent = uiT("aiu_itemof", "Item {0} of {1}", pendingPosition.index, pendingPosition.total);
|
|
4787
|
+
queueChip.setAttribute("aria-label", uiT("aiu_queuepos", "Current AI review queue position"));
|
|
4168
4788
|
}
|
|
4169
4789
|
else if (queueChip && queueChip.parentNode) {
|
|
4170
4790
|
queueChip.parentNode.removeChild(queueChip);
|
|
@@ -4240,7 +4860,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4240
4860
|
wrappers[i].appendChild(undoNextChip);
|
|
4241
4861
|
}
|
|
4242
4862
|
}
|
|
4243
|
-
undoNextChip.textContent = "Then "
|
|
4863
|
+
undoNextChip.textContent = uiT("aiu_then", "Then {0}", aiqText(undoInlineNextItem.label) || undoInlineNextItem.label);
|
|
4244
4864
|
undoNextChip.setAttribute("aria-label", "Undo after this: " + undoInlineNextItem.detail);
|
|
4245
4865
|
}
|
|
4246
4866
|
else if (undoNextChip && undoNextChip.parentNode) {
|
|
@@ -4276,7 +4896,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4276
4896
|
wrappers[i].appendChild(redoNextChip);
|
|
4277
4897
|
}
|
|
4278
4898
|
}
|
|
4279
|
-
redoNextChip.textContent = "Then "
|
|
4899
|
+
redoNextChip.textContent = uiT("aiu_then", "Then {0}", aiqText(redoInlineNextItem.label) || redoInlineNextItem.label);
|
|
4280
4900
|
redoNextChip.setAttribute("aria-label", "Redo after this: " + redoInlineNextItem.detail);
|
|
4281
4901
|
}
|
|
4282
4902
|
else if (redoNextChip && redoNextChip.parentNode) {
|
|
@@ -4295,7 +4915,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4295
4915
|
}
|
|
4296
4916
|
}
|
|
4297
4917
|
shortcutsChip.textContent = getSuggestionQueueShortcutHint(suggestion);
|
|
4298
|
-
shortcutsChip.setAttribute("aria-label", "Inline queue preview shortcut");
|
|
4918
|
+
shortcutsChip.setAttribute("aria-label", uiT("aiu_previewshortcut", "Inline queue preview shortcut"));
|
|
4299
4919
|
}
|
|
4300
4920
|
else if (!shortcutsChip) {
|
|
4301
4921
|
shortcutsChip = document.createElement("span");
|
|
@@ -4475,7 +5095,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4475
5095
|
wrappers[i].appendChild(focusChip);
|
|
4476
5096
|
}
|
|
4477
5097
|
}
|
|
4478
|
-
focusChip.textContent = "Focus "
|
|
5098
|
+
focusChip.textContent = uiT("aiu_focus", "Focus {0}", aiqText(reviewFocusLabel) || reviewFocusLabel);
|
|
4479
5099
|
focusChip.setAttribute("aria-label", "Review opens on " + reviewFocusLabel);
|
|
4480
5100
|
}
|
|
4481
5101
|
else if (focusChip && focusChip.parentNode) {
|
|
@@ -4942,13 +5562,13 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4942
5562
|
var bodyNode = ownerDocument.createElement("span");
|
|
4943
5563
|
bodyNode.className = "rte-ai-inline-preview-shortcuts-body";
|
|
4944
5564
|
shortcutsChip.appendChild(bodyNode);
|
|
4945
|
-
var pieces = String(text || "").split(/(\s
|
|
5565
|
+
var pieces = String(text || "").split(/(\s+\xb7\s+|\s+-\s+)/);
|
|
4946
5566
|
for (var pieceIndex = 0; pieceIndex < pieces.length; pieceIndex++) {
|
|
4947
5567
|
var piece = pieces[pieceIndex];
|
|
4948
5568
|
if (!piece) {
|
|
4949
5569
|
continue;
|
|
4950
5570
|
}
|
|
4951
|
-
if (/^\s+[
|
|
5571
|
+
if (/^\s+[\xb7-]\s+$/.test(piece)) {
|
|
4952
5572
|
var separator = ownerDocument.createElement("span");
|
|
4953
5573
|
separator.className = "rte-ai-inline-preview-shortcuts-separator";
|
|
4954
5574
|
separator.innerText = piece.replace(/^\s+|\s+$/g, "");
|
|
@@ -4987,17 +5607,17 @@ function RTE_Plugin_AIToolkit() {
|
|
|
4987
5607
|
shortcutsChip.classList.toggle("is-preview", state === "preview");
|
|
4988
5608
|
if (state === "preview") {
|
|
4989
5609
|
renderInlineReviewShortcutDisplayContent(shortcutsChip, "Queue shortcut", getSuggestionQueueShortcutHint(options.suggestion));
|
|
4990
|
-
shortcutsChip.setAttribute("aria-label", "Inline queue preview shortcut");
|
|
5610
|
+
shortcutsChip.setAttribute("aria-label", uiT("aiu_previewshortcut", "Inline queue preview shortcut"));
|
|
4991
5611
|
return true;
|
|
4992
5612
|
}
|
|
4993
5613
|
if (state && state !== "wrapper") {
|
|
4994
5614
|
shortcutsChip.classList.add("is-action");
|
|
4995
5615
|
renderInlineReviewShortcutDisplayContent(shortcutsChip, "Keyboard guide", getInlineReviewActionShortcutHint(state, options));
|
|
4996
|
-
shortcutsChip.setAttribute("aria-label", "Inline AI review action shortcuts");
|
|
5616
|
+
shortcutsChip.setAttribute("aria-label", uiT("aiu_actionshortcuts", "Inline AI review action shortcuts"));
|
|
4997
5617
|
return true;
|
|
4998
5618
|
}
|
|
4999
5619
|
renderInlineReviewShortcutDisplayContent(shortcutsChip, "Keyboard guide", getInlineReviewWrapperShortcutHint(options));
|
|
5000
|
-
shortcutsChip.setAttribute("aria-label", "Inline AI review shortcuts");
|
|
5620
|
+
shortcutsChip.setAttribute("aria-label", uiT("aiu_reviewshortcuts", "Inline AI review shortcuts"));
|
|
5001
5621
|
return true;
|
|
5002
5622
|
}
|
|
5003
5623
|
|
|
@@ -5141,13 +5761,13 @@ function RTE_Plugin_AIToolkit() {
|
|
|
5141
5761
|
function getSuggestionStatusLabel(status) {
|
|
5142
5762
|
switch (status) {
|
|
5143
5763
|
case "accepted":
|
|
5144
|
-
return "Accepted";
|
|
5764
|
+
return (obj.__aiT ? obj.__aiT("air_status_accepted", "Accepted") : "Accepted");
|
|
5145
5765
|
case "rejected":
|
|
5146
|
-
return "Rejected";
|
|
5766
|
+
return (obj.__aiT ? obj.__aiT("air_status_rejected", "Rejected") : "Rejected");
|
|
5147
5767
|
case "stale":
|
|
5148
|
-
return "Needs refresh";
|
|
5768
|
+
return (obj.__aiT ? obj.__aiT("air_status_stale", "Needs refresh") : "Needs refresh");
|
|
5149
5769
|
default:
|
|
5150
|
-
return "Pending";
|
|
5770
|
+
return (obj.__aiT ? obj.__aiT("air_status_pending", "Pending") : "Pending");
|
|
5151
5771
|
}
|
|
5152
5772
|
}
|
|
5153
5773
|
|
|
@@ -5407,7 +6027,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
5407
6027
|
if (summaryData.detail) {
|
|
5408
6028
|
parts.push(summaryData.detail);
|
|
5409
6029
|
}
|
|
5410
|
-
return parts
|
|
6030
|
+
return joinSentences(parts);
|
|
5411
6031
|
}
|
|
5412
6032
|
|
|
5413
6033
|
function createInlinePreviewActionSummaryHtml(previewState) {
|
|
@@ -5566,10 +6186,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
5566
6186
|
}
|
|
5567
6187
|
var ariaLabel = label ? (label + " actions") : "AI suggestion actions";
|
|
5568
6188
|
if (detailText) {
|
|
5569
|
-
ariaLabel
|
|
6189
|
+
ariaLabel = joinSentences([ariaLabel, detailText]);
|
|
5570
6190
|
}
|
|
5571
6191
|
if (isCurrentGroup && badgeText) {
|
|
5572
|
-
ariaLabel
|
|
6192
|
+
ariaLabel = joinSentences([ariaLabel, "Current lane", badgeText]);
|
|
5573
6193
|
}
|
|
5574
6194
|
groupNode.setAttribute("aria-label", ariaLabel);
|
|
5575
6195
|
}
|
|
@@ -5618,7 +6238,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
5618
6238
|
button.setAttribute("aria-keyshortcuts", shortcutKey ? ("Enter Space " + shortcutKey) : "Enter Space");
|
|
5619
6239
|
button.setAttribute("data-rte-ai-enter-target-label", "Enter");
|
|
5620
6240
|
if (ariaLabel && !/current enter target/i.test(ariaLabel)) {
|
|
5621
|
-
button.setAttribute("aria-label", ariaLabel
|
|
6241
|
+
button.setAttribute("aria-label", joinSentences([ariaLabel, "Current Enter target."]));
|
|
5622
6242
|
}
|
|
5623
6243
|
if (title && !/enter or space activates this action/i.test(title)) {
|
|
5624
6244
|
title += ". Enter or Space activates this action";
|
|
@@ -5627,7 +6247,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
5627
6247
|
}
|
|
5628
6248
|
}
|
|
5629
6249
|
if (title && !/current enter target/i.test(title)) {
|
|
5630
|
-
button.title = title
|
|
6250
|
+
button.title = joinSentences([title, "Current Enter target."]);
|
|
5631
6251
|
}
|
|
5632
6252
|
}
|
|
5633
6253
|
else {
|
|
@@ -5703,7 +6323,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
5703
6323
|
labelNode.className = "rte-ai-inline-preview-reason-label";
|
|
5704
6324
|
reasonNode.appendChild(labelNode);
|
|
5705
6325
|
}
|
|
5706
|
-
labelNode.textContent = "Why";
|
|
6326
|
+
labelNode.textContent = uiT("air_why", "Why");
|
|
5707
6327
|
if (!copyNode) {
|
|
5708
6328
|
copyNode = document.createElement("span");
|
|
5709
6329
|
copyNode.className = "rte-ai-inline-preview-reason-copy";
|
|
@@ -6161,7 +6781,32 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6161
6781
|
+ "</" + resolvedTag + ">";
|
|
6162
6782
|
}
|
|
6163
6783
|
|
|
6784
|
+
// 2026-10-18 The card is inserted into the editing document - an iframe by default - but the toolkit's stylesheet
|
|
6785
|
+
// was linked into the host page only, so every card rendered as unstyled run-on text. The host page's copy is
|
|
6786
|
+
// linked into the editing document once (never into the saved HTML). tools/ai/inline-card-styled.mjs
|
|
6787
|
+
function ensureCardStylesheet() {
|
|
6788
|
+
try {
|
|
6789
|
+
var editable = editor.getEditable ? editor.getEditable() : null;
|
|
6790
|
+
var doc = editable && editable.ownerDocument;
|
|
6791
|
+
if (!doc || doc === document || doc.querySelector("link[data-rte-ai-card-css]")) return;
|
|
6792
|
+
var src = document.querySelector("link[data-rte-auto-injected=aitoolkit]");
|
|
6793
|
+
if (!src) {
|
|
6794
|
+
var all = document.querySelectorAll("link[rel=stylesheet]");
|
|
6795
|
+
for (var i = 0; i < all.length; i++) {
|
|
6796
|
+
if (/(?:^|\/)aitoolkit(?:\.min)?\.css(?:[?#].*)?$/i.test(all[i].getAttribute("href") || "")) { src = all[i]; break; }
|
|
6797
|
+
}
|
|
6798
|
+
}
|
|
6799
|
+
if (!src || !src.href) return;
|
|
6800
|
+
var link = doc.createElement("link");
|
|
6801
|
+
link.rel = "stylesheet";
|
|
6802
|
+
link.href = src.href;
|
|
6803
|
+
link.setAttribute("data-rte-ai-card-css", "1");
|
|
6804
|
+
(doc.head || doc.documentElement).appendChild(link);
|
|
6805
|
+
} catch (e) { /* the card stays unstyled, as before */ }
|
|
6806
|
+
}
|
|
6807
|
+
|
|
6164
6808
|
function createInlinePreviewHtml(previewState) {
|
|
6809
|
+
ensureCardStylesheet();
|
|
6165
6810
|
var isBlock = !!previewState.isBlock;
|
|
6166
6811
|
var wrapperTag = isBlock ? "div" : "span";
|
|
6167
6812
|
var partTag = isBlock ? "div" : "span";
|
|
@@ -6239,6 +6884,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6239
6884
|
editor.__aiBindInlinePreviewEventHandlers();
|
|
6240
6885
|
}
|
|
6241
6886
|
editor.insertHTML(createInlinePreviewHtml(previewState));
|
|
6887
|
+
aiqWatchCards();
|
|
6242
6888
|
persistSuggestionStore();
|
|
6243
6889
|
emitReviewLogEvent("suggestion-created", previewState);
|
|
6244
6890
|
if (editor.__aiReviewPanel && editor.__aiReviewPanel.isConnected) {
|
|
@@ -6290,7 +6936,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6290
6936
|
info.className = "rte-ai-menu-info is-minimal is-detached";
|
|
6291
6937
|
var titleRow = append(info, "div", "", "rte-ai-menu-title-row");
|
|
6292
6938
|
var titleIcon = append(titleRow, "span", "", "rte-ai-menu-title-icon");
|
|
6293
|
-
titleIcon.innerHTML = config.svgCode_aiassist || "";
|
|
6939
|
+
titleIcon.innerHTML = __RTE_TT(config.svgCode_aiassist || "");
|
|
6294
6940
|
append(titleRow, "div", "", "rte-ai-menu-title", config.text_aiassist || "Ask AI");
|
|
6295
6941
|
|
|
6296
6942
|
// 2026-05-27 (v20260527a): type-to-filter search bar pinned to the
|
|
@@ -6322,12 +6968,12 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6322
6968
|
// still click anywhere in the input to focus the textbox.
|
|
6323
6969
|
var searchIcon = append(searchRow, "span", "", "rte-ai-menu-search-icon");
|
|
6324
6970
|
searchIcon.setAttribute("aria-hidden", "true");
|
|
6325
|
-
searchIcon.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6"/><path d="M19 19l-3.4-3.4"/></svg>';
|
|
6971
|
+
searchIcon.innerHTML = __RTE_TT('<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6"/><path d="M19 19l-3.4-3.4"/></svg>');
|
|
6326
6972
|
var searchInput = panel.ownerDocument.createElement("input");
|
|
6327
6973
|
searchInput.type = "text";
|
|
6328
6974
|
searchInput.className = "rte-ai-menu-search-input";
|
|
6329
|
-
searchInput.placeholder = "Filter actions
|
|
6330
|
-
searchInput.setAttribute("aria-label", "Filter AI actions");
|
|
6975
|
+
searchInput.placeholder = (obj.__aiT ? obj.__aiT("aia_filter", "Filter actions\u2026") : "Filter actions\u2026");
|
|
6976
|
+
searchInput.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aia_filteraria", "Filter AI actions") : "Filter AI actions"));
|
|
6331
6977
|
searchInput.setAttribute("autocomplete", "off");
|
|
6332
6978
|
searchInput.setAttribute("spellcheck", "false");
|
|
6333
6979
|
searchRow.appendChild(searchInput);
|
|
@@ -6387,10 +7033,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6387
7033
|
// 26px row floor and 2-col grid measure identically.
|
|
6388
7034
|
if (action.description) {
|
|
6389
7035
|
button.title = action.description;
|
|
6390
|
-
button.setAttribute("aria-label", (action.title || action.id) + "
|
|
7036
|
+
button.setAttribute("aria-label", (action.title || action.id) + " \u2014 " + action.description);
|
|
6391
7037
|
}
|
|
6392
7038
|
var icon = append(button, "span", "", "rte-ai-menu-item-icon");
|
|
6393
|
-
icon.innerHTML = getActionIconSvg(action);
|
|
7039
|
+
icon.innerHTML = __RTE_TT(getActionIconSvg(action));
|
|
6394
7040
|
var body = append(button, "span", "", "rte-ai-menu-item-body");
|
|
6395
7041
|
append(body, "span", "", "rte-ai-menu-item-title", action.title || action.id);
|
|
6396
7042
|
append(body, "span", "", "rte-ai-menu-item-copy", action.description || "");
|
|
@@ -6455,7 +7101,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6455
7101
|
if (!searchRow.__aiEmptyHint) {
|
|
6456
7102
|
var hint = panel.ownerDocument.createElement("div");
|
|
6457
7103
|
hint.className = "rte-ai-menu-empty-hint";
|
|
6458
|
-
hint.textContent = "No actions match.";
|
|
7104
|
+
hint.textContent = (obj.__aiT ? obj.__aiT("aia_nomatch", "No actions match.") : "No actions match.");
|
|
6459
7105
|
panel.appendChild(hint);
|
|
6460
7106
|
searchRow.__aiEmptyHint = hint;
|
|
6461
7107
|
}
|
|
@@ -6644,6 +7290,19 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6644
7290
|
});
|
|
6645
7291
|
}
|
|
6646
7292
|
|
|
7293
|
+
// 2026-10-17 a locked document stays locked: in read-only mode (Ask AI opened through the API) and in comments-only
|
|
7294
|
+
// mode (its button stays enabled there) "Replace document", applyResult() and executeResolvedAction() rewrote the
|
|
7295
|
+
// document. Text-changing operations are refused and the refusal is announced; opening a panel and adding a
|
|
7296
|
+
// comment still work. tools/ai/ai-locked.mjs
|
|
7297
|
+
function documentLocked() {
|
|
7298
|
+
try { return !!((editor.getReadOnly && editor.getReadOnly()) || (editor.getCommentsOnly && editor.getCommentsOnly())); } catch (e) { return false; }
|
|
7299
|
+
}
|
|
7300
|
+
|
|
7301
|
+
function refuseLocked() {
|
|
7302
|
+
announceReviewStatus(config.text_aitoolkitlocked || "This document is read-only, so the AI result was not applied.");
|
|
7303
|
+
return false;
|
|
7304
|
+
}
|
|
7305
|
+
|
|
6647
7306
|
function executeOperations(operations, options) {
|
|
6648
7307
|
options = options || {};
|
|
6649
7308
|
var snapshot = options.snapshot || captureSelectionSnapshot();
|
|
@@ -6680,6 +7339,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6680
7339
|
});
|
|
6681
7340
|
}
|
|
6682
7341
|
|
|
7342
|
+
if (documentLocked() && !/^open-|comment/i.test(String(operation.type))) return refuseLocked();
|
|
6683
7343
|
switch (operation.type) {
|
|
6684
7344
|
case "open-chat-panel":
|
|
6685
7345
|
openChatPanel({ focusComposer: true });
|
|
@@ -6742,7 +7402,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6742
7402
|
return false;
|
|
6743
7403
|
}
|
|
6744
7404
|
|
|
6745
|
-
wrapper.outerHTML = getResolvedSuggestionHtml(previewState, "accepted");
|
|
7405
|
+
wrapper.outerHTML = __RTE_TT(getResolvedSuggestionHtml(previewState, "accepted"));
|
|
6746
7406
|
previewState.status = "accepted";
|
|
6747
7407
|
previewState.decidedAt = new Date().getTime();
|
|
6748
7408
|
setLastReviewDecision(previewState, "accepted");
|
|
@@ -6780,7 +7440,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6780
7440
|
return false;
|
|
6781
7441
|
}
|
|
6782
7442
|
|
|
6783
|
-
wrapper.outerHTML = getResolvedSuggestionHtml(previewState, "rejected");
|
|
7443
|
+
wrapper.outerHTML = __RTE_TT(getResolvedSuggestionHtml(previewState, "rejected"));
|
|
6784
7444
|
previewState.status = "rejected";
|
|
6785
7445
|
previewState.decidedAt = new Date().getTime();
|
|
6786
7446
|
setLastReviewDecision(previewState, "rejected");
|
|
@@ -6816,7 +7476,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6816
7476
|
|
|
6817
7477
|
suggestion.status = "pending";
|
|
6818
7478
|
suggestion.decidedAt = 0;
|
|
6819
|
-
wrapper.outerHTML = createInlinePreviewHtml(suggestion);
|
|
7479
|
+
wrapper.outerHTML = __RTE_TT(createInlinePreviewHtml(suggestion));
|
|
6820
7480
|
getReviewState().showResolved = false;
|
|
6821
7481
|
pushRedoReviewDecision(suggestion, undoable.status);
|
|
6822
7482
|
popLastReviewDecision();
|
|
@@ -6855,7 +7515,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6855
7515
|
return false;
|
|
6856
7516
|
}
|
|
6857
7517
|
|
|
6858
|
-
wrapper.outerHTML = getResolvedSuggestionHtml(suggestion, redoable.status);
|
|
7518
|
+
wrapper.outerHTML = __RTE_TT(getResolvedSuggestionHtml(suggestion, redoable.status));
|
|
6859
7519
|
suggestion.status = redoable.status;
|
|
6860
7520
|
suggestion.decidedAt = new Date().getTime();
|
|
6861
7521
|
getReviewState().showResolved = false;
|
|
@@ -6891,6 +7551,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6891
7551
|
}
|
|
6892
7552
|
|
|
6893
7553
|
function applyResult(result, options) {
|
|
7554
|
+
if (documentLocked()) return refuseLocked();
|
|
6894
7555
|
var clean = normalizeText(result);
|
|
6895
7556
|
if (!clean) {
|
|
6896
7557
|
return false;
|
|
@@ -6903,7 +7564,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
6903
7564
|
var snapshot = options.snapshot || captureSelectionSnapshot();
|
|
6904
7565
|
|
|
6905
7566
|
if (mode === "document") {
|
|
6906
|
-
|
|
7567
|
+
// 2026-10-03 undoable: an AI rewrite of the whole document is one Ctrl+Z back to exactly
|
|
7568
|
+
// what was there, edits made just before included (tools/import/replace-undo-plugins.mjs)
|
|
7569
|
+
editor.setHTMLCode(textToHtml(clean), { undoable: true });
|
|
6907
7570
|
syncSuggestionStates();
|
|
6908
7571
|
persistSuggestionStore();
|
|
6909
7572
|
if (editor.__aiReviewPanel && editor.__aiReviewPanel.isConnected) {
|
|
@@ -7116,7 +7779,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
7116
7779
|
if (options.redoNextLabel) {
|
|
7117
7780
|
parts.push(options.redoNextLabel);
|
|
7118
7781
|
}
|
|
7119
|
-
return parts
|
|
7782
|
+
return joinSentences(parts);
|
|
7120
7783
|
}
|
|
7121
7784
|
|
|
7122
7785
|
function buildReviewQueuePositionData(visibleSuggestions, activeSuggestionId, suggestion) {
|
|
@@ -7701,7 +8364,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
7701
8364
|
|| "Locate";
|
|
7702
8365
|
actionNode.innerText = focusLabel;
|
|
7703
8366
|
if (detailNode) {
|
|
7704
|
-
detailNode.innerText = "Press Enter to reopen this suggestion and land on "
|
|
8367
|
+
detailNode.innerText = uiT("aiu_reopenhint", "Press Enter to reopen this suggestion and land on {0}.", aiqText(focusLabel) || focusLabel);
|
|
7705
8368
|
}
|
|
7706
8369
|
if (item && item.setAttribute) {
|
|
7707
8370
|
item.setAttribute("data-rte-ai-review-open-action-label", focusLabel);
|
|
@@ -7727,7 +8390,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
7727
8390
|
if (!titleNode) {
|
|
7728
8391
|
titleNode = append(moduleNode, "span", "", "rte-ai-review-item-condensed-shortcuts-title");
|
|
7729
8392
|
}
|
|
7730
|
-
titleNode.textContent = "More keys";
|
|
8393
|
+
titleNode.textContent = uiT("aiu_morekeys", "More keys");
|
|
7731
8394
|
var bodyNode = moduleNode.querySelector ? moduleNode.querySelector(".rte-ai-review-item-condensed-shortcuts-body") : null;
|
|
7732
8395
|
if (!bodyNode) {
|
|
7733
8396
|
bodyNode = append(moduleNode, "div", "", "rte-ai-review-shortcuts rte-ai-review-item-condensed-shortcuts-body");
|
|
@@ -7897,7 +8560,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
7897
8560
|
parts.push(options.queueTransitionData.followupDetail);
|
|
7898
8561
|
}
|
|
7899
8562
|
}
|
|
7900
|
-
return parts
|
|
8563
|
+
return joinSentences(parts);
|
|
7901
8564
|
}
|
|
7902
8565
|
|
|
7903
8566
|
function updateReviewCondensedPreviewAria(item, suggestion, panel) {
|
|
@@ -8007,7 +8670,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
8007
8670
|
wrapper.appendChild(focusChip);
|
|
8008
8671
|
}
|
|
8009
8672
|
}
|
|
8010
|
-
focusChip.textContent = "Focus "
|
|
8673
|
+
focusChip.textContent = uiT("aiu_focus", "Focus {0}", aiqText(reviewFocusLabel) || reviewFocusLabel);
|
|
8011
8674
|
focusChip.setAttribute("aria-label", "Review opens on " + reviewFocusLabel);
|
|
8012
8675
|
}
|
|
8013
8676
|
else if (focusChip && focusChip.parentNode) {
|
|
@@ -8222,7 +8885,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
8222
8885
|
focusActionLabel: getReviewFocusActionDisplayLabel(findSuggestionById(nextOverallPendingId), preferredQueueFocusAction)
|
|
8223
8886
|
} : null,
|
|
8224
8887
|
undoAction,
|
|
8225
|
-
{ id: "all-types", label: "All types" },
|
|
8888
|
+
{ id: "all-types", label: (obj.__aiT ? obj.__aiT("air_alltypes", "All types") : "All types") },
|
|
8226
8889
|
hasResolved && !showResolved ? { id: "show-resolved", label: "Show resolved" } : null,
|
|
8227
8890
|
{ id: "open-chat", label: "AI Chat" }
|
|
8228
8891
|
])
|
|
@@ -8250,7 +8913,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
8250
8913
|
announceMessage: "",
|
|
8251
8914
|
actions: [
|
|
8252
8915
|
undoAction,
|
|
8253
|
-
typeFilter !== "all" ? { id: "all-types", label: "All types" } : null,
|
|
8916
|
+
typeFilter !== "all" ? { id: "all-types", label: (obj.__aiT ? obj.__aiT("air_alltypes", "All types") : "All types") } : null,
|
|
8254
8917
|
hasResolved && !showResolved ? { id: "show-resolved", label: "Show resolved" } : null,
|
|
8255
8918
|
{ id: "open-chat", label: "AI Chat" }
|
|
8256
8919
|
]
|
|
@@ -9416,7 +10079,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
9416
10079
|
if (contextCardData.copy) {
|
|
9417
10080
|
parts.push(contextCardData.copy);
|
|
9418
10081
|
}
|
|
9419
|
-
return parts
|
|
10082
|
+
return joinSentences(parts);
|
|
9420
10083
|
}
|
|
9421
10084
|
|
|
9422
10085
|
function getChatMessageStateTitle(message) {
|
|
@@ -9629,7 +10292,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
9629
10292
|
if (isRecommended) {
|
|
9630
10293
|
parts.push("Recommended next step.");
|
|
9631
10294
|
}
|
|
9632
|
-
button.setAttribute("aria-label", parts
|
|
10295
|
+
button.setAttribute("aria-label", joinSentences(parts));
|
|
9633
10296
|
button.title = detail
|
|
9634
10297
|
? label + " - " + detail + (isRecommended ? " Recommended next step." : "")
|
|
9635
10298
|
: label + (isRecommended ? " - Recommended next step." : "");
|
|
@@ -9864,7 +10527,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
9864
10527
|
if (actionLabels.length) {
|
|
9865
10528
|
parts.push("Actions: " + actionLabels.join(", "));
|
|
9866
10529
|
}
|
|
9867
|
-
return parts
|
|
10530
|
+
return joinSentences(parts);
|
|
9868
10531
|
}
|
|
9869
10532
|
|
|
9870
10533
|
function syncChatActionAccessibility(actionsNode, recommendedActionId, message, currentSnapshot) {
|
|
@@ -9874,8 +10537,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
9874
10537
|
var recommendedLabel = getChatRecommendedActionLabel(recommendedActionId);
|
|
9875
10538
|
actionsNode.setAttribute("role", "group");
|
|
9876
10539
|
actionsNode.setAttribute("aria-label", recommendedLabel
|
|
9877
|
-
? "AI chat actions. Recommended next step: " + recommendedLabel + "."
|
|
9878
|
-
: "AI chat actions");
|
|
10540
|
+
? (obj.__aiT ? obj.__aiT("aic_actionsrec", "AI chat actions. Recommended next step: {0}.", recommendedLabel) : "AI chat actions. Recommended next step: " + recommendedLabel + ".")
|
|
10541
|
+
: (obj.__aiT ? obj.__aiT("aic_actions", "AI chat actions") : "AI chat actions"));
|
|
9879
10542
|
var groupNodes = actionsNode.querySelectorAll(".rte-ai-chat-message-action-group");
|
|
9880
10543
|
for (var groupIndex = 0; groupIndex < groupNodes.length; groupIndex++) {
|
|
9881
10544
|
var groupNode = groupNodes[groupIndex];
|
|
@@ -10001,7 +10664,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10001
10664
|
if (planItem.detail) {
|
|
10002
10665
|
parts.push(planItem.detail);
|
|
10003
10666
|
}
|
|
10004
|
-
return parts
|
|
10667
|
+
return joinSentences(parts);
|
|
10005
10668
|
}
|
|
10006
10669
|
|
|
10007
10670
|
function buildChatPreviewPlanItems(message, recommendedActionId, currentSnapshot) {
|
|
@@ -10128,7 +10791,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10128
10791
|
parts.push("+" + resolvedPreview.hiddenPlanCount + " more");
|
|
10129
10792
|
}
|
|
10130
10793
|
}
|
|
10131
|
-
return parts
|
|
10794
|
+
return joinSentences(parts);
|
|
10132
10795
|
}
|
|
10133
10796
|
|
|
10134
10797
|
function summarizeChatPromptCopy(text) {
|
|
@@ -10227,7 +10890,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10227
10890
|
if (message.text) {
|
|
10228
10891
|
parts.push(message.text);
|
|
10229
10892
|
}
|
|
10230
|
-
return parts
|
|
10893
|
+
return joinSentences(parts);
|
|
10231
10894
|
}
|
|
10232
10895
|
|
|
10233
10896
|
function buildChatAssistantRequestCardAriaLabel(requestCardData, exchangeLabel) {
|
|
@@ -10250,7 +10913,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10250
10913
|
if (requestCardData.promptText) {
|
|
10251
10914
|
parts.push(requestCardData.promptText);
|
|
10252
10915
|
}
|
|
10253
|
-
return parts
|
|
10916
|
+
return joinSentences(parts);
|
|
10254
10917
|
}
|
|
10255
10918
|
|
|
10256
10919
|
function buildChatMessageAriaLabel(messages, messageIndex, currentSnapshot) {
|
|
@@ -10322,7 +10985,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10322
10985
|
parts.push(actionSummary.title);
|
|
10323
10986
|
}
|
|
10324
10987
|
}
|
|
10325
|
-
return parts
|
|
10988
|
+
return joinSentences(parts);
|
|
10326
10989
|
}
|
|
10327
10990
|
|
|
10328
10991
|
function buildChatMessageStateCardAriaLabel(message) {
|
|
@@ -10342,7 +11005,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10342
11005
|
if (stateDetail) {
|
|
10343
11006
|
parts.push(stateDetail);
|
|
10344
11007
|
}
|
|
10345
|
-
return parts
|
|
11008
|
+
return joinSentences(parts);
|
|
10346
11009
|
}
|
|
10347
11010
|
|
|
10348
11011
|
function getChatMessageThreadRole(messages, messageIndex) {
|
|
@@ -10496,7 +11159,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10496
11159
|
if (bannerData.detail) {
|
|
10497
11160
|
parts.push(bannerData.detail);
|
|
10498
11161
|
}
|
|
10499
|
-
return parts
|
|
11162
|
+
return joinSentences(parts);
|
|
10500
11163
|
}
|
|
10501
11164
|
|
|
10502
11165
|
function buildChatExchangeGroupAriaLabel(messages, requestIndex, currentSnapshot) {
|
|
@@ -10552,7 +11215,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10552
11215
|
if (bannerData && bannerData.isCurrent) {
|
|
10553
11216
|
parts.push("Current exchange");
|
|
10554
11217
|
}
|
|
10555
|
-
return parts
|
|
11218
|
+
return joinSentences(parts);
|
|
10556
11219
|
}
|
|
10557
11220
|
|
|
10558
11221
|
function buildChatExchangeOutcomeData(messages, messageIndex, currentSnapshot) {
|
|
@@ -10636,7 +11299,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10636
11299
|
if (outcomeData.detail) {
|
|
10637
11300
|
parts.push(outcomeData.detail);
|
|
10638
11301
|
}
|
|
10639
|
-
return parts
|
|
11302
|
+
return joinSentences(parts);
|
|
10640
11303
|
}
|
|
10641
11304
|
|
|
10642
11305
|
function getChatContextWordCount(text) {
|
|
@@ -10779,46 +11442,51 @@ function RTE_Plugin_AIToolkit() {
|
|
|
10779
11442
|
}
|
|
10780
11443
|
}
|
|
10781
11444
|
}
|
|
10782
|
-
return parts
|
|
11445
|
+
return joinSentences(parts);
|
|
10783
11446
|
}
|
|
10784
11447
|
|
|
10785
11448
|
function buildChatSendActionData(state, context, activePrompt) {
|
|
10786
11449
|
var scopeLabel = context && context.scope === "selection" ? "selection" : "document";
|
|
11450
|
+
// 2026-10-18 every sentence reads a config.text_ key per scope (word order and gender differ by language);
|
|
11451
|
+
// the English fallbacks are the sentences this built before. tools/i18n/ai-chat-language.mjs
|
|
11452
|
+
var sc = scopeLabel === "selection" ? "sel" : "doc";
|
|
11453
|
+
var L = function (key, en, arg) { var s = (obj.__aiT ? obj.__aiT(key, en) : en); return arg === undefined ? s : s.split("{0}").join(String(arg)); };
|
|
11454
|
+
var LS = function (key, enSel, enDoc, arg) { return L(key + "_" + sc, sc === "sel" ? enSel : enDoc, arg); };
|
|
10787
11455
|
var hasCustomDraft = !!normalizeText(state && state.draft ? state.draft : "");
|
|
10788
11456
|
if (state && state.busy) {
|
|
10789
11457
|
return {
|
|
10790
|
-
text: "Thinking...",
|
|
11458
|
+
text: L("aic_thinking", "Thinking..."),
|
|
10791
11459
|
disabled: true,
|
|
10792
|
-
ariaLabel: "Send disabled while AI Chat is thinking about the current "
|
|
10793
|
-
title: "AI Chat is thinking about the current "
|
|
11460
|
+
ariaLabel: LS("aic_busyaria", "Send disabled while AI Chat is thinking about the current selection.", "Send disabled while AI Chat is thinking about the current document."),
|
|
11461
|
+
title: LS("aic_busytitle", "AI Chat is thinking about the current selection.", "AI Chat is thinking about the current document.")
|
|
10794
11462
|
};
|
|
10795
11463
|
}
|
|
10796
11464
|
if (activePrompt && activePrompt.label) {
|
|
10797
11465
|
return {
|
|
10798
|
-
text: "Send starter",
|
|
11466
|
+
text: L("aic_sendstarter", "Send starter"),
|
|
10799
11467
|
disabled: false,
|
|
10800
|
-
ariaLabel: "Send starter. Send the
|
|
10801
|
-
title: "Send the
|
|
11468
|
+
ariaLabel: LS("aic_starteraria", "Send starter. Send the {0} starter for the current selection.", "Send starter. Send the {0} starter for the current document.", activePrompt.label),
|
|
11469
|
+
title: LS("aic_startertitle", "Send the {0} starter for the current selection.", "Send the {0} starter for the current document.", activePrompt.label)
|
|
10802
11470
|
};
|
|
10803
11471
|
}
|
|
10804
11472
|
if (hasCustomDraft) {
|
|
10805
11473
|
return {
|
|
10806
|
-
text: "Send prompt",
|
|
11474
|
+
text: L("aic_sendprompt", "Send prompt"),
|
|
10807
11475
|
disabled: false,
|
|
10808
|
-
ariaLabel: "Send prompt. Send the custom prompt for the current "
|
|
10809
|
-
title: "Send the custom prompt for the current "
|
|
11476
|
+
ariaLabel: LS("aic_promptaria", "Send prompt. Send the custom prompt for the current selection.", "Send prompt. Send the custom prompt for the current document."),
|
|
11477
|
+
title: LS("aic_prompttitle", "Send the custom prompt for the current selection.", "Send the custom prompt for the current document.")
|
|
10810
11478
|
};
|
|
10811
11479
|
}
|
|
10812
11480
|
return {
|
|
10813
|
-
text: "Send",
|
|
11481
|
+
text: L("aic_send", "Send"),
|
|
10814
11482
|
disabled: true,
|
|
10815
|
-
ariaLabel: "Send disabled. Type a prompt or load a starter for the current "
|
|
10816
|
-
title: "Type a prompt or load a starter for the current "
|
|
11483
|
+
ariaLabel: LS("aic_emptyaria", "Send disabled. Type a prompt or load a starter for the current selection first.", "Send disabled. Type a prompt or load a starter for the current document first."),
|
|
11484
|
+
title: LS("aic_emptytitle", "Type a prompt or load a starter for the current selection first.", "Type a prompt or load a starter for the current document first.")
|
|
10817
11485
|
};
|
|
10818
11486
|
}
|
|
10819
11487
|
|
|
10820
11488
|
function buildChatComposerActionsAriaLabel(sendActionData) {
|
|
10821
|
-
return "Compose actions. Open Ask AI. " + (sendActionData && sendActionData.ariaLabel ? sendActionData.ariaLabel : "Send.");
|
|
11489
|
+
return (obj.__aiT ? obj.__aiT("aic_composeactions", "Compose actions. Open Ask AI.") : "Compose actions. Open Ask AI.") + " " + (sendActionData && sendActionData.ariaLabel ? sendActionData.ariaLabel : (obj.__aiT ? obj.__aiT("aic_sendp", "Send.") : "Send."));
|
|
10822
11490
|
}
|
|
10823
11491
|
|
|
10824
11492
|
function getLatestChatMessage(state) {
|
|
@@ -11032,7 +11700,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11032
11700
|
parts.push(summaryData.changeGlance.detail);
|
|
11033
11701
|
}
|
|
11034
11702
|
}
|
|
11035
|
-
return parts
|
|
11703
|
+
return joinSentences(parts);
|
|
11036
11704
|
}
|
|
11037
11705
|
|
|
11038
11706
|
function buildChatFeedIntroData(state, context, activePrompt) {
|
|
@@ -11104,7 +11772,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11104
11772
|
if (feedIntroData.detail) {
|
|
11105
11773
|
parts.push(feedIntroData.detail);
|
|
11106
11774
|
}
|
|
11107
|
-
return parts
|
|
11775
|
+
return joinSentences(parts);
|
|
11108
11776
|
}
|
|
11109
11777
|
|
|
11110
11778
|
function buildChatFeedSectionAriaLabel(state, context, activePrompt) {
|
|
@@ -11133,7 +11801,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11133
11801
|
if (summaryData && summaryData.detail) {
|
|
11134
11802
|
parts.push(summaryData.detail);
|
|
11135
11803
|
}
|
|
11136
|
-
return parts
|
|
11804
|
+
return joinSentences(parts);
|
|
11137
11805
|
}
|
|
11138
11806
|
var feedIntroData = buildChatFeedIntroData(state, context, activePrompt);
|
|
11139
11807
|
if (feedIntroData.title) {
|
|
@@ -11149,7 +11817,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11149
11817
|
if (feedIntroData.detail) {
|
|
11150
11818
|
parts.push(feedIntroData.detail);
|
|
11151
11819
|
}
|
|
11152
|
-
return parts
|
|
11820
|
+
return joinSentences(parts);
|
|
11153
11821
|
}
|
|
11154
11822
|
|
|
11155
11823
|
function getChatConversationSummaryTitle(state, context) {
|
|
@@ -11256,7 +11924,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11256
11924
|
parts.push(titleText);
|
|
11257
11925
|
}
|
|
11258
11926
|
if (!headerData) {
|
|
11259
|
-
return parts
|
|
11927
|
+
return joinSentences(parts);
|
|
11260
11928
|
}
|
|
11261
11929
|
if (headerData.statusLabel) {
|
|
11262
11930
|
parts.push(headerData.statusLabel);
|
|
@@ -11274,7 +11942,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11274
11942
|
}
|
|
11275
11943
|
}
|
|
11276
11944
|
}
|
|
11277
|
-
return parts
|
|
11945
|
+
return joinSentences(parts);
|
|
11278
11946
|
}
|
|
11279
11947
|
|
|
11280
11948
|
function buildChatContextData(context) {
|
|
@@ -11354,7 +12022,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11354
12022
|
if (contextData.previewSummary) {
|
|
11355
12023
|
parts.push(contextData.previewSummary);
|
|
11356
12024
|
}
|
|
11357
|
-
return parts
|
|
12025
|
+
return joinSentences(parts);
|
|
11358
12026
|
}
|
|
11359
12027
|
|
|
11360
12028
|
function buildChatContextBarAriaLabel(contextData) {
|
|
@@ -11369,7 +12037,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11369
12037
|
}
|
|
11370
12038
|
}
|
|
11371
12039
|
}
|
|
11372
|
-
return parts
|
|
12040
|
+
return joinSentences(parts);
|
|
11373
12041
|
}
|
|
11374
12042
|
|
|
11375
12043
|
function buildChatContextScopeButtonAriaLabel(scopeId, contextData) {
|
|
@@ -11405,7 +12073,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11405
12073
|
if (contextData.previewSummary) {
|
|
11406
12074
|
parts.push(contextData.previewSummary);
|
|
11407
12075
|
}
|
|
11408
|
-
return parts
|
|
12076
|
+
return joinSentences(parts);
|
|
11409
12077
|
}
|
|
11410
12078
|
|
|
11411
12079
|
function buildChatQuickStartData(state, prompts, activePrompt, context) {
|
|
@@ -11458,7 +12126,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11458
12126
|
if (quickStartData.detail) {
|
|
11459
12127
|
parts.push(quickStartData.detail);
|
|
11460
12128
|
}
|
|
11461
|
-
return parts
|
|
12129
|
+
return joinSentences(parts);
|
|
11462
12130
|
}
|
|
11463
12131
|
|
|
11464
12132
|
function buildChatQuickButtonAriaLabel(prompt, isActivePrompt, context) {
|
|
@@ -11477,7 +12145,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11477
12145
|
parts.push(isActivePrompt
|
|
11478
12146
|
? "Current starter loaded in Compose for the current " + scopeLabel
|
|
11479
12147
|
: "Loads this starter into Compose for the current " + scopeLabel);
|
|
11480
|
-
return parts
|
|
12148
|
+
return joinSentences(parts);
|
|
11481
12149
|
}
|
|
11482
12150
|
|
|
11483
12151
|
function buildChatQuickRowAriaLabel(context) {
|
|
@@ -11512,21 +12180,21 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11512
12180
|
// The capability-cards data is still attached to emptyStateData.aria
|
|
11513
12181
|
// so screen-reader users hear the long form via the aria-label.
|
|
11514
12182
|
return {
|
|
11515
|
-
title: "Start with AI Chat",
|
|
11516
|
-
detail: context.scope === "selection"
|
|
11517
|
-
? "Ask anything about the current selection
|
|
11518
|
-
: "Ask anything about the current document.",
|
|
12183
|
+
title: (obj.__aiT ? obj.__aiT("aic_starttitle", "Start with AI Chat") : "Start with AI Chat"),
|
|
12184
|
+
detail: (context.scope === "selection"
|
|
12185
|
+
? (obj.__aiT ? obj.__aiT("aic_empty_sel", "Ask anything about the current selection") : "Ask anything about the current selection")
|
|
12186
|
+
: (obj.__aiT ? obj.__aiT("aic_empty_doc", "Ask anything about the current document") : "Ask anything about the current document")) + ".",
|
|
11519
12187
|
metaPills: [
|
|
11520
12188
|
{
|
|
11521
|
-
text: context.scope === "selection" ? "Selection context" : "Document context",
|
|
12189
|
+
text: context.scope === "selection" ? (obj.__aiT ? obj.__aiT("aic_pill_sel", "Selection context") : "Selection context") : (obj.__aiT ? obj.__aiT("aic_pill_doc", "Document context") : "Document context"),
|
|
11522
12190
|
className: "is-scope"
|
|
11523
12191
|
},
|
|
11524
12192
|
{
|
|
11525
|
-
text: (prompts && prompts.length ? prompts.length : 0) + " starters",
|
|
12193
|
+
text: (obj.__aiT ? obj.__aiT("aic_pill_starters", "{0} starters", prompts && prompts.length ? prompts.length : 0) : (prompts && prompts.length ? prompts.length : 0) + " starters"),
|
|
11526
12194
|
className: "is-prompts"
|
|
11527
12195
|
},
|
|
11528
12196
|
{
|
|
11529
|
-
text: getChatContextWordCount(context.source) + " words in scope",
|
|
12197
|
+
text: (obj.__aiT ? obj.__aiT("aic_pill_words", "{0} words in scope", getChatContextWordCount(context.source)) : getChatContextWordCount(context.source) + " words in scope"),
|
|
11530
12198
|
className: "is-size"
|
|
11531
12199
|
}
|
|
11532
12200
|
],
|
|
@@ -11545,7 +12213,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11545
12213
|
if (capabilityCard.copy) {
|
|
11546
12214
|
parts.push(capabilityCard.copy);
|
|
11547
12215
|
}
|
|
11548
|
-
return parts
|
|
12216
|
+
return joinSentences(parts);
|
|
11549
12217
|
}
|
|
11550
12218
|
|
|
11551
12219
|
function buildChatEmptyStateAriaLabel(emptyStateData) {
|
|
@@ -11571,7 +12239,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11571
12239
|
parts.push(buildChatEmptyCapabilityAriaLabel(emptyStateData.capabilityCards[cardIndex]));
|
|
11572
12240
|
}
|
|
11573
12241
|
}
|
|
11574
|
-
return parts
|
|
12242
|
+
return joinSentences(parts);
|
|
11575
12243
|
}
|
|
11576
12244
|
|
|
11577
12245
|
function clearChatNode(node) {
|
|
@@ -11616,17 +12284,17 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11616
12284
|
}
|
|
11617
12285
|
var headerStatusNode = panel.querySelector(".rte-ai-chat-header-status.is-status");
|
|
11618
12286
|
if (headerStatusNode) {
|
|
11619
|
-
headerStatusNode.innerHTML = "";
|
|
12287
|
+
headerStatusNode.innerHTML = __RTE_TT("");
|
|
11620
12288
|
headerStatusNode.innerText = headerData.statusLabel;
|
|
11621
12289
|
}
|
|
11622
12290
|
var headerScopeNode = panel.querySelector(".rte-ai-chat-header-status.is-scope");
|
|
11623
12291
|
if (headerScopeNode) {
|
|
11624
|
-
headerScopeNode.innerHTML = "";
|
|
12292
|
+
headerScopeNode.innerHTML = __RTE_TT("");
|
|
11625
12293
|
headerScopeNode.innerText = headerData.scopeFocusLabel;
|
|
11626
12294
|
}
|
|
11627
12295
|
var headerSubtitleNode = panel.querySelector(".rte-ai-chat-subtitle");
|
|
11628
12296
|
if (headerSubtitleNode) {
|
|
11629
|
-
headerSubtitleNode.innerHTML = "";
|
|
12297
|
+
headerSubtitleNode.innerHTML = __RTE_TT("");
|
|
11630
12298
|
headerSubtitleNode.innerText = headerData.subtitle;
|
|
11631
12299
|
}
|
|
11632
12300
|
syncChatPillGroup(panel.querySelector(".rte-ai-chat-header-meta"), headerData.metaPills, "rte-ai-chat-header-meta-pill");
|
|
@@ -11667,7 +12335,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11667
12335
|
syncChatPillGroup(panel.querySelector(".rte-ai-chat-context-summary-meta"), contextData.summaryPills, "rte-ai-chat-context-summary-pill");
|
|
11668
12336
|
var contextSummaryTextNode = panel.querySelector(".rte-ai-chat-context-summary-text");
|
|
11669
12337
|
if (contextSummaryTextNode) {
|
|
11670
|
-
contextSummaryTextNode.innerHTML = "";
|
|
12338
|
+
contextSummaryTextNode.innerHTML = __RTE_TT("");
|
|
11671
12339
|
contextSummaryTextNode.innerText = contextData.detail;
|
|
11672
12340
|
}
|
|
11673
12341
|
var contextPreviewNode = panel.querySelector(".rte-ai-chat-context-preview");
|
|
@@ -11677,13 +12345,13 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11677
12345
|
}
|
|
11678
12346
|
var contextPreviewTitleNode = panel.querySelector(".rte-ai-chat-context-preview-title");
|
|
11679
12347
|
if (contextPreviewTitleNode) {
|
|
11680
|
-
contextPreviewTitleNode.innerHTML = "";
|
|
12348
|
+
contextPreviewTitleNode.innerHTML = __RTE_TT("");
|
|
11681
12349
|
contextPreviewTitleNode.innerText = contextData.previewTitle;
|
|
11682
12350
|
}
|
|
11683
12351
|
syncChatPillGroup(panel.querySelector(".rte-ai-chat-context-preview-meta"), contextData.previewMetaPills, "rte-ai-chat-context-preview-pill");
|
|
11684
12352
|
var contextPreviewCopyNode = panel.querySelector(".rte-ai-chat-context-preview-copy");
|
|
11685
12353
|
if (contextPreviewCopyNode) {
|
|
11686
|
-
contextPreviewCopyNode.innerHTML = "";
|
|
12354
|
+
contextPreviewCopyNode.innerHTML = __RTE_TT("");
|
|
11687
12355
|
contextPreviewCopyNode.innerText = contextData.previewSummary;
|
|
11688
12356
|
}
|
|
11689
12357
|
|
|
@@ -11710,7 +12378,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11710
12378
|
syncChatPillGroup(panel.querySelector(".rte-ai-chat-quick-summary-meta"), quickStartData.metaPills, "rte-ai-chat-quick-summary-pill");
|
|
11711
12379
|
var quickSummaryTextNode = panel.querySelector(".rte-ai-chat-quick-summary-text");
|
|
11712
12380
|
if (quickSummaryTextNode) {
|
|
11713
|
-
quickSummaryTextNode.innerHTML = "";
|
|
12381
|
+
quickSummaryTextNode.innerHTML = __RTE_TT("");
|
|
11714
12382
|
quickSummaryTextNode.innerText = quickStartData.detail;
|
|
11715
12383
|
}
|
|
11716
12384
|
|
|
@@ -11739,12 +12407,12 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11739
12407
|
var composerStatusPillNode = panel.querySelector(".rte-ai-chat-status-pill");
|
|
11740
12408
|
if (composerStatusPillNode) {
|
|
11741
12409
|
composerStatusPillNode.className = "rte-ai-chat-status-pill is-" + composerData.statusTone;
|
|
11742
|
-
composerStatusPillNode.innerHTML = "";
|
|
12410
|
+
composerStatusPillNode.innerHTML = __RTE_TT("");
|
|
11743
12411
|
composerStatusPillNode.innerText = composerData.statusLabel;
|
|
11744
12412
|
}
|
|
11745
12413
|
var composerStatusTextNode = panel.querySelector(".rte-ai-chat-status-text");
|
|
11746
12414
|
if (composerStatusTextNode) {
|
|
11747
|
-
composerStatusTextNode.innerHTML = "";
|
|
12415
|
+
composerStatusTextNode.innerHTML = __RTE_TT("");
|
|
11748
12416
|
composerStatusTextNode.innerText = composerData.statusText;
|
|
11749
12417
|
}
|
|
11750
12418
|
var composerActionsNode = panel.querySelector(".rte-ai-chat-composer-actions");
|
|
@@ -11774,12 +12442,12 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11774
12442
|
}
|
|
11775
12443
|
var feedIntroTitleNode = panel.querySelector(".rte-ai-chat-feed-intro-title");
|
|
11776
12444
|
if (feedIntroTitleNode) {
|
|
11777
|
-
feedIntroTitleNode.innerHTML = "";
|
|
12445
|
+
feedIntroTitleNode.innerHTML = __RTE_TT("");
|
|
11778
12446
|
feedIntroTitleNode.innerText = feedIntroData.title;
|
|
11779
12447
|
}
|
|
11780
12448
|
var feedIntroDetailNode = panel.querySelector(".rte-ai-chat-feed-intro-detail");
|
|
11781
12449
|
if (feedIntroDetailNode) {
|
|
11782
|
-
feedIntroDetailNode.innerHTML = "";
|
|
12450
|
+
feedIntroDetailNode.innerHTML = __RTE_TT("");
|
|
11783
12451
|
feedIntroDetailNode.innerText = feedIntroData.detail;
|
|
11784
12452
|
}
|
|
11785
12453
|
syncChatPillGroup(panel.querySelector(".rte-ai-chat-feed-intro-meta"), feedIntroData.metaPills, "rte-ai-chat-feed-intro-pill");
|
|
@@ -11790,12 +12458,12 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11790
12458
|
}
|
|
11791
12459
|
var emptyTitleNode = panel.querySelector(".rte-ai-chat-empty-title");
|
|
11792
12460
|
if (emptyTitleNode && emptyStateData) {
|
|
11793
|
-
emptyTitleNode.innerHTML = "";
|
|
12461
|
+
emptyTitleNode.innerHTML = __RTE_TT("");
|
|
11794
12462
|
emptyTitleNode.innerText = emptyStateData.title;
|
|
11795
12463
|
}
|
|
11796
12464
|
var emptyDetailNode = panel.querySelector(".rte-ai-chat-empty-detail");
|
|
11797
12465
|
if (emptyDetailNode && emptyStateData) {
|
|
11798
|
-
emptyDetailNode.innerHTML = "";
|
|
12466
|
+
emptyDetailNode.innerHTML = __RTE_TT("");
|
|
11799
12467
|
emptyDetailNode.innerText = emptyStateData.detail;
|
|
11800
12468
|
}
|
|
11801
12469
|
syncChatPillGroup(panel.querySelector(".rte-ai-chat-empty-meta"), emptyStateData ? emptyStateData.metaPills : [], "rte-ai-chat-empty-pill");
|
|
@@ -11930,6 +12598,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11930
12598
|
panel.setAttribute("aria-label", config.text_aichat || "AI Chat");
|
|
11931
12599
|
panel.tabIndex = -1;
|
|
11932
12600
|
editor.__aiChatPanel = panel;
|
|
12601
|
+
aiqWatch(panel);
|
|
12602
|
+
appendDemoNotice(panel);
|
|
11933
12603
|
panel.onkeydown = function (e) {
|
|
11934
12604
|
if (e.key === "Escape") {
|
|
11935
12605
|
e.preventDefault();
|
|
@@ -11955,7 +12625,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11955
12625
|
var headerCopy = append(header, "div", "", "rte-ai-chat-header-copy");
|
|
11956
12626
|
var titleRow = append(headerCopy, "div", "", "rte-ai-chat-title-row");
|
|
11957
12627
|
var titleIcon = append(titleRow, "span", "", "rte-ai-chat-title-icon");
|
|
11958
|
-
titleIcon.innerHTML = config.svgCode_aiassist_chat || config.svgCode_aiassist || "";
|
|
12628
|
+
titleIcon.innerHTML = __RTE_TT(config.svgCode_aiassist_chat || config.svgCode_aiassist || "");
|
|
11959
12629
|
append(titleRow, "div", "", "rte-ai-chat-title", headerTitleText);
|
|
11960
12630
|
var headerActions = append(header, "div", "", "rte-ai-chat-header-actions");
|
|
11961
12631
|
// 2026-05-15 (v20260515c): New chat button → icon-only. Sat next
|
|
@@ -11971,8 +12641,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11971
12641
|
var clearButton = append(headerActions, "button", "", "secondary rte-ai-chat-header-button is-icon-only");
|
|
11972
12642
|
clearButton.type = "button";
|
|
11973
12643
|
clearButton.setAttribute("data-rte-ai-chat-header-action", "new-chat");
|
|
11974
|
-
clearButton.title = "Start a fresh chat";
|
|
11975
|
-
clearButton.setAttribute("aria-label", "Start a fresh chat");
|
|
12644
|
+
clearButton.title = (obj.__aiT ? obj.__aiT("aic_newchat", "Start a fresh chat") : "Start a fresh chat");
|
|
12645
|
+
clearButton.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aic_newchat", "Start a fresh chat") : "Start a fresh chat"));
|
|
11976
12646
|
setReviewV2ButtonContent(clearButton, "refresh", "");
|
|
11977
12647
|
clearButton.onclick = function () {
|
|
11978
12648
|
resetChatConversationState(state, "Started a fresh AI chat.");
|
|
@@ -11981,9 +12651,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
11981
12651
|
var closeButton = append(headerActions, "button", "", "rte-ai-panel-close-button");
|
|
11982
12652
|
closeButton.type = "button";
|
|
11983
12653
|
closeButton.setAttribute("data-rte-ai-chat-header-action", "close");
|
|
11984
|
-
closeButton.setAttribute("aria-label", "Close AI chat");
|
|
11985
|
-
closeButton.title = "Close";
|
|
11986
|
-
closeButton.innerHTML = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>';
|
|
12654
|
+
closeButton.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aic_closechat", "Close AI chat") : "Close AI chat"));
|
|
12655
|
+
closeButton.title = (obj.__aiT ? obj.__aiT("aic_close", "Close") : "Close");
|
|
12656
|
+
closeButton.innerHTML = __RTE_TT('<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>');
|
|
11987
12657
|
closeButton.onclick = function () {
|
|
11988
12658
|
closeChatPanel({ restoreFocus: true });
|
|
11989
12659
|
};
|
|
@@ -12026,7 +12696,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12026
12696
|
selectionButton.disabled = !context.snapshot.hasSelection;
|
|
12027
12697
|
selectionButton.setAttribute("data-rte-ai-chat-scope-target", "selection");
|
|
12028
12698
|
selectionButton.setAttribute("aria-label", buildChatContextScopeButtonAriaLabel("selection", contextData));
|
|
12029
|
-
selectionButton.title = "Use selection";
|
|
12699
|
+
selectionButton.title = (obj.__aiT ? obj.__aiT("aic_usesel", "Use selection") : "Use selection");
|
|
12030
12700
|
setReviewV2ButtonContent(selectionButton, "cursorText", "");
|
|
12031
12701
|
selectionButton.onclick = function () {
|
|
12032
12702
|
var currentSnapshot = captureSelectionSnapshot();
|
|
@@ -12038,7 +12708,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12038
12708
|
documentButton.type = "button";
|
|
12039
12709
|
documentButton.setAttribute("data-rte-ai-chat-scope-target", "document");
|
|
12040
12710
|
documentButton.setAttribute("aria-label", buildChatContextScopeButtonAriaLabel("document", contextData));
|
|
12041
|
-
documentButton.title = "Use document";
|
|
12711
|
+
documentButton.title = (obj.__aiT ? obj.__aiT("aic_usedoc", "Use document") : "Use document");
|
|
12042
12712
|
setReviewV2ButtonContent(documentButton, "document", "");
|
|
12043
12713
|
documentButton.onclick = function () {
|
|
12044
12714
|
state.scope = "document";
|
|
@@ -12093,7 +12763,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12093
12763
|
if (recentSessions.length > 1) {
|
|
12094
12764
|
var historySection = append(panel, "div", "", "rte-ai-chat-stack rte-ai-chat-history-shell is-minimal");
|
|
12095
12765
|
historySection.setAttribute("role", "group");
|
|
12096
|
-
historySection.setAttribute("aria-label", "Recent AI chats");
|
|
12766
|
+
historySection.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aic_recent", "Recent AI chats") : "Recent AI chats"));
|
|
12097
12767
|
var historyRow = append(historySection, "div", "", "rte-ai-chat-quick-row rte-ai-chat-history-row");
|
|
12098
12768
|
for (var s = 0; s < recentSessions.length; s++) {
|
|
12099
12769
|
(function (session, index) {
|
|
@@ -12160,10 +12830,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12160
12830
|
// reference drops with the chips.
|
|
12161
12831
|
var hasQuickStarts = !!(prompts && prompts.length);
|
|
12162
12832
|
var emptyHintBase = context.scope === "selection"
|
|
12163
|
-
? "Ask anything about the current selection"
|
|
12164
|
-
: "Ask anything about the current document";
|
|
12833
|
+
? (obj.__aiT ? obj.__aiT("aic_empty_sel", "Ask anything about the current selection") : "Ask anything about the current selection")
|
|
12834
|
+
: (obj.__aiT ? obj.__aiT("aic_empty_doc", "Ask anything about the current document") : "Ask anything about the current document");
|
|
12165
12835
|
append(emptyState, "div", "", "rte-ai-chat-empty-detail",
|
|
12166
|
-
hasQuickStarts ? (emptyHintBase + "
|
|
12836
|
+
hasQuickStarts ? (emptyHintBase + (obj.__aiT ? obj.__aiT("aic_orquick", " \u2014 or tap a quick start above.") : " \u2014 or tap a quick start above.")) : (emptyHintBase + "."));
|
|
12167
12837
|
}
|
|
12168
12838
|
var activeExchangeGroup = null;
|
|
12169
12839
|
var activeExchangeIndex = 0;
|
|
@@ -12300,11 +12970,11 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12300
12970
|
var avatarKind = message.isError ? "error" : message.role;
|
|
12301
12971
|
var avatar = append(messageHeader, "span", "", "rte-ai-chat-message-avatar is-" + avatarKind);
|
|
12302
12972
|
avatar.setAttribute("aria-hidden", "true");
|
|
12303
|
-
avatar.innerHTML = avatarKind === "user"
|
|
12973
|
+
avatar.innerHTML = __RTE_TT(avatarKind === "user"
|
|
12304
12974
|
? '<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><circle cx="8" cy="5.5" r="2.8"/><path d="M8 9.4c-2.8 0-5.2 1.5-5.2 3.4 0 .4.3.7.7.7h9c.4 0 .7-.3.7-.7 0-1.9-2.4-3.4-5.2-3.4z"/></svg>'
|
|
12305
12975
|
: (avatarKind === "error"
|
|
12306
12976
|
? '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="8" cy="8" r="6.5"/><path d="M8 5v3.5M8 11.2v.1"/></svg>'
|
|
12307
|
-
: '<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><rect x="3" y="5" width="10" height="8" rx="2"/><circle cx="8" cy="3" r="0.9"/><line x1="8" y1="3.9" x2="8" y2="5" stroke="currentColor" stroke-width="1"/><circle cx="6" cy="9" r="1.1" fill="#ffffff"/><circle cx="10" cy="9" r="1.1" fill="#ffffff"/></svg>');
|
|
12977
|
+
: '<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><rect x="3" y="5" width="10" height="8" rx="2"/><circle cx="8" cy="3" r="0.9"/><line x1="8" y1="3.9" x2="8" y2="5" stroke="currentColor" stroke-width="1"/><circle cx="6" cy="9" r="1.1" fill="#ffffff"/><circle cx="10" cy="9" r="1.1" fill="#ffffff"/></svg>'));
|
|
12308
12978
|
append(messageHeader, "span", "", "rte-ai-chat-message-role is-" + (message.isError ? "error" : message.role), getChatMessageRoleLabel(message));
|
|
12309
12979
|
append(item, "div", "", "rte-ai-chat-message-text", message.text || "");
|
|
12310
12980
|
// 2026-05-08: per-message Copy + Regenerate row for assistant
|
|
@@ -12315,8 +12985,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12315
12985
|
var msgActions = append(item, "div", "", "rte-ai-chat-message-actions-row");
|
|
12316
12986
|
var msgCopyBtn = append(msgActions, "button", "", "rte-ai-chat-message-action is-copy");
|
|
12317
12987
|
msgCopyBtn.type = "button";
|
|
12318
|
-
msgCopyBtn.title = "Copy message text";
|
|
12319
|
-
setReviewV2ButtonContent(msgCopyBtn, "checkAll", "Copy");
|
|
12988
|
+
msgCopyBtn.title = (obj.__aiT ? obj.__aiT("aic_copymsg", "Copy message text") : "Copy message text");
|
|
12989
|
+
setReviewV2ButtonContent(msgCopyBtn, "checkAll", (obj.__aiT ? obj.__aiT("aic_copy", "Copy") : "Copy"));
|
|
12320
12990
|
msgCopyBtn.onclick = (function (text, btn) {
|
|
12321
12991
|
return function (e) {
|
|
12322
12992
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
@@ -12341,10 +13011,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12341
13011
|
}
|
|
12342
13012
|
if (copied) {
|
|
12343
13013
|
btn.classList.add("is-just-copied");
|
|
12344
|
-
setReviewV2ButtonContent(btn, "check", "Copied");
|
|
13014
|
+
setReviewV2ButtonContent(btn, "check", (obj.__aiT ? obj.__aiT("aic_copied", "Copied") : "Copied"));
|
|
12345
13015
|
setTimeout(function () {
|
|
12346
13016
|
btn.classList.remove("is-just-copied");
|
|
12347
|
-
setReviewV2ButtonContent(btn, "checkAll", "Copy");
|
|
13017
|
+
setReviewV2ButtonContent(btn, "checkAll", (obj.__aiT ? obj.__aiT("aic_copy", "Copy") : "Copy"));
|
|
12348
13018
|
}, 1400);
|
|
12349
13019
|
}
|
|
12350
13020
|
};
|
|
@@ -12362,8 +13032,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12362
13032
|
if (precedingUserPrompt) {
|
|
12363
13033
|
var msgRegenBtn = append(msgActions, "button", "", "rte-ai-chat-message-action is-regen");
|
|
12364
13034
|
msgRegenBtn.type = "button";
|
|
12365
|
-
msgRegenBtn.title = "Regenerate response";
|
|
12366
|
-
setReviewV2ButtonContent(msgRegenBtn, "refresh", "Regenerate");
|
|
13035
|
+
msgRegenBtn.title = (obj.__aiT ? obj.__aiT("aic_regen", "Regenerate response") : "Regenerate response");
|
|
13036
|
+
setReviewV2ButtonContent(msgRegenBtn, "refresh", (obj.__aiT ? obj.__aiT("aid_regenerate", "Regenerate") : "Regenerate"));
|
|
12367
13037
|
msgRegenBtn.onclick = (function (prompt) {
|
|
12368
13038
|
return function (e) {
|
|
12369
13039
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
@@ -12622,7 +13292,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12622
13292
|
moreToggle.type = "button";
|
|
12623
13293
|
moreToggle.setAttribute("data-rte-ai-chat-action", "more");
|
|
12624
13294
|
moreToggle.setAttribute("aria-expanded", "false");
|
|
12625
|
-
moreToggle.title = "More apply options";
|
|
13295
|
+
moreToggle.title = (obj.__aiT ? obj.__aiT("ai2_moreopts", "More apply options") : "More apply options");
|
|
12626
13296
|
setReviewV2ButtonContent(moreToggle, "more", "More");
|
|
12627
13297
|
moreToggle.onclick = (function (host) {
|
|
12628
13298
|
return function (e) {
|
|
@@ -12711,8 +13381,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12711
13381
|
// 51 chars → 14 chars. Same shape Claude composer ("Ask
|
|
12712
13382
|
// anything") / ChatGPT composer ("Message ChatGPT") / Notion AI
|
|
12713
13383
|
// ("Tell AI what to do…") ship.
|
|
12714
|
-
composerArea.placeholder = "Ask anything
|
|
12715
|
-
composerArea.setAttribute("aria-label", "Compose next AI request for the current "
|
|
13384
|
+
composerArea.placeholder = (obj.__aiT ? obj.__aiT("aic_askanything", "Ask anything\u2026") : "Ask anything\u2026");
|
|
13385
|
+
composerArea.setAttribute("aria-label", context.scope === "selection" ? (obj.__aiT ? obj.__aiT("aic_compose_sel", "Compose next AI request for the current selection") : "Compose next AI request for the current selection") : (obj.__aiT ? obj.__aiT("aic_compose_doc", "Compose next AI request for the current document") : "Compose next AI request for the current document"));
|
|
12716
13386
|
composerArea.value = state.draft || "";
|
|
12717
13387
|
composerArea.disabled = !!state.busy;
|
|
12718
13388
|
composerArea.oninput = function () {
|
|
@@ -12839,7 +13509,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
12839
13509
|
}
|
|
12840
13510
|
|
|
12841
13511
|
function getReviewTypeOptions(suggestions) {
|
|
12842
|
-
var map = { all: "All types" };
|
|
13512
|
+
var map = { all: (obj.__aiT ? obj.__aiT("air_alltypes", "All types") : "All types") };
|
|
12843
13513
|
for (var i = 0; i < suggestions.length; i++) {
|
|
12844
13514
|
var typeValue = getSuggestionTypeValue(suggestions[i] && suggestions[i].suggestionType || "");
|
|
12845
13515
|
if (!map[typeValue]) {
|
|
@@ -13782,7 +14452,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
13782
14452
|
if (summaryData.detail) {
|
|
13783
14453
|
parts.push(summaryData.detail);
|
|
13784
14454
|
}
|
|
13785
|
-
return parts
|
|
14455
|
+
return joinSentences(parts);
|
|
13786
14456
|
}
|
|
13787
14457
|
|
|
13788
14458
|
function syncActiveReviewActionSummary(preferredAction) {
|
|
@@ -14005,10 +14675,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14005
14675
|
if (isTarget) {
|
|
14006
14676
|
button.setAttribute("data-rte-ai-review-enter-target-label", "Enter");
|
|
14007
14677
|
if (ariaLabel && !/current enter target/i.test(ariaLabel)) {
|
|
14008
|
-
button.setAttribute("aria-label", ariaLabel
|
|
14678
|
+
button.setAttribute("aria-label", joinSentences([ariaLabel, "Current Enter target."]));
|
|
14009
14679
|
}
|
|
14010
14680
|
if (title && !/current enter target/i.test(title)) {
|
|
14011
|
-
button.title = title
|
|
14681
|
+
button.title = joinSentences([title, "Current Enter target."]);
|
|
14012
14682
|
}
|
|
14013
14683
|
}
|
|
14014
14684
|
else {
|
|
@@ -14163,7 +14833,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14163
14833
|
if (prefixMatch) {
|
|
14164
14834
|
var label = ownerDocument.createElement("span");
|
|
14165
14835
|
label.className = "rte-ai-review-shortcuts-label";
|
|
14166
|
-
label.innerText = "Shortcuts:";
|
|
14836
|
+
label.innerText = uiT("aiu_shortcuts", "Shortcuts:");
|
|
14167
14837
|
node.appendChild(label);
|
|
14168
14838
|
node.appendChild(ownerDocument.createTextNode(" "));
|
|
14169
14839
|
}
|
|
@@ -14255,7 +14925,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14255
14925
|
titleNode.className = "rte-ai-review-item-shortcuts-title";
|
|
14256
14926
|
moduleNode.appendChild(titleNode);
|
|
14257
14927
|
}
|
|
14258
|
-
titleNode.textContent = "Keyboard guide";
|
|
14928
|
+
titleNode.textContent = uiT("aiq_kbguide", "Keyboard guide");
|
|
14259
14929
|
var bodyNode = moduleNode.querySelector ? moduleNode.querySelector(".rte-ai-review-item-shortcuts-body") : null;
|
|
14260
14930
|
if (!bodyNode) {
|
|
14261
14931
|
bodyNode = document.createElement("div");
|
|
@@ -14717,7 +15387,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14717
15387
|
var iconSpan = btn.ownerDocument.createElement("span");
|
|
14718
15388
|
iconSpan.className = "rte-ai-review-v2-action-icon";
|
|
14719
15389
|
iconSpan.setAttribute("aria-hidden", "true");
|
|
14720
|
-
iconSpan.innerHTML = REVIEW_V2_ICONS[iconKey];
|
|
15390
|
+
iconSpan.innerHTML = __RTE_TT(REVIEW_V2_ICONS[iconKey]);
|
|
14721
15391
|
btn.appendChild(iconSpan);
|
|
14722
15392
|
}
|
|
14723
15393
|
if (label) {
|
|
@@ -14787,15 +15457,15 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14787
15457
|
// Header
|
|
14788
15458
|
var header = append(panel, "div", "", "rte-ai-review-v2-header");
|
|
14789
15459
|
var iconWrap = append(header, "span", "", "rte-ai-review-v2-icon");
|
|
14790
|
-
iconWrap.innerHTML = config.svgCode_aiassist_review || config.svgCode_aiassist || "";
|
|
15460
|
+
iconWrap.innerHTML = __RTE_TT(config.svgCode_aiassist_review || config.svgCode_aiassist || "");
|
|
14791
15461
|
append(header, "div", "", "rte-ai-review-v2-title", config.text_aireview || "AI Review");
|
|
14792
15462
|
// Pending count moved into the "To review" tab badge below; the
|
|
14793
15463
|
// header pill would have duplicated that signal.
|
|
14794
15464
|
var closeBtn = append(header, "button", "", "rte-ai-review-v2-close");
|
|
14795
15465
|
closeBtn.type = "button";
|
|
14796
|
-
closeBtn.setAttribute("aria-label", "Close AI review");
|
|
14797
|
-
closeBtn.title = "Close";
|
|
14798
|
-
closeBtn.innerHTML = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>';
|
|
15466
|
+
closeBtn.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("air_closearia", "Close AI review") : "Close AI review"));
|
|
15467
|
+
closeBtn.title = (obj.__aiT ? obj.__aiT("air_close", "Close") : "Close");
|
|
15468
|
+
closeBtn.innerHTML = __RTE_TT('<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>');
|
|
14799
15469
|
closeBtn.onclick = function () {
|
|
14800
15470
|
closeReviewPanel();
|
|
14801
15471
|
editor.focus();
|
|
@@ -14819,7 +15489,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14819
15489
|
var iconSpan = tab.ownerDocument.createElement("span");
|
|
14820
15490
|
iconSpan.className = "rte-ai-review-v2-tab-icon";
|
|
14821
15491
|
iconSpan.setAttribute("aria-hidden", "true");
|
|
14822
|
-
iconSpan.innerHTML = REVIEW_V2_ICONS[iconKey];
|
|
15492
|
+
iconSpan.innerHTML = __RTE_TT(REVIEW_V2_ICONS[iconKey]);
|
|
14823
15493
|
tab.appendChild(iconSpan);
|
|
14824
15494
|
}
|
|
14825
15495
|
var labelSpan = tab.ownerDocument.createElement("span");
|
|
@@ -14840,9 +15510,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14840
15510
|
return tab;
|
|
14841
15511
|
}
|
|
14842
15512
|
|
|
14843
|
-
makeTab("pending", "inbox", "To review", pendingCountForTabs);
|
|
14844
|
-
makeTab("resolved", "history", "History", resolvedCountForTabs);
|
|
14845
|
-
makeTab("all", "filter", "All", counts.total);
|
|
15513
|
+
makeTab("pending", "inbox", (obj.__aiT ? obj.__aiT("air_tab_pending", "To review") : "To review"), pendingCountForTabs);
|
|
15514
|
+
makeTab("resolved", "history", (obj.__aiT ? obj.__aiT("air_tab_history", "History") : "History"), resolvedCountForTabs);
|
|
15515
|
+
makeTab("all", "filter", (obj.__aiT ? obj.__aiT("air_tab_all", "All") : "All"), counts.total);
|
|
14846
15516
|
|
|
14847
15517
|
// Toolbar: type filter + (on Pending tab only) Accept all / Reject all
|
|
14848
15518
|
var toolbar = append(panel, "div", "", "rte-ai-review-v2-toolbar");
|
|
@@ -14872,14 +15542,14 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14872
15542
|
var acceptAllBtn = append(toolbar, "button", "", "rte-ai-review-v2-batch is-accept");
|
|
14873
15543
|
acceptAllBtn.type = "button";
|
|
14874
15544
|
acceptAllBtn.disabled = !pendingForBatch;
|
|
14875
|
-
setReviewV2ButtonContent(acceptAllBtn, "checkAll", "Accept all");
|
|
15545
|
+
setReviewV2ButtonContent(acceptAllBtn, "checkAll", (obj.__aiT ? obj.__aiT("air_acceptall", "Accept all") : "Accept all"));
|
|
14876
15546
|
acceptAllBtn.onclick = function () {
|
|
14877
15547
|
if (acceptPendingSuggestionsByType(typeFilter)) renderReviewPanelV2(true);
|
|
14878
15548
|
};
|
|
14879
15549
|
var rejectAllBtn = append(toolbar, "button", "", "rte-ai-review-v2-batch is-reject");
|
|
14880
15550
|
rejectAllBtn.type = "button";
|
|
14881
15551
|
rejectAllBtn.disabled = !pendingForBatch;
|
|
14882
|
-
setReviewV2ButtonContent(rejectAllBtn, "x", "Reject all");
|
|
15552
|
+
setReviewV2ButtonContent(rejectAllBtn, "x", (obj.__aiT ? obj.__aiT("air_rejectall", "Reject all") : "Reject all"));
|
|
14883
15553
|
rejectAllBtn.onclick = function () {
|
|
14884
15554
|
if (rejectPendingSuggestionsByType(typeFilter)) renderReviewPanelV2(true);
|
|
14885
15555
|
};
|
|
@@ -14923,11 +15593,11 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14923
15593
|
}
|
|
14924
15594
|
var activeV2Suggestion = findSuggestionById(activeId);
|
|
14925
15595
|
var resolvedProgress = counts.total ? Math.max(0, Math.min(100, Math.round((resolvedCountForTabs / counts.total) * 100))) : 0;
|
|
14926
|
-
var queueScopeLabel = typeFilter === "all" ? "All types" : getSuggestionTypeLabel(typeFilter);
|
|
15596
|
+
var queueScopeLabel = typeFilter === "all" ? (obj.__aiT ? obj.__aiT("air_alltypes", "All types") : "All types") : getSuggestionTypeLabel(typeFilter);
|
|
14927
15597
|
var v2Center = append(panel, "div", "", "rte-ai-review-v2-center");
|
|
14928
15598
|
panel.insertBefore(v2Center, body);
|
|
14929
15599
|
v2Center.setAttribute("role", "group");
|
|
14930
|
-
v2Center.setAttribute("aria-label", "AI review summary");
|
|
15600
|
+
v2Center.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("air_summary", "AI review summary") : "AI review summary"));
|
|
14931
15601
|
function appendReviewV2CenterTile(className, label, value, detail) {
|
|
14932
15602
|
var tile = append(v2Center, "div", "", "rte-ai-review-v2-center-tile " + className);
|
|
14933
15603
|
append(tile, "span", "", "rte-ai-review-v2-center-label", label);
|
|
@@ -14935,19 +15605,19 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14935
15605
|
append(tile, "span", "", "rte-ai-review-v2-center-detail", detail);
|
|
14936
15606
|
return tile;
|
|
14937
15607
|
}
|
|
14938
|
-
appendReviewV2CenterTile("is-queue", "Queue",
|
|
14939
|
-
appendReviewV2CenterTile("is-progress", "Progress", resolvedProgress + "% done", resolvedCountForTabs + " resolved of " + counts.total);
|
|
15608
|
+
appendReviewV2CenterTile("is-queue", (obj.__aiT ? obj.__aiT("air_queue", "Queue") : "Queue"), (obj.__aiT ? obj.__aiT("air_npending", "{0} pending", pendingForBatch) : pendingForBatch + " pending"), activeTab === "pending" ? (obj.__aiT ? obj.__aiT("air_toreview", "{0} to review", queueScopeLabel) : queueScopeLabel + " to review") : (obj.__aiT ? obj.__aiT("air_filter", "{0} filter", queueScopeLabel) : queueScopeLabel + " filter"));
|
|
15609
|
+
appendReviewV2CenterTile("is-progress", (obj.__aiT ? obj.__aiT("air_progress", "Progress") : "Progress"), (obj.__aiT ? obj.__aiT("air_pctdone", "{0}% done", resolvedProgress) : resolvedProgress + "% done"), (obj.__aiT ? obj.__aiT("air_resolvedof", "{0} resolved of {1}").split("{0}").join(String(resolvedCountForTabs)).split("{1}").join(String(counts.total)) : resolvedCountForTabs + " resolved of " + counts.total));
|
|
14940
15610
|
var nextV2Value = activeV2Suggestion
|
|
14941
|
-
? ((activeV2Suggestion.status === "pending" || activeV2Suggestion.status === "stale") ? "Review current" : "Inspect item")
|
|
14942
|
-
: (pendingForBatch ? "Pick an item" : (counts.total ? "All caught up" : "Start with Ask AI"));
|
|
15611
|
+
? ((activeV2Suggestion.status === "pending" || activeV2Suggestion.status === "stale") ? (obj.__aiT ? obj.__aiT("air_reviewcurrent", "Review current") : "Review current") : (obj.__aiT ? obj.__aiT("air_inspect", "Inspect item") : "Inspect item"))
|
|
15612
|
+
: (pendingForBatch ? (obj.__aiT ? obj.__aiT("air_pick", "Pick an item") : "Pick an item") : (counts.total ? (obj.__aiT ? obj.__aiT("air_caughtup", "All caught up") : "All caught up") : (obj.__aiT ? obj.__aiT("air_startask", "Start with Ask AI") : "Start with Ask AI")));
|
|
14943
15613
|
var nextV2Detail = activeV2Suggestion
|
|
14944
15614
|
? summarizeSuggestionText(activeV2Suggestion.originalText || activeV2Suggestion.resultText || "AI suggestion", 72)
|
|
14945
|
-
: (pendingForBatch ? "Select a card below to compare the change." : (counts.total ? "History keeps accepted and rejected changes." : "AI suggestions will appear here."));
|
|
14946
|
-
var nextV2Tile = appendReviewV2CenterTile("is-next", "Next step", nextV2Value, nextV2Detail);
|
|
15615
|
+
: (pendingForBatch ? (obj.__aiT ? obj.__aiT("air_d_pick", "Select a card below to compare the change.") : "Select a card below to compare the change.") : (counts.total ? (obj.__aiT ? obj.__aiT("air_d_history", "History keeps accepted and rejected changes.") : "History keeps accepted and rejected changes.") : (obj.__aiT ? obj.__aiT("air_d_empty", "AI suggestions will appear here.") : "AI suggestions will appear here.")));
|
|
15616
|
+
var nextV2Tile = appendReviewV2CenterTile("is-next", (obj.__aiT ? obj.__aiT("air_next", "Next step") : "Next step"), nextV2Value, nextV2Detail);
|
|
14947
15617
|
if (activeV2Suggestion) {
|
|
14948
|
-
var focusV2Button = append(nextV2Tile, "button", "", "rte-ai-review-v2-center-action", "Focus");
|
|
15618
|
+
var focusV2Button = append(nextV2Tile, "button", "", "rte-ai-review-v2-center-action", (obj.__aiT ? obj.__aiT("air_focus", "Focus") : "Focus"));
|
|
14949
15619
|
focusV2Button.type = "button";
|
|
14950
|
-
focusV2Button.setAttribute("aria-label", "Focus the current AI review item");
|
|
15620
|
+
focusV2Button.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("air_focusaria", "Focus the current AI review item") : "Focus the current AI review item"));
|
|
14951
15621
|
focusV2Button.onclick = function () {
|
|
14952
15622
|
setActiveSuggestionId(activeId);
|
|
14953
15623
|
renderReviewPanelV2(true);
|
|
@@ -14959,19 +15629,19 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14959
15629
|
if (counts.total === 0) {
|
|
14960
15630
|
// Truly empty store — guide the user to AI Chat / Ask AI.
|
|
14961
15631
|
append(empty, "div", "", "rte-ai-review-v2-empty-art is-prompt");
|
|
14962
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-title", "No AI suggestions yet");
|
|
14963
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-detail", "Ask AI or AI Chat will drop suggestions here for you to accept or reject.");
|
|
15632
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-title", (obj.__aiT ? obj.__aiT("air_e_none_t", "No AI suggestions yet") : "No AI suggestions yet"));
|
|
15633
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-detail", (obj.__aiT ? obj.__aiT("air_e_none_d", "Ask AI or AI Chat will drop suggestions here for you to accept or reject.") : "Ask AI or AI Chat will drop suggestions here for you to accept or reject."));
|
|
14964
15634
|
} else if (activeTab === "pending") {
|
|
14965
15635
|
// History exists but Pending is empty — celebrate.
|
|
14966
15636
|
append(empty, "div", "", "rte-ai-review-v2-empty-art is-clear");
|
|
14967
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-title", "Nothing to review");
|
|
14968
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-detail", "You're all caught up. Switch to History to see past decisions.");
|
|
15637
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-title", (obj.__aiT ? obj.__aiT("air_e_done_t", "Nothing to review") : "Nothing to review"));
|
|
15638
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-detail", (obj.__aiT ? obj.__aiT("air_e_done_d", "You're all caught up. Switch to History to see past decisions.") : "You're all caught up. Switch to History to see past decisions."));
|
|
14969
15639
|
} else if (activeTab === "resolved") {
|
|
14970
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-title", "No history yet");
|
|
14971
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-detail", "Decisions you make on the To review tab will show up here.");
|
|
15640
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-title", (obj.__aiT ? obj.__aiT("air_e_nohist_t", "No history yet") : "No history yet"));
|
|
15641
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-detail", (obj.__aiT ? obj.__aiT("air_e_nohist_d", "Decisions you make on the To review tab will show up here.") : "Decisions you make on the To review tab will show up here."));
|
|
14972
15642
|
} else {
|
|
14973
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-title", "No suggestions match this filter");
|
|
14974
|
-
append(empty, "div", "", "rte-ai-review-v2-empty-detail", "Try a different type, or pick a different tab.");
|
|
15643
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-title", (obj.__aiT ? obj.__aiT("air_e_nomatch_t", "No suggestions match this filter") : "No suggestions match this filter"));
|
|
15644
|
+
append(empty, "div", "", "rte-ai-review-v2-empty-detail", (obj.__aiT ? obj.__aiT("air_e_nomatch_d", "Try a different type, or pick a different tab.") : "Try a different type, or pick a different tab."));
|
|
14975
15645
|
}
|
|
14976
15646
|
} else {
|
|
14977
15647
|
for (var vi = 0; vi < visible.length; vi++) {
|
|
@@ -14986,9 +15656,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14986
15656
|
append(head, "span", "", "rte-ai-review-v2-item-type", getSuggestionTypeLabel(sug.suggestionType));
|
|
14987
15657
|
}
|
|
14988
15658
|
if (sug.snapshot && sug.snapshot.hasSelection) {
|
|
14989
|
-
append(head, "span", "", "rte-ai-review-v2-item-scope", "Selection");
|
|
15659
|
+
append(head, "span", "", "rte-ai-review-v2-item-scope", (obj.__aiT ? obj.__aiT("air_scope_sel", "Selection") : "Selection"));
|
|
14990
15660
|
} else {
|
|
14991
|
-
append(head, "span", "", "rte-ai-review-v2-item-scope", "Document");
|
|
15661
|
+
append(head, "span", "", "rte-ai-review-v2-item-scope", (obj.__aiT ? obj.__aiT("air_scope_doc", "Document") : "Document"));
|
|
14992
15662
|
}
|
|
14993
15663
|
|
|
14994
15664
|
var titleText = summarizeSuggestionText(sug.originalText || sug.resultText || "AI suggestion", 120);
|
|
@@ -14998,15 +15668,15 @@ function RTE_Plugin_AIToolkit() {
|
|
|
14998
15668
|
if (sug.originalText && sug.resultText && normalizeText(sug.originalText) !== normalizeText(sug.resultText)) {
|
|
14999
15669
|
var compare = append(item, "div", "", "rte-ai-review-v2-compare");
|
|
15000
15670
|
var before = append(compare, "div", "", "rte-ai-review-v2-before");
|
|
15001
|
-
append(before, "span", "", "rte-ai-review-v2-compare-label", "Current");
|
|
15671
|
+
append(before, "span", "", "rte-ai-review-v2-compare-label", (obj.__aiT ? obj.__aiT("air_current", "Current") : "Current"));
|
|
15002
15672
|
append(before, "div", "", "rte-ai-review-v2-compare-text", normalizeText(sug.originalText));
|
|
15003
15673
|
// Decorative arrow on the centerline of the
|
|
15004
15674
|
// grid pointing from Current -> Suggested.
|
|
15005
15675
|
var compareArrow = append(compare, "span", "", "rte-ai-review-v2-compare-arrow");
|
|
15006
15676
|
compareArrow.setAttribute("aria-hidden", "true");
|
|
15007
|
-
compareArrow.innerHTML = REVIEW_V2_ICONS.arrowRight;
|
|
15677
|
+
compareArrow.innerHTML = __RTE_TT(REVIEW_V2_ICONS.arrowRight);
|
|
15008
15678
|
var after = append(compare, "div", "", "rte-ai-review-v2-after");
|
|
15009
|
-
append(after, "span", "", "rte-ai-review-v2-compare-label", "Suggested");
|
|
15679
|
+
append(after, "span", "", "rte-ai-review-v2-compare-label", (obj.__aiT ? obj.__aiT("air_suggested", "Suggested") : "Suggested"));
|
|
15010
15680
|
append(after, "div", "", "rte-ai-review-v2-compare-text", normalizeText(sug.resultText));
|
|
15011
15681
|
}
|
|
15012
15682
|
if (sug.reason) {
|
|
@@ -15015,17 +15685,17 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15015
15685
|
var bulbWrap = reason.ownerDocument.createElement("span");
|
|
15016
15686
|
bulbWrap.className = "rte-ai-review-v2-reason-icon";
|
|
15017
15687
|
bulbWrap.setAttribute("aria-hidden", "true");
|
|
15018
|
-
bulbWrap.innerHTML = REVIEW_V2_ICONS.bulb;
|
|
15688
|
+
bulbWrap.innerHTML = __RTE_TT(REVIEW_V2_ICONS.bulb);
|
|
15019
15689
|
reasonLabel.appendChild(bulbWrap);
|
|
15020
15690
|
var reasonLabelText = reason.ownerDocument.createElement("span");
|
|
15021
|
-
reasonLabelText.textContent = "Why";
|
|
15691
|
+
reasonLabelText.textContent = (obj.__aiT ? obj.__aiT("air_why", "Why") : "Why");
|
|
15022
15692
|
reasonLabel.appendChild(reasonLabelText);
|
|
15023
15693
|
append(reason, "span", "", "rte-ai-review-v2-reason-text", sug.reason);
|
|
15024
15694
|
}
|
|
15025
15695
|
var actions = append(item, "div", "", "rte-ai-review-v2-actions");
|
|
15026
15696
|
var locateBtn = append(actions, "button", "", "rte-ai-review-v2-action is-locate");
|
|
15027
15697
|
locateBtn.type = "button";
|
|
15028
|
-
setReviewV2ButtonContent(locateBtn, "target", "Locate");
|
|
15698
|
+
setReviewV2ButtonContent(locateBtn, "target", (obj.__aiT ? obj.__aiT("air_locate", "Locate") : "Locate"));
|
|
15029
15699
|
locateBtn.onclick = function (e) {
|
|
15030
15700
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
15031
15701
|
locateSuggestion(sug.id);
|
|
@@ -15033,14 +15703,14 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15033
15703
|
if (sug.status === "pending" || sug.status === "stale") {
|
|
15034
15704
|
var acceptBtn = append(actions, "button", "", "rte-ai-review-v2-action is-accept");
|
|
15035
15705
|
acceptBtn.type = "button";
|
|
15036
|
-
setReviewV2ButtonContent(acceptBtn, "check", "Accept");
|
|
15706
|
+
setReviewV2ButtonContent(acceptBtn, "check", (obj.__aiT ? obj.__aiT("air_accept", "Accept") : "Accept"));
|
|
15037
15707
|
acceptBtn.onclick = function (e) {
|
|
15038
15708
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
15039
15709
|
applyReviewDecision(sug.id, "accept", { focusAction: "accept" });
|
|
15040
15710
|
};
|
|
15041
15711
|
var rejectBtn = append(actions, "button", "", "rte-ai-review-v2-action is-reject");
|
|
15042
15712
|
rejectBtn.type = "button";
|
|
15043
|
-
setReviewV2ButtonContent(rejectBtn, "x", "Reject");
|
|
15713
|
+
setReviewV2ButtonContent(rejectBtn, "x", (obj.__aiT ? obj.__aiT("air_reject", "Reject") : "Reject"));
|
|
15044
15714
|
rejectBtn.onclick = function (e) {
|
|
15045
15715
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
15046
15716
|
applyReviewDecision(sug.id, "reject", { focusAction: "reject" });
|
|
@@ -15289,7 +15959,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15289
15959
|
}
|
|
15290
15960
|
var titleRow = append(headerCopy, "div", "", "rte-ai-review-title-row");
|
|
15291
15961
|
var titleIcon = append(titleRow, "span", "", "rte-ai-review-title-icon");
|
|
15292
|
-
titleIcon.innerHTML = config.svgCode_aiassist_review || config.svgCode_aiassist || "";
|
|
15962
|
+
titleIcon.innerHTML = __RTE_TT(config.svgCode_aiassist_review || config.svgCode_aiassist || "");
|
|
15293
15963
|
append(titleRow, "div", "", "rte-ai-review-title", config.text_aireview || "AI Review");
|
|
15294
15964
|
if (hasRemoteReviewSync()) {
|
|
15295
15965
|
editor.__aiReviewSyncBadgeNode = append(titleRow, "span", "", "rte-ai-review-sync-badge", "");
|
|
@@ -15332,7 +16002,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15332
16002
|
var newestSharedButton = append(headerGroupContext, "button", "", "secondary rte-ai-review-header-button is-shared", "Newest shared");
|
|
15333
16003
|
newestSharedButton.type = "button";
|
|
15334
16004
|
newestSharedButton.setAttribute("data-rte-ai-review-focus-key", "newest-shared");
|
|
15335
|
-
newestSharedButton.setAttribute("aria-label", "Jump to the newest shared AI review update");
|
|
16005
|
+
newestSharedButton.setAttribute("aria-label", uiT("aiu_jumpnewest", "Jump to the newest shared AI review update"));
|
|
15336
16006
|
newestSharedButton.onclick = function () {
|
|
15337
16007
|
locateSuggestion(latestRemoteSuggestionId);
|
|
15338
16008
|
};
|
|
@@ -15342,7 +16012,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15342
16012
|
var currentPendingButton = append(headerGroupContext, "button", "", "secondary rte-ai-review-header-button is-locate-current", "Locate current");
|
|
15343
16013
|
currentPendingButton.type = "button";
|
|
15344
16014
|
currentPendingButton.setAttribute("data-rte-ai-review-focus-key", "locate-current");
|
|
15345
|
-
currentPendingButton.setAttribute("aria-label", "Locate the current active AI review item in the editor");
|
|
16015
|
+
currentPendingButton.setAttribute("aria-label", uiT("aiu_locatecurrent", "Locate the current active AI review item in the editor"));
|
|
15346
16016
|
currentPendingButton.onclick = function () {
|
|
15347
16017
|
locateSuggestion(activeFilteredSuggestionId);
|
|
15348
16018
|
};
|
|
@@ -15353,7 +16023,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15353
16023
|
var previousPendingButton = append(headerGroupMove, "button", "", "secondary rte-ai-review-header-button is-nav", "Previous");
|
|
15354
16024
|
previousPendingButton.type = "button";
|
|
15355
16025
|
previousPendingButton.setAttribute("data-rte-ai-review-focus-key", "previous-pending");
|
|
15356
|
-
previousPendingButton.setAttribute("aria-label", "Jump to the previous pending AI review item in the current filter");
|
|
16026
|
+
previousPendingButton.setAttribute("aria-label", uiT("aiu_jumpprev", "Jump to the previous pending AI review item in the current filter"));
|
|
15357
16027
|
previousPendingButton.onclick = function () {
|
|
15358
16028
|
activateReviewSuggestionWithDefaultActionFocus(previousPendingSuggestionId, { focusPanel: true });
|
|
15359
16029
|
};
|
|
@@ -15363,7 +16033,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15363
16033
|
var nextPendingButton = append(headerGroupMove, "button", "", "secondary rte-ai-review-header-button is-nav", "Next pending");
|
|
15364
16034
|
nextPendingButton.type = "button";
|
|
15365
16035
|
nextPendingButton.setAttribute("data-rte-ai-review-focus-key", "next-pending");
|
|
15366
|
-
nextPendingButton.setAttribute("aria-label", "Jump to the next pending AI review item in the current filter");
|
|
16036
|
+
nextPendingButton.setAttribute("aria-label", uiT("aiu_jumpnext", "Jump to the next pending AI review item in the current filter"));
|
|
15367
16037
|
nextPendingButton.onclick = function () {
|
|
15368
16038
|
activateReviewSuggestionWithDefaultActionFocus(nextPendingSuggestionId, { focusPanel: true });
|
|
15369
16039
|
};
|
|
@@ -15395,9 +16065,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15395
16065
|
var closeButton = append(headerUtility, "button", "", "rte-ai-panel-close-button is-review-close");
|
|
15396
16066
|
closeButton.type = "button";
|
|
15397
16067
|
closeButton.setAttribute("data-rte-ai-review-focus-key", "close-review");
|
|
15398
|
-
closeButton.setAttribute("aria-label", "Close AI review");
|
|
15399
|
-
closeButton.title = "Close";
|
|
15400
|
-
closeButton.innerHTML = '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>';
|
|
16068
|
+
closeButton.setAttribute("aria-label", uiT("air_closearia", "Close AI review"));
|
|
16069
|
+
closeButton.title = uiT("air_close", "Close");
|
|
16070
|
+
closeButton.innerHTML = __RTE_TT('<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>');
|
|
15401
16071
|
closeButton.onclick = function () {
|
|
15402
16072
|
closeReviewPanel();
|
|
15403
16073
|
};
|
|
@@ -15513,7 +16183,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15513
16183
|
var dismissActivityButton = append(activityCard, "button", "", "secondary rte-ai-review-activity-button", "Got it");
|
|
15514
16184
|
dismissActivityButton.type = "button";
|
|
15515
16185
|
dismissActivityButton.setAttribute("data-rte-ai-review-focus-key", "dismiss-activity");
|
|
15516
|
-
dismissActivityButton.setAttribute("aria-label", "Dismiss shared AI review update notice");
|
|
16186
|
+
dismissActivityButton.setAttribute("aria-label", uiT("aiu_dismissshared", "Dismiss shared AI review update notice"));
|
|
15517
16187
|
dismissActivityButton.onclick = function () {
|
|
15518
16188
|
markReviewActivitySeen();
|
|
15519
16189
|
renderReviewPanel(true);
|
|
@@ -15552,7 +16222,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15552
16222
|
acceptAllButton.setAttribute("data-rte-ai-review-focus-key", "accept-all");
|
|
15553
16223
|
acceptAllButton.disabled = typeFilter === "all" ? !counts.pending : !filteredPendingCount;
|
|
15554
16224
|
if (typeFilter !== "all") {
|
|
15555
|
-
acceptAllButton.innerText = "Accept filtered";
|
|
16225
|
+
acceptAllButton.innerText = uiT("aiu_acceptfiltered", "Accept filtered");
|
|
15556
16226
|
}
|
|
15557
16227
|
acceptAllButton.onclick = function () {
|
|
15558
16228
|
if (acceptPendingSuggestionsByType(typeFilter)) {
|
|
@@ -15564,7 +16234,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15564
16234
|
rejectAllButton.setAttribute("data-rte-ai-review-focus-key", "reject-all");
|
|
15565
16235
|
rejectAllButton.disabled = typeFilter === "all" ? !counts.pending : !filteredPendingCount;
|
|
15566
16236
|
if (typeFilter !== "all") {
|
|
15567
|
-
rejectAllButton.innerText = "Reject filtered";
|
|
16237
|
+
rejectAllButton.innerText = uiT("aiu_rejectfiltered", "Reject filtered");
|
|
15568
16238
|
}
|
|
15569
16239
|
rejectAllButton.onclick = function () {
|
|
15570
16240
|
if (rejectPendingSuggestionsByType(typeFilter)) {
|
|
@@ -15857,7 +16527,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15857
16527
|
appendPanelSectionLabel(previewSection, "rte-ai-review-section-label is-feed", emptyState.previewItems.length > 1 ? "Next queues" : "Next queue");
|
|
15858
16528
|
var emptyPreviewList = append(previewSection, "div", "", "rte-ai-review-empty-previews");
|
|
15859
16529
|
emptyPreviewList.setAttribute("role", "toolbar");
|
|
15860
|
-
emptyPreviewList.setAttribute("aria-label", "Next review queues");
|
|
16530
|
+
emptyPreviewList.setAttribute("aria-label", uiT("aiu_nextqueues", "Next review queues"));
|
|
15861
16531
|
for (var previewIndex = 0; previewIndex < emptyState.previewItems.length; previewIndex++) {
|
|
15862
16532
|
var previewItem = emptyState.previewItems[previewIndex];
|
|
15863
16533
|
var previewTag = previewItem.typeValue ? "button" : "div";
|
|
@@ -15903,7 +16573,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
15903
16573
|
if (previewItem.reasonText) {
|
|
15904
16574
|
previewAriaParts.push("Why this next: " + previewItem.reasonText);
|
|
15905
16575
|
}
|
|
15906
|
-
previewRow.setAttribute("aria-label", previewAriaParts
|
|
16576
|
+
previewRow.setAttribute("aria-label", joinSentences(previewAriaParts));
|
|
15907
16577
|
previewRow.setAttribute("data-rte-ai-primary-label", previewItem.actionLabel || previewItem.label || "Open next queue");
|
|
15908
16578
|
if (previewItem.focusActionLabel) {
|
|
15909
16579
|
previewRow.setAttribute("data-rte-ai-empty-focus-label", previewItem.focusActionLabel);
|
|
@@ -16433,6 +17103,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16433
17103
|
modeChip.className = "rte-ai-dialog-mode-chip is-detached";
|
|
16434
17104
|
modeChip.setAttribute("aria-hidden", "true");
|
|
16435
17105
|
|
|
17106
|
+
appendDemoNotice(dialoginner);
|
|
16436
17107
|
var grid = append(dialoginner, "div", "", "demo-ai-dialog-grid");
|
|
16437
17108
|
var dialogIdSuffix = String(Date.now()) + "-" + String(Math.floor(Math.random() * 1000000));
|
|
16438
17109
|
var modeHelpId = "rte-ai-mode-help-" + dialogIdSuffix;
|
|
@@ -16441,11 +17112,11 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16441
17112
|
var guidanceId = "rte-ai-apply-guidance-" + dialogIdSuffix;
|
|
16442
17113
|
var statusId = "rte-ai-dialog-status-" + dialogIdSuffix;
|
|
16443
17114
|
grid.setAttribute("role", "form");
|
|
16444
|
-
grid.setAttribute("aria-label", "Ask AI controls");
|
|
17115
|
+
grid.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_controls", "Ask AI controls") : "Ask AI controls"));
|
|
16445
17116
|
|
|
16446
17117
|
var compactControls = append(grid, "div", "", "demo-ai-compact-controls");
|
|
16447
17118
|
compactControls.setAttribute("role", "group");
|
|
16448
|
-
compactControls.setAttribute("aria-label", "Ask AI setup");
|
|
17119
|
+
compactControls.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_setup", "Ask AI setup") : "Ask AI setup"));
|
|
16449
17120
|
|
|
16450
17121
|
// 2026-05-08 compact pass: dropped the per-field uppercase mini-labels
|
|
16451
17122
|
// ("Action" / "Language" / "Use" / blank-spacer) and the duplicate
|
|
@@ -16454,7 +17125,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16454
17125
|
// select's title attribute (still surfaced on hover).
|
|
16455
17126
|
var actionField = append(compactControls, "div", "", "demo-ai-field demo-ai-action-field");
|
|
16456
17127
|
var modeSelect = append(actionField, "select");
|
|
16457
|
-
modeSelect.setAttribute("aria-label", "AI action");
|
|
17128
|
+
modeSelect.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_action", "AI action") : "AI action"));
|
|
16458
17129
|
// 2026-05-17 (v20260517a): the mode help line is back on-screen,
|
|
16459
17130
|
// attached directly to the dialog grid (full-width row under the
|
|
16460
17131
|
// controls strip). The prior hover-only `title` attribute meant
|
|
@@ -16481,7 +17152,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16481
17152
|
|
|
16482
17153
|
var languageField = append(compactControls, "div", "", "demo-ai-field demo-ai-language-field");
|
|
16483
17154
|
var languageSelect = append(languageField, "select");
|
|
16484
|
-
languageSelect.setAttribute("aria-label", "Translation target language");
|
|
17155
|
+
languageSelect.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_targetlang", "Translation target language") : "Translation target language"));
|
|
16485
17156
|
populateDialogModes();
|
|
16486
17157
|
if (options.presetMode) {
|
|
16487
17158
|
// 2026-05-19 (v20260519a): only honor presetMode when it
|
|
@@ -16532,11 +17203,11 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16532
17203
|
// can override with `.demo-ai-scope-select { display: none }` +
|
|
16533
17204
|
// `.demo-ai-scope-row.is-detached { display: flex !important }`.
|
|
16534
17205
|
var scopeSelect = append(scopeField, "select", "", "demo-ai-scope-select");
|
|
16535
|
-
scopeSelect.setAttribute("aria-label", "Source for Ask AI");
|
|
17206
|
+
scopeSelect.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_source", "Source for Ask AI") : "Source for Ask AI"));
|
|
16536
17207
|
scopeSelect.setAttribute("data-rte-ai-dialog-action", "scope");
|
|
16537
|
-
var scopeOptionSelection = append(scopeSelect, "option", "", "", "Selection");
|
|
17208
|
+
var scopeOptionSelection = append(scopeSelect, "option", "", "", (obj.__aiT ? obj.__aiT("aid_selection", "Selection") : "Selection"));
|
|
16538
17209
|
scopeOptionSelection.value = "selection";
|
|
16539
|
-
var scopeOptionDocument = append(scopeSelect, "option", "", "", "Document");
|
|
17210
|
+
var scopeOptionDocument = append(scopeSelect, "option", "", "", (obj.__aiT ? obj.__aiT("aid_document", "Document") : "Document"));
|
|
16540
17211
|
scopeOptionDocument.value = "document";
|
|
16541
17212
|
|
|
16542
17213
|
// 2026-06-01 (v20260601a): scope caption surfaced inline when only
|
|
@@ -16561,21 +17232,21 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16561
17232
|
var loadRow = scopeField.ownerDocument.createElement("div");
|
|
16562
17233
|
loadRow.className = "demo-actions-row demo-ai-scope-row is-detached";
|
|
16563
17234
|
loadRow.setAttribute("role", "group");
|
|
16564
|
-
loadRow.setAttribute("aria-label", "Source scope");
|
|
17235
|
+
loadRow.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_scope", "Source scope") : "Source scope"));
|
|
16565
17236
|
var loadSelectionButton = scopeField.ownerDocument.createElement("button");
|
|
16566
17237
|
loadSelectionButton.type = "button";
|
|
16567
17238
|
loadSelectionButton.className = "is-icon-only";
|
|
16568
17239
|
loadSelectionButton.setAttribute("data-rte-ai-dialog-action", "load-selection");
|
|
16569
|
-
loadSelectionButton.title = "Use selection";
|
|
16570
|
-
loadSelectionButton.setAttribute("aria-label", "Use selection");
|
|
17240
|
+
loadSelectionButton.title = (obj.__aiT ? obj.__aiT("aid_usesel", "Use selection") : "Use selection");
|
|
17241
|
+
loadSelectionButton.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_usesel", "Use selection") : "Use selection"));
|
|
16571
17242
|
setReviewV2ButtonContent(loadSelectionButton, "cursorText", "");
|
|
16572
17243
|
loadRow.appendChild(loadSelectionButton);
|
|
16573
17244
|
var loadDocumentButton = scopeField.ownerDocument.createElement("button");
|
|
16574
17245
|
loadDocumentButton.type = "button";
|
|
16575
17246
|
loadDocumentButton.className = "secondary is-icon-only";
|
|
16576
17247
|
loadDocumentButton.setAttribute("data-rte-ai-dialog-action", "load-document");
|
|
16577
|
-
loadDocumentButton.title = "Use document";
|
|
16578
|
-
loadDocumentButton.setAttribute("aria-label", "Use document");
|
|
17248
|
+
loadDocumentButton.title = (obj.__aiT ? obj.__aiT("aid_usedoc", "Use document") : "Use document");
|
|
17249
|
+
loadDocumentButton.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_usedoc", "Use document") : "Use document"));
|
|
16579
17250
|
setReviewV2ButtonContent(loadDocumentButton, "document", "");
|
|
16580
17251
|
loadRow.appendChild(loadDocumentButton);
|
|
16581
17252
|
// 2026-05-17 (v20260523a): append the legacy scope row to
|
|
@@ -16589,20 +17260,20 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16589
17260
|
var runField = append(compactControls, "div", "", "demo-ai-field demo-ai-run-field");
|
|
16590
17261
|
var runRow = append(runField, "div", "", "demo-actions-row demo-ai-run-row");
|
|
16591
17262
|
runRow.setAttribute("role", "group");
|
|
16592
|
-
runRow.setAttribute("aria-label", "Ask AI run actions");
|
|
17263
|
+
runRow.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_run", "Ask AI run actions") : "Ask AI run actions"));
|
|
16593
17264
|
var runButton = append(runRow, "button", "", "is-primary");
|
|
16594
17265
|
runButton.type = "button";
|
|
16595
17266
|
runButton.setAttribute("data-rte-ai-dialog-action", "run");
|
|
16596
17267
|
// Sparkle glyph + "Generate" — same icon vocabulary as AI Chat
|
|
16597
17268
|
// composer's Send and AI Review V2's Accept buttons.
|
|
16598
|
-
setReviewV2ButtonContent(runButton, "sparkles", "Generate");
|
|
17269
|
+
setReviewV2ButtonContent(runButton, "sparkles", (obj.__aiT ? obj.__aiT("aid_generate", "Generate") : "Generate"));
|
|
16599
17270
|
// 2026-05-09 (v20260509j): surface the Ctrl/Cmd+Enter shortcut on
|
|
16600
17271
|
// hover and to screen readers. Same idiom every modern AI surface
|
|
16601
17272
|
// uses (ChatGPT Send: "Send (⌘↵)", Notion AI Generate: "Generate
|
|
16602
17273
|
// (Ctrl+Enter)"). aria-keyshortcuts is the WAI-ARIA standard way
|
|
16603
17274
|
// to advertise a keyboard shortcut so screen readers announce
|
|
16604
17275
|
// "Generate, Control+Enter" alongside the button name.
|
|
16605
|
-
runButton.title = "Generate AI suggestion (Ctrl+Enter)";
|
|
17276
|
+
runButton.title = (obj.__aiT ? obj.__aiT("ai2_gentitle", "Generate AI suggestion (Ctrl+Enter)") : "Generate AI suggestion (Ctrl+Enter)");
|
|
16606
17277
|
runButton.setAttribute("aria-keyshortcuts", "Control+Enter");
|
|
16607
17278
|
// 2026-05-17 (v20260517a): visible Ctrl+↵ / ⌘↵ chip baked into
|
|
16608
17279
|
// the Generate button. Pre-v20260517a the shortcut only lived in
|
|
@@ -16614,7 +17285,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16614
17285
|
// from navigator.platform so the hint matches the actual key
|
|
16615
17286
|
// the user would press. */
|
|
16616
17287
|
var isMacOs = /Mac|iPad|iPhone|iPod/i.test((navigator.platform || "") + " " + (navigator.userAgent || ""));
|
|
16617
|
-
var runKbdLabel = isMacOs ? "
|
|
17288
|
+
var runKbdLabel = isMacOs ? "\u2318\u23ce" : "Ctrl \u23ce";
|
|
16618
17289
|
function refreshRunKbdHint() {
|
|
16619
17290
|
if (!runButton) return;
|
|
16620
17291
|
var existing = runButton.querySelector(".demo-ai-kbd-hint");
|
|
@@ -16632,8 +17303,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16632
17303
|
// 540px dialog width.
|
|
16633
17304
|
var copyButton = append(runRow, "button", "", "secondary is-icon-only");
|
|
16634
17305
|
copyButton.type = "button";
|
|
16635
|
-
copyButton.title = "Copy result into source";
|
|
16636
|
-
copyButton.setAttribute("aria-label", "Copy result into source");
|
|
17306
|
+
copyButton.title = uiT("aiu_copytosource", "Copy result into source");
|
|
17307
|
+
copyButton.setAttribute("aria-label", uiT("aiu_copytosource", "Copy result into source"));
|
|
16637
17308
|
copyButton.setAttribute("data-rte-ai-dialog-action", "copy-to-source");
|
|
16638
17309
|
setReviewV2ButtonContent(copyButton, "checkAll", "");
|
|
16639
17310
|
|
|
@@ -16664,7 +17335,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16664
17335
|
|
|
16665
17336
|
var textGrid = append(grid, "div", "", "demo-ai-text-grid");
|
|
16666
17337
|
textGrid.setAttribute("role", "group");
|
|
16667
|
-
textGrid.setAttribute("aria-label", "Ask AI source and result");
|
|
17338
|
+
textGrid.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_srcresult", "Ask AI source and result") : "Ask AI source and result"));
|
|
16668
17339
|
|
|
16669
17340
|
// 2026-05-09 (v20260509j): dropped the "Source" / "Result"
|
|
16670
17341
|
// text-tag spans. They had no CSS rule (the class was
|
|
@@ -16682,7 +17353,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16682
17353
|
// Pre-result it was already hidden (CSS .is-pre-result cascade); the
|
|
16683
17354
|
// remaining showing case was post-result + source-expanded, but the
|
|
16684
17355
|
// user only reaches that flow by clicking the "Edit" toggle pill —
|
|
16685
|
-
// which already names the field's role ("Edit the prompt and retry").
|
|
17356
|
+
// which already names the field's role ((obj.__aiT ? obj.__aiT("ai2_editretry", "Edit the prompt and retry") : "Edit the prompt and retry")).
|
|
16686
17357
|
// Restating "Source" 4px above the textarea was a third copy of the
|
|
16687
17358
|
// same fact (toggle label + textarea placeholder + this eyebrow).
|
|
16688
17359
|
// Saves ~16px vertical when the user expands source for retry/refine.
|
|
@@ -16692,7 +17363,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16692
17363
|
var sourceHelp = append(sourceField, "span", "", "demo-ai-field-help is-detached", "Edit the source text or prompt that Ask AI will use.");
|
|
16693
17364
|
sourceHelp.id = sourceHelpId;
|
|
16694
17365
|
var sourceArea = append(sourceField, "textarea");
|
|
16695
|
-
sourceArea.setAttribute("aria-label", "Source text for Ask AI");
|
|
17366
|
+
sourceArea.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_srctext", "Source text for Ask AI") : "Source text for Ask AI"));
|
|
16696
17367
|
sourceArea.setAttribute("aria-describedby", sourceHelpId + " " + modeHelpId);
|
|
16697
17368
|
// 2026-05-26 (v20260526a): reparent the run-row (Generate + Copy
|
|
16698
17369
|
// buttons) from the compact-controls strip INTO the source field,
|
|
@@ -16743,7 +17414,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16743
17414
|
// verb phrase, no inline shortcut hint.
|
|
16744
17415
|
// Earlier baseline:
|
|
16745
17416
|
// v20260509j: 95 → 47 chars after the scope toggle landed.
|
|
16746
|
-
sourceArea.placeholder = "Type or paste text
|
|
17417
|
+
sourceArea.placeholder = (obj.__aiT ? obj.__aiT("aid_typeorpaste", "Type or paste text\u2026") : "Type or paste text\u2026");
|
|
16747
17418
|
|
|
16748
17419
|
// 2026-06-03 (v20260603a): live character counter pinned to the
|
|
16749
17420
|
// bottom-LEFT corner of the source textarea. Pre-pass users
|
|
@@ -16777,8 +17448,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16777
17448
|
return;
|
|
16778
17449
|
}
|
|
16779
17450
|
var label = len > 999
|
|
16780
|
-
? (Math.round(len / 100) / 10) + "K chars"
|
|
16781
|
-
:
|
|
17451
|
+
? (obj.__aiT ? obj.__aiT("aid_kchars", "{0}K chars", Math.round(len / 100) / 10) : (Math.round(len / 100) / 10) + "K chars")
|
|
17452
|
+
: (len === 1 ? (obj.__aiT ? obj.__aiT("aid_char", "1 char") : "1 char") : (obj.__aiT ? obj.__aiT("aid_chars", "{0} chars", len) : len + " chars"));
|
|
16782
17453
|
sourceCounter.textContent = label;
|
|
16783
17454
|
sourceCounter.classList.add("is-visible");
|
|
16784
17455
|
}
|
|
@@ -16811,7 +17482,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16811
17482
|
// without throwing.
|
|
16812
17483
|
var resultLabel = document.createElement("span");
|
|
16813
17484
|
resultLabel.className = "demo-ai-text-label-inline is-detached";
|
|
16814
|
-
resultLabel.innerText = "Result";
|
|
17485
|
+
resultLabel.innerText = uiT("aiu_result", "Result");
|
|
16815
17486
|
var resultHelp = append(resultField, "span", "", "demo-ai-field-help is-detached", "Review the generated AI suggestion before applying it.");
|
|
16816
17487
|
resultHelp.id = resultHelpId;
|
|
16817
17488
|
// 2026-06-03 (v20260603a): real "Copy to clipboard" affordance
|
|
@@ -16832,9 +17503,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16832
17503
|
var copyClipboardButton = append(resultHead, "button", "", "demo-ai-clipboard-toggle");
|
|
16833
17504
|
copyClipboardButton.type = "button";
|
|
16834
17505
|
copyClipboardButton.setAttribute("data-rte-ai-dialog-action", "copy-clipboard");
|
|
16835
|
-
copyClipboardButton.title = "Copy AI output to clipboard";
|
|
16836
|
-
copyClipboardButton.setAttribute("aria-label", "Copy AI output to clipboard");
|
|
16837
|
-
setReviewV2ButtonContent(copyClipboardButton, "clipboard", "Copy");
|
|
17506
|
+
copyClipboardButton.title = (obj.__aiT ? obj.__aiT("ai2_copyclip", "Copy AI output to clipboard") : "Copy AI output to clipboard");
|
|
17507
|
+
copyClipboardButton.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("ai2_copyclip", "Copy AI output to clipboard") : "Copy AI output to clipboard"));
|
|
17508
|
+
setReviewV2ButtonContent(copyClipboardButton, "clipboard", (obj.__aiT ? obj.__aiT("ai2_copy", "Copy") : "Copy"));
|
|
16838
17509
|
var copyClipboardResetTimer = null;
|
|
16839
17510
|
copyClipboardButton.onclick = function (e) {
|
|
16840
17511
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
@@ -16846,13 +17517,13 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16846
17517
|
return;
|
|
16847
17518
|
}
|
|
16848
17519
|
copyClipboardButton.classList.add("is-copied");
|
|
16849
|
-
setReviewV2ButtonContent(copyClipboardButton, "check", "Copied");
|
|
17520
|
+
setReviewV2ButtonContent(copyClipboardButton, "check", (obj.__aiT ? obj.__aiT("aic_copied", "Copied") : "Copied"));
|
|
16850
17521
|
if (copyClipboardResetTimer) {
|
|
16851
17522
|
clearTimeout(copyClipboardResetTimer);
|
|
16852
17523
|
}
|
|
16853
17524
|
copyClipboardResetTimer = setTimeout(function () {
|
|
16854
17525
|
copyClipboardButton.classList.remove("is-copied");
|
|
16855
|
-
setReviewV2ButtonContent(copyClipboardButton, "clipboard", "Copy");
|
|
17526
|
+
setReviewV2ButtonContent(copyClipboardButton, "clipboard", (obj.__aiT ? obj.__aiT("ai2_copy", "Copy") : "Copy"));
|
|
16856
17527
|
copyClipboardResetTimer = null;
|
|
16857
17528
|
}, 1400);
|
|
16858
17529
|
});
|
|
@@ -16870,8 +17541,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16870
17541
|
var whyButton = append(resultHead, "button", "", "demo-ai-clipboard-toggle demo-ai-why-toggle");
|
|
16871
17542
|
whyButton.type = "button";
|
|
16872
17543
|
whyButton.setAttribute("data-rte-ai-dialog-action", "why");
|
|
16873
|
-
whyButton.title = "Why this AI suggestion?";
|
|
16874
|
-
whyButton.setAttribute("aria-label", "Show why this AI suggestion was generated");
|
|
17544
|
+
whyButton.title = (obj.__aiT ? obj.__aiT("ai2_whytitle", "Why this AI suggestion?") : "Why this AI suggestion?");
|
|
17545
|
+
whyButton.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("ai2_whyaria", "Show why this AI suggestion was generated") : "Show why this AI suggestion was generated"));
|
|
16875
17546
|
whyButton.setAttribute("aria-expanded", "false");
|
|
16876
17547
|
setReviewV2ButtonContent(whyButton, "info", "");
|
|
16877
17548
|
|
|
@@ -16890,12 +17561,12 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16890
17561
|
// saying the same thing twice (open the prompt + edit the prompt).
|
|
16891
17562
|
// "Edit" preserves the verb-action shape Pass v20260513b adopted,
|
|
16892
17563
|
// saves ~30px horizontal real estate in the result-head pill row,
|
|
16893
|
-
// and the title attribute ("Edit the prompt and retry") still
|
|
17564
|
+
// and the title attribute ((obj.__aiT ? obj.__aiT("ai2_editretry", "Edit the prompt and retry") : "Edit the prompt and retry")) still
|
|
16894
17565
|
// surfaces the long form on hover + to screen readers via
|
|
16895
17566
|
// aria-label.
|
|
16896
|
-
sourceToggle.title = "Edit the prompt and retry";
|
|
16897
|
-
sourceToggle.setAttribute("aria-label", "Edit the prompt and retry");
|
|
16898
|
-
sourceToggle.innerText = "Edit";
|
|
17567
|
+
sourceToggle.title = (obj.__aiT ? obj.__aiT("ai2_editretry", "Edit the prompt and retry") : "Edit the prompt and retry");
|
|
17568
|
+
sourceToggle.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("ai2_editretry", "Edit the prompt and retry") : "Edit the prompt and retry"));
|
|
17569
|
+
sourceToggle.innerText = (obj.__aiT ? obj.__aiT("ai2_edit", "Edit") : "Edit");
|
|
16899
17570
|
sourceField.id = sourceToggle.getAttribute("aria-controls");
|
|
16900
17571
|
sourceToggle.onclick = function (e) {
|
|
16901
17572
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
@@ -16905,7 +17576,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16905
17576
|
};
|
|
16906
17577
|
var resultArea = append(resultField, "textarea");
|
|
16907
17578
|
resultArea.readOnly = true;
|
|
16908
|
-
resultArea.setAttribute("aria-label", "AI suggestion result");
|
|
17579
|
+
resultArea.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("ai2_result", "AI suggestion result") : "AI suggestion result"));
|
|
16909
17580
|
resultArea.setAttribute("aria-describedby", resultHelpId + " " + statusId);
|
|
16910
17581
|
// 2026-05-17 (v20260520b): rows=1 lets the CSS min-height: 52px
|
|
16911
17582
|
// floor (since v20260513a) actually bind. Browser default rows=2
|
|
@@ -16921,7 +17592,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16921
17592
|
// here." (20 chars). Same idiom Notion AI's inline composer
|
|
16922
17593
|
// uses ("AI response..."). At 20 chars it never line-wraps
|
|
16923
17594
|
// inside the textarea even at 320px viewport.
|
|
16924
|
-
resultArea.placeholder = "Output appears here.";
|
|
17595
|
+
resultArea.placeholder = (obj.__aiT ? obj.__aiT("ai2_outputph", "Output appears here.") : "Output appears here.");
|
|
16925
17596
|
|
|
16926
17597
|
var oldPreview = document.createElement("pre");
|
|
16927
17598
|
var newPreview = document.createElement("pre");
|
|
@@ -16950,7 +17621,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16950
17621
|
var refineRow = document.createElement("div");
|
|
16951
17622
|
refineRow.className = "demo-ai-refine-row is-detached";
|
|
16952
17623
|
refineRow.setAttribute("role", "group");
|
|
16953
|
-
refineRow.setAttribute("aria-label", "Refine AI suggestion");
|
|
17624
|
+
refineRow.setAttribute("aria-label", uiT("aiu_refine", "Refine AI suggestion"));
|
|
16954
17625
|
// Keep the (now empty) refineRow attached to the dialog grid so any
|
|
16955
17626
|
// external integration that walks `.demo-ai-refine-row` from the
|
|
16956
17627
|
// dialog root keeps resolving. The `is-detached` class collapses it
|
|
@@ -16970,19 +17641,19 @@ function RTE_Plugin_AIToolkit() {
|
|
|
16970
17641
|
// setBusyState / focus-traversal walker keeps resolving.
|
|
16971
17642
|
var refineRetryChip = append(refineRow, "button", "", "secondary demo-ai-refine-chip");
|
|
16972
17643
|
refineRetryChip.type = "button";
|
|
16973
|
-
refineRetryChip.title = "Re-run with the same prompt";
|
|
17644
|
+
refineRetryChip.title = (obj.__aiT ? obj.__aiT("ai2_retrytitle", "Re-run with the same prompt") : "Re-run with the same prompt");
|
|
16974
17645
|
refineRetryChip.setAttribute("data-rte-ai-dialog-action", "refine-retry");
|
|
16975
|
-
setReviewV2ButtonContent(refineRetryChip, "refresh", "Try again");
|
|
17646
|
+
setReviewV2ButtonContent(refineRetryChip, "refresh", (obj.__aiT ? obj.__aiT("ai2_tryagain", "Try again") : "Try again"));
|
|
16976
17647
|
var refineShorterChip = append(refineRow, "button", "", "secondary demo-ai-refine-chip");
|
|
16977
17648
|
refineShorterChip.type = "button";
|
|
16978
|
-
refineShorterChip.title = "Make the suggestion shorter";
|
|
17649
|
+
refineShorterChip.title = (obj.__aiT ? obj.__aiT("ai2_shortertitle", "Make the suggestion shorter") : "Make the suggestion shorter");
|
|
16979
17650
|
refineShorterChip.setAttribute("data-rte-ai-dialog-action", "refine-shorter");
|
|
16980
|
-
setReviewV2ButtonContent(refineShorterChip, "shrink", "Shorter");
|
|
17651
|
+
setReviewV2ButtonContent(refineShorterChip, "shrink", (obj.__aiT ? obj.__aiT("ai2_shorter", "Shorter") : "Shorter"));
|
|
16981
17652
|
var refineLongerChip = append(refineRow, "button", "", "secondary demo-ai-refine-chip");
|
|
16982
17653
|
refineLongerChip.type = "button";
|
|
16983
|
-
refineLongerChip.title = "Expand the suggestion with more detail";
|
|
17654
|
+
refineLongerChip.title = (obj.__aiT ? obj.__aiT("ai2_longertitle", "Expand the suggestion with more detail") : "Expand the suggestion with more detail");
|
|
16984
17655
|
refineLongerChip.setAttribute("data-rte-ai-dialog-action", "refine-longer");
|
|
16985
|
-
setReviewV2ButtonContent(refineLongerChip, "expand", "Longer");
|
|
17656
|
+
setReviewV2ButtonContent(refineLongerChip, "expand", (obj.__aiT ? obj.__aiT("ai2_longer", "Longer") : "Longer"));
|
|
16986
17657
|
// 2026-05-29 (v20260529a): "Why" disclosure folded into the refine
|
|
16987
17658
|
// chip row as a 4th ghost chip — the standalone Details toggle row
|
|
16988
17659
|
// that previously sat on its own line between the chip strip and
|
|
@@ -17028,8 +17699,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17028
17699
|
var refineWhyChip = document.createElement("button");
|
|
17029
17700
|
refineWhyChip.type = "button";
|
|
17030
17701
|
refineWhyChip.className = "secondary demo-ai-refine-chip demo-ai-refine-why-chip is-detached";
|
|
17031
|
-
refineWhyChip.innerText = "Why";
|
|
17032
|
-
refineWhyChip.title = "Show why this AI suggestion was generated";
|
|
17702
|
+
refineWhyChip.innerText = uiT("air_why", "Why");
|
|
17703
|
+
refineWhyChip.title = (obj.__aiT ? obj.__aiT("ai2_whyaria", "Show why this AI suggestion was generated") : "Show why this AI suggestion was generated");
|
|
17033
17704
|
refineWhyChip.setAttribute("data-rte-ai-dialog-action", "refine-why");
|
|
17034
17705
|
refineWhyChip.setAttribute("aria-expanded", "false");
|
|
17035
17706
|
|
|
@@ -17102,7 +17773,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17102
17773
|
|
|
17103
17774
|
var applyRow = append(grid, "div", "", "demo-actions-row demo-ai-apply-row");
|
|
17104
17775
|
applyRow.setAttribute("role", "group");
|
|
17105
|
-
applyRow.setAttribute("aria-label", "Ask AI apply actions");
|
|
17776
|
+
applyRow.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("ai2_applyrow", "Ask AI apply actions") : "Ask AI apply actions"));
|
|
17106
17777
|
var applyPlanButton = append(applyRow, "button", "", "is-primary");
|
|
17107
17778
|
applyPlanButton.type = "button";
|
|
17108
17779
|
applyPlanButton.disabled = true;
|
|
@@ -17114,34 +17785,34 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17114
17785
|
// dialog-level keydown handler (added below) fires this button
|
|
17115
17786
|
// when the shortcut hits from anywhere in the dialog outside the
|
|
17116
17787
|
// source textarea.
|
|
17117
|
-
applyPlanButton.title = "Apply AI suggestion (Ctrl+Enter)";
|
|
17788
|
+
applyPlanButton.title = (obj.__aiT ? obj.__aiT("ai2_applytitle", "Apply AI suggestion (Ctrl+Enter)") : "Apply AI suggestion (Ctrl+Enter)");
|
|
17118
17789
|
applyPlanButton.setAttribute("aria-keyshortcuts", "Control+Enter");
|
|
17119
|
-
setReviewV2ButtonContent(applyPlanButton, "check", "Apply");
|
|
17790
|
+
setReviewV2ButtonContent(applyPlanButton, "check", (obj.__aiT ? obj.__aiT("ai2_apply", "Apply") : "Apply"));
|
|
17120
17791
|
var acceptSelectionButton = append(applyRow, "button", "", "");
|
|
17121
17792
|
acceptSelectionButton.type = "button";
|
|
17122
17793
|
acceptSelectionButton.disabled = !snapshot.hasSelection;
|
|
17123
17794
|
acceptSelectionButton.setAttribute("data-rte-ai-dialog-action", "selection");
|
|
17124
|
-
setReviewV2ButtonContent(acceptSelectionButton, "check", "Replace selection");
|
|
17795
|
+
setReviewV2ButtonContent(acceptSelectionButton, "check", (obj.__aiT ? obj.__aiT("ai2_replsel", "Replace selection") : "Replace selection"));
|
|
17125
17796
|
var previewSelectionButton = append(applyRow, "button", "", "secondary");
|
|
17126
17797
|
previewSelectionButton.type = "button";
|
|
17127
17798
|
previewSelectionButton.disabled = !snapshot.hasSelection;
|
|
17128
17799
|
previewSelectionButton.setAttribute("data-rte-ai-dialog-action", "preview");
|
|
17129
|
-
setReviewV2ButtonContent(previewSelectionButton, "eyeOn", "Preview");
|
|
17800
|
+
setReviewV2ButtonContent(previewSelectionButton, "eyeOn", (obj.__aiT ? obj.__aiT("ai2_preview", "Preview") : "Preview"));
|
|
17130
17801
|
var acceptBelowButton = append(applyRow, "button", "", "secondary");
|
|
17131
17802
|
acceptBelowButton.type = "button";
|
|
17132
17803
|
acceptBelowButton.setAttribute("data-rte-ai-dialog-action", "insert");
|
|
17133
|
-
setReviewV2ButtonContent(acceptBelowButton, "arrowRight", "Insert below");
|
|
17804
|
+
setReviewV2ButtonContent(acceptBelowButton, "arrowRight", (obj.__aiT ? obj.__aiT("ai2_insbelow", "Insert below") : "Insert below"));
|
|
17134
17805
|
var acceptDocumentButton = append(applyRow, "button", "", "secondary");
|
|
17135
17806
|
acceptDocumentButton.type = "button";
|
|
17136
17807
|
acceptDocumentButton.setAttribute("data-rte-ai-dialog-action", "document");
|
|
17137
|
-
// 2026-05-20 (v20260520h): "Replace doc" → "Replace document". The
|
|
17808
|
+
// 2026-05-20 (v20260520h): "Replace doc" → (obj.__aiT ? obj.__aiT("ai2_repldoc", "Replace document") : "Replace document"). The
|
|
17138
17809
|
// abbreviation read as developer shorthand; the full word costs ~28px
|
|
17139
17810
|
// of horizontal real estate at the apply row, but this button only
|
|
17140
17811
|
// appears behind the ⋯ More toggle so the row's spare space is
|
|
17141
17812
|
// available. Vocabulary now matches getOperationPlanButtonLabel's
|
|
17142
|
-
// primary path ("Replace document") and the chat panel's secondary
|
|
17143
|
-
// button ("Replace document").
|
|
17144
|
-
setReviewV2ButtonContent(acceptDocumentButton, "checkAll", "Replace document");
|
|
17813
|
+
// primary path ((obj.__aiT ? obj.__aiT("ai2_repldoc", "Replace document") : "Replace document")) and the chat panel's secondary
|
|
17814
|
+
// button ((obj.__aiT ? obj.__aiT("ai2_repldoc", "Replace document") : "Replace document")).
|
|
17815
|
+
setReviewV2ButtonContent(acceptDocumentButton, "checkAll", (obj.__aiT ? obj.__aiT("ai2_repldoc", "Replace document") : "Replace document"));
|
|
17145
17816
|
// 2026-05-08 (v20260508t): "More" toggle pinned just before Discard.
|
|
17146
17817
|
// Hides Replace selection / Preview / Insert below / Replace doc by
|
|
17147
17818
|
// default so the default surface only shows Apply (smart primary) +
|
|
@@ -17165,8 +17836,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17165
17836
|
applyRowMoreToggle.type = "button";
|
|
17166
17837
|
applyRowMoreToggle.setAttribute("data-rte-ai-dialog-action", "more");
|
|
17167
17838
|
applyRowMoreToggle.setAttribute("aria-expanded", "false");
|
|
17168
|
-
applyRowMoreToggle.title = "More apply options";
|
|
17169
|
-
applyRowMoreToggle.setAttribute("aria-label", "More apply options");
|
|
17839
|
+
applyRowMoreToggle.title = (obj.__aiT ? obj.__aiT("ai2_moreopts", "More apply options") : "More apply options");
|
|
17840
|
+
applyRowMoreToggle.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("ai2_moreopts", "More apply options") : "More apply options"));
|
|
17170
17841
|
setReviewV2ButtonContent(applyRowMoreToggle, "more", "");
|
|
17171
17842
|
applyRowMoreToggle.onclick = function (e) {
|
|
17172
17843
|
if (e && e.stopPropagation) e.stopPropagation();
|
|
@@ -17225,7 +17896,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17225
17896
|
applyGuidance.className = "demo-ai-apply-guidance";
|
|
17226
17897
|
applyGuidance.style.display = "none";
|
|
17227
17898
|
applyGuidance.setAttribute("role", "group");
|
|
17228
|
-
applyGuidance.setAttribute("aria-label", "Best next step");
|
|
17899
|
+
applyGuidance.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_bestnext", "Best next step") : "Best next step"));
|
|
17229
17900
|
var applyGuidanceHeader = append(applyGuidance, "div", "", "demo-ai-apply-guidance-header");
|
|
17230
17901
|
var applyGuidanceTitle = append(applyGuidanceHeader, "span", "", "demo-ai-apply-guidance-title", "Next");
|
|
17231
17902
|
var applyGuidanceBadge = append(applyGuidanceHeader, "span", "", "demo-ai-apply-guidance-badge");
|
|
@@ -17242,7 +17913,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17242
17913
|
detailsToggle.type = "button";
|
|
17243
17914
|
detailsToggle.setAttribute("aria-expanded", "false");
|
|
17244
17915
|
detailsToggle.setAttribute("aria-controls", "rte-ai-details-" + dialogIdSuffix);
|
|
17245
|
-
detailsToggle.title = "Show why and the operation plan";
|
|
17916
|
+
detailsToggle.title = uiT("aiu_showwhy", "Show why and the operation plan");
|
|
17246
17917
|
|
|
17247
17918
|
var insightGrid = append(grid, "div", "", "demo-ai-insight-grid is-collapsed");
|
|
17248
17919
|
insightGrid.id = detailsToggle.getAttribute("aria-controls");
|
|
@@ -17314,7 +17985,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17314
17985
|
|
|
17315
17986
|
function populateDialogModes() {
|
|
17316
17987
|
var modes = getDialogModes();
|
|
17317
|
-
modeSelect.innerHTML = "";
|
|
17988
|
+
modeSelect.innerHTML = __RTE_TT("");
|
|
17318
17989
|
// 2026-05-20 (v20260520g) — Pass 59: group the 7-mode picker
|
|
17319
17990
|
// into 2 <optgroup> sections so the dropdown reads as one
|
|
17320
17991
|
// semantic cluster per intent ("Edit text" vs "Transform")
|
|
@@ -17403,9 +18074,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17403
18074
|
|
|
17404
18075
|
function populateTranslateLanguages() {
|
|
17405
18076
|
var languages = getTranslateLanguages();
|
|
17406
|
-
languageSelect.innerHTML = "";
|
|
18077
|
+
languageSelect.innerHTML = __RTE_TT("");
|
|
17407
18078
|
for (var index = 0; index < languages.length; index++) {
|
|
17408
|
-
var option = append(languageSelect, "option", "", "", languages[index]
|
|
18079
|
+
var option = append(languageSelect, "option", "", "", getTranslateLanguageDisplay(languages[index]));
|
|
17409
18080
|
option.value = languages[index].value || languages[index].label;
|
|
17410
18081
|
}
|
|
17411
18082
|
if (options.presetLanguage) {
|
|
@@ -17481,7 +18152,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17481
18152
|
else {
|
|
17482
18153
|
scopeLabel = "Document";
|
|
17483
18154
|
}
|
|
17484
|
-
return scopeLabel + "
|
|
18155
|
+
return scopeLabel + " \xb7 " + countLabel + " chars";
|
|
17485
18156
|
}
|
|
17486
18157
|
|
|
17487
18158
|
// 2026-05-19 (v20260519a): mirror the active AI mode into the
|
|
@@ -17588,7 +18259,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17588
18259
|
}
|
|
17589
18260
|
titleSpan.innerText = resolvedLabel || base;
|
|
17590
18261
|
if (dialoginner.setAttribute) {
|
|
17591
|
-
dialoginner.setAttribute("aria-label", resolvedLabel ? (base + "
|
|
18262
|
+
dialoginner.setAttribute("aria-label", resolvedLabel ? (base + " \xb7 " + resolvedLabel) : base);
|
|
17592
18263
|
}
|
|
17593
18264
|
}
|
|
17594
18265
|
|
|
@@ -17674,16 +18345,16 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17674
18345
|
if (sourceArea && !sourceArea.value) {
|
|
17675
18346
|
var modeId = modeSelect.value || "";
|
|
17676
18347
|
var placeholders = {
|
|
17677
|
-
proofread: "Paste text to proofread
|
|
17678
|
-
rewrite: "Paste text to rewrite
|
|
17679
|
-
shorten: "Paste text to shorten
|
|
17680
|
-
expand: "Paste text to expand
|
|
17681
|
-
summarize: "Paste text to summarize
|
|
17682
|
-
translate: "Paste text to translate
|
|
17683
|
-
justify: "Paste text to rewrite + explain
|
|
17684
|
-
explain: "Paste text to explain
|
|
18348
|
+
proofread: "Paste text to proofread\u2026",
|
|
18349
|
+
rewrite: "Paste text to rewrite\u2026",
|
|
18350
|
+
shorten: "Paste text to shorten\u2026",
|
|
18351
|
+
expand: "Paste text to expand\u2026",
|
|
18352
|
+
summarize: "Paste text to summarize\u2026",
|
|
18353
|
+
translate: "Paste text to translate\u2026",
|
|
18354
|
+
justify: "Paste text to rewrite + explain\u2026",
|
|
18355
|
+
explain: "Paste text to explain\u2026"
|
|
17685
18356
|
};
|
|
17686
|
-
sourceArea.placeholder = placeholders[modeId] || "Type or paste text
|
|
18357
|
+
sourceArea.placeholder = placeholders[modeId] || "Type or paste text\u2026";
|
|
17687
18358
|
}
|
|
17688
18359
|
// 2026-05-08 (v20260508s): refresh the header mode-name chip.
|
|
17689
18360
|
// For Translate the chip carries the target language so users
|
|
@@ -17691,7 +18362,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17691
18362
|
if (modeChip) {
|
|
17692
18363
|
var chipLabel = modeLabel || "";
|
|
17693
18364
|
if (modeLabel && modeSelect.value === "translate") {
|
|
17694
|
-
chipLabel = modeLabel + "
|
|
18365
|
+
chipLabel = modeLabel + " \xb7 " + getTranslateLanguageLabel(languageSelect.value || "spanish");
|
|
17695
18366
|
}
|
|
17696
18367
|
modeChip.innerText = chipLabel;
|
|
17697
18368
|
modeChip.style.display = chipLabel ? "" : "none";
|
|
@@ -17860,9 +18531,9 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17860
18531
|
var docChars = snap ? (snap.wholeText || "").length : 0;
|
|
17861
18532
|
scopeOptionSelection.disabled = !hasSelection;
|
|
17862
18533
|
scopeOptionSelection.text = hasSelection
|
|
17863
|
-
? "Selection"
|
|
17864
|
-
: "Selection (none)";
|
|
17865
|
-
scopeOptionDocument.text = "Document";
|
|
18534
|
+
? (obj.__aiT ? obj.__aiT("aid_selection", "Selection") : "Selection")
|
|
18535
|
+
: (obj.__aiT ? obj.__aiT("aid_selectionnone", "Selection (none)") : "Selection (none)");
|
|
18536
|
+
scopeOptionDocument.text = (obj.__aiT ? obj.__aiT("aid_document", "Document") : "Document");
|
|
17866
18537
|
scopeSelect.value = activeScope === "selection" ? "selection" : "document";
|
|
17867
18538
|
scopeSelect.setAttribute("title", buildDialogScopeHint(snap, scope));
|
|
17868
18539
|
// 2026-06-01 (v20260601a): swap the <select> for a quiet inline
|
|
@@ -17877,7 +18548,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17877
18548
|
// 2026-05-20 (v20260520i) — Pass 61: caption mirrors the option
|
|
17878
18549
|
// label — scope name only, no char-count suffix.
|
|
17879
18550
|
if (scopeCaption) {
|
|
17880
|
-
scopeCaption.innerText = "Document";
|
|
18551
|
+
scopeCaption.innerText = (obj.__aiT ? obj.__aiT("aid_document", "Document") : "Document");
|
|
17881
18552
|
}
|
|
17882
18553
|
if (compactControls && compactControls.classList) {
|
|
17883
18554
|
if (hasSelection) {
|
|
@@ -17892,8 +18563,8 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17892
18563
|
|
|
17893
18564
|
function formatDialogScopeCount(n) {
|
|
17894
18565
|
if (!n) return "0";
|
|
17895
|
-
if (n > 999) return (Math.round(n / 100) / 10) + "K chars";
|
|
17896
|
-
return n + " chars";
|
|
18566
|
+
if (n > 999) return (obj.__aiT ? obj.__aiT("aid_kchars", "{0}K chars", Math.round(n / 100) / 10) : (Math.round(n / 100) / 10) + "K chars");
|
|
18567
|
+
return obj.__aiT ? obj.__aiT("aid_chars", "{0} chars", n) : n + " chars";
|
|
17897
18568
|
}
|
|
17898
18569
|
|
|
17899
18570
|
function markDialogSourceDetached() {
|
|
@@ -17940,11 +18611,11 @@ function RTE_Plugin_AIToolkit() {
|
|
|
17940
18611
|
}
|
|
17941
18612
|
|
|
17942
18613
|
function getDialogLanguageChangeMessage(language) {
|
|
17943
|
-
return "Language
|
|
18614
|
+
return "Language \u2192 " + getTranslateLanguageLabel(language || "spanish") + ". Re-run to refresh.";
|
|
17944
18615
|
}
|
|
17945
18616
|
|
|
17946
18617
|
function getDialogScopeChangeMessage(scope) {
|
|
17947
|
-
return "Scope
|
|
18618
|
+
return "Scope \u2192 " + (scope === "selection" ? "selection" : "document") + ". Re-run to refresh.";
|
|
17948
18619
|
}
|
|
17949
18620
|
|
|
17950
18621
|
function getDialogEditorReloadMessage(scope) {
|
|
@@ -18029,70 +18700,70 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18029
18700
|
: "Select text in the editor, then reload it into Ask AI.";
|
|
18030
18701
|
}
|
|
18031
18702
|
if (actionId === "load-document") {
|
|
18032
|
-
return "Reload the current editor document into Ask AI.";
|
|
18703
|
+
return (obj.__aiT ? obj.__aiT("aid_reloaddesc", "Reload the current editor document into Ask AI.") : "Reload the current editor document into Ask AI.");
|
|
18033
18704
|
}
|
|
18034
18705
|
if (actionId === "run") {
|
|
18035
18706
|
return actionState.hasSource
|
|
18036
|
-
? "Generate a new AI suggestion from the current source text using the selected mode."
|
|
18037
|
-
: "Load or type source text, then run Ask AI to generate a suggestion.";
|
|
18707
|
+
? (obj.__aiT ? obj.__aiT("aid_gendesc", "Generate a new AI suggestion from the current source text using the selected mode.") : "Generate a new AI suggestion from the current source text using the selected mode.")
|
|
18708
|
+
: (obj.__aiT ? obj.__aiT("aid_loaddesc", "Load or type source text, then run Ask AI to generate a suggestion.") : "Load or type source text, then run Ask AI to generate a suggestion.");
|
|
18038
18709
|
}
|
|
18039
18710
|
if (actionId === "rerun") {
|
|
18040
18711
|
return actionState.staleAction === "source"
|
|
18041
|
-
? "Refresh this suggestion from the current dialog source before applying it."
|
|
18042
|
-
: "Refresh this suggestion from the current editor state before applying it.";
|
|
18712
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_refreshsrc", "Refresh this suggestion from the current dialog source before applying it.") : "Refresh this suggestion from the current dialog source before applying it.")
|
|
18713
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_refreshed", "Refresh this suggestion from the current editor state before applying it.") : "Refresh this suggestion from the current editor state before applying it.");
|
|
18043
18714
|
}
|
|
18044
18715
|
if (actionId === "copy-to-source") {
|
|
18045
18716
|
return actionState.hasResult
|
|
18046
|
-
? "Copy the current AI result back into the source field before rerunning it."
|
|
18047
|
-
: "Run Ask AI first, then copy the generated result back into the source field.";
|
|
18717
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_copyback", "Copy the current AI result back into the source field before rerunning it.") : "Copy the current AI result back into the source field before rerunning it.")
|
|
18718
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_copyfirst", "Run Ask AI first, then copy the generated result back into the source field.") : "Run Ask AI first, then copy the generated result back into the source field.");
|
|
18048
18719
|
}
|
|
18049
18720
|
if (actionId === "apply") {
|
|
18050
18721
|
if (actionState.pendingIndexes.length > 1) {
|
|
18051
18722
|
return actionState.pendingSelectionDependent && !actionState.hasSelection
|
|
18052
|
-
? "Select text before applying this selection-based AI plan."
|
|
18053
|
-
: "Run the remaining " + actionState.pendingIndexes.length + "-step AI plan directly in the editor.";
|
|
18723
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_selectplan", "Select text before applying this selection-based AI plan.") : "Select text before applying this selection-based AI plan.")
|
|
18724
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_steps", "Run the remaining {0}-step AI plan directly in the editor.", actionState.pendingIndexes.length) : "Run the remaining " + actionState.pendingIndexes.length + "-step AI plan directly in the editor.");
|
|
18054
18725
|
}
|
|
18055
18726
|
switch (actionState.pendingOperationType) {
|
|
18056
18727
|
case "preview-suggestion":
|
|
18057
18728
|
return actionState.hasSelection
|
|
18058
|
-
? "Show the prepared inline diff in the editor before deciding it."
|
|
18059
|
-
: "Select text before previewing this prepared inline diff in the editor.";
|
|
18729
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_showdiff", "Show the prepared inline diff in the editor before deciding it.") : "Show the prepared inline diff in the editor before deciding it.")
|
|
18730
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_selectdiff", "Select text before previewing this prepared inline diff in the editor.") : "Select text before previewing this prepared inline diff in the editor.");
|
|
18060
18731
|
case "replace-selection":
|
|
18061
18732
|
return actionState.hasSelection
|
|
18062
|
-
? "Replace the current selection with this prepared draft."
|
|
18063
|
-
: "Select text before replacing it with this prepared draft.";
|
|
18733
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_replsel", "Replace the current selection with this prepared draft.") : "Replace the current selection with this prepared draft.")
|
|
18734
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_selectrepl", "Select text before replacing it with this prepared draft.") : "Select text before replacing it with this prepared draft.");
|
|
18064
18735
|
case "replace-document":
|
|
18065
|
-
return "Replace the full document with this prepared draft.";
|
|
18736
|
+
return (obj.__aiT ? obj.__aiT("ai2_d_repldoc", "Replace the full document with this prepared draft.") : "Replace the full document with this prepared draft.");
|
|
18066
18737
|
case "insert-below":
|
|
18067
18738
|
return actionState.hasSelection
|
|
18068
|
-
? "Insert this prepared draft below the current selection."
|
|
18069
|
-
: "Insert this prepared draft below the current content.";
|
|
18739
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_insbelowsel", "Insert this prepared draft below the current selection.") : "Insert this prepared draft below the current selection.")
|
|
18740
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_insbelow", "Insert this prepared draft below the current content.") : "Insert this prepared draft below the current content.");
|
|
18070
18741
|
case "add-comment":
|
|
18071
|
-
return "Add this prepared AI comment without rewriting the document body.";
|
|
18742
|
+
return (obj.__aiT ? obj.__aiT("ai2_d_comment", "Add this prepared AI comment without rewriting the document body.") : "Add this prepared AI comment without rewriting the document body.");
|
|
18072
18743
|
default:
|
|
18073
|
-
return "Run the prepared AI plan directly in the editor.";
|
|
18744
|
+
return (obj.__aiT ? obj.__aiT("ai2_d_runplan", "Run the prepared AI plan directly in the editor.") : "Run the prepared AI plan directly in the editor.");
|
|
18074
18745
|
}
|
|
18075
18746
|
}
|
|
18076
18747
|
if (actionId === "selection") {
|
|
18077
18748
|
return actionState.hasSelection
|
|
18078
|
-
? "Replace the current selection with this prepared draft."
|
|
18079
|
-
: "Select text before replacing it with this prepared draft.";
|
|
18749
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_replsel", "Replace the current selection with this prepared draft.") : "Replace the current selection with this prepared draft.")
|
|
18750
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_selectrepl", "Select text before replacing it with this prepared draft.") : "Select text before replacing it with this prepared draft.");
|
|
18080
18751
|
}
|
|
18081
18752
|
if (actionId === "preview") {
|
|
18082
18753
|
return actionState.hasSelection
|
|
18083
|
-
? "Show this change inline in the editor before deciding it."
|
|
18084
|
-
: "Select text to preview this change inline in the editor.";
|
|
18754
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_previewsel", "Show this change inline in the editor before deciding it.") : "Show this change inline in the editor before deciding it.")
|
|
18755
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_previewselect", "Select text to preview this change inline in the editor.") : "Select text to preview this change inline in the editor.");
|
|
18085
18756
|
}
|
|
18086
18757
|
if (actionId === "insert") {
|
|
18087
18758
|
return actionState.hasSelection
|
|
18088
|
-
? "Insert this prepared draft below the current selection."
|
|
18089
|
-
: "Insert this prepared draft below the current content.";
|
|
18759
|
+
? (obj.__aiT ? obj.__aiT("ai2_d_insbelowsel", "Insert this prepared draft below the current selection.") : "Insert this prepared draft below the current selection.")
|
|
18760
|
+
: (obj.__aiT ? obj.__aiT("ai2_d_insbelow", "Insert this prepared draft below the current content.") : "Insert this prepared draft below the current content.");
|
|
18090
18761
|
}
|
|
18091
18762
|
if (actionId === "document") {
|
|
18092
|
-
return "Replace the full document with this prepared draft.";
|
|
18763
|
+
return (obj.__aiT ? obj.__aiT("ai2_d_repldoc", "Replace the full document with this prepared draft.") : "Replace the full document with this prepared draft.");
|
|
18093
18764
|
}
|
|
18094
18765
|
if (actionId === "reject") {
|
|
18095
|
-
return "Dismiss this prepared suggestion without changing the document.";
|
|
18766
|
+
return (obj.__aiT ? obj.__aiT("ai2_d_dismiss", "Dismiss this prepared suggestion without changing the document.") : "Dismiss this prepared suggestion without changing the document.");
|
|
18096
18767
|
}
|
|
18097
18768
|
return "";
|
|
18098
18769
|
}
|
|
@@ -18180,22 +18851,22 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18180
18851
|
var pendingOperationType = actionState.pendingOperationType || "";
|
|
18181
18852
|
if (actionState.actionScope === "selection") {
|
|
18182
18853
|
if (actionState.hasSelection && pendingOperationType !== "preview-suggestion") {
|
|
18183
|
-
addDialogReadyAlternative(alternatives, covered, "preview", "preview inline");
|
|
18854
|
+
addDialogReadyAlternative(alternatives, covered, "preview", (obj.__aiT ? obj.__aiT("ai2_alt_preview", "preview inline") : "preview inline"));
|
|
18184
18855
|
}
|
|
18185
18856
|
if (actionState.hasSelection && pendingOperationType !== "replace-selection") {
|
|
18186
|
-
addDialogReadyAlternative(alternatives, covered, "selection", "replace the selection");
|
|
18857
|
+
addDialogReadyAlternative(alternatives, covered, "selection", (obj.__aiT ? obj.__aiT("ai2_alt_selection", "replace the selection") : "replace the selection"));
|
|
18187
18858
|
}
|
|
18188
18859
|
if (actionState.canInsert && pendingOperationType !== "insert-below") {
|
|
18189
|
-
addDialogReadyAlternative(alternatives, covered, "insert", "insert below");
|
|
18860
|
+
addDialogReadyAlternative(alternatives, covered, "insert", (obj.__aiT ? obj.__aiT("ai2_alt_insert", "insert below") : "insert below"));
|
|
18190
18861
|
}
|
|
18191
18862
|
return alternatives;
|
|
18192
18863
|
}
|
|
18193
18864
|
if (actionState.actionScope === "document") {
|
|
18194
18865
|
if (actionState.canReplaceDocument && pendingOperationType !== "replace-document") {
|
|
18195
|
-
addDialogReadyAlternative(alternatives, covered, "document", "replace the document");
|
|
18866
|
+
addDialogReadyAlternative(alternatives, covered, "document", (obj.__aiT ? obj.__aiT("ai2_alt_document", "replace the document") : "replace the document"));
|
|
18196
18867
|
}
|
|
18197
18868
|
if (actionState.canInsert && pendingOperationType !== "insert-below") {
|
|
18198
|
-
addDialogReadyAlternative(alternatives, covered, "insert", "insert below");
|
|
18869
|
+
addDialogReadyAlternative(alternatives, covered, "insert", (obj.__aiT ? obj.__aiT("ai2_alt_insert", "insert below") : "insert below"));
|
|
18199
18870
|
}
|
|
18200
18871
|
}
|
|
18201
18872
|
return alternatives;
|
|
@@ -18213,10 +18884,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18213
18884
|
? (recommended.label || "").replace(/\s+/g, " ").trim()
|
|
18214
18885
|
: "";
|
|
18215
18886
|
if (recommendedLabel) {
|
|
18216
|
-
return "Ready
|
|
18887
|
+
return "Ready \xb7 " + recommendedLabel;
|
|
18217
18888
|
}
|
|
18218
18889
|
if (actionState.actionScope === "selection" && !actionState.hasSelection) {
|
|
18219
|
-
return "Ready
|
|
18890
|
+
return "Ready \xb7 Insert below";
|
|
18220
18891
|
}
|
|
18221
18892
|
return "Ready";
|
|
18222
18893
|
}
|
|
@@ -18294,25 +18965,25 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18294
18965
|
parts.push(detail);
|
|
18295
18966
|
}
|
|
18296
18967
|
if (alternativeText) {
|
|
18297
|
-
parts.push("Other available actions: " + alternativeText + ".");
|
|
18968
|
+
parts.push(obj.__aiT ? obj.__aiT("aid_otheractions", "Other available actions: {0}.", alternativeText) : "Other available actions: " + alternativeText + ".");
|
|
18298
18969
|
}
|
|
18299
18970
|
if (isRecommended) {
|
|
18300
|
-
parts.push("Recommended next step.");
|
|
18971
|
+
parts.push((obj.__aiT ? obj.__aiT("aid_recommended", "Recommended next step.") : "Recommended next step."));
|
|
18301
18972
|
button.setAttribute("data-rte-ai-dialog-recommended", "true");
|
|
18302
18973
|
}
|
|
18303
18974
|
else {
|
|
18304
18975
|
button.removeAttribute("data-rte-ai-dialog-recommended");
|
|
18305
18976
|
}
|
|
18306
|
-
button.setAttribute("aria-label", parts
|
|
18977
|
+
button.setAttribute("aria-label", joinSentences(parts));
|
|
18307
18978
|
var titleParts = [label];
|
|
18308
18979
|
if (detail) {
|
|
18309
18980
|
titleParts.push(detail);
|
|
18310
18981
|
}
|
|
18311
18982
|
if (alternativeText) {
|
|
18312
|
-
titleParts.push("Other available actions: " + alternativeText + ".");
|
|
18983
|
+
titleParts.push(obj.__aiT ? obj.__aiT("aid_otheractions", "Other available actions: {0}.", alternativeText) : "Other available actions: " + alternativeText + ".");
|
|
18313
18984
|
}
|
|
18314
18985
|
if (isRecommended) {
|
|
18315
|
-
titleParts.push("Recommended next step.");
|
|
18986
|
+
titleParts.push((obj.__aiT ? obj.__aiT("aid_recommended", "Recommended next step.") : "Recommended next step."));
|
|
18316
18987
|
}
|
|
18317
18988
|
// 2026-05-22 (v20260522a): preserve any pre-set keyboard shortcut
|
|
18318
18989
|
// hint on the button by reading aria-keyshortcuts (the WAI-ARIA
|
|
@@ -18322,7 +18993,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18322
18993
|
// shortcut would only be discoverable via screen-reader
|
|
18323
18994
|
// announcement of aria-keyshortcuts and never via mouse hover.
|
|
18324
18995
|
// Formatting matches the Generate button's pre-existing title
|
|
18325
|
-
// suffix ("Generate AI suggestion (Ctrl+Enter)").
|
|
18996
|
+
// suffix ((obj.__aiT ? obj.__aiT("ai2_gentitle", "Generate AI suggestion (Ctrl+Enter)") : "Generate AI suggestion (Ctrl+Enter)")).
|
|
18326
18997
|
var keyHint = button.getAttribute && button.getAttribute("aria-keyshortcuts");
|
|
18327
18998
|
if (keyHint) {
|
|
18328
18999
|
var keyHintLabel = keyHint
|
|
@@ -18379,7 +19050,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18379
19050
|
return {
|
|
18380
19051
|
actionId: "run",
|
|
18381
19052
|
button: runButton,
|
|
18382
|
-
label: "Ask AI",
|
|
19053
|
+
label: (obj.__aiT ? obj.__aiT("aiassist", "Ask AI") : "Ask AI"),
|
|
18383
19054
|
detail: getDialogActionDetail("run", actionState)
|
|
18384
19055
|
};
|
|
18385
19056
|
}
|
|
@@ -18411,7 +19082,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18411
19082
|
return {
|
|
18412
19083
|
actionId: "document",
|
|
18413
19084
|
button: acceptDocumentButton,
|
|
18414
|
-
label: (acceptDocumentButton.innerText || acceptDocumentButton.textContent || "").replace(/\s+/g, " ").trim() || "Replace document",
|
|
19085
|
+
label: (acceptDocumentButton.innerText || acceptDocumentButton.textContent || "").replace(/\s+/g, " ").trim() || (obj.__aiT ? obj.__aiT("ai2_repldoc", "Replace document") : "Replace document"),
|
|
18415
19086
|
detail: getDialogActionDetail("document", actionState)
|
|
18416
19087
|
};
|
|
18417
19088
|
}
|
|
@@ -18460,15 +19131,15 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18460
19131
|
applyGuidance.style.display = "none";
|
|
18461
19132
|
applyGuidanceBadge.innerText = "";
|
|
18462
19133
|
applyGuidanceDetail.innerText = "";
|
|
18463
|
-
applyGuidance.setAttribute("aria-label", "No recommended Ask AI follow-up action yet.");
|
|
19134
|
+
applyGuidance.setAttribute("aria-label", uiT("aiu_norecommended", "No recommended Ask AI follow-up action yet."));
|
|
18464
19135
|
return;
|
|
18465
19136
|
}
|
|
18466
19137
|
applyGuidance.style.display = "";
|
|
18467
|
-
applyGuidanceTitle.innerText = "Best next step";
|
|
19138
|
+
applyGuidanceTitle.innerText = (obj.__aiT ? obj.__aiT("aid_bestnext", "Best next step") : "Best next step");
|
|
18468
19139
|
applyGuidanceBadge.innerText = recommended.label || "";
|
|
18469
19140
|
var summaryDetail = getDialogRecommendedSummaryDetail(actionState, recommended);
|
|
18470
19141
|
applyGuidanceDetail.innerText = summaryDetail || "";
|
|
18471
|
-
applyGuidance.setAttribute("aria-label", "Best next step: " + (recommended.label || "Action") + "." + (summaryDetail ? " " + summaryDetail : ""));
|
|
19142
|
+
applyGuidance.setAttribute("aria-label", (obj.__aiT ? obj.__aiT("aid_bestnextaria", "Best next step: {0}.", recommended.label || "Action") : "Best next step: " + (recommended.label || "Action") + ".") + (summaryDetail ? " " + summaryDetail : ""));
|
|
18472
19143
|
}
|
|
18473
19144
|
|
|
18474
19145
|
function rerunDialogPlanFromEditor() {
|
|
@@ -18495,7 +19166,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18495
19166
|
function renderOperationPlan(resolved) {
|
|
18496
19167
|
var operations = resolved && resolved.operations ? resolved.operations : [];
|
|
18497
19168
|
var actionState = getDialogActionState();
|
|
18498
|
-
planList.innerHTML = "";
|
|
19169
|
+
planList.innerHTML = __RTE_TT("");
|
|
18499
19170
|
planStatusMessage.innerText = dialoginner.__aiPlanStale
|
|
18500
19171
|
? (dialoginner.__aiPlanStaleReason || "Editor changed. Re-run to refresh.")
|
|
18501
19172
|
: "";
|
|
@@ -18515,7 +19186,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18515
19186
|
planSummary.innerText = "";
|
|
18516
19187
|
planStatusAction.style.display = "none";
|
|
18517
19188
|
applyPlanButton.disabled = true;
|
|
18518
|
-
applyPlanButton.innerText = "Apply";
|
|
19189
|
+
applyPlanButton.innerText = uiT("aiu_apply", "Apply");
|
|
18519
19190
|
return;
|
|
18520
19191
|
}
|
|
18521
19192
|
|
|
@@ -18598,10 +19269,10 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18598
19269
|
+ " \u2022 " + skippedCount + " skipped";
|
|
18599
19270
|
applyPlanButton.disabled = !pendingIndexes.length || !!dialoginner.__aiPlanStale || !actionState.canApplyPlan;
|
|
18600
19271
|
if (dialoginner.__aiPlanStale) {
|
|
18601
|
-
applyPlanButton.innerText = "Re-run to refresh plan";
|
|
19272
|
+
applyPlanButton.innerText = uiT("aiu_rerunplan", "Re-run to refresh plan");
|
|
18602
19273
|
}
|
|
18603
19274
|
else if (!pendingIndexes.length) {
|
|
18604
|
-
applyPlanButton.innerText = "No pending steps";
|
|
19275
|
+
applyPlanButton.innerText = uiT("aiu_nopending", "No pending steps");
|
|
18605
19276
|
}
|
|
18606
19277
|
else if (actionState.pendingSelectionDependent && !actionState.hasSelection) {
|
|
18607
19278
|
applyPlanButton.innerText = getSelectionRequiredPlanButtonLabel(pendingOperations);
|
|
@@ -18610,7 +19281,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18610
19281
|
applyPlanButton.innerText = getOperationPlanButtonLabel(resolved);
|
|
18611
19282
|
}
|
|
18612
19283
|
else {
|
|
18613
|
-
applyPlanButton.innerText = "
|
|
19284
|
+
applyPlanButton.innerText = uiT("aiu_applypending", "Apply {0} pending steps", pendingIndexes.length);
|
|
18614
19285
|
}
|
|
18615
19286
|
}
|
|
18616
19287
|
|
|
@@ -18672,7 +19343,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18672
19343
|
// setBusyState(false) is called.
|
|
18673
19344
|
if (isBusy) {
|
|
18674
19345
|
runButton.classList.add("is-busy");
|
|
18675
|
-
setReviewV2ButtonContent(runButton, "spinner", "Thinking...");
|
|
19346
|
+
setReviewV2ButtonContent(runButton, "spinner", (obj.__aiT ? obj.__aiT("aic_thinking", "Thinking...") : "Thinking..."));
|
|
18676
19347
|
} else {
|
|
18677
19348
|
runButton.classList.remove("is-busy");
|
|
18678
19349
|
}
|
|
@@ -18792,7 +19463,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18792
19463
|
// hidden apply options on the kebab's title + aria-label so
|
|
18793
19464
|
// users discover *what's behind the dots* on hover or with a
|
|
18794
19465
|
// screen reader, instead of clicking blind. Pre-pass the
|
|
18795
|
-
// tooltip read as "More apply options" — accurate but content-
|
|
19466
|
+
// tooltip read as (obj.__aiT ? obj.__aiT("ai2_moreopts", "More apply options") : "More apply options") — accurate but content-
|
|
18796
19467
|
// free; now it reads "More apply options (3): Replace
|
|
18797
19468
|
// selection, Insert below, Replace doc" so the count + the
|
|
18798
19469
|
// names live where the affordance is. Same shape Notion AI's
|
|
@@ -18804,7 +19475,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18804
19475
|
if (showsSelectionAction) moreOptionNames.push("Replace selection");
|
|
18805
19476
|
if (showsPreviewAction) moreOptionNames.push("Preview");
|
|
18806
19477
|
if (showsInsertAction) moreOptionNames.push("Insert below");
|
|
18807
|
-
if (showsDocumentAction) moreOptionNames.push("Replace document");
|
|
19478
|
+
if (showsDocumentAction) moreOptionNames.push((obj.__aiT ? obj.__aiT("ai2_repldoc", "Replace document") : "Replace document"));
|
|
18808
19479
|
var moreCount = moreOptionNames.length;
|
|
18809
19480
|
var anyMoreAvailable = moreCount > 0;
|
|
18810
19481
|
applyRowMoreToggle.style.display = anyMoreAvailable ? "" : "none";
|
|
@@ -18829,7 +19500,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18829
19500
|
// 2026-05-08 (v20260508s): clarify the run button — when a
|
|
18830
19501
|
// result already exists the button re-runs the same source, so
|
|
18831
19502
|
// call it Regenerate. Also flips when the plan goes stale.
|
|
18832
|
-
var runLabel = (hasResult || isStale) ? "Regenerate" : "Generate";
|
|
19503
|
+
var runLabel = (hasResult || isStale) ? (obj.__aiT ? obj.__aiT("aid_regenerate", "Regenerate") : "Regenerate") : (obj.__aiT ? obj.__aiT("aid_generate", "Generate") : "Generate");
|
|
18833
19504
|
setReviewV2ButtonContent(runButton, "sparkles", runLabel);
|
|
18834
19505
|
// 2026-05-17 (v20260517a): re-attach the keyboard hint chip,
|
|
18835
19506
|
// since setReviewV2ButtonContent clears textContent and loses
|
|
@@ -18991,7 +19662,7 @@ function RTE_Plugin_AIToolkit() {
|
|
|
18991
19662
|
}
|
|
18992
19663
|
syncDialogScopeUi();
|
|
18993
19664
|
if (!normalizeText(sourceArea.value)) {
|
|
18994
|
-
status.innerText = "Load or type source text before running Ask AI.";
|
|
19665
|
+
status.innerText = uiT("aiu_loadsource", "Load or type source text before running Ask AI.");
|
|
18995
19666
|
updatePreview();
|
|
18996
19667
|
return;
|
|
18997
19668
|
}
|