@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,362 @@
1
+ RTE_DefaultConfig.plugin_insertgallery = RTE_Plugin_InsertGallery;
2
+
3
+ function RTE_Plugin_InsertGallery() {
4
+ var obj = this;
5
+ var config;
6
+ var editor;
7
+
8
+ obj.PluginName = "InsertGallery";
9
+
10
+ obj.InitConfig = function (argconfig) {
11
+ config = argconfig;
12
+ if (!config.galleryImages) {
13
+ config.galleryImages = [];
14
+ }
15
+ };
16
+
17
+ obj.InitEditor = function (argeditor) {
18
+ editor = argeditor;
19
+
20
+ editor.attachEvent("exec_command_insertgallery", function (state) {
21
+ state.returnValue = true;
22
+ obj.DoInsertGallery();
23
+ });
24
+ };
25
+
26
+ function append(parent, tagName, cssText, className) {
27
+ var tag = parent.ownerDocument.createElement(tagName);
28
+ if (cssText) {
29
+ tag.style.cssText = cssText;
30
+ }
31
+ if (className) {
32
+ tag.className = className;
33
+ }
34
+ parent.appendChild(tag);
35
+ return tag;
36
+ }
37
+
38
+ function clear(node) {
39
+ while (node.firstChild) {
40
+ node.removeChild(node.firstChild);
41
+ }
42
+ }
43
+
44
+ function getFileName(url) {
45
+ var value = String(url || "").split("#")[0].split("?")[0];
46
+ var lastSlash = value.lastIndexOf("/");
47
+ var name = lastSlash >= 0 ? value.substring(lastSlash + 1) : value;
48
+ try {
49
+ name = decodeURIComponent(name);
50
+ } catch (ex) {
51
+ }
52
+ return name || "Image";
53
+ }
54
+
55
+ function getMetaText(item) {
56
+ if (item.meta) {
57
+ return item.meta;
58
+ }
59
+ if (item.alt) {
60
+ return item.alt;
61
+ }
62
+ return item.url;
63
+ }
64
+
65
+ function normalizeGalleryItem(item) {
66
+ var normalized = null;
67
+
68
+ if (typeof item === "string") {
69
+ normalized = {
70
+ url: item,
71
+ thumbnail: item,
72
+ name: getFileName(item)
73
+ };
74
+ } else if (item instanceof Array) {
75
+ normalized = {
76
+ url: item[0],
77
+ thumbnail: item[0],
78
+ name: item[1] || getFileName(item[0]),
79
+ meta: item[2] || ""
80
+ };
81
+ } else if (item && typeof item === "object") {
82
+ var url = item.url || item.src || item.href;
83
+ if (!url) {
84
+ return null;
85
+ }
86
+
87
+ normalized = {
88
+ url: url,
89
+ thumbnail: item.thumbnail || item.thumb || item.preview || url,
90
+ name: item.name || item.text || item.title || getFileName(url),
91
+ meta: item.meta || item.description || item.alt || ""
92
+ };
93
+ }
94
+
95
+ if (!normalized || !normalized.url) {
96
+ return null;
97
+ }
98
+
99
+ if (!normalized.thumbnail) {
100
+ normalized.thumbnail = normalized.url;
101
+ }
102
+
103
+ if (!normalized.name) {
104
+ normalized.name = getFileName(normalized.url);
105
+ }
106
+
107
+ return normalized;
108
+ }
109
+
110
+ function uploadFiles(fileList, onUploaded, onFinished, onFailed) {
111
+ var files = [];
112
+ var handler = window.rte_file_upload_handler;
113
+ var i;
114
+
115
+ for (i = 0; i < fileList.length; i++) {
116
+ files.push(fileList[i]);
117
+ }
118
+
119
+ if (!files.length) {
120
+ onFinished();
121
+ return;
122
+ }
123
+
124
+ if (typeof handler !== "function") {
125
+ if (onFailed) {
126
+ onFailed("Upload handler is not configured.");
127
+ }
128
+ onFinished();
129
+ return;
130
+ }
131
+
132
+ var index = 0;
133
+
134
+ function next() {
135
+ if (index >= files.length) {
136
+ onFinished();
137
+ return;
138
+ }
139
+
140
+ var file = files[index];
141
+ handler(file, function (url, error) {
142
+ if (url) {
143
+ onUploaded(url, file, index, files);
144
+ } else if (onFailed) {
145
+ onFailed(error || ("Upload failed for " + file.name), file);
146
+ }
147
+
148
+ index++;
149
+ next();
150
+ }, index, files);
151
+ }
152
+
153
+ next();
154
+ }
155
+
156
+ obj.DoInsertGallery = function () {
157
+ var dialoginner = editor.createDialog(editor.getLangText("insertgallerytitle") || "Image gallery", "rte-dialog-insertgallery");
158
+ var closeDialog = typeof dialoginner.close === "function" ? function () {
159
+ dialoginner.close();
160
+ } : function () {
161
+ editor.closeCurrentPopup();
162
+ };
163
+
164
+ var browser = append(dialoginner, "div", "", "rte-gallery-browser");
165
+ // The outer dialog frame already supplies a title bar + close button via
166
+ // __UI_CreateDialogFrame, so we only render a short subtitle here (no
167
+ // duplicate "Image gallery" heading underneath the frame title).
168
+ var header = append(browser, "div", "", "rte-dialog-browser-header");
169
+ var copy = append(header, "div", "", "rte-dialog-browser-copy");
170
+ copy.innerText = "Browse uploaded assets, filter by name, and insert the selected image into the editor.";
171
+
172
+ var toolbar = append(browser, "div", "", "rte-gallery-browser-toolbar");
173
+ var path = append(toolbar, "div", "", "rte-gallery-browser-path");
174
+ path.innerText = "/";
175
+ var type = append(toolbar, "div", "", "rte-gallery-browser-type");
176
+ type.innerText = "Image Files";
177
+
178
+ var uploadButton = append(toolbar, "button", "", "rte-gallery-browser-button");
179
+ uploadButton.type = "button";
180
+ uploadButton.innerText = "Upload";
181
+
182
+ var refreshButton = append(toolbar, "button", "", "rte-gallery-browser-button");
183
+ refreshButton.type = "button";
184
+ refreshButton.innerText = "Refresh";
185
+
186
+ var search = append(toolbar, "input", "", "rte-gallery-browser-search");
187
+ search.type = "search";
188
+ search.placeholder = "Search images";
189
+ search.setAttribute("aria-label", "Search images");
190
+
191
+ var fileInput = append(toolbar, "input", "display:none;");
192
+ fileInput.type = "file";
193
+ fileInput.accept = "image/*,.jpg,.jpeg,.png,.gif,.bmp,.webp,.svg";
194
+ fileInput.multiple = true;
195
+
196
+ var status = append(browser, "div", "", "rte-gallery-browser-status");
197
+ status.setAttribute("role", "status");
198
+ status.setAttribute("aria-live", "polite");
199
+ var surface = append(browser, "div", "", "rte-gallery-browser-surface");
200
+ var grid = append(surface, "div", "", "rte-gallery-browser-grid");
201
+ grid.setAttribute("role", "listbox");
202
+ grid.setAttribute("aria-label", "Available images");
203
+ var empty = append(surface, "div", "", "rte-gallery-browser-empty");
204
+ empty.innerText = "No images match this search. Upload a file or adjust the filter.";
205
+
206
+ var footer = append(browser, "div", "", "rte-gallery-browser-footer");
207
+ var footerText = append(footer, "div", "", "rte-gallery-browser-footer-text");
208
+ footerText.innerText = "Choose an image to enable insert.";
209
+
210
+ var cancelButton = append(footer, "button", "", "rte-gallery-browser-button");
211
+ cancelButton.type = "button";
212
+ cancelButton.innerText = "Cancel";
213
+
214
+ var insertButton = append(footer, "button", "", "rte-gallery-browser-button rte-gallery-browser-button-primary");
215
+ insertButton.type = "button";
216
+ insertButton.innerText = "Insert";
217
+ insertButton.disabled = true;
218
+
219
+ var selectedUrl = "";
220
+
221
+ function getNormalizedItems() {
222
+ var list = [];
223
+ var items = config.galleryImages || [];
224
+ var i;
225
+ for (i = 0; i < items.length; i++) {
226
+ var normalized = normalizeGalleryItem(items[i]);
227
+ if (normalized) {
228
+ list.push(normalized);
229
+ }
230
+ }
231
+ return list;
232
+ }
233
+
234
+ function getFilteredItems() {
235
+ var keyword = search.value.replace(/^\s+|\s+$/g, "").toLowerCase();
236
+ var items = getNormalizedItems();
237
+ if (!keyword) {
238
+ return items;
239
+ }
240
+
241
+ return items.filter(function (item) {
242
+ return (item.name && item.name.toLowerCase().indexOf(keyword) >= 0)
243
+ || (item.meta && item.meta.toLowerCase().indexOf(keyword) >= 0)
244
+ || (item.url && item.url.toLowerCase().indexOf(keyword) >= 0);
245
+ });
246
+ }
247
+
248
+ function updateStatus(items) {
249
+ var selectedName = "";
250
+ var i;
251
+ for (i = 0; i < items.length; i++) {
252
+ if (items[i].url === selectedUrl) {
253
+ selectedName = items[i].name;
254
+ break;
255
+ }
256
+ }
257
+
258
+ status.innerText = items.length + " item" + (items.length === 1 ? "" : "s") + " available."
259
+ + (selectedName ? " " + selectedName + " selected." : " No image selected.");
260
+ footerText.innerText = selectedName ? ("Ready to insert " + selectedName + ".") : "Choose an image to enable insert.";
261
+ insertButton.disabled = !selectedName;
262
+ }
263
+
264
+ function insertSelected() {
265
+ if (!selectedUrl) {
266
+ return;
267
+ }
268
+ editor.insertImageByUrl(selectedUrl);
269
+ closeDialog();
270
+ editor.focus();
271
+ }
272
+
273
+ function render() {
274
+ clear(grid);
275
+ var items = getFilteredItems();
276
+ var i;
277
+
278
+ empty.style.display = items.length ? "none" : "block";
279
+
280
+ for (i = 0; i < items.length; i++) {
281
+ (function (item) {
282
+ var card = append(grid, "button", "", "rte-gallery-browser-card");
283
+ card.type = "button";
284
+ card.setAttribute("role", "option");
285
+ card.setAttribute("aria-selected", item.url === selectedUrl ? "true" : "false");
286
+ if (item.url === selectedUrl) {
287
+ card.classList.add("is-selected");
288
+ }
289
+
290
+ var selection = append(card, "div", "", "rte-gallery-browser-selection");
291
+ selection.innerText = item.url === selectedUrl ? "Selected" : "";
292
+
293
+ var thumb = append(card, "div", "", "rte-gallery-browser-thumbnail");
294
+ var image = append(thumb, "img", "", "rte-gallery-browser-thumbnail-image");
295
+ image.src = item.thumbnail;
296
+ image.alt = item.name;
297
+
298
+ var name = append(card, "div", "", "rte-gallery-browser-name");
299
+ name.innerText = item.name;
300
+
301
+ var meta = append(card, "div", "", "rte-gallery-browser-meta");
302
+ meta.innerText = getMetaText(item);
303
+
304
+ card.onclick = function () {
305
+ selectedUrl = item.url;
306
+ render();
307
+ };
308
+
309
+ card.ondblclick = function () {
310
+ selectedUrl = item.url;
311
+ insertSelected();
312
+ };
313
+ })(items[i]);
314
+ }
315
+
316
+ if (selectedUrl) {
317
+ var stillVisible = false;
318
+ for (i = 0; i < items.length; i++) {
319
+ if (items[i].url === selectedUrl) {
320
+ stillVisible = true;
321
+ break;
322
+ }
323
+ }
324
+ if (!stillVisible) {
325
+ selectedUrl = "";
326
+ }
327
+ }
328
+
329
+ updateStatus(items);
330
+ }
331
+
332
+ uploadButton.onclick = function () {
333
+ fileInput.click();
334
+ };
335
+
336
+ fileInput.onchange = function () {
337
+ var lastUploaded = "";
338
+ status.innerText = "Uploading images...";
339
+
340
+ uploadFiles(fileInput.files, function (url) {
341
+ lastUploaded = url;
342
+ config.galleryImages.unshift(url);
343
+ }, function () {
344
+ if (lastUploaded) {
345
+ selectedUrl = lastUploaded;
346
+ }
347
+ fileInput.value = "";
348
+ render();
349
+ }, function (error) {
350
+ status.innerText = error || "Upload failed.";
351
+ });
352
+ };
353
+
354
+ refreshButton.onclick = render;
355
+ search.oninput = render;
356
+ cancelButton.onclick = closeDialog;
357
+ insertButton.onclick = insertSelected;
358
+
359
+ render();
360
+ search.focus();
361
+ };
362
+ }
@@ -0,0 +1,261 @@
1
+ RTE_DefaultConfig.plugin_inserttemplate = RTE_Plugin_InsertTemplate;
2
+
3
+ function RTE_Plugin_InsertTemplate() {
4
+ var obj = this;
5
+ var config;
6
+ var editor;
7
+
8
+ obj.PluginName = "InsertTemplate";
9
+
10
+ obj.InitConfig = function (argconfig) {
11
+ config = argconfig;
12
+ if (!config.htmlTemplates) {
13
+ config.htmlTemplates = [];
14
+ }
15
+ };
16
+
17
+ obj.InitEditor = function (argeditor) {
18
+ editor = argeditor;
19
+
20
+ editor.attachEvent("exec_command_inserttemplate", function (state) {
21
+ state.returnValue = true;
22
+ obj.DoInsertTemplate();
23
+ });
24
+ };
25
+
26
+ function append(parent, tagName, cssText, className) {
27
+ var tag = parent.ownerDocument.createElement(tagName);
28
+ if (cssText) {
29
+ tag.style.cssText = cssText;
30
+ }
31
+ if (className) {
32
+ tag.className = className;
33
+ }
34
+ parent.appendChild(tag);
35
+ return tag;
36
+ }
37
+
38
+ function clear(node) {
39
+ while (node.firstChild) {
40
+ node.removeChild(node.firstChild);
41
+ }
42
+ }
43
+
44
+ function stripHtml(html) {
45
+ var div = document.createElement("div");
46
+ div.innerHTML = html || "";
47
+ return div.innerText || div.textContent || "";
48
+ }
49
+
50
+ function normalizeTemplateItem(item, index) {
51
+ if (item instanceof Array) {
52
+ return {
53
+ id: "template-" + index,
54
+ title: item[0] || ("Template " + (index + 1)),
55
+ html: item[1] || "",
56
+ meta: item[2] || ""
57
+ };
58
+ }
59
+
60
+ if (item && typeof item === "object") {
61
+ return {
62
+ id: item.id || ("template-" + index),
63
+ title: item.title || item.name || item.text || ("Template " + (index + 1)),
64
+ html: item.html || item.content || "",
65
+ meta: item.meta || item.description || ""
66
+ };
67
+ }
68
+
69
+ if (typeof item === "string") {
70
+ return {
71
+ id: "template-" + index,
72
+ title: "Template " + (index + 1),
73
+ html: item,
74
+ meta: ""
75
+ };
76
+ }
77
+
78
+ return null;
79
+ }
80
+
81
+ function scalePreview(body, canvas) {
82
+ var maxWidth = 206;
83
+ var maxHeight = 166;
84
+ var width = Math.max(canvas.scrollWidth, 1);
85
+ var height = Math.max(canvas.scrollHeight, 1);
86
+ var scale = Math.min(1, maxWidth / width, maxHeight / height);
87
+
88
+ canvas.style.transformOrigin = "top left";
89
+ canvas.style.transform = "scale(" + scale + ")";
90
+ canvas.style.width = width + "px";
91
+ canvas.style.height = height + "px";
92
+ }
93
+
94
+ obj.DoInsertTemplate = function () {
95
+ var dialoginner = editor.createDialog(editor.getLangText("inserttemplatetitle") || "Insert template", "rte-dialog-inserttemplate");
96
+ var closeDialog = typeof dialoginner.close === "function" ? function () {
97
+ dialoginner.close();
98
+ } : function () {
99
+ editor.closeCurrentPopup();
100
+ };
101
+
102
+ var browser = append(dialoginner, "div", "", "rte-dialog-browser");
103
+ // The outer dialog frame supplies the title bar — only render a subtitle here.
104
+ var header = append(browser, "div", "", "rte-dialog-browser-header");
105
+ var copy = append(header, "div", "", "rte-dialog-browser-copy");
106
+ copy.innerText = "Preview reusable layouts, search by name, and replace the current editor content with a selected template.";
107
+
108
+ var toolbar = append(browser, "div", "", "rte-dialog-browser-toolbar");
109
+ var search = append(toolbar, "input", "", "rte-dialog-browser-search");
110
+ search.type = "search";
111
+ search.placeholder = "Search templates";
112
+ search.setAttribute("aria-label", "Search templates");
113
+ var count = append(toolbar, "div", "", "rte-dialog-browser-count");
114
+ count.setAttribute("role", "status");
115
+ count.setAttribute("aria-live", "polite");
116
+
117
+ var scrollpanel = append(browser, "div", "", "rte-dialog-browser-scrollpanel");
118
+ var grid = append(scrollpanel, "div", "", "rte-dialog-browser-grid rte-template-grid");
119
+ grid.setAttribute("role", "listbox");
120
+ grid.setAttribute("aria-label", "Available templates");
121
+ var empty = append(scrollpanel, "div", "", "rte-dialog-browser-empty");
122
+ empty.innerText = "No templates match the current filter.";
123
+
124
+ var footer = append(browser, "div", "", "rte-gallery-browser-footer");
125
+ var footerText = append(footer, "div", "", "rte-gallery-browser-footer-text");
126
+ footerText.innerText = "Select a template to replace the current content.";
127
+
128
+ var cancelButton = append(footer, "button", "", "rte-gallery-browser-button");
129
+ cancelButton.type = "button";
130
+ cancelButton.innerText = "Cancel";
131
+
132
+ var applyButton = append(footer, "button", "", "rte-gallery-browser-button rte-gallery-browser-button-primary");
133
+ applyButton.type = "button";
134
+ applyButton.innerText = "Replace Content";
135
+ applyButton.disabled = true;
136
+
137
+ var selectedId = "";
138
+
139
+ function getTemplates() {
140
+ var list = [];
141
+ var items = config.htmlTemplates || [];
142
+ var i;
143
+ for (i = 0; i < items.length; i++) {
144
+ var normalized = normalizeTemplateItem(items[i], i);
145
+ if (normalized && normalized.html) {
146
+ list.push(normalized);
147
+ }
148
+ }
149
+ return list;
150
+ }
151
+
152
+ function getFilteredTemplates() {
153
+ var keyword = search.value.replace(/^\s+|\s+$/g, "").toLowerCase();
154
+ var items = getTemplates();
155
+ if (!keyword) {
156
+ return items;
157
+ }
158
+
159
+ return items.filter(function (item) {
160
+ var plainText = stripHtml(item.html).toLowerCase();
161
+ return item.title.toLowerCase().indexOf(keyword) >= 0
162
+ || plainText.indexOf(keyword) >= 0
163
+ || (item.meta && item.meta.toLowerCase().indexOf(keyword) >= 0);
164
+ });
165
+ }
166
+
167
+ function updateFooter(items) {
168
+ var selectedTemplate = null;
169
+ var i;
170
+ for (i = 0; i < items.length; i++) {
171
+ if (items[i].id === selectedId) {
172
+ selectedTemplate = items[i];
173
+ break;
174
+ }
175
+ }
176
+
177
+ count.innerText = items.length + " template" + (items.length === 1 ? "" : "s");
178
+ footerText.innerText = selectedTemplate
179
+ ? ("Ready to replace the editor content with " + selectedTemplate.title + ".")
180
+ : "Select a template to replace the current content.";
181
+ applyButton.disabled = !selectedTemplate;
182
+ }
183
+
184
+ function applySelected() {
185
+ var items = getTemplates();
186
+ var i;
187
+ for (i = 0; i < items.length; i++) {
188
+ if (items[i].id === selectedId) {
189
+ editor.setHTMLCode(items[i].html);
190
+ closeDialog();
191
+ editor.focus();
192
+ return;
193
+ }
194
+ }
195
+ }
196
+
197
+ function render() {
198
+ clear(grid);
199
+ var items = getFilteredTemplates();
200
+ var i;
201
+
202
+ empty.style.display = items.length ? "none" : "block";
203
+
204
+ for (i = 0; i < items.length; i++) {
205
+ (function (item) {
206
+ var card = append(grid, "button", "", "rte-dialog-browser-card");
207
+ card.type = "button";
208
+ card.setAttribute("role", "option");
209
+ card.setAttribute("aria-selected", item.id === selectedId ? "true" : "false");
210
+ if (item.id === selectedId) {
211
+ card.classList.add("is-selected");
212
+ }
213
+
214
+ var preview = append(card, "div", "", "rte-template-card-preview");
215
+ var previewBody = append(preview, "div", "", "rte-template-card-preview-body");
216
+ var canvas = append(previewBody, "div", "", "rte-template-card-preview-canvas");
217
+ canvas.innerHTML = item.html;
218
+ scalePreview(previewBody, canvas);
219
+
220
+ var footer = append(card, "div", "", "rte-template-card-footer");
221
+ var title = append(footer, "div", "", "rte-template-card-title");
222
+ title.innerText = item.title;
223
+ var meta = append(footer, "div", "", "rte-template-card-meta");
224
+ meta.innerText = item.meta || stripHtml(item.html).substring(0, 80) || "Reusable template";
225
+
226
+ card.onclick = function () {
227
+ selectedId = item.id;
228
+ render();
229
+ };
230
+
231
+ card.ondblclick = function () {
232
+ selectedId = item.id;
233
+ applySelected();
234
+ };
235
+ })(items[i]);
236
+ }
237
+
238
+ if (selectedId) {
239
+ var visible = false;
240
+ for (i = 0; i < items.length; i++) {
241
+ if (items[i].id === selectedId) {
242
+ visible = true;
243
+ break;
244
+ }
245
+ }
246
+ if (!visible) {
247
+ selectedId = "";
248
+ }
249
+ }
250
+
251
+ updateFooter(items);
252
+ }
253
+
254
+ search.oninput = render;
255
+ cancelButton.onclick = closeDialog;
256
+ applyButton.onclick = applySelected;
257
+
258
+ render();
259
+ search.focus();
260
+ };
261
+ }