@richscripts/richtexteditor 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +360 -0
  2. package/admin/index.d.ts +100 -0
  3. package/admin/index.js +94 -0
  4. package/angular/component.ts +284 -0
  5. package/angular/index.d.ts +80 -0
  6. package/angular/index.ts +24 -0
  7. package/headless/index.d.ts +65 -0
  8. package/headless/index.js +272 -0
  9. package/index.d.ts +1412 -0
  10. package/integrations/shared.d.ts +138 -0
  11. package/integrations/shared.js +5182 -0
  12. package/package.json +130 -0
  13. package/react/index.d.ts +104 -0
  14. package/react/index.js +310 -0
  15. package/richtexteditor/CHANGELOG.md +1876 -0
  16. package/richtexteditor/all_plugins.js +31125 -0
  17. package/richtexteditor/all_plugins.min.js +78 -0
  18. package/richtexteditor/lang/rte-lang-af.js +193 -0
  19. package/richtexteditor/lang/rte-lang-ar.js +193 -0
  20. package/richtexteditor/lang/rte-lang-bg.js +193 -0
  21. package/richtexteditor/lang/rte-lang-bn.js +193 -0
  22. package/richtexteditor/lang/rte-lang-bs.js +193 -0
  23. package/richtexteditor/lang/rte-lang-ca.js +193 -0
  24. package/richtexteditor/lang/rte-lang-cs.js +193 -0
  25. package/richtexteditor/lang/rte-lang-cy.js +193 -0
  26. package/richtexteditor/lang/rte-lang-da.js +193 -0
  27. package/richtexteditor/lang/rte-lang-de.js +193 -0
  28. package/richtexteditor/lang/rte-lang-el.js +193 -0
  29. package/richtexteditor/lang/rte-lang-en.js +6 -0
  30. package/richtexteditor/lang/rte-lang-es.js +193 -0
  31. package/richtexteditor/lang/rte-lang-et.js +193 -0
  32. package/richtexteditor/lang/rte-lang-fa.js +193 -0
  33. package/richtexteditor/lang/rte-lang-fi.js +193 -0
  34. package/richtexteditor/lang/rte-lang-fil.js +193 -0
  35. package/richtexteditor/lang/rte-lang-fj.js +193 -0
  36. package/richtexteditor/lang/rte-lang-fr.js +193 -0
  37. package/richtexteditor/lang/rte-lang-ga.js +193 -0
  38. package/richtexteditor/lang/rte-lang-gu.js +193 -0
  39. package/richtexteditor/lang/rte-lang-he.js +193 -0
  40. package/richtexteditor/lang/rte-lang-hi.js +193 -0
  41. package/richtexteditor/lang/rte-lang-hr.js +193 -0
  42. package/richtexteditor/lang/rte-lang-ht.js +193 -0
  43. package/richtexteditor/lang/rte-lang-hu.js +193 -0
  44. package/richtexteditor/lang/rte-lang-id.js +193 -0
  45. package/richtexteditor/lang/rte-lang-is.js +193 -0
  46. package/richtexteditor/lang/rte-lang-it.js +193 -0
  47. package/richtexteditor/lang/rte-lang-ja.js +193 -0
  48. package/richtexteditor/lang/rte-lang-kn.js +193 -0
  49. package/richtexteditor/lang/rte-lang-ko.js +193 -0
  50. package/richtexteditor/lang/rte-lang-lt.js +193 -0
  51. package/richtexteditor/lang/rte-lang-lv.js +193 -0
  52. package/richtexteditor/lang/rte-lang-mg.js +193 -0
  53. package/richtexteditor/lang/rte-lang-mi.js +193 -0
  54. package/richtexteditor/lang/rte-lang-ml.js +193 -0
  55. package/richtexteditor/lang/rte-lang-mr.js +193 -0
  56. package/richtexteditor/lang/rte-lang-ms.js +193 -0
  57. package/richtexteditor/lang/rte-lang-mt.js +193 -0
  58. package/richtexteditor/lang/rte-lang-mww.js +193 -0
  59. package/richtexteditor/lang/rte-lang-nb.js +193 -0
  60. package/richtexteditor/lang/rte-lang-nl.js +193 -0
  61. package/richtexteditor/lang/rte-lang-otq.js +193 -0
  62. package/richtexteditor/lang/rte-lang-pa.js +193 -0
  63. package/richtexteditor/lang/rte-lang-pl.js +193 -0
  64. package/richtexteditor/lang/rte-lang-pt-pt.js +193 -0
  65. package/richtexteditor/lang/rte-lang-pt.js +193 -0
  66. package/richtexteditor/lang/rte-lang-ro.js +193 -0
  67. package/richtexteditor/lang/rte-lang-ru.js +193 -0
  68. package/richtexteditor/lang/rte-lang-sk.js +193 -0
  69. package/richtexteditor/lang/rte-lang-sl.js +193 -0
  70. package/richtexteditor/lang/rte-lang-sm.js +193 -0
  71. package/richtexteditor/lang/rte-lang-sr-Cyrl.js +193 -0
  72. package/richtexteditor/lang/rte-lang-sr-Latn.js +193 -0
  73. package/richtexteditor/lang/rte-lang-sv.js +193 -0
  74. package/richtexteditor/lang/rte-lang-sw.js +193 -0
  75. package/richtexteditor/lang/rte-lang-ta.js +193 -0
  76. package/richtexteditor/lang/rte-lang-te.js +193 -0
  77. package/richtexteditor/lang/rte-lang-th.js +193 -0
  78. package/richtexteditor/lang/rte-lang-tlh-Latn.js +193 -0
  79. package/richtexteditor/lang/rte-lang-tlh-Piqd.js +193 -0
  80. package/richtexteditor/lang/rte-lang-to.js +193 -0
  81. package/richtexteditor/lang/rte-lang-tr.js +193 -0
  82. package/richtexteditor/lang/rte-lang-ty.js +193 -0
  83. package/richtexteditor/lang/rte-lang-uk.js +193 -0
  84. package/richtexteditor/lang/rte-lang-ur.js +193 -0
  85. package/richtexteditor/lang/rte-lang-vi.js +193 -0
  86. package/richtexteditor/lang/rte-lang-yua.js +193 -0
  87. package/richtexteditor/lang/rte-lang-zh-Hans.js +193 -0
  88. package/richtexteditor/lang/rte-lang-zh-Hant.js +193 -0
  89. package/richtexteditor/lang/rte-lang.js +1 -0
  90. package/richtexteditor/plugins/-combine-plugin.txt +2 -0
  91. package/richtexteditor/plugins/-combine-plugins.bat +20 -0
  92. package/richtexteditor/plugins/a11yenhance.js +90 -0
  93. package/richtexteditor/plugins/accessibilitychecker.js +579 -0
  94. package/richtexteditor/plugins/aitoolkit.css +15830 -0
  95. package/richtexteditor/plugins/aitoolkit.js +19171 -0
  96. package/richtexteditor/plugins/all_plugins.js +31125 -0
  97. package/richtexteditor/plugins/all_plugins.min.js +78 -0
  98. package/richtexteditor/plugins/autoembed.js +174 -0
  99. package/richtexteditor/plugins/blocktypes.js +175 -0
  100. package/richtexteditor/plugins/bookmarkcard.js +226 -0
  101. package/richtexteditor/plugins/charlimit.js +195 -0
  102. package/richtexteditor/plugins/comments.js +672 -0
  103. package/richtexteditor/plugins/contentminimap.js +369 -0
  104. package/richtexteditor/plugins/crdt-engine.js +8905 -0
  105. package/richtexteditor/plugins/crdt-engine.min.js +5 -0
  106. package/richtexteditor/plugins/dialoga11y.js +174 -0
  107. package/richtexteditor/plugins/dictation.js +268 -0
  108. package/richtexteditor/plugins/documentimport.js +369 -0
  109. package/richtexteditor/plugins/documentoutline.js +341 -0
  110. package/richtexteditor/plugins/emailtoolkit.js +165 -0
  111. package/richtexteditor/plugins/emojiautocomplete.js +241 -0
  112. package/richtexteditor/plugins/foldheadings.js +181 -0
  113. package/richtexteditor/plugins/ghostcomplete.js +297 -0
  114. package/richtexteditor/plugins/html2pdf.js +158 -0
  115. package/richtexteditor/plugins/imageeditor.js +159 -0
  116. package/richtexteditor/plugins/insertcode.js +319 -0
  117. package/richtexteditor/plugins/insertemoji.js +229 -0
  118. package/richtexteditor/plugins/insertgallery.js +362 -0
  119. package/richtexteditor/plugins/inserttemplate.js +261 -0
  120. package/richtexteditor/plugins/localdraft.js +213 -0
  121. package/richtexteditor/plugins/markdownexport.js +110 -0
  122. package/richtexteditor/plugins/mathdialog.js +153 -0
  123. package/richtexteditor/plugins/mentionplugin.js +534 -0
  124. package/richtexteditor/plugins/mermaiddiagram.js +294 -0
  125. package/richtexteditor/plugins/readabilitystats.js +148 -0
  126. package/richtexteditor/plugins/readaloud.js +243 -0
  127. package/richtexteditor/plugins/restrictedediting.js +208 -0
  128. package/richtexteditor/plugins/revisionhistory.js +670 -0
  129. package/richtexteditor/plugins/samples/insertcode_v1.js +76 -0
  130. package/richtexteditor/plugins/slashcommand.js +705 -0
  131. package/richtexteditor/plugins/smartchips.js +250 -0
  132. package/richtexteditor/plugins/spellcheck.js +181 -0
  133. package/richtexteditor/plugins/todolist.js +137 -0
  134. package/richtexteditor/plugins/trackedchanges.js +658 -0
  135. package/richtexteditor/plugins/tui.image-editor/fabric.min.js +8 -0
  136. package/richtexteditor/plugins/tui.image-editor/note.txt +5 -0
  137. package/richtexteditor/plugins/tui.image-editor/svg/icon-a.svg +235 -0
  138. package/richtexteditor/plugins/tui.image-editor/svg/icon-b.svg +224 -0
  139. package/richtexteditor/plugins/tui.image-editor/svg/icon-c.svg +224 -0
  140. package/richtexteditor/plugins/tui.image-editor/svg/icon-d.svg +224 -0
  141. package/richtexteditor/plugins/tui.image-editor/tui-code-snippet.min.js +7 -0
  142. package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.css +6 -0
  143. package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.js +7 -0
  144. package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.css +7 -0
  145. package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.js +15 -0
  146. package/richtexteditor/plugins/typewriter.js +203 -0
  147. package/richtexteditor/plugins/wordexport.js +0 -0
  148. package/richtexteditor/plugins/yjscollab.js +693 -0
  149. package/richtexteditor/plugins/zz_richtextbox_dialog_style.js +335 -0
  150. package/richtexteditor/rte-config.js +933 -0
  151. package/richtexteditor/rte.js +943 -0
  152. package/richtexteditor/rte_mobile.css +234 -0
  153. package/richtexteditor/rte_theme_default.css +4819 -0
  154. package/richtexteditor/runtime/colorpicker_more_ns.htm +2613 -0
  155. package/richtexteditor/runtime/help.htm +162 -0
  156. package/richtexteditor/runtime/images/1x1.gif +0 -0
  157. package/richtexteditor/runtime/images/cpie_Color.cur +0 -0
  158. package/richtexteditor/runtime/images/cpie_GradientPositionDark.gif +0 -0
  159. package/richtexteditor/runtime/images/cpie_GradientPositionLight.gif +0 -0
  160. package/richtexteditor/runtime/images/cpie_VerticalPosition.gif +0 -0
  161. package/richtexteditor/runtime/images/cpie_WebSafe.gif +0 -0
  162. package/richtexteditor/runtime/images/cpie_gradients.png +0 -0
  163. package/richtexteditor/runtime/images/cpns_Color.cur +0 -0
  164. package/richtexteditor/runtime/images/cpns_ColorSpace1.png +0 -0
  165. package/richtexteditor/runtime/images/cpns_ColorSpace2.png +0 -0
  166. package/richtexteditor/runtime/images/cpns_GradientPositionDark.gif +0 -0
  167. package/richtexteditor/runtime/images/cpns_GradientPositionLight.gif +0 -0
  168. package/richtexteditor/runtime/images/cpns_Vertical1.png +0 -0
  169. package/richtexteditor/runtime/images/cpns_Vertical2.png +0 -0
  170. package/richtexteditor/runtime/images/cpns_VerticalPosition.gif +0 -0
  171. package/richtexteditor/runtime/images/cpns_WebSafe.gif +0 -0
  172. package/richtexteditor/runtime/images/cpns_gradients.png +0 -0
  173. package/richtexteditor/runtime/images/cpns_hue2.png +0 -0
  174. package/richtexteditor/runtime/images/formbn.gif +0 -0
  175. package/richtexteditor/runtime/images/multiclavier.gif +0 -0
  176. package/richtexteditor/runtime/richtexteditor_content.css +362 -0
  177. package/richtexteditor/runtime/richtexteditor_preview.css +302 -0
  178. package/richtexteditor/runtime/richtexteditor_preview.js +1 -0
  179. package/server/index.d.ts +21 -0
  180. package/server/index.js +23 -0
  181. package/svelte/index.d.ts +19 -0
  182. package/svelte/index.js +59 -0
  183. package/vue/index.d.ts +94 -0
  184. package/vue/index.js +291 -0
@@ -0,0 +1,534 @@
1
+ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
2
+
3
+ RTE_DefaultConfig.plugin_mention = RTE_Plugin_Mention;
4
+
5
+ function RTE_Plugin_Mention() {
6
+ var obj = this;
7
+ var config;
8
+ var editor;
9
+
10
+ var popupHost = null;
11
+ var popupEl = null;
12
+ var statusEl = null;
13
+
14
+ var triggers = [];
15
+ var activeTrigger = null;
16
+ var trigger = null; // currently-open invocation
17
+ var items = [];
18
+ var activeIndex = 0;
19
+ var composing = false;
20
+ var searchSeq = 0;
21
+ var debounceTimer = null;
22
+
23
+ obj.PluginName = "Mention";
24
+
25
+ obj.InitConfig = function (argconfig) {
26
+ config = argconfig;
27
+ if (config.mentionEnabled === false) return;
28
+
29
+ config.mentionTrigger = config.mentionTrigger || "@";
30
+ config.mentionDebounceMs = config.mentionDebounceMs == null ? 150 : config.mentionDebounceMs;
31
+ config.mentionMaxItems = config.mentionMaxItems || 8;
32
+ config.mentionStaticList = config.mentionStaticList || null;
33
+ config.mentionSource = config.mentionSource || null;
34
+ config.mentionInsertClass = config.mentionInsertClass || "rte-mention";
35
+ config.mentionTriggers = config.mentionTriggers || null; // optional array of extra triggers
36
+ };
37
+
38
+ obj.InitEditor = function (argeditor) {
39
+ editor = argeditor;
40
+ if (config.mentionEnabled === false) return;
41
+
42
+ editor.mentions = {
43
+ register: registerTrigger,
44
+ remove: removeTrigger,
45
+ list: function () { return triggers.slice(); },
46
+ close: closePopup,
47
+ isOpen: function () { return !!popupEl; }
48
+ };
49
+
50
+ // Register the default @ trigger if a source or static list is configured.
51
+ if (config.mentionSource || config.mentionStaticList) {
52
+ registerTrigger({
53
+ trigger: config.mentionTrigger,
54
+ source: config.mentionSource || function (q) {
55
+ return filterStatic(config.mentionStaticList, q);
56
+ }
57
+ });
58
+ }
59
+
60
+ // Declarative extras from config.
61
+ if (Array.isArray(config.mentionTriggers)) {
62
+ for (var i = 0; i < config.mentionTriggers.length; i++) {
63
+ registerTrigger(config.mentionTriggers[i]);
64
+ }
65
+ }
66
+
67
+ injectStyles();
68
+
69
+ var editdoc = editor.getDocument();
70
+ editdoc.addEventListener("keydown", onEditDocKeyDown, true);
71
+ editdoc.addEventListener("input", onEditDocInput, true);
72
+ editdoc.addEventListener("compositionstart", function () { composing = true; });
73
+ editdoc.addEventListener("compositionend", function () { composing = false; });
74
+ editdoc.addEventListener("mousedown", function (e) {
75
+ // Don't close when the user is clicking on a mention span (for selection/delete).
76
+ if (e.target && e.target.closest && e.target.closest("." + config.mentionInsertClass)) return;
77
+ closePopup();
78
+ }, true);
79
+ editdoc.addEventListener("blur", function () { setTimeout(closePopup, 150); }, true);
80
+
81
+ window.addEventListener("scroll", onHostScrollOrResize, true);
82
+ window.addEventListener("resize", onHostScrollOrResize, true);
83
+ };
84
+
85
+ function registerTrigger(def) {
86
+ if (!def || !def.trigger || typeof def.source !== "function") return;
87
+ var existingIdx = findTriggerIndex(def.trigger);
88
+ var normalized = {
89
+ trigger: def.trigger,
90
+ source: def.source,
91
+ renderItem: def.renderItem || null,
92
+ renderInsert: def.renderInsert || null,
93
+ insertClass: def.insertClass || config.mentionInsertClass,
94
+ label: def.label || ("mentions " + def.trigger)
95
+ };
96
+ if (existingIdx >= 0) triggers[existingIdx] = normalized;
97
+ else triggers.push(normalized);
98
+ }
99
+
100
+ function removeTrigger(ch) {
101
+ var idx = findTriggerIndex(ch);
102
+ if (idx >= 0) triggers.splice(idx, 1);
103
+ }
104
+
105
+ function findTriggerIndex(ch) {
106
+ for (var i = 0; i < triggers.length; i++) if (triggers[i].trigger === ch) return i;
107
+ return -1;
108
+ }
109
+
110
+ // Item display helpers. Accept the common `{name, email}` shape (what most
111
+ // mention data sources / CKEditor-style configs use) as well as the native
112
+ // `{label, subtitle}` shape, so a plain `[{id, name, email}]` list renders
113
+ // and filters correctly without remapping.
114
+ function itemLabel(item) {
115
+ return (item && (item.label || item.name || item.id)) || "";
116
+ }
117
+ function itemSubtitle(item) {
118
+ return (item && (item.subtitle || item.email)) || "";
119
+ }
120
+
121
+ function filterStatic(list, q) {
122
+ if (!Array.isArray(list)) return [];
123
+ if (!q) return list.slice(0, 50);
124
+ var ql = q.toLowerCase();
125
+ return list.filter(function (item) {
126
+ var hay = (itemLabel(item) + " " + itemSubtitle(item) + " " + (item.id || "")).toLowerCase();
127
+ return hay.indexOf(ql) !== -1;
128
+ });
129
+ }
130
+
131
+ function onEditDocKeyDown(e) {
132
+ if (composing) return;
133
+
134
+ if (popupEl) {
135
+ switch (e.key) {
136
+ case "ArrowDown":
137
+ e.preventDefault(); e.stopPropagation();
138
+ moveActive(1);
139
+ return;
140
+ case "ArrowUp":
141
+ e.preventDefault(); e.stopPropagation();
142
+ moveActive(-1);
143
+ return;
144
+ case "Enter":
145
+ case "Tab":
146
+ if (items.length) {
147
+ e.preventDefault(); e.stopPropagation();
148
+ selectActive();
149
+ return;
150
+ }
151
+ closePopup();
152
+ return;
153
+ case "Escape":
154
+ case "Esc":
155
+ e.preventDefault(); e.stopPropagation();
156
+ closePopup();
157
+ return;
158
+ }
159
+ }
160
+
161
+ if (!e.ctrlKey && !e.metaKey && !e.altKey) {
162
+ var matched = findTriggerIndex(e.key);
163
+ if (matched >= 0 && isAtTriggerBoundary()) {
164
+ var tdef = triggers[matched];
165
+ setTimeout(function () { openPopup(tdef); }, 0);
166
+ }
167
+ }
168
+ }
169
+
170
+ function onEditDocInput() {
171
+ if (!popupEl) return;
172
+ updateTriggerState();
173
+ }
174
+
175
+ function isAtTriggerBoundary() {
176
+ var sel = editor.getSelection();
177
+ if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
178
+ var range = sel.getRangeAt(0);
179
+ var node = range.startContainer;
180
+ var offset = range.startOffset;
181
+
182
+ var editable = editor.getEditable();
183
+ var walk = node.nodeType === 1 ? node : node.parentNode;
184
+ while (walk && walk !== editable) {
185
+ var name = walk.nodeName;
186
+ if (name === "CODE" || name === "PRE") return false;
187
+ // Avoid triggering a fresh mention inside an existing mention span.
188
+ if (walk.classList && walk.classList.contains(config.mentionInsertClass)) return false;
189
+ walk = walk.parentNode;
190
+ }
191
+
192
+ if (node.nodeType === 3) {
193
+ if (offset === 0) return true;
194
+ var ch = node.nodeValue.charAt(offset - 1);
195
+ return /\s/.test(ch);
196
+ }
197
+ return true;
198
+ }
199
+
200
+ function openPopup(triggerDef) {
201
+ closePopup();
202
+ var sel = editor.getSelection();
203
+ if (!sel || sel.rangeCount === 0) return;
204
+ var range = sel.getRangeAt(0).cloneRange();
205
+
206
+ activeTrigger = triggerDef;
207
+ trigger = {
208
+ range: range,
209
+ startNode: range.startContainer,
210
+ startOffset: range.startOffset,
211
+ triggerCharCount: 1,
212
+ query: ""
213
+ };
214
+
215
+ renderPopup();
216
+ positionPopup();
217
+ runSource("");
218
+ }
219
+
220
+ function closePopup() {
221
+ if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }
222
+ if (popupEl && popupEl.parentNode) popupEl.parentNode.removeChild(popupEl);
223
+ popupEl = null;
224
+ statusEl = null;
225
+ activeTrigger = null;
226
+ trigger = null;
227
+ items = [];
228
+ activeIndex = 0;
229
+ }
230
+
231
+ function updateTriggerState() {
232
+ if (!trigger) return;
233
+ var sel = editor.getSelection();
234
+ if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) { closePopup(); return; }
235
+ var range = sel.getRangeAt(0);
236
+ var node = range.startContainer;
237
+ if (node !== trigger.startNode) { closePopup(); return; }
238
+ var caret = range.startOffset;
239
+ if (caret < trigger.startOffset) { closePopup(); return; }
240
+
241
+ var text = (node.nodeType === 3 ? node.nodeValue : "") || "";
242
+ var query = text.substring(trigger.startOffset, caret);
243
+ if (/\s/.test(query)) { closePopup(); return; }
244
+ trigger.query = query;
245
+ runSource(query);
246
+ positionPopup();
247
+ }
248
+
249
+ function runSource(query) {
250
+ if (!activeTrigger) return;
251
+ var seq = ++searchSeq;
252
+
253
+ if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }
254
+
255
+ var delay = query.length === 0 ? 0 : config.mentionDebounceMs;
256
+
257
+ function execute() {
258
+ showLoading();
259
+ var invocation;
260
+ try {
261
+ invocation = activeTrigger.source(query, { trigger: activeTrigger.trigger });
262
+ } catch (err) {
263
+ console.warn("Mention source threw:", err);
264
+ invocation = [];
265
+ }
266
+ Promise.resolve(invocation).then(function (results) {
267
+ if (seq !== searchSeq || !popupEl) return;
268
+ items = Array.isArray(results) ? results.slice(0, config.mentionMaxItems) : [];
269
+ activeIndex = 0;
270
+ renderItems();
271
+ }, function (err) {
272
+ if (seq !== searchSeq || !popupEl) return;
273
+ console.warn("Mention source failed:", err);
274
+ items = [];
275
+ renderItems();
276
+ });
277
+ }
278
+
279
+ if (delay > 0) debounceTimer = setTimeout(execute, delay);
280
+ else execute();
281
+ }
282
+
283
+ function renderPopup() {
284
+ popupHost = editor.iframe.ownerDocument;
285
+ popupEl = popupHost.createElement("div");
286
+ popupEl.className = "rte-mention-popup";
287
+ popupEl.setAttribute("role", "listbox");
288
+ popupEl.setAttribute("aria-label", activeTrigger.label);
289
+ popupHost.body.appendChild(popupEl);
290
+ }
291
+
292
+ function showLoading() {
293
+ if (!popupEl) return;
294
+ popupEl.innerHTML = "";
295
+ var loader = popupHost.createElement("div");
296
+ loader.className = "rte-mention-loading";
297
+ loader.textContent = "Searching\u2026";
298
+ popupEl.appendChild(loader);
299
+ statusEl = loader;
300
+ }
301
+
302
+ function renderItems() {
303
+ if (!popupEl) return;
304
+ popupEl.innerHTML = "";
305
+ statusEl = null;
306
+
307
+ if (!items.length) {
308
+ var empty = popupHost.createElement("div");
309
+ empty.className = "rte-mention-empty";
310
+ empty.textContent = "No matches";
311
+ popupEl.appendChild(empty);
312
+ return;
313
+ }
314
+
315
+ for (var i = 0; i < items.length; i++) {
316
+ (function (item, index) {
317
+ var btn = popupHost.createElement("button");
318
+ btn.type = "button";
319
+ btn.className = "rte-mention-item" + (index === activeIndex ? " rte-mention-item-active" : "");
320
+ btn.setAttribute("role", "option");
321
+ btn.setAttribute("aria-selected", index === activeIndex ? "true" : "false");
322
+ btn.setAttribute("data-index", index);
323
+
324
+ if (activeTrigger.renderItem) {
325
+ activeTrigger.renderItem(btn, item);
326
+ } else {
327
+ renderDefaultItem(btn, item);
328
+ }
329
+
330
+ btn.addEventListener("mousedown", function (e) {
331
+ e.preventDefault(); e.stopPropagation();
332
+ activeIndex = index;
333
+ selectActive();
334
+ });
335
+ btn.addEventListener("click", function (e) {
336
+ if (!popupEl) return;
337
+ e.preventDefault(); e.stopPropagation();
338
+ activeIndex = index;
339
+ selectActive();
340
+ });
341
+ btn.addEventListener("mouseenter", function () {
342
+ if (activeIndex !== index) { activeIndex = index; updateActiveClass(); }
343
+ });
344
+
345
+ popupEl.appendChild(btn);
346
+ })(items[i], i);
347
+ }
348
+ }
349
+
350
+ function renderDefaultItem(btn, item) {
351
+ var avatar = popupHost.createElement("span");
352
+ avatar.className = "rte-mention-avatar";
353
+ if (item.avatarUrl) {
354
+ var img = popupHost.createElement("img");
355
+ img.src = item.avatarUrl;
356
+ img.alt = "";
357
+ avatar.appendChild(img);
358
+ } else {
359
+ avatar.textContent = initialsOf(itemLabel(item) || "?");
360
+ }
361
+ btn.appendChild(avatar);
362
+
363
+ var body = popupHost.createElement("span");
364
+ body.className = "rte-mention-body";
365
+ var label = popupHost.createElement("span");
366
+ label.className = "rte-mention-label";
367
+ label.textContent = itemLabel(item);
368
+ body.appendChild(label);
369
+ var subtitleText = itemSubtitle(item);
370
+ if (subtitleText) {
371
+ var sub = popupHost.createElement("span");
372
+ sub.className = "rte-mention-subtitle";
373
+ sub.textContent = subtitleText;
374
+ body.appendChild(sub);
375
+ }
376
+ btn.appendChild(body);
377
+ }
378
+
379
+ function initialsOf(label) {
380
+ var parts = String(label).trim().split(/\s+/);
381
+ if (!parts[0]) return "?";
382
+ if (parts.length === 1) return parts[0].charAt(0).toUpperCase();
383
+ return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
384
+ }
385
+
386
+ function updateActiveClass() {
387
+ if (!popupEl) return;
388
+ var nodes = popupEl.querySelectorAll(".rte-mention-item");
389
+ for (var i = 0; i < nodes.length; i++) {
390
+ var idx = +nodes[i].getAttribute("data-index");
391
+ var active = idx === activeIndex;
392
+ nodes[i].classList.toggle("rte-mention-item-active", active);
393
+ nodes[i].setAttribute("aria-selected", active ? "true" : "false");
394
+ }
395
+ scrollActiveIntoView();
396
+ }
397
+
398
+ function scrollActiveIntoView() {
399
+ if (!popupEl) return;
400
+ var active = popupEl.querySelector(".rte-mention-item-active");
401
+ if (!active) return;
402
+ var top = active.offsetTop;
403
+ var bot = top + active.offsetHeight;
404
+ if (top < popupEl.scrollTop) popupEl.scrollTop = top;
405
+ else if (bot > popupEl.scrollTop + popupEl.clientHeight) popupEl.scrollTop = bot - popupEl.clientHeight;
406
+ }
407
+
408
+ function moveActive(delta) {
409
+ if (!items.length) return;
410
+ activeIndex = (activeIndex + delta + items.length) % items.length;
411
+ updateActiveClass();
412
+ }
413
+
414
+ function selectActive() {
415
+ if (!items.length) { closePopup(); return; }
416
+ var item = items[activeIndex];
417
+ var triggerSnapshot = trigger;
418
+ var triggerDef = activeTrigger;
419
+ closePopup();
420
+ if (!item || !triggerSnapshot || !triggerDef) return;
421
+ deleteTriggerText(triggerSnapshot);
422
+ insertMention(triggerDef, item);
423
+ }
424
+
425
+ function deleteTriggerText(triggerSnapshot) {
426
+ var node = triggerSnapshot.startNode;
427
+ if (!node) return;
428
+ var start = triggerSnapshot.startOffset - (triggerSnapshot.triggerCharCount || 0);
429
+ if (start < 0) start = 0;
430
+ var sel = editor.getSelection();
431
+ if (!sel || sel.rangeCount === 0) return;
432
+ var currentRange = sel.getRangeAt(0);
433
+ var endNode = currentRange.startContainer, endOffset = currentRange.startOffset;
434
+ var delRange = editor.getDocument().createRange();
435
+ delRange.setStart(node, start);
436
+ delRange.setEnd(endNode, endOffset);
437
+ try { delRange.deleteContents(); } catch (err) { return; }
438
+ sel.removeAllRanges();
439
+ sel.addRange(delRange);
440
+ }
441
+
442
+ function insertMention(triggerDef, item) {
443
+ var editdoc = editor.getDocument();
444
+ var span;
445
+ if (triggerDef.renderInsert) {
446
+ span = triggerDef.renderInsert(editdoc, item);
447
+ } else {
448
+ span = editdoc.createElement("span");
449
+ span.className = triggerDef.insertClass;
450
+ span.setAttribute("contenteditable", "false");
451
+ span.setAttribute("data-rte-mention-id", item.id != null ? item.id : "");
452
+ span.setAttribute("data-rte-mention-trigger", triggerDef.trigger);
453
+ span.textContent = triggerDef.trigger + itemLabel(item);
454
+ }
455
+ if (!span) return;
456
+
457
+ // Insert the mention + a trailing space so the caret naturally lives in text, not inside
458
+ // the atomic span.
459
+ var sel = editor.getSelection();
460
+ if (!sel || sel.rangeCount === 0) return;
461
+ var range = sel.getRangeAt(0);
462
+ range.insertNode(span);
463
+
464
+ var spaceNode = editdoc.createTextNode("\u00a0");
465
+ span.parentNode.insertBefore(spaceNode, span.nextSibling);
466
+
467
+ var newRange = editdoc.createRange();
468
+ newRange.setStartAfter(spaceNode);
469
+ newRange.collapse(true);
470
+ sel.removeAllRanges();
471
+ sel.addRange(newRange);
472
+ }
473
+
474
+ function positionPopup() {
475
+ if (!popupEl || !trigger) return;
476
+ var iframe = editor.iframe;
477
+ var ir = iframe.getBoundingClientRect();
478
+ var rects = trigger.range.getClientRects();
479
+ var r = rects && rects.length ? rects[rects.length - 1] : null;
480
+ if (!r) r = trigger.range.getBoundingClientRect();
481
+
482
+ var left = ir.left + (r.left || 0) + window.pageXOffset;
483
+ var top = ir.top + (r.bottom || r.top || 0) + window.pageYOffset + 4;
484
+
485
+ popupEl.style.position = "absolute";
486
+ popupEl.style.left = left + "px";
487
+ popupEl.style.top = top + "px";
488
+
489
+ var vh = window.innerHeight || document.documentElement.clientHeight;
490
+ var popupRect = popupEl.getBoundingClientRect();
491
+ if (popupRect.bottom > vh - 8 && (ir.top + (r.top || 0)) > popupRect.height + 16) {
492
+ popupEl.style.top = (ir.top + (r.top || 0) + window.pageYOffset - popupRect.height - 4) + "px";
493
+ }
494
+ }
495
+
496
+ function onHostScrollOrResize() {
497
+ if (popupEl) positionPopup();
498
+ }
499
+
500
+ function injectStyles() {
501
+ var host = (editor && editor.iframe && editor.iframe.ownerDocument) || document;
502
+ if (host.querySelector("style[data-rte-mention]")) return;
503
+ var style = host.createElement("style");
504
+ style.setAttribute("data-rte-mention", "1");
505
+ style.textContent = [
506
+ ".rte-mention-popup{position:absolute;z-index:2147483000;min-width:240px;max-width:min(340px,calc(100vw - 24px));max-height:min(320px,60vh);overflow-y:auto;padding:5px;background:linear-gradient(180deg,rgba(255,255,255,.98),rgba(248,251,255,.96));border:1px solid rgba(148,163,184,.22);box-shadow:0 18px 42px rgba(29,78,216,.16),0 2px 8px rgba(15,23,42,.08);border-radius:14px;font-family:Aptos,'Segoe UI',sans-serif;font-size:13px;color:#172033;scrollbar-width:thin}",
507
+ ".rte-mention-item{display:flex;align-items:center;gap:9px;width:100%;min-height:40px;padding:6px 8px;border:0;background:transparent;text-align:left;cursor:pointer;color:inherit;font:inherit;border-radius:11px}",
508
+ ".rte-mention-item:hover,.rte-mention-item-active{background:#eef4ff;color:#0f3f9f}",
509
+ ".rte-mention-avatar{flex:0 0 30px;width:30px;height:30px;border-radius:11px;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;background:#e7eefb;color:#315277;font-size:11px;font-weight:800;letter-spacing:.02em;box-shadow:inset 0 0 0 1px rgba(148,163,184,.18)}",
510
+ ".rte-mention-avatar img{width:100%;height:100%;object-fit:cover}",
511
+ ".rte-mention-item-active .rte-mention-avatar{background:#ffffff;color:#0f3f9f}",
512
+ ".rte-mention-body{display:flex;flex-direction:column;min-width:0;flex:1}",
513
+ ".rte-mention-label{font-weight:750;font-size:13px;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}",
514
+ ".rte-mention-subtitle{font-size:11px;color:#64748b;line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}",
515
+ ".rte-mention-item-active .rte-mention-subtitle{color:#315277}",
516
+ ".rte-mention-loading,.rte-mention-empty{padding:14px 16px;color:#52657e;font-size:12px;font-weight:700;text-align:center}",
517
+ ".rte-mention{display:inline-block;padding:1px 7px;border-radius:999px;background:#eef4ff;color:#0f3f9f;font-weight:650;cursor:default;border:1px solid rgba(37,99,235,.16)}",
518
+ ".rte-mention:hover{background:#e4edff}"
519
+ ].join("\n");
520
+ host.head.appendChild(style);
521
+
522
+ // Also inject mention-span styles inside the iframe so the pill looks right while editing.
523
+ var editdoc = editor.getDocument();
524
+ if (editdoc && editdoc.head && !editdoc.querySelector("style[data-rte-mention-inline]")) {
525
+ var iStyle = editdoc.createElement("style");
526
+ iStyle.setAttribute("data-rte-mention-inline", "1");
527
+ iStyle.textContent = [
528
+ ".rte-mention{display:inline-block;padding:1px 7px;border-radius:999px;background:#eef4ff;color:#0f3f9f;font-weight:650;cursor:default;border:1px solid rgba(37,99,235,.16);user-select:all}",
529
+ ".rte-mention:hover{background:#e4edff}"
530
+ ].join("\n");
531
+ editdoc.head.appendChild(iStyle);
532
+ }
533
+ }
534
+ }