@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.
- package/AppSkin/AppSkin.css +1268 -0
- package/AppSkin/AppSkin.js +2748 -0
- package/AppSkin/Themes/Default.css +241 -0
- package/Base/Base.js +3407 -0
- package/Base/ComponentIcons.css +66 -0
- package/Base/Font/ComponentIcons.woff +0 -0
- package/Base/Font/UI.woff +0 -0
- package/Base/Library.js +8432 -0
- package/Base/NavigationManager.js +462 -0
- package/Base/ResponsiveTemplates.js +371 -0
- package/Base/Sanitizer.js +288 -0
- package/Base/Themes/Default.css +255 -0
- package/Base/UI.css +618 -0
- package/Base/UIResourcePath.js +6 -0
- package/Bindary/Bindary.js +2011 -0
- package/Bindary/Modules/Connection.js +216 -0
- package/Bindary/Modules/Core.js +854 -0
- package/Bindary/Modules/DataUpdater.js +351 -0
- package/Bindary/Modules/ExpressionEngine.js +347 -0
- package/Bindary/Modules/ProxyManager.js +482 -0
- package/Bindary/Modules/Renderer.js +605 -0
- package/Bindary/Modules/Router.js +291 -0
- package/Bindary/Modules/Scroller.js +89 -0
- package/Bindary/Modules/Template.js +1273 -0
- package/BookmarkSpy/BookmarkSpy.js +430 -0
- package/Box/Box.css +36 -0
- package/Box/Box.js +1685 -0
- package/Button/Button.css +470 -0
- package/Button/Button.js +1398 -0
- package/Button/Themes/Default.css +200 -0
- package/Carousel/Carousel.css +273 -0
- package/Carousel/Carousel.js +607 -0
- package/ColorButton/ColorButton.css +39 -0
- package/ColorButton/ColorButton.js +336 -0
- package/ColorPicker/ColorPicker.css +359 -0
- package/ColorPicker/ColorPicker.js +972 -0
- package/ComboBox/ComboBox.css +357 -0
- package/ComboBox/ComboBox.js +2342 -0
- package/ComboBox/Themes/Default.css +23 -0
- package/DataPager/DataPager.css +72 -0
- package/DataPager/DataPager.js +674 -0
- package/DatePicker/DatePicker.css +227 -0
- package/DatePicker/DatePicker.js +1531 -0
- package/DatePicker/Themes/Default.css +26 -0
- package/Dialog/Dialog.css +106 -0
- package/Dialog/Dialog.js +572 -0
- package/Dialog/Themes/Default.css +10 -0
- package/Editor/Data/Emoji.json +8285 -0
- package/Editor/Data/Special.json +1042 -0
- package/Editor/Editor.css +1562 -0
- package/Editor/Editor.js +4058 -0
- package/Editor/Font/Editor.woff +0 -0
- package/Editor/Modules/ComponentFactory.js +565 -0
- package/Editor/Modules/ContentManager.js +748 -0
- package/Editor/Modules/DialogManager.js +1234 -0
- package/Editor/Modules/EventManager.js +458 -0
- package/Editor/Modules/Format.js +950 -0
- package/Editor/Modules/History.js +191 -0
- package/Editor/Modules/LayoutState.js +379 -0
- package/Editor/Modules/ListManager.js +296 -0
- package/Editor/Modules/MenuManager.js +388 -0
- package/Editor/Modules/NodeManager.js +681 -0
- package/Editor/Modules/ParagraphButtons.js +122 -0
- package/Editor/Modules/Resizer.js +176 -0
- package/Editor/Modules/SelectionRange.js +564 -0
- package/Editor/Modules/SourceViewBuilder.js +212 -0
- package/Editor/Modules/SymbolPicker.js +208 -0
- package/Editor/Modules/Table.js +2327 -0
- package/Editor/Modules/TableDialog.js +757 -0
- package/Editor/Modules/Toolbar.js +375 -0
- package/Editor/Modules/TooltipMenu.js +125 -0
- package/Editor/Modules/Utility.js +131 -0
- package/Editor/Themes/Default.css +204 -0
- package/FileUpload/FileUpload.css +156 -0
- package/FileUpload/FileUpload.js +898 -0
- package/FileUpload/Themes/Default.css +17 -0
- package/Form/Form.css +1934 -0
- package/Form/Form.js +4943 -0
- package/Form/Modules/ActionManager.js +368 -0
- package/Form/Modules/BuildPanelManager.js +319 -0
- package/Form/Modules/ComponentFactory.js +468 -0
- package/Form/Modules/ComponentPanel.js +265 -0
- package/Form/Modules/ConfigPanelManager.js +685 -0
- package/Form/Modules/DataBinder.js +602 -0
- package/Form/Modules/DataObserver.js +717 -0
- package/Form/Modules/Draggable.js +756 -0
- package/Form/Modules/OptionsPanel.js +342 -0
- package/Form/Modules/Renderer.js +1889 -0
- package/Form/Modules/RuleEngine.js +585 -0
- package/Form/Modules/RulesPanel.js +1158 -0
- package/Form/Modules/Types.js +1709 -0
- package/Form/Modules/ValidationManager.js +194 -0
- package/Form/Themes/Default.css +216 -0
- package/FormField/FormField.css +468 -0
- package/FormField/FormField.js +576 -0
- package/FormField/Themes/Default.css +99 -0
- package/Grid/Grid.css +544 -0
- package/Grid/Grid.js +3761 -0
- package/Grid/Themes/Default.css +43 -0
- package/LICENSE +126 -0
- package/MaskedTextBox/MaskedTextBox.css +28 -0
- package/MaskedTextBox/MaskedTextBox.js +642 -0
- package/MaskedTextBox/Themes/Default.css +6 -0
- package/Menu/Menu.css +328 -0
- package/Menu/Menu.js +2386 -0
- package/Menu/Themes/Default.css +24 -0
- package/NumericBox/NumericBox.css +120 -0
- package/NumericBox/NumericBox.js +984 -0
- package/PanelBar/PanelBar.css +123 -0
- package/PanelBar/PanelBar.js +505 -0
- package/PanelBar/Themes/Default.css +51 -0
- package/PieChart/PieChart.css +95 -0
- package/PieChart/PieChart.js +820 -0
- package/PieChart/Themes/Default.css +9 -0
- package/README.md +178 -3
- package/Slider/Slider.css +348 -0
- package/Slider/Slider.js +1306 -0
- package/Slider/Themes/Default.css +44 -0
- package/TabStrip/TabStrip.css +52 -0
- package/TabStrip/TabStrip.js +362 -0
- package/TabStrip/Themes/Default.css +35 -0
- package/TimePicker/Themes/Default.css +30 -0
- package/TimePicker/TimePicker.css +253 -0
- package/TimePicker/TimePicker.js +1485 -0
- package/TooltipManager/Themes/Default.css +21 -0
- package/TooltipManager/TooltipManager.css +227 -0
- package/TooltipManager/TooltipManager.js +791 -0
- package/Validator/Validator.css +54 -0
- package/Validator/Validator.js +2508 -0
- package/componyx.html-data.json +619 -0
- package/index.js +27 -0
- package/package.json +43 -4
- package/types/AppSkin.d.ts +842 -0
- package/types/Base.d.ts +1034 -0
- package/types/Bindary.d.ts +1196 -0
- package/types/BookmarkSpy.d.ts +112 -0
- package/types/Box.d.ts +374 -0
- package/types/Button.d.ts +455 -0
- package/types/Carousel.d.ts +136 -0
- package/types/ColorButton.d.ts +120 -0
- package/types/ColorPicker.d.ts +225 -0
- package/types/ComboBox.d.ts +507 -0
- package/types/DataPager.d.ts +152 -0
- package/types/DatePicker.d.ts +354 -0
- package/types/Dialog.d.ts +160 -0
- package/types/Editor.d.ts +1289 -0
- package/types/FileUpload.d.ts +206 -0
- package/types/Form.d.ts +3078 -0
- package/types/FormField.d.ts +204 -0
- package/types/Grid.d.ts +911 -0
- package/types/Library.d.ts +1899 -0
- package/types/MaskedTextBox.d.ts +91 -0
- package/types/Menu.d.ts +577 -0
- package/types/NumericBox.d.ts +310 -0
- package/types/PanelBar.d.ts +223 -0
- package/types/PieChart.d.ts +224 -0
- package/types/ResponsiveTemplates.d.ts +108 -0
- package/types/Slider.d.ts +227 -0
- package/types/TabStrip.d.ts +185 -0
- package/types/TimePicker.d.ts +265 -0
- package/types/TooltipManager.d.ts +178 -0
- package/types/UI.d.ts +29 -0
- package/types/Validator.d.ts +653 -0
- package/types/index.d.ts +59 -0
- package/ui.css +11783 -0
- package/ui.js +79477 -0
- package/ui.min.css +138 -0
- package/ui.min.js +264 -0
- 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 };
|