@componyx/ui 0.0.0-stage → 1.0.4

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 (169) hide show
  1. package/AppSkin/AppSkin.css +1268 -0
  2. package/AppSkin/AppSkin.js +2748 -0
  3. package/AppSkin/Themes/Default.css +241 -0
  4. package/Base/Base.js +3407 -0
  5. package/Base/ComponentIcons.css +66 -0
  6. package/Base/Font/ComponentIcons.woff +0 -0
  7. package/Base/Font/UI.woff +0 -0
  8. package/Base/Library.js +8432 -0
  9. package/Base/NavigationManager.js +462 -0
  10. package/Base/ResponsiveTemplates.js +371 -0
  11. package/Base/Sanitizer.js +288 -0
  12. package/Base/Themes/Default.css +255 -0
  13. package/Base/UI.css +618 -0
  14. package/Base/UIResourcePath.js +6 -0
  15. package/Bindary/Bindary.js +2011 -0
  16. package/Bindary/Modules/Connection.js +216 -0
  17. package/Bindary/Modules/Core.js +854 -0
  18. package/Bindary/Modules/DataUpdater.js +351 -0
  19. package/Bindary/Modules/ExpressionEngine.js +347 -0
  20. package/Bindary/Modules/ProxyManager.js +482 -0
  21. package/Bindary/Modules/Renderer.js +605 -0
  22. package/Bindary/Modules/Router.js +291 -0
  23. package/Bindary/Modules/Scroller.js +89 -0
  24. package/Bindary/Modules/Template.js +1273 -0
  25. package/BookmarkSpy/BookmarkSpy.js +430 -0
  26. package/Box/Box.css +36 -0
  27. package/Box/Box.js +1685 -0
  28. package/Button/Button.css +470 -0
  29. package/Button/Button.js +1398 -0
  30. package/Button/Themes/Default.css +200 -0
  31. package/Carousel/Carousel.css +273 -0
  32. package/Carousel/Carousel.js +607 -0
  33. package/ColorButton/ColorButton.css +39 -0
  34. package/ColorButton/ColorButton.js +336 -0
  35. package/ColorPicker/ColorPicker.css +359 -0
  36. package/ColorPicker/ColorPicker.js +972 -0
  37. package/ComboBox/ComboBox.css +357 -0
  38. package/ComboBox/ComboBox.js +2342 -0
  39. package/ComboBox/Themes/Default.css +23 -0
  40. package/DataPager/DataPager.css +72 -0
  41. package/DataPager/DataPager.js +674 -0
  42. package/DatePicker/DatePicker.css +227 -0
  43. package/DatePicker/DatePicker.js +1531 -0
  44. package/DatePicker/Themes/Default.css +26 -0
  45. package/Dialog/Dialog.css +106 -0
  46. package/Dialog/Dialog.js +572 -0
  47. package/Dialog/Themes/Default.css +10 -0
  48. package/Editor/Data/Emoji.json +8285 -0
  49. package/Editor/Data/Special.json +1042 -0
  50. package/Editor/Editor.css +1562 -0
  51. package/Editor/Editor.js +4058 -0
  52. package/Editor/Font/Editor.woff +0 -0
  53. package/Editor/Modules/ComponentFactory.js +565 -0
  54. package/Editor/Modules/ContentManager.js +748 -0
  55. package/Editor/Modules/DialogManager.js +1234 -0
  56. package/Editor/Modules/EventManager.js +458 -0
  57. package/Editor/Modules/Format.js +950 -0
  58. package/Editor/Modules/History.js +191 -0
  59. package/Editor/Modules/LayoutState.js +379 -0
  60. package/Editor/Modules/ListManager.js +296 -0
  61. package/Editor/Modules/MenuManager.js +388 -0
  62. package/Editor/Modules/NodeManager.js +681 -0
  63. package/Editor/Modules/ParagraphButtons.js +122 -0
  64. package/Editor/Modules/Resizer.js +176 -0
  65. package/Editor/Modules/SelectionRange.js +564 -0
  66. package/Editor/Modules/SourceViewBuilder.js +212 -0
  67. package/Editor/Modules/SymbolPicker.js +208 -0
  68. package/Editor/Modules/Table.js +2327 -0
  69. package/Editor/Modules/TableDialog.js +757 -0
  70. package/Editor/Modules/Toolbar.js +375 -0
  71. package/Editor/Modules/TooltipMenu.js +125 -0
  72. package/Editor/Modules/Utility.js +131 -0
  73. package/Editor/Themes/Default.css +204 -0
  74. package/FileUpload/FileUpload.css +156 -0
  75. package/FileUpload/FileUpload.js +898 -0
  76. package/FileUpload/Themes/Default.css +17 -0
  77. package/Form/Form.css +1934 -0
  78. package/Form/Form.js +4943 -0
  79. package/Form/Modules/ActionManager.js +368 -0
  80. package/Form/Modules/BuildPanelManager.js +319 -0
  81. package/Form/Modules/ComponentFactory.js +468 -0
  82. package/Form/Modules/ComponentPanel.js +265 -0
  83. package/Form/Modules/ConfigPanelManager.js +685 -0
  84. package/Form/Modules/DataBinder.js +602 -0
  85. package/Form/Modules/DataObserver.js +717 -0
  86. package/Form/Modules/Draggable.js +756 -0
  87. package/Form/Modules/OptionsPanel.js +342 -0
  88. package/Form/Modules/Renderer.js +1889 -0
  89. package/Form/Modules/RuleEngine.js +585 -0
  90. package/Form/Modules/RulesPanel.js +1158 -0
  91. package/Form/Modules/Types.js +1709 -0
  92. package/Form/Modules/ValidationManager.js +194 -0
  93. package/Form/Themes/Default.css +216 -0
  94. package/FormField/FormField.css +468 -0
  95. package/FormField/FormField.js +576 -0
  96. package/FormField/Themes/Default.css +99 -0
  97. package/Grid/Grid.css +544 -0
  98. package/Grid/Grid.js +3761 -0
  99. package/Grid/Themes/Default.css +43 -0
  100. package/LICENSE +126 -0
  101. package/MaskedTextBox/MaskedTextBox.css +28 -0
  102. package/MaskedTextBox/MaskedTextBox.js +642 -0
  103. package/MaskedTextBox/Themes/Default.css +6 -0
  104. package/Menu/Menu.css +328 -0
  105. package/Menu/Menu.js +2386 -0
  106. package/Menu/Themes/Default.css +24 -0
  107. package/NumericBox/NumericBox.css +120 -0
  108. package/NumericBox/NumericBox.js +984 -0
  109. package/PanelBar/PanelBar.css +123 -0
  110. package/PanelBar/PanelBar.js +505 -0
  111. package/PanelBar/Themes/Default.css +51 -0
  112. package/PieChart/PieChart.css +95 -0
  113. package/PieChart/PieChart.js +820 -0
  114. package/PieChart/Themes/Default.css +9 -0
  115. package/README.md +178 -3
  116. package/Slider/Slider.css +348 -0
  117. package/Slider/Slider.js +1306 -0
  118. package/Slider/Themes/Default.css +44 -0
  119. package/TabStrip/TabStrip.css +52 -0
  120. package/TabStrip/TabStrip.js +362 -0
  121. package/TabStrip/Themes/Default.css +35 -0
  122. package/TimePicker/Themes/Default.css +30 -0
  123. package/TimePicker/TimePicker.css +253 -0
  124. package/TimePicker/TimePicker.js +1485 -0
  125. package/TooltipManager/Themes/Default.css +21 -0
  126. package/TooltipManager/TooltipManager.css +227 -0
  127. package/TooltipManager/TooltipManager.js +791 -0
  128. package/Validator/Validator.css +54 -0
  129. package/Validator/Validator.js +2508 -0
  130. package/componyx.html-data.json +619 -0
  131. package/index.js +27 -0
  132. package/package.json +43 -4
  133. package/types/AppSkin.d.ts +842 -0
  134. package/types/Base.d.ts +1034 -0
  135. package/types/Bindary.d.ts +1196 -0
  136. package/types/BookmarkSpy.d.ts +112 -0
  137. package/types/Box.d.ts +374 -0
  138. package/types/Button.d.ts +455 -0
  139. package/types/Carousel.d.ts +136 -0
  140. package/types/ColorButton.d.ts +120 -0
  141. package/types/ColorPicker.d.ts +225 -0
  142. package/types/ComboBox.d.ts +507 -0
  143. package/types/DataPager.d.ts +152 -0
  144. package/types/DatePicker.d.ts +354 -0
  145. package/types/Dialog.d.ts +160 -0
  146. package/types/Editor.d.ts +1289 -0
  147. package/types/FileUpload.d.ts +206 -0
  148. package/types/Form.d.ts +3078 -0
  149. package/types/FormField.d.ts +204 -0
  150. package/types/Grid.d.ts +911 -0
  151. package/types/Library.d.ts +1899 -0
  152. package/types/MaskedTextBox.d.ts +91 -0
  153. package/types/Menu.d.ts +577 -0
  154. package/types/NumericBox.d.ts +310 -0
  155. package/types/PanelBar.d.ts +223 -0
  156. package/types/PieChart.d.ts +224 -0
  157. package/types/ResponsiveTemplates.d.ts +108 -0
  158. package/types/Slider.d.ts +227 -0
  159. package/types/TabStrip.d.ts +185 -0
  160. package/types/TimePicker.d.ts +265 -0
  161. package/types/TooltipManager.d.ts +178 -0
  162. package/types/UI.d.ts +29 -0
  163. package/types/Validator.d.ts +653 -0
  164. package/types/index.d.ts +59 -0
  165. package/ui.css +11783 -0
  166. package/ui.js +79477 -0
  167. package/ui.min.css +138 -0
  168. package/ui.min.js +264 -0
  169. package/ui.min.js.map +1 -0
@@ -0,0 +1,375 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ componyx.UI.editor_modules = componyx.UI.editor_modules || {};
3
+
4
+ /**
5
+ * Toolbar module — builds the editor toolbar, manages the toolbar box (floating/footer
6
+ * display modes), the "more" overflow box, symbol pickers, and box-hiding logic.
7
+ * @class Toolbar
8
+ * @memberof componyx.UI.editor_modules
9
+ * @ignore
10
+ */
11
+ componyx.UI.editor_modules.Toolbar = class Toolbar
12
+ {
13
+ #toolbarEl = null; // The toolbar <div>
14
+ #toolbarBox = null; // Floating Box component (for externalEditable / caret mode)
15
+ #toolbarMoreBox = null; // "More" overflow Box
16
+ #toolbarBoxTimerId = null;
17
+
18
+ #emojiPicker = null; // SymbolPicker instance
19
+ #specialPicker = null; // SymbolPicker instance
20
+
21
+ constructor(editor)
22
+ {
23
+ this.editor = editor;
24
+ this.cf = editor.componentFactory;
25
+ }
26
+
27
+ /** The root toolbar DOM element. */
28
+ get element() { return this.#toolbarEl; }
29
+
30
+ /** The emoji SymbolPicker instance (may be null). */
31
+ get emojiPicker() { return this.#emojiPicker; }
32
+
33
+ /** Returns true if the floating toolbar box is currently showing. */
34
+ get toolbarBoxShowing() { return this.#toolbarBox?.showing ?? false; }
35
+
36
+ /** The special-character SymbolPicker instance (may be null). */
37
+ get specialPicker() { return this.#specialPicker; }
38
+
39
+ /**
40
+ * Creates the toolbar DOM element and all its buttons.
41
+ * Must be called during draw().
42
+ */
43
+ createToolbar()
44
+ {
45
+ const editor = this.editor,
46
+ cf = editor.componentFactory,
47
+ co = editor.classOption,
48
+ commands = editor.commands,
49
+ sorted = editor.getSortedCommands();
50
+
51
+ this.#toolbarEl = editor.element.appendChild($lib.element());
52
+ this.#toolbarEl.className = editor.getCssClass(co.TOOLBAR);
53
+
54
+ // Populate & sort the shared sorted-commands array
55
+ $lib.each(commands, (cmd, key) =>
56
+ {
57
+ cmd.id = cmd.id || key;
58
+ cmd.name = key;
59
+ cmd.tooltip = editor.labels[`${cmd.name}CommandTooltip`] || cmd.tooltip;
60
+ sorted.push(cmd);
61
+
62
+ if (cmd.selector && !editor.selectableNodes.includes(cmd.selector))
63
+ editor.selectableNodes.push(cmd.selector); // the selector defines if elements created with this command are selectable
64
+ });
65
+
66
+ sorted.sort((a, b) =>
67
+ {
68
+ if (a.group < b.group) return -1;
69
+ if (a.group > b.group) return 1;
70
+ if (a.position < b.position) return -1;
71
+ if (a.position > b.position) return 1;
72
+ return 0;
73
+ });
74
+
75
+ let prevGroup, container, target = this.#toolbarEl;
76
+
77
+ $lib.each(sorted, (cmd) =>
78
+ {
79
+ if (!cmd.show)
80
+ return;
81
+
82
+ if (prevGroup !== cmd.group)
83
+ {
84
+ prevGroup = cmd.group;
85
+ container = $lib.element(target, '', '', '', '', { className: editor.getCssClass(co.GROUP) });
86
+ }
87
+
88
+ cf.createButton(cmd.id, cmd.buttonId, container, cmd);
89
+
90
+ if (cmd.id === 'more')
91
+ target = this.#createMoreBox();
92
+ });
93
+
94
+ // Undo/redo start disabled
95
+ const getId = (id) => editor.utility.getId(id);
96
+ $UI.store[getId('undo')]?.disable();
97
+ $UI.store[getId('redo')]?.disable();
98
+
99
+ return this.#toolbarEl;
100
+ }
101
+
102
+ /**
103
+ * Creates the floating toolbar Box (used in caret / externalEditable mode).
104
+ */
105
+ createToolbarBox()
106
+ {
107
+ const editor = this.editor;
108
+
109
+ this.#toolbarBox = this.cf.createBox('Toolbar', editor.toolbarBoxId, editor.element, { cssClass: editor.getCssClass(editor.classOption.TOOLBAR_BOX), content: this.#toolbarEl });
110
+ this.#toolbarBox.render();
111
+
112
+ $lib.on(this.#toolbarBox.element, 'pointerdown', () => { editor.allowToolbarBoxHide = false; });
113
+ }
114
+
115
+ /**
116
+ * Builds the emoji symbol picker.
117
+ */
118
+ async createEmojiSymbolPicker()
119
+ {
120
+ const editor = this.editor;
121
+ let path = editor.emojiSymbolResourcePath;
122
+
123
+ if (!editor.emojiSymbolData && !path)
124
+ return;
125
+
126
+ if (!editor.emojiSymbolData)
127
+ editor.emojiSymbolData = await editor.utility.fetchData(path);
128
+
129
+ this.#emojiPicker = new componyx.UI.editor_modules.SymbolPicker(
130
+ editor,
131
+ editor.emojiSymbolPickerBoxId,
132
+ 'EmojiSymbolPicker',
133
+ editor.getCssClass(editor.classOption.EMOJI_SYMBOL_PICKER),
134
+ editor.labels.emojiSymbolCategories,
135
+ editor.emojiSymbolData
136
+ );
137
+ }
138
+
139
+ /**
140
+ * Builds the special-character symbol picker.
141
+ */
142
+ async createSpecialSymbolPicker()
143
+ {
144
+ const editor = this.editor;
145
+ let path = editor.specialSymbolResourcePath;
146
+
147
+ if (!editor.specialSymbolData && !path)
148
+ return;
149
+
150
+ if (!editor.specialSymbolData)
151
+ editor.specialSymbolData = await editor.utility.fetchData(path);
152
+
153
+ this.#specialPicker = new componyx.UI.editor_modules.SymbolPicker(
154
+ editor,
155
+ editor.specialSymbolPickerBoxId,
156
+ 'SpecialSymbolPicker',
157
+ editor.getCssClass(editor.classOption.SPECIAL_SYMBOL_PICKER),
158
+ editor.labels.specialSymbolCategories,
159
+ editor.specialSymbolData
160
+ );
161
+ }
162
+
163
+ /**
164
+ * Schedules showing or hiding the toolbar box.
165
+ * @param {boolean} [show=true]
166
+ */
167
+ setToolbarBoxDisplay(show = true)
168
+ {
169
+ const editor = this.editor,
170
+ isFullscreen = editor.element.className.includes(' fullscreen');
171
+
172
+ if (!this.#toolbarBox || editor.renderState !== 2 || (!show && isFullscreen))
173
+ return;
174
+
175
+ if (!editor.allowToolbarBoxHide && !show)
176
+ {
177
+ editor.allowToolbarBoxHide = true;
178
+ return;
179
+ }
180
+
181
+ clearTimeout(this.#toolbarBoxTimerId);
182
+ this.#toolbarBoxTimerId = setTimeout(() =>
183
+ {
184
+ if (show)
185
+ this.#showToolbarBox();
186
+ else
187
+ this.#toolbarBox.hide();
188
+ }, 0);
189
+ }
190
+
191
+ /**
192
+ * Enables or disables all visible toolbar buttons (with optional exclusions).
193
+ * @param {boolean} enable
194
+ * @param {string[]} [exclude=[]] Command ids to leave unchanged.
195
+ */
196
+ setButtonState(enable, exclude = [])
197
+ {
198
+ const editor = this.editor,
199
+ getId = (id) => editor.utility.getId(id);
200
+
201
+ $lib.each(editor.getSortedCommands(), (cmd) =>
202
+ {
203
+ if (!cmd.show || exclude.includes(cmd.id))
204
+ return;
205
+
206
+ const button = $UI.store[getId(cmd.id)];
207
+
208
+ if (!button) return;
209
+
210
+ if (enable && button.disabled)
211
+ button.enable();
212
+ else if (!enable && !button.disabled)
213
+ button.disable();
214
+ });
215
+ }
216
+
217
+ /**
218
+ * Hides all open overlay boxes (color swatch, symbol pickers, more box)
219
+ * that should close when the user interacts elsewhere.
220
+ * @param {Event} e
221
+ */
222
+ hideBoxes(e)
223
+ {
224
+ const editor = this.editor,
225
+ target = e.target,
226
+ getId = (id) => editor.utility.getId(id),
227
+ cmds = editor.commands,
228
+ fontColor = cmds.fontColor,
229
+ fontBGColor = cmds.fontBGColor,
230
+ emoji = cmds.emoji,
231
+ special = cmds.special,
232
+ cf = editor.componentFactory,
233
+ colorSwatchBox = cf.colorSwatchBox,
234
+ colorPicker = cf.colorPicker,
235
+ tablePickerBox = editor.table.pickerBox,
236
+ swatchShowing = colorSwatchBox?.showing,
237
+ emojiShowing = this.#emojiPicker?.box.showing,
238
+ specialShowing = this.#specialPicker?.box.showing,
239
+ moreEl = this.#toolbarMoreBox?.element;
240
+
241
+ const toolbarMoreIsActive =
242
+ (swatchShowing && fontColor && moreEl?.contains($UI.store[getId(fontColor.id)]?.element)) ||
243
+ (swatchShowing && fontBGColor && moreEl?.contains($UI.store[getId(fontBGColor.id)]?.element)) ||
244
+ (emojiShowing && emoji && moreEl?.contains($UI.store[getId(emoji.id)]?.element)) ||
245
+ (specialShowing && special && moreEl?.contains($UI.store[getId(special.id)]?.element));
246
+
247
+ if (this.#allowHide(target, [colorSwatchBox?.element, colorPicker?.element]))
248
+ colorSwatchBox?.hide();
249
+
250
+ if (this.#emojiPicker && this.#allowHide(target, [this.#emojiPicker.box.element]))
251
+ this.#emojiPicker.box.hide();
252
+
253
+ if (this.#specialPicker && this.#allowHide(target, [this.#specialPicker.box.element]))
254
+ this.#specialPicker.box.hide();
255
+
256
+ if (tablePickerBox && this.#allowHide(target, [tablePickerBox.element]))
257
+ tablePickerBox.hide();
258
+
259
+ if (this.#toolbarMoreBox && !toolbarMoreIsActive && this.#allowHide(target, [moreEl]))
260
+ {
261
+ this.#toolbarMoreBox.hide();
262
+ $UI.store[getId('more')]?.deselect();
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Opens the special-character picker anchored to its toolbar button.
268
+ * @param {Object} cmd The command settings object.
269
+ */
270
+ showSpecialSymbolPicker(cmd) { this.#specialPicker?.show(cmd); }
271
+
272
+ /**
273
+ * Opens the emoji picker anchored to its toolbar button.
274
+ * @param {Object} cmd The command settings object.
275
+ */
276
+ showEmojiSymbolPicker(cmd) { this.#emojiPicker?.show(cmd); }
277
+
278
+ /**
279
+ * Creates the "more" overflow Box and returns the content container element.
280
+ * @returns {HTMLElement}
281
+ */
282
+ #createMoreBox()
283
+ {
284
+ const editor = this.editor,
285
+ content = $lib.element();
286
+
287
+ this.#toolbarMoreBox = this.cf.createBox('ToolbarMore', editor.toolbarMoreBoxId, editor.element, { cssClass: editor.getCssClass(editor.classOption.TOOLBAR_MORE), content });
288
+ this.#toolbarMoreBox.render();
289
+
290
+ return content;
291
+ }
292
+
293
+ /**
294
+ * Positions and shows the floating toolbar box based on display mode and caret position.
295
+ */
296
+ #showToolbarBox()
297
+ {
298
+ const editor = this.editor,
299
+ sr = editor.selectionRange,
300
+ editableEl = editor.getEditorElement(),
301
+ boxOptions = componyx.UI.Box,
302
+ isFullscreen = editor.element.className.includes(' fullscreen'),
303
+ toolbarDisplay = editor.getToolbarDisplay(editableEl),
304
+ tdOption = componyx.UI.Editor.ToolbarDisplayOption,
305
+ width = editableEl.offsetWidth / 3;
306
+
307
+ this.#toolbarBox.expander = editableEl;
308
+ this.#toolbarBox.alignX = null;
309
+ this.#toolbarBox.expandDirection = boxOptions.ExpandDirectionOption.UP;
310
+
311
+ if (!isFullscreen && toolbarDisplay === tdOption.CARET)
312
+ {
313
+ const range = sr.getRange();
314
+
315
+ if (range.collapsed)
316
+ return;
317
+
318
+ const rect = this.#getCaretCoordinates();
319
+
320
+ this.#toolbarBox.expander = sr.getRootNodesInRange(range)[0];
321
+ this.#toolbarBox.alignX = boxOptions.AlignXOption.CENTER;
322
+
323
+ if (rect.x <= width)
324
+ this.#toolbarBox.alignX = boxOptions.AlignXOption.LEFT;
325
+ else if (rect.x > width * 2)
326
+ this.#toolbarBox.alignX = boxOptions.AlignXOption.RIGHT;
327
+ }
328
+ else if (toolbarDisplay === tdOption.HEADER || toolbarDisplay === tdOption.CARET)
329
+ this.#toolbarBox.expandDirection = boxOptions.ExpandDirectionOption.UP;
330
+ else
331
+ this.#toolbarBox.expandDirection = boxOptions.ExpandDirectionOption.DOWN;
332
+
333
+ this.#toolbarBox.update(null, true);
334
+ }
335
+
336
+ /**
337
+ * Gets the {x, y} screen coordinates of the caret.
338
+ * @returns {{ x: number, y: number }}
339
+ */
340
+ #getCaretCoordinates()
341
+ {
342
+ const range = this.editor.selectionRange.getRange().cloneRange();
343
+ range.collapse(true);
344
+
345
+ const rect = range.getClientRects()[0];
346
+ return rect ? { x: rect.left, y: rect.top } : { x: 0, y: 0 };
347
+ }
348
+
349
+ /**
350
+ * Returns true when it is safe to hide a box (i.e. the active element is not
351
+ * inside any of the provided elements).
352
+ * @param {Element} activeEl
353
+ * @param {Array<Element|undefined>} elements
354
+ * @returns {boolean}
355
+ */
356
+ #allowHide(activeEl, elements)
357
+ {
358
+ if (!activeEl)
359
+ return true;
360
+
361
+ let allow = true;
362
+
363
+ $lib.each(elements, (el) =>
364
+ {
365
+ if (!el) return;
366
+ return (allow = activeEl !== el && !el.contains(activeEl));
367
+ });
368
+
369
+ return allow;
370
+ }
371
+ };
372
+
373
+ var Toolbar = componyx.UI.editor_modules.Toolbar;
374
+
375
+ export { Toolbar as default };
@@ -0,0 +1,125 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ componyx.UI.editor_modules = componyx.UI.editor_modules || {};
3
+
4
+ /**
5
+ * TooltipMenu module - manages the contextual tooltip that appears on link, image and media selection.
6
+ * @class TooltipMenu
7
+ * @memberof componyx.UI.editor_modules
8
+ * @ignore
9
+ */
10
+ componyx.UI.editor_modules.TooltipMenu = class TooltipMenu
11
+ {
12
+ #tooltipId = null;
13
+ #menu = { link: null, editButton: null, removeButton: null };
14
+
15
+ constructor(editor)
16
+ {
17
+ this.editor = editor;
18
+ this.utility = editor.utility;
19
+ this.tooltipManager = editor.componentFactory.createTooltipManager('documentTooltipManager', editor.documentTooltipManagerId, editor.element, { cssClass: editor.getCssClass(editor.classOption.DOC_TOOLTIPS), showOnPointerEvent: 0 });
20
+ }
21
+
22
+ show(node)
23
+ {
24
+ const layout = this.editor.layoutState.activeLayout,
25
+ menu = this.#menu;
26
+
27
+ // Show tooltip only when a supported layout is active.
28
+ if (!layout.link && !layout.image && !layout.media)
29
+ return;
30
+
31
+ if (!menu.link)
32
+ this.#create();
33
+
34
+ // Show link only when editing a hyperlink.
35
+ menu.link.style.display = 'none';
36
+
37
+ if (layout.link?.href)
38
+ {
39
+ menu.link.style.display = '';
40
+ menu.link.href = layout.link.href;
41
+ menu.link.textContent = layout.link.href;
42
+ }
43
+
44
+ this.tooltipManager.addTrigger(node, this.#tooltipId);
45
+ this.tooltipManager.showTooltip(node);
46
+ }
47
+
48
+ dispose()
49
+ {
50
+ this.tooltipManager?.destroy();
51
+ this.tooltipManager = null;
52
+ }
53
+
54
+ #create()
55
+ {
56
+ const content = $lib.element();
57
+
58
+ this.#tooltipId = this.utility.getId('selectedNode');
59
+
60
+ this.#buildMenu(content);
61
+
62
+ $lib.on(content, 'pointerdown', () =>
63
+ {
64
+ this.editor.allowToolbarBoxHide = false;
65
+ });
66
+
67
+ this.tooltipManager.addTooltip(this.#tooltipId, content, false);
68
+ }
69
+
70
+ #buildMenu(content)
71
+ {
72
+ const templateId = 'TooltipMenu',
73
+ buttonCss = `${this.utility.buttonLucentCss} ${this.editor.getThemeCSS()}`,
74
+ linkCss = this.editor.getCssClass(this.editor.classOption.TOOLTIP_MENU_LINK),
75
+ values =
76
+ {
77
+ link: `<a class="${linkCss}" target="_blank">`,
78
+ editButton: `<a class="${buttonCss} edit ico-pencil">`,
79
+ removeButton: `<a class="${buttonCss} remove ico-bin">`
80
+ };
81
+
82
+ values['/link'] = values['/editButton'] = values['/removeButton'] = '</a>';
83
+
84
+ if (!this.editor.hasTemplate(templateId))
85
+ this.editor.addTemplate(templateId, '{link}{/link}{editButton}{/editButton}{removeButton}{/removeButton}', true);
86
+
87
+ this.editor.applyTemplate(content, templateId, values);
88
+
89
+ const menu = this.#menu;
90
+
91
+ menu.link = content.querySelector(`a.${linkCss.replaceAll(' ', '.')}`);
92
+ menu.editButton = content.querySelector(`a.${buttonCss.replaceAll(' ', '.')}.edit`);
93
+ menu.removeButton = content.querySelector(`a.${buttonCss.replaceAll(' ', '.')}.remove`);
94
+
95
+ menu.editButton.onclick = () =>
96
+ {
97
+ const layout = this.editor.layoutState.activeLayout;
98
+
99
+ if (layout.link)
100
+ this.editor.insertLink();
101
+ else if (layout.image)
102
+ this.editor.insertImage();
103
+ else if (layout.media)
104
+ this.editor.insertMedia();
105
+ };
106
+
107
+ menu.removeButton.onclick = () =>
108
+ {
109
+ const layout = this.editor.layoutState.activeLayout;
110
+
111
+ this.tooltipManager.hideAllTooltips(true);
112
+
113
+ if (layout.link)
114
+ this.editor.removeLink();
115
+ else if (layout.image)
116
+ this.editor.removeImage();
117
+ else if (layout.media)
118
+ this.editor.removeMedia();
119
+ };
120
+ }
121
+ };
122
+
123
+ var TooltipMenu = componyx.UI.editor_modules.TooltipMenu;
124
+
125
+ export { TooltipMenu as default };
@@ -0,0 +1,131 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ componyx.UI.editor_modules = componyx.UI.editor_modules || {};
3
+
4
+ /**
5
+ * Utility module - common helper functions.
6
+ * @class Utility
7
+ * @memberof componyx.UI.editor_modules
8
+ * @ignore
9
+ */
10
+ componyx.UI.editor_modules.Utility = class Utility
11
+ {
12
+ constructor(editor)
13
+ {
14
+ this.editor = editor;
15
+ this.webFonts = ["Helvetica", "Arial", "Arial Black", "Verdana", "Tahoma", "Trebuchet MS", "Impact", "Gill Sans", "Times New Roman", "Georgia", "Palatino", "Baskerville", "Andal� Mon", "Courier", "Lucida", "Monaco", "Bradley Hand", "Brush Script MT", "Luminari", "Comic Sans MS"];
16
+ this.zeroWidthChar = '\uFEFF';
17
+ this.tabChar = '\u2003';
18
+ this.attrPrefix = 'data-ui-editor-';
19
+ this.iconPrefix = 'ico-editor-';
20
+ this.markerAttr = this.attrPrefix + 'marker';
21
+ this.selAttr = this.attrPrefix + 'selected';
22
+ this.tableIdAttr = this.attrPrefix + 'te-id';
23
+ this.localStoragePrefix = 'componyx.UI.Editor.';
24
+ this.zeroWidthRegEx = /[\uFEFF]/gm;
25
+ this.prevWordRegEx = /([\s])*([^\s]*$|[\uFEFF]+$)/m;
26
+ this.nextWordRegEx = /(^[^\s]*|^[\uFEFF]+)([\s]*)/m;
27
+ this.voidNodeRegEx = /^(AREA|BASE|BR|COL|EMBED|HR|IMG|INPUT|LINK|META|SOURCE|TRACK|WBR)$/i;
28
+ this.blockNodeRegEx = /^(FIGURE|UL|OL|DIV|P|H\d+)$/i;
29
+ this.wrappedNodesRegEx = /^(TABLE|HR|OBJECT|EMBED|SVG|VIDEO)$/i;
30
+ this.figureNodesRegEx = /^(IMG|VIDEO|TABLE|SVG|EMBED|OBJECT)$/i;
31
+ this.layoutNodeNames = ['strong', 'em', 'u', 's', 'sub', 'sup', 'span'];
32
+ this.listFilter = 'UL,OL';
33
+ this.buttonCss = 'button theme basic';
34
+ this.buttonLucentCss = this.buttonCss + ' lucent';
35
+ this.cssVariables = {
36
+ fontColor: '--font-color',
37
+ fontBGColor: '--font-bg-color'
38
+ };
39
+ }
40
+
41
+ /** Returns a new identifier. */
42
+ newGuid()
43
+ {
44
+ return this.editor.id + '_' + $lib.guid();
45
+ }
46
+
47
+ /**
48
+ * Gets an ID with the editor prefix
49
+ * @param {string} id
50
+ */
51
+ getId(id)
52
+ {
53
+ return this.editor.id + '_' + id;
54
+ }
55
+
56
+ /**
57
+ * Returns a value indicating if the key is a printable character.
58
+ * @param {Event} e
59
+ */
60
+ isPrintableChar(e)
61
+ {
62
+ return ' capslock shift backspace control tab enter insert delete home end pageup pagedown arrowleft arrowright arrowup arrowdown numlock '.indexOf(' ' + e.key.toLowerCase() + ' ') == -1 && !e.ctrlKey;
63
+ }
64
+
65
+ /**
66
+ * Converts the color to CSS rgba string.
67
+ * @param {string[]|string} color
68
+ */
69
+ toCSSColor(color)
70
+ {
71
+ if ($lib.isArray(color))
72
+ return `rgba(${color.join(',')})`;
73
+ else
74
+ return color;
75
+ }
76
+
77
+ /**
78
+ * Saves scroll position
79
+ * @param {HTMLElement} source
80
+ */
81
+ saveScroll(source)
82
+ {
83
+ let values = [source.scrollTop, source.scrollLeft];
84
+ source.scrollTop = source.scrollLeft = 0;
85
+ return values;
86
+ }
87
+
88
+ /**
89
+ * Resets scroll position
90
+ * @param {HTMLElement} source
91
+ * @param {Array} values
92
+ */
93
+ resetScroll(source, values)
94
+ {
95
+ source.scrollTop = values[0];
96
+ source.scrollLeft = values[1];
97
+ }
98
+
99
+ /**
100
+ * Gets the corresponding content editable element.
101
+ * @param {any} activeNode
102
+ */
103
+ getContentEditable(activeNode)
104
+ {
105
+ let element = activeNode;
106
+
107
+ if (element && element.window === element) // focus/blur in iframe mode fire on the window
108
+ element = element.document.body;
109
+ else if (element && element.nodeType !== Node.ELEMENT_NODE) // selection nodes are often text nodes, which have no closest()
110
+ element = element.parentElement;
111
+
112
+ if (!element)
113
+ return null;
114
+
115
+ return element.closest(`.editor[contenteditable="true"]`) || element.closest(`.${this.editor.getCssClass(this.editor.classOption.CONTENT)}[contenteditable="true"]`);
116
+ }
117
+
118
+ /**
119
+ * Fetches the data resource with the specified path.
120
+ * @param {string} path The path of the resource file.
121
+ */
122
+ async fetchData(path)
123
+ {
124
+ let response = await fetch(path);
125
+ return await response.json();
126
+ }
127
+ };
128
+
129
+ var Utility = componyx.UI.editor_modules.Utility;
130
+
131
+ export { Utility as default };