@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,681 @@
|
|
|
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
|
+
* NodeManager module - node manipulation and tree operations.
|
|
6
|
+
* @class NodeManager
|
|
7
|
+
* @memberof componyx.UI.editor_modules
|
|
8
|
+
* @ignore
|
|
9
|
+
*/
|
|
10
|
+
componyx.UI.editor_modules.NodeManager = class NodeManager
|
|
11
|
+
{
|
|
12
|
+
constructor(editor)
|
|
13
|
+
{
|
|
14
|
+
this.editor = editor;
|
|
15
|
+
this.utility = editor.utility;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns a value indicating if the node is a bookmark node.
|
|
20
|
+
* @param {Node} node
|
|
21
|
+
*/
|
|
22
|
+
isBookmark(node)
|
|
23
|
+
{
|
|
24
|
+
return node && node.nodeType == 1 && node.nodeName == 'A' && node.hasAttribute('id') && !node.hasAttribute('href');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns a value indicating if the node contains an image.
|
|
29
|
+
* @param {Node} node
|
|
30
|
+
*/
|
|
31
|
+
isImage(node)
|
|
32
|
+
{
|
|
33
|
+
return node && node.nodeType == 1 && !!node.querySelector(':scope > img');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns a value indicating if the node is a media node.
|
|
38
|
+
* @param {Node} node
|
|
39
|
+
*/
|
|
40
|
+
isMedia(node)
|
|
41
|
+
{
|
|
42
|
+
return node && node.nodeType == 1 && node.nodeName == 'FIGURE' && node.hasAttribute(this.utility.attrPrefix + 'media');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns a value indicating if the node is a link node.
|
|
47
|
+
* @param {Node} node
|
|
48
|
+
*/
|
|
49
|
+
isLink(node)
|
|
50
|
+
{
|
|
51
|
+
return node && node.nodeType == 1 && node.nodeName == 'A' && node.href;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns a value indicating if the node matches the tag.
|
|
56
|
+
* @param {string[]|string} tag
|
|
57
|
+
* @param {Node} node
|
|
58
|
+
*/
|
|
59
|
+
isTagMatch(tag, node)
|
|
60
|
+
{
|
|
61
|
+
let isMatch = false, name = node.nodeName.toLowerCase();
|
|
62
|
+
tag = ($lib.isArray(tag)) ? tag : [tag];
|
|
63
|
+
|
|
64
|
+
$lib.each(tag, function (t)
|
|
65
|
+
{
|
|
66
|
+
isMatch = (name == t.toLowerCase());
|
|
67
|
+
return !isMatch;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return isMatch;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns a value indicating if the node is a block node.
|
|
75
|
+
* @param {Node} node
|
|
76
|
+
*/
|
|
77
|
+
isBlock(node, includeWrapped = false)
|
|
78
|
+
{
|
|
79
|
+
if (!node || node.nodeType != 1)
|
|
80
|
+
return false;
|
|
81
|
+
|
|
82
|
+
let name = node.nodeName;
|
|
83
|
+
|
|
84
|
+
if (!includeWrapped && name.match(this.utility.wrappedNodesRegEx))
|
|
85
|
+
return false;
|
|
86
|
+
else if (name.match(this.utility.blockNodeRegEx))
|
|
87
|
+
return true;
|
|
88
|
+
|
|
89
|
+
return window.getComputedStyle(node, null).getPropertyValue('position') == 'static' && window.getComputedStyle(node, null).getPropertyValue('display') == 'block';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Returns a value indicating if the node is a list node.
|
|
94
|
+
* @param {Node} node
|
|
95
|
+
*/
|
|
96
|
+
isList(node)
|
|
97
|
+
{
|
|
98
|
+
return node.nodeType == 1 && 'UL OL'.split(' ').indexOf(node.nodeName) > -1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns a value indicating if the node is a root node for layout elements (LI).
|
|
103
|
+
* @param {Node} node
|
|
104
|
+
*/
|
|
105
|
+
isLayoutRoot(node)
|
|
106
|
+
{
|
|
107
|
+
return node.nodeType == 1 && 'LI'.split(' ').indexOf(node.nodeName) > -1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Returns a value indicating if the node is a layout node.
|
|
112
|
+
* @param {Node} node
|
|
113
|
+
*/
|
|
114
|
+
isLayoutNode(node)
|
|
115
|
+
{
|
|
116
|
+
return this.isTextDecorationNode(node) || this.isStyleNode(node);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Returns a value indicating if the node is a text decoration node.
|
|
121
|
+
* @param {Node} node
|
|
122
|
+
*/
|
|
123
|
+
isTextDecorationNode(node)
|
|
124
|
+
{
|
|
125
|
+
return node.nodeType == 1 && $lib.isEmpty(node.id) && this.utility.layoutNodeNames.filter((val) => { return val != 'span' }).indexOf(node.nodeName.toLowerCase()) > -1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns a value indicating if the node is a style node.
|
|
130
|
+
* @param {Node} node
|
|
131
|
+
*/
|
|
132
|
+
isStyleNode(node)
|
|
133
|
+
{
|
|
134
|
+
return node.nodeType == 1 && node.nodeName == 'SPAN' && !$lib.isEmpty(node.style.cssText);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Returns a value indicating if the parent node contains the node.
|
|
139
|
+
* @param {Node} parent
|
|
140
|
+
* @param {Node} node
|
|
141
|
+
*/
|
|
142
|
+
contains(parent, node)
|
|
143
|
+
{
|
|
144
|
+
return $lib.contains(parent, node);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Gets the image element inside the figure element.
|
|
149
|
+
* @param {Node} el
|
|
150
|
+
*/
|
|
151
|
+
getImageFromNode(el)
|
|
152
|
+
{
|
|
153
|
+
return el.nodeName === 'IMG' ? el : el.querySelector('img');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Gets the node with the specified node name inside the specified element.
|
|
158
|
+
* @param {Node} el The root element from where to search.
|
|
159
|
+
* @param {String} name The name of the node to find.
|
|
160
|
+
*/
|
|
161
|
+
getInnerNodeByName(el, name)
|
|
162
|
+
{
|
|
163
|
+
if (el.nodeName === name) return el;
|
|
164
|
+
return el.querySelector(name);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Gets the root node (block) for the specified node.
|
|
169
|
+
* @param {Node} node
|
|
170
|
+
* @param {boolean} [useLayoutRoot = true]
|
|
171
|
+
*/
|
|
172
|
+
getRootNode(node, useLayoutRoot = true)
|
|
173
|
+
{
|
|
174
|
+
let editableElement = this.editor.getEditorElement();
|
|
175
|
+
|
|
176
|
+
if (node == editableElement)
|
|
177
|
+
return node.firstChild;
|
|
178
|
+
else if (node.parentElement == editableElement)
|
|
179
|
+
return node;
|
|
180
|
+
|
|
181
|
+
while (node)
|
|
182
|
+
{
|
|
183
|
+
if (node.parentElement && !this.isBlock(node) && (!useLayoutRoot || !this.isLayoutRoot(node)))
|
|
184
|
+
node = node.parentElement;
|
|
185
|
+
else
|
|
186
|
+
return node;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Gets the surrounding nodes for the specified element.
|
|
192
|
+
* @param {Node} el
|
|
193
|
+
* @param {Node} rootEl
|
|
194
|
+
*/
|
|
195
|
+
getSurroundingNodes(el, rootEl)
|
|
196
|
+
{
|
|
197
|
+
let editableElement = this.editor.getEditorElement(),
|
|
198
|
+
nodes = [];
|
|
199
|
+
|
|
200
|
+
rootEl = rootEl || editableElement;
|
|
201
|
+
|
|
202
|
+
while (el && el != rootEl)
|
|
203
|
+
{
|
|
204
|
+
nodes.push(el);
|
|
205
|
+
el = el.parentElement;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return nodes;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Gets the previous or next sibling node.
|
|
213
|
+
* @param {Node} node
|
|
214
|
+
* @param {Node} parent
|
|
215
|
+
* @param {boolean} previous
|
|
216
|
+
* @param {number} nodeType
|
|
217
|
+
* @param {boolean} skipEmpty
|
|
218
|
+
*/
|
|
219
|
+
sibling(node, parent, previous, nodeType, skipEmpty)
|
|
220
|
+
{
|
|
221
|
+
let fnGet = (previous) ? function (node) { return node.previousSibling; } : function (node) { return node.nextSibling; },
|
|
222
|
+
fnNext = function (node)
|
|
223
|
+
{
|
|
224
|
+
let next;
|
|
225
|
+
|
|
226
|
+
while (node && node != parent && !(next = fnGet(node)))
|
|
227
|
+
{
|
|
228
|
+
if (node.parentNode != parent)
|
|
229
|
+
node = node.parentNode;
|
|
230
|
+
else
|
|
231
|
+
node = null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return next;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
while ((node = fnNext(node)) && ((nodeType && nodeType != node.nodeType) || (skipEmpty && !node.nodeName.match(this.utility.voidNodeRegEx) && !node.textContent.length) || (node.nodeType == 1 && node.hasAttribute(this.utility.markerAttr))))
|
|
238
|
+
{
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return node;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Gets the previous sibling nodes for the startnode and the next sibling nodes for the endnode.
|
|
246
|
+
* @param {Node} parent
|
|
247
|
+
* @param {Node} startNode
|
|
248
|
+
* @param {Node} endNode
|
|
249
|
+
*/
|
|
250
|
+
getSiblings(parent, startNode, endNode, skipEmpty = true)
|
|
251
|
+
{
|
|
252
|
+
let node = startNode,
|
|
253
|
+
nodes = [];
|
|
254
|
+
|
|
255
|
+
if (node && this.contains(parent, node))
|
|
256
|
+
{
|
|
257
|
+
while ((node = this.sibling(node, parent, true, null, skipEmpty)))
|
|
258
|
+
{
|
|
259
|
+
nodes.unshift(node);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
node = endNode;
|
|
264
|
+
|
|
265
|
+
if (node && this.contains(parent, node))
|
|
266
|
+
{
|
|
267
|
+
while ((node = this.sibling(node, parent, false, null, skipEmpty)))
|
|
268
|
+
{
|
|
269
|
+
nodes.push(node);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return nodes;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Gets the elements by tag name and returns them in a modifiable array.
|
|
278
|
+
* @param {Node} node
|
|
279
|
+
* @param {String} tagName
|
|
280
|
+
* @param {Boolean} filterMarkers
|
|
281
|
+
*/
|
|
282
|
+
getElementsByTagName(node, tagName, filterMarkers = true)
|
|
283
|
+
{
|
|
284
|
+
let mustFilter = (tagName.split(' ').length > 1),
|
|
285
|
+
elements = node.getElementsByTagName((mustFilter) ? '*' : tagName),
|
|
286
|
+
nodes = [];
|
|
287
|
+
|
|
288
|
+
tagName = ' ' + tagName.toUpperCase() + ' ';
|
|
289
|
+
|
|
290
|
+
$lib.each(elements, (el) =>
|
|
291
|
+
{
|
|
292
|
+
if ((!mustFilter || tagName.indexOf(' ' + el.nodeName + ' ') > -1) && (!filterMarkers || !el.hasAttribute(this.utility.markerAttr)))
|
|
293
|
+
nodes.push(el);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
return nodes;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Gets the first text node within the specified node.
|
|
301
|
+
* @param {Node} node
|
|
302
|
+
* @param {Node} parent
|
|
303
|
+
* @param {boolean} last
|
|
304
|
+
* @param {boolean} skipEmpty
|
|
305
|
+
*/
|
|
306
|
+
getFirstTextNode(node, parent, last, skipEmpty)
|
|
307
|
+
{
|
|
308
|
+
if (skipEmpty == undefined)
|
|
309
|
+
skipEmpty = true;
|
|
310
|
+
|
|
311
|
+
while (node && (node.nodeType != 3 || (skipEmpty && !node.textContent.length)))
|
|
312
|
+
{
|
|
313
|
+
if (node.hasChildNodes())
|
|
314
|
+
node = (last) ? node.lastChild : node.firstChild;
|
|
315
|
+
else
|
|
316
|
+
node = this.sibling(node, parent, last, null, skipEmpty);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return node;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Gets the next sibling node
|
|
324
|
+
* @param {Node} node
|
|
325
|
+
*/
|
|
326
|
+
nextNode(node)
|
|
327
|
+
{
|
|
328
|
+
if (!node)
|
|
329
|
+
return null;
|
|
330
|
+
|
|
331
|
+
if (node.hasChildNodes())
|
|
332
|
+
{
|
|
333
|
+
return node.firstChild;
|
|
334
|
+
}
|
|
335
|
+
else
|
|
336
|
+
{
|
|
337
|
+
while (node && !node.nextSibling)
|
|
338
|
+
{
|
|
339
|
+
node = node.parentNode;
|
|
340
|
+
}
|
|
341
|
+
if (!node)
|
|
342
|
+
{
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return node.nextSibling;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Returns a value indicating if the node can be removed.
|
|
351
|
+
* @param {Node} node
|
|
352
|
+
*/
|
|
353
|
+
canRemove(node)
|
|
354
|
+
{
|
|
355
|
+
return (this.isLayoutNode(node) && (!this.nodeHasContent(node, false) || (node.firstElementChild == null && node.textContent.match(/^\uFEFF+$/g))));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Returns a value indicating if the node has content.
|
|
360
|
+
* @param {Node} node
|
|
361
|
+
* @param {boolean} [ignoreBR=true]
|
|
362
|
+
*/
|
|
363
|
+
nodeHasContent(node, ignoreBR = true)
|
|
364
|
+
{
|
|
365
|
+
if (node.textContent.length)
|
|
366
|
+
return true;
|
|
367
|
+
|
|
368
|
+
node = node.firstElementChild;
|
|
369
|
+
|
|
370
|
+
while (node)
|
|
371
|
+
{
|
|
372
|
+
if ((!ignoreBR || (ignoreBR && node.nodeName != 'BR')) && !node.hasAttribute(this.utility.markerAttr))
|
|
373
|
+
return true;
|
|
374
|
+
|
|
375
|
+
node = node.nextElementSibling;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Creates a text node inside the node.
|
|
383
|
+
* @param {Node} node
|
|
384
|
+
* @param {Node} beforeNode
|
|
385
|
+
* @param {string} text
|
|
386
|
+
*/
|
|
387
|
+
createTextNodePlaceHolder(node, beforeNode, text)
|
|
388
|
+
{
|
|
389
|
+
let doc = this.editor.getDoc(),
|
|
390
|
+
textNode = doc.createTextNode(text || '');
|
|
391
|
+
|
|
392
|
+
if (beforeNode)
|
|
393
|
+
beforeNode.parentNode.insertBefore(textNode, beforeNode);
|
|
394
|
+
else if (node.nodeName.match(this.utility.voidNodeRegEx))
|
|
395
|
+
node.parentNode.insertBefore(textNode, node);
|
|
396
|
+
else
|
|
397
|
+
node.appendChild(textNode);
|
|
398
|
+
|
|
399
|
+
return textNode;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Creates node with specified settings.
|
|
404
|
+
* @param {any} settings
|
|
405
|
+
* @returns {HTMLElement} node
|
|
406
|
+
*/
|
|
407
|
+
createNode(settings)
|
|
408
|
+
{
|
|
409
|
+
let node;
|
|
410
|
+
|
|
411
|
+
if (!settings.attributes)
|
|
412
|
+
settings.attributes = {};
|
|
413
|
+
|
|
414
|
+
if (settings.cssClass)
|
|
415
|
+
settings.attributes.class = settings.cssClass;
|
|
416
|
+
|
|
417
|
+
if (settings.outerHTML)
|
|
418
|
+
{
|
|
419
|
+
let el = $lib.element();
|
|
420
|
+
el.innerHTML = settings.outerHTML;
|
|
421
|
+
node = $lib.unsurround(el); // document fragment node
|
|
422
|
+
}
|
|
423
|
+
else
|
|
424
|
+
node = this.editor.format.createLayoutNode(settings.tag, settings.styles, (settings.innerHTML) ? [settings.innerHTML] : settings.textContent, settings.attributes, settings.properties);
|
|
425
|
+
|
|
426
|
+
if (!$lib.isEmpty(settings.allowContent))
|
|
427
|
+
node.contentEditable = settings.allowContent; // FF will remove any empty nodes on delete/backspace
|
|
428
|
+
|
|
429
|
+
if (settings.selectable)
|
|
430
|
+
this.editor.bindNodeEvents(node);
|
|
431
|
+
|
|
432
|
+
return node;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Gets the text container.
|
|
437
|
+
* @param {Node} node
|
|
438
|
+
* @param {Node} parent
|
|
439
|
+
*/
|
|
440
|
+
getTextContainer(node, parent)
|
|
441
|
+
{
|
|
442
|
+
while (node != parent && 'DIV TD LI'.split(' ').indexOf(node.nodeName) == -1)
|
|
443
|
+
{
|
|
444
|
+
node = node.parentNode;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return node;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Gets the nodes before the specified node.
|
|
452
|
+
* @param {Node} parentNode The parent node.
|
|
453
|
+
* @param {Node} endNode The ending node.
|
|
454
|
+
* @returns {DocumentFragment} A fragment containing the nodes.
|
|
455
|
+
*/
|
|
456
|
+
getNodesBefore(parentNode, endNode)
|
|
457
|
+
{
|
|
458
|
+
let node = parentNode.firstChild,
|
|
459
|
+
fragment = document.createDocumentFragment(),
|
|
460
|
+
next, current = fragment;
|
|
461
|
+
|
|
462
|
+
while (node && node != endNode && node != parentNode)
|
|
463
|
+
{
|
|
464
|
+
if (!node.contains(endNode))
|
|
465
|
+
{
|
|
466
|
+
next = node.nextSibling;
|
|
467
|
+
current.appendChild(node);
|
|
468
|
+
node = next;
|
|
469
|
+
}
|
|
470
|
+
else
|
|
471
|
+
{
|
|
472
|
+
current = node.cloneNode(false);
|
|
473
|
+
fragment.appendChild(current);
|
|
474
|
+
node = node.firstChild;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return fragment;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Get the list (UL/OL) node.
|
|
483
|
+
* @param {Node} startNode
|
|
484
|
+
* @param {Node} rootNode
|
|
485
|
+
*/
|
|
486
|
+
getListNode(startNode, rootNode)
|
|
487
|
+
{
|
|
488
|
+
return this.getMatchingNode(startNode, rootNode, (node) => { return this.utility.listFilter.indexOf(node.nodeName) > -1 });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Get the list-item (LI) node.
|
|
493
|
+
* @param {Node} startNode
|
|
494
|
+
* @param {Node} rootNode
|
|
495
|
+
*/
|
|
496
|
+
getListItemNode(startNode, rootNode)
|
|
497
|
+
{
|
|
498
|
+
return this.getMatchingNode(startNode, rootNode, (node) => { return node.nodeName == 'LI'; });
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Get the layout node for the startNode.
|
|
503
|
+
* @param {String} nodeName
|
|
504
|
+
* @param {Node} startNode
|
|
505
|
+
* @param {Node} rootNode
|
|
506
|
+
*/
|
|
507
|
+
getLayoutNode(nodeName, startNode, rootNode)
|
|
508
|
+
{
|
|
509
|
+
nodeName = nodeName.toUpperCase();
|
|
510
|
+
|
|
511
|
+
let isMatch = (node) =>
|
|
512
|
+
{
|
|
513
|
+
if (node.nodeName === nodeName)
|
|
514
|
+
return true;
|
|
515
|
+
|
|
516
|
+
// Only match style spans if the layout operation IS a style operation
|
|
517
|
+
if (nodeName === 'SPAN' && this.isStyleNode(node))
|
|
518
|
+
return true;
|
|
519
|
+
|
|
520
|
+
return false;
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
return this.getMatchingNode(startNode, rootNode, isMatch);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Gets the node that matches the specified condition.
|
|
528
|
+
* @param {Node} startNode
|
|
529
|
+
* @param {Node} rootNode
|
|
530
|
+
* @param {Function} isMatch
|
|
531
|
+
*/
|
|
532
|
+
getMatchingNode(startNode, rootNode, isMatch)
|
|
533
|
+
{
|
|
534
|
+
let node = startNode;
|
|
535
|
+
|
|
536
|
+
while (node && node != rootNode && !isMatch(node))
|
|
537
|
+
{
|
|
538
|
+
node = node.parentNode;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return (isMatch(node)) ? node : null;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Gets the layout nodes from a specific start node.
|
|
546
|
+
* @param {Node} startNode The node to start from.
|
|
547
|
+
* @param {Node} rootNode The highest node in the tree to check.
|
|
548
|
+
* @param {Boolean} [clone] A value indicating if a found layout-node is cloned.
|
|
549
|
+
* @param {Number} [type] The type of the nodes to add (1: layout-node, 2: style-node, null/undefined/0: both)
|
|
550
|
+
* @returns {Node[]} The list of layout-nodes.
|
|
551
|
+
*/
|
|
552
|
+
getLayoutNodes(startNode, rootNode, clone, type)
|
|
553
|
+
{
|
|
554
|
+
let nodes = [], node = startNode, isLayout, isStyle;
|
|
555
|
+
|
|
556
|
+
while (node != rootNode)
|
|
557
|
+
{
|
|
558
|
+
isLayout = this.isTextDecorationNode(node);
|
|
559
|
+
isStyle = this.isStyleNode(node);
|
|
560
|
+
|
|
561
|
+
if ((!type && (isLayout || isStyle)) || (type == 1 && isLayout) || (type > 1 && isStyle))
|
|
562
|
+
nodes.push((clone) ? node.cloneNode(false) : node);
|
|
563
|
+
|
|
564
|
+
node = node.parentNode;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return nodes.reverse();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Builds the layout node tree with the specified nodes.
|
|
572
|
+
* @param {Node[]} nodes
|
|
573
|
+
*/
|
|
574
|
+
buildLayoutTree(nodes)
|
|
575
|
+
{
|
|
576
|
+
let layoutNode;
|
|
577
|
+
|
|
578
|
+
$lib.each(nodes, (node) =>
|
|
579
|
+
{
|
|
580
|
+
let clone = node.cloneNode(false);
|
|
581
|
+
|
|
582
|
+
if (node.hasAttribute(this.utility.selAttr))
|
|
583
|
+
this.editor.bindNodeEvents(clone);
|
|
584
|
+
|
|
585
|
+
if (layoutNode)
|
|
586
|
+
layoutNode.appendChild(clone);
|
|
587
|
+
|
|
588
|
+
layoutNode = clone;
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
return layoutNode;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Removes the node while keeping markers.
|
|
596
|
+
* @param {Node} node
|
|
597
|
+
* @param {Object} marker
|
|
598
|
+
*/
|
|
599
|
+
removeNodeAndKeepMarkers(node, marker)
|
|
600
|
+
{
|
|
601
|
+
let doc = this.editor.getDoc(),
|
|
602
|
+
startMarker = node.querySelector('#' + marker.startId),
|
|
603
|
+
endMarker = (marker.endId) ? node.querySelector('#' + marker.endId) : null;
|
|
604
|
+
|
|
605
|
+
if (startMarker || endMarker)
|
|
606
|
+
{
|
|
607
|
+
let fragment = doc.createDocumentFragment();
|
|
608
|
+
|
|
609
|
+
if (startMarker)
|
|
610
|
+
fragment.appendChild(startMarker);
|
|
611
|
+
|
|
612
|
+
if (endMarker)
|
|
613
|
+
fragment.appendChild(endMarker);
|
|
614
|
+
|
|
615
|
+
node.replaceWith(fragment);
|
|
616
|
+
}
|
|
617
|
+
else
|
|
618
|
+
$lib.remove(node);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Change node to specified block element.
|
|
623
|
+
* @param {Node} node
|
|
624
|
+
* @param {Node} blockNode
|
|
625
|
+
*/
|
|
626
|
+
setBlockElement(node, blockNode)
|
|
627
|
+
{
|
|
628
|
+
let childNode = (blockNode && blockNode.firstElementChild) ? blockNode.firstElementChild : blockNode;
|
|
629
|
+
|
|
630
|
+
childNode.appendChild($lib.extract(node));
|
|
631
|
+
|
|
632
|
+
if (this.isLayoutRoot(node)) // exception for LI/TH/TD
|
|
633
|
+
node.appendChild(blockNode);
|
|
634
|
+
else
|
|
635
|
+
{
|
|
636
|
+
this.editor.format.copyStyles(node, blockNode);
|
|
637
|
+
node.replaceWith(blockNode);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (!childNode.childNodes.length)
|
|
641
|
+
childNode.appendChild(this.editor.getDoc().createTextNode(this.utility.zeroWidthChar));
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
createCursorSpace(x)
|
|
645
|
+
{
|
|
646
|
+
this.editor.activateDocument();
|
|
647
|
+
|
|
648
|
+
if (!this.editor.contentManager.hasContent())
|
|
649
|
+
return;
|
|
650
|
+
|
|
651
|
+
let range = this.editor.selectionRange.getRange(),
|
|
652
|
+
rootNodes = this.editor.selectionRange.getRootNodesInRange(range),
|
|
653
|
+
rootNode = rootNodes[0],
|
|
654
|
+
firstChild = rootNode.firstChild,
|
|
655
|
+
lastChild = rootNode.lastChild;
|
|
656
|
+
|
|
657
|
+
if (firstChild && firstChild != rootNode && firstChild.nodeType == 1 && firstChild.hasAttribute(this.utility.selAttr) && firstChild.contentEditable == 'false')
|
|
658
|
+
{
|
|
659
|
+
let textNode = this.editor.getDoc().createTextNode(this.utility.zeroWidthChar);
|
|
660
|
+
|
|
661
|
+
if (x < $lib.getPos(firstChild).left && !firstChild?.previousSibling?.nodeValue?.match(this.utility.zeroWidthRegEx))
|
|
662
|
+
{
|
|
663
|
+
firstChild.parentNode.insertBefore(textNode, firstChild);
|
|
664
|
+
range.setStart(textNode, 0);
|
|
665
|
+
range.collapse(true);
|
|
666
|
+
this.editor.selectionRange.restoreRange(range);
|
|
667
|
+
}
|
|
668
|
+
else if (lastChild.nodeType == 1 && lastChild.nodeName != 'BR' && x > $lib.getPos(lastChild).right && !lastChild?.nextSibling?.nodeValue?.match(this.utility.zeroWidthRegEx))
|
|
669
|
+
{
|
|
670
|
+
lastChild.parentNode.insertBefore(textNode, lastChild.nextSibling);
|
|
671
|
+
range.setStart(textNode, 0);
|
|
672
|
+
range.collapse(true);
|
|
673
|
+
this.editor.selectionRange.restoreRange(range);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
var NodeManager = componyx.UI.editor_modules.NodeManager;
|
|
680
|
+
|
|
681
|
+
export { NodeManager as default };
|