@componyx/ui 0.0.0-stage → 1.0.3
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/DataObserver.js +717 -0
- package/Form/Modules/Databinder.js +602 -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,605 @@
|
|
|
1
|
+
/*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
|
|
2
|
+
await (async function ()
|
|
3
|
+
{
|
|
4
|
+
await import(`${$UI.getScriptResourcePath('Base.Bindary.Core')}`);
|
|
5
|
+
const core = componyx.bindary_modules.core;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Represents a renderer that is responsible for rendering and managing DOM elements for items.
|
|
9
|
+
*
|
|
10
|
+
* @class
|
|
11
|
+
* @property {componyx.bindary.TemplateItem} item - The item being rendered.
|
|
12
|
+
* @property {boolean} update - A value indicating if its an update or render.
|
|
13
|
+
* @property {boolean} inRepeat - A value indicating if the item is part of a repeat section.
|
|
14
|
+
* @property {Function} next - The function to fetch the next item in the render cycle.
|
|
15
|
+
* @property {HTMLElement} element - The DOM element for the item.
|
|
16
|
+
* @property {Object|null} treeState - The tree state for the item.
|
|
17
|
+
* @property {Object} context - The context for the item renderer.
|
|
18
|
+
* @property {string|null} key - The key associated with the item.
|
|
19
|
+
* @property {Object|null} dataChange - Data change information for the item.
|
|
20
|
+
*/
|
|
21
|
+
componyx.bindary_modules.Renderer = class
|
|
22
|
+
{
|
|
23
|
+
/**
|
|
24
|
+
* Creates an instance of Renderer.
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} item - The item to be rendered.
|
|
27
|
+
* @param {HTMLElement} element - The DOM element associated with the item.
|
|
28
|
+
* @param {Function} update - The function responsible for updating the item renderer.
|
|
29
|
+
* @param {Function} next - The function to fetch the next item in the rendering process.
|
|
30
|
+
*/
|
|
31
|
+
constructor(item, element, update, next)
|
|
32
|
+
{
|
|
33
|
+
this.item = item;
|
|
34
|
+
this.update = update;
|
|
35
|
+
this.inRepeat = item.inRepeat;
|
|
36
|
+
this.next = next;
|
|
37
|
+
this.element = element;
|
|
38
|
+
this.treeState = null;
|
|
39
|
+
this.context = null;
|
|
40
|
+
this.key = null;
|
|
41
|
+
this.dataChange = null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
render(context, key)
|
|
46
|
+
{
|
|
47
|
+
let me = this, item = me.item;
|
|
48
|
+
|
|
49
|
+
me.treeState = null;
|
|
50
|
+
|
|
51
|
+
if (item.repeatDataKey)
|
|
52
|
+
{
|
|
53
|
+
|
|
54
|
+
me.context = context || me.context;
|
|
55
|
+
me.key = (!$lib.isEmpty(key)) ? key : me.key;
|
|
56
|
+
me.renderRepeatItem(me.context, me.key);
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
{
|
|
61
|
+
me.renderItem();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
renderRepeatItem(context, key)
|
|
66
|
+
{
|
|
67
|
+
let me = this, item = me.item;
|
|
68
|
+
|
|
69
|
+
if ($lib.isArray(item.repeatValue))
|
|
70
|
+
{
|
|
71
|
+
item.index = parseInt(key);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
item.key = key;
|
|
75
|
+
item.defineContext(context);
|
|
76
|
+
item.setContextValue();
|
|
77
|
+
item.element = item.repeatElements[key] || item.repeatPlaceHolder;
|
|
78
|
+
|
|
79
|
+
if (item.repeatItemIdDataKey)
|
|
80
|
+
item.repeatItemIdValue = item.getDataValue(item.repeatItemIdDataKey, item.context);
|
|
81
|
+
|
|
82
|
+
me.renderElement(me.createRepeatElement);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
renderItem()
|
|
86
|
+
{
|
|
87
|
+
let me = this, item = me.item;
|
|
88
|
+
|
|
89
|
+
item.setContextValue();
|
|
90
|
+
item.element = me.element;
|
|
91
|
+
me.renderElement(me.createElement);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
renderElement(create)
|
|
95
|
+
{
|
|
96
|
+
|
|
97
|
+
let me = this, item = me.item, element = item.element;
|
|
98
|
+
|
|
99
|
+
if (me.mustRender(item, element))
|
|
100
|
+
{
|
|
101
|
+
|
|
102
|
+
create.bind(this)();
|
|
103
|
+
|
|
104
|
+
if (item.include)
|
|
105
|
+
me.includeItem();
|
|
106
|
+
else if (item.includeFile)
|
|
107
|
+
me.includeFile();
|
|
108
|
+
else if (item.component)
|
|
109
|
+
me.load();
|
|
110
|
+
else
|
|
111
|
+
me.postRender();
|
|
112
|
+
} else
|
|
113
|
+
{
|
|
114
|
+
me.next(); // fetch next
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
mustRender()
|
|
120
|
+
{
|
|
121
|
+
let me = this, item = me.item, element = item.element;
|
|
122
|
+
|
|
123
|
+
if (!item.isActiveRepeatItem(item) || (item.hasValue != null && me.isEmpty(item)) || (core.call(item.preRender, [item, me.render]) === false))
|
|
124
|
+
{
|
|
125
|
+
// element should not be visible and children should not be part of the DOM tree
|
|
126
|
+
core.setItemPlaceHolder(item, element);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
isEmpty(item)
|
|
134
|
+
{
|
|
135
|
+
let value = (item.hasValue[0].length == 0) ? (item.dataKey) ? item.value : item.context : item.getDataValue(item.hasValue, item.context);
|
|
136
|
+
return $lib.isEmpty(value);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
includeItem()
|
|
140
|
+
{
|
|
141
|
+
let me = this, item = me.item, include;
|
|
142
|
+
|
|
143
|
+
if (item.component && core.components[item.component])
|
|
144
|
+
item.context = core.components[item.component](item); // context is defined before include, therefore a possible includable data-key can be defined in the component's context
|
|
145
|
+
|
|
146
|
+
include = item.getIncludeItem();
|
|
147
|
+
|
|
148
|
+
if (!item.children.length && (!include && core.hasLoadingIncludes()))
|
|
149
|
+
{ // include item not found and busy including files, add to global waiters list
|
|
150
|
+
|
|
151
|
+
me.waiting = true;
|
|
152
|
+
core.waiters.push(me);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
me.waiting = false;
|
|
157
|
+
me.load(include);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
includeFile()
|
|
161
|
+
{
|
|
162
|
+
let me = this, item = me.item,
|
|
163
|
+
includeURL = $bindary.includeRootURL + (($lib.startsWith(item.includeFile, '/')) ? item.includeFile.substr(1) : item.getDataValue(item.includeFile, item.context)),
|
|
164
|
+
include = core.cache.include[includeURL];
|
|
165
|
+
|
|
166
|
+
if (include)
|
|
167
|
+
{
|
|
168
|
+
if (include.loading)
|
|
169
|
+
{
|
|
170
|
+
|
|
171
|
+
include.waiters.push(me);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
me.load(include);
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
else
|
|
179
|
+
{
|
|
180
|
+
me.createFileInclude(includeURL);
|
|
181
|
+
|
|
182
|
+
core.xhr.push($lib.load({
|
|
183
|
+
url: includeURL,
|
|
184
|
+
onSuccess: function (args)
|
|
185
|
+
{
|
|
186
|
+
let include = core.cache.include[args.settings.url];
|
|
187
|
+
include.dataLoaded(args);
|
|
188
|
+
}
|
|
189
|
+
}, item.element));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
createFileInclude(includeURL)
|
|
194
|
+
{
|
|
195
|
+
let me = this,
|
|
196
|
+
include = {};
|
|
197
|
+
|
|
198
|
+
core.cache.include[includeURL] = include;
|
|
199
|
+
|
|
200
|
+
include.loading = true;
|
|
201
|
+
include.waiters = [];
|
|
202
|
+
include.waiters.push(me);
|
|
203
|
+
include.dataLoaded = function (args)
|
|
204
|
+
{
|
|
205
|
+
let include = core.cache.include[args.settings.url];
|
|
206
|
+
include.loading = false;
|
|
207
|
+
include.html = args.html;
|
|
208
|
+
include.css = args.css;
|
|
209
|
+
include.script = args.script;
|
|
210
|
+
|
|
211
|
+
core.renderPass++; // resuming after an async gap: nothing cached from before this point can be trusted
|
|
212
|
+
|
|
213
|
+
$lib.each(include.waiters, function (itemRenderer)
|
|
214
|
+
{ // file includes
|
|
215
|
+
|
|
216
|
+
itemRenderer.item.restoreContext(itemRenderer.treeState);
|
|
217
|
+
itemRenderer.load.bind(itemRenderer)(include);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
$lib.each(core.waiters, function (itemRenderer)
|
|
221
|
+
{ // item includes
|
|
222
|
+
|
|
223
|
+
itemRenderer.item.restoreContext(itemRenderer.treeState);
|
|
224
|
+
itemRenderer.includeItem.bind(itemRenderer)();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
delete include.waiters;
|
|
228
|
+
core.clearWaiters();
|
|
229
|
+
|
|
230
|
+
if (core.postRenderFlag) // post-render was called while loading data
|
|
231
|
+
core.postRender();
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
load(include)
|
|
236
|
+
{
|
|
237
|
+
let me = this, item = me.item, element = item.element;
|
|
238
|
+
|
|
239
|
+
if (include)
|
|
240
|
+
{
|
|
241
|
+
if (!element.childNodes.length)
|
|
242
|
+
{
|
|
243
|
+
item.loaded = false;
|
|
244
|
+
|
|
245
|
+
if (include.html)
|
|
246
|
+
{ // file-include
|
|
247
|
+
|
|
248
|
+
let html = (item.children.length) ? include.cachedHtml : include.html; // the item has already been added to the view-tree before, so it's not unique and inside a repeater. Since we dont build the view-tree again, we must use the same html with set bindary identifiers.
|
|
249
|
+
$lib.addHTML(html, item.element);
|
|
250
|
+
}
|
|
251
|
+
else
|
|
252
|
+
{ // item-include
|
|
253
|
+
element.appendChild(include.sourceElement.cloneNode(true));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!item.children.length)
|
|
258
|
+
{
|
|
259
|
+
if (include.html)
|
|
260
|
+
{ // file-include
|
|
261
|
+
|
|
262
|
+
$bindary.createViewTree(element, item); // append view tree
|
|
263
|
+
$lib.each(item.children, (i) => { i.included = true; });
|
|
264
|
+
include.cachedHtml = element.innerHTML;
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
else
|
|
268
|
+
{ // item-include
|
|
269
|
+
|
|
270
|
+
let clone = include.clone(item);
|
|
271
|
+
clone.included = true;
|
|
272
|
+
item.children.push(clone);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else
|
|
277
|
+
{
|
|
278
|
+
item.loaded = false;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (item.loaded)
|
|
282
|
+
me.postRender();
|
|
283
|
+
else
|
|
284
|
+
{
|
|
285
|
+
item.loaded = true;
|
|
286
|
+
|
|
287
|
+
if (item.component)
|
|
288
|
+
{
|
|
289
|
+
if (!include || include.html) // context already set for item-include
|
|
290
|
+
item.context = core.components[item.component](item);
|
|
291
|
+
|
|
292
|
+
if (item.context?.load)
|
|
293
|
+
item.context.load(item); // invoke load method on component if exists
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
core.call(item.load, [item]); // invoke custom load method if exists
|
|
297
|
+
|
|
298
|
+
if (item.observeDataKeyPath)
|
|
299
|
+
{
|
|
300
|
+
|
|
301
|
+
let keyPath = (item.contextDataKeyPath) ? item.livePath[item.contextDataKeyPath] + core.dksc + item.observeDataKeyPath : item.observeDataKeyPath; // configure root key-path for component using current full context path
|
|
302
|
+
item.context[item.observeDataKeyPath] = $bindary.observe(item.context[item.observeDataKeyPath], keyPath, { viewTree: [item], reuseProxy: false }); // own proxy per component instance, so viewTree isn't silently dropped by reuse and component data will trigger view-tree update only for corresponding tree-item
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
me.postRender();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
componentDataChange(event)
|
|
310
|
+
{
|
|
311
|
+
|
|
312
|
+
let payload = event.detail.eventPayload;
|
|
313
|
+
|
|
314
|
+
item.restoreContext(payload.treeState);
|
|
315
|
+
event.detail.viewTree = [item];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
createRepeatElement()
|
|
319
|
+
{
|
|
320
|
+
|
|
321
|
+
let me = this,
|
|
322
|
+
item = me.item,
|
|
323
|
+
placeHolder = item.repeatPlaceHolder,
|
|
324
|
+
reps = item.repeatElements;
|
|
325
|
+
|
|
326
|
+
let element = reps[item.key];
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
if (!element || element._bindaryPlaceholder || item.dataChange?.recreate ||
|
|
330
|
+
($lib.isEmpty(item.dataChange?.recreate) && $bindary.defaultRecreateRule))
|
|
331
|
+
{
|
|
332
|
+
element = item.sourceElement.cloneNode(true);
|
|
333
|
+
element.removeAttribute('id');
|
|
334
|
+
element.setAttribute(core.attr.id, item.id); // keep id as bindary attribute
|
|
335
|
+
element.style.display = item.display;
|
|
336
|
+
placeHolder.parentNode.insertBefore(element, placeHolder);
|
|
337
|
+
reps[item.key] = element;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
item.element = element;
|
|
341
|
+
me.inRepeat = true;
|
|
342
|
+
return me.createElement();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
createElement()
|
|
346
|
+
{
|
|
347
|
+
let me = this, item = me.item, context = item.context,
|
|
348
|
+
element = item.element,
|
|
349
|
+
setValue = function (name, value)
|
|
350
|
+
{
|
|
351
|
+
if (value === null || value === undefined)
|
|
352
|
+
{
|
|
353
|
+
if (element.hasAttribute(name))
|
|
354
|
+
element.removeAttribute(name);
|
|
355
|
+
}
|
|
356
|
+
else
|
|
357
|
+
{
|
|
358
|
+
if (typeof value === 'object')
|
|
359
|
+
value = JSON.stringify(value);
|
|
360
|
+
|
|
361
|
+
if (element.getAttribute(name) !== value)
|
|
362
|
+
element.setAttribute(name, value);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
me.treeState = item.captureTreeState();
|
|
367
|
+
element.style.display = item.display; // element could be invisible if it was not rendered before
|
|
368
|
+
|
|
369
|
+
// set attributes
|
|
370
|
+
$lib.each(item.attributes, function (value, name)
|
|
371
|
+
{
|
|
372
|
+
if (item.attributeExpressions && item.attributeExpressions[name])
|
|
373
|
+
{
|
|
374
|
+
let exprFn = item.attributeExpressions[name],
|
|
375
|
+
resolvedValue = exprFn(item.expressionTokenResolver.bind(item));
|
|
376
|
+
|
|
377
|
+
setValue(name, resolvedValue);
|
|
378
|
+
}
|
|
379
|
+
else
|
|
380
|
+
{
|
|
381
|
+
let dataValue = (value.match(core.singleWord)) ? item.getDataValue(item.createDataKey(value, false), context) : undefined;
|
|
382
|
+
setValue(name, (dataValue == undefined) ? value : dataValue);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
$lib.each(item.events, function (method, event)
|
|
387
|
+
{
|
|
388
|
+
if ($lib.has(element, event, core.customEventHandler))
|
|
389
|
+
$lib.off(element, event, core.customEventHandler);
|
|
390
|
+
|
|
391
|
+
$lib.on(element, event, core.customEventHandler, [method, item, me.treeState, null, false, core.getMethodContext(method, item)]);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
me.clearInputEvents();
|
|
395
|
+
me.setElementValue();
|
|
396
|
+
me.bindInputEvents();
|
|
397
|
+
|
|
398
|
+
return element;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
setElementValue()
|
|
402
|
+
{
|
|
403
|
+
let me = this, item = me.item,
|
|
404
|
+
el = item.element,
|
|
405
|
+
info = item.elementInfo,
|
|
406
|
+
value = item.value,
|
|
407
|
+
type = item.dataType;
|
|
408
|
+
|
|
409
|
+
if (el === core.dataBindTrigger && core.dataBindLive) // skip updating the element while the user is actively typing to avoid overwriting input
|
|
410
|
+
return;
|
|
411
|
+
|
|
412
|
+
if ((!item.dataKey && !item.expression) || info.isSelect) // select type is handled in item postrender
|
|
413
|
+
return;
|
|
414
|
+
|
|
415
|
+
if (item.viewFormatter)
|
|
416
|
+
value = core.call(item.viewFormatter, [item, el, value]);
|
|
417
|
+
|
|
418
|
+
value = me.formatValue(value);
|
|
419
|
+
|
|
420
|
+
if (info.isRadio || info.isCheck)
|
|
421
|
+
{
|
|
422
|
+
if (Array.isArray(value)) // check if this checkbox/radio value exists in the array
|
|
423
|
+
{
|
|
424
|
+
const elValue = ($lib.isEmpty(el.value) || el.value === 'on') ? el.name : el.value;
|
|
425
|
+
el.checked = value.includes(elValue);
|
|
426
|
+
}
|
|
427
|
+
else if (typeof value == 'boolean')
|
|
428
|
+
el.checked = ($lib.isEmpty(el.value) || type != 'boolean') ? value : (core.toBoolean(el.value) == value); // checkbox with value="false" is checked when value == false (e.g. checkbox with label 'enabled' and data property 'disabled')
|
|
429
|
+
else
|
|
430
|
+
el.checked = value == el.value;
|
|
431
|
+
|
|
432
|
+
el._bindaryLastState = `${el.checked}:${el.value}`;
|
|
433
|
+
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (Array.isArray(value)) // convert array
|
|
438
|
+
value = value.map(v => { return me.formatValue(v); }).join(',');
|
|
439
|
+
|
|
440
|
+
value = ($lib.isEmpty(value, false)) ? '' : value.toString();
|
|
441
|
+
|
|
442
|
+
const isHTML = item.isHTML || el.contentEditable === 'true';
|
|
443
|
+
value = isHTML
|
|
444
|
+
? ($bindary.trustHTML || item.trusted) ? value : ($bindary.sanitizer ? $bindary.sanitizer(value) : core.sanitizer.sanitize(value))
|
|
445
|
+
: value;
|
|
446
|
+
|
|
447
|
+
core.setElementValue(item, value, isHTML);
|
|
448
|
+
el._bindaryLastState = isHTML ? el.innerHTML : el.value;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
formatValue(value)
|
|
452
|
+
{
|
|
453
|
+
let me = this,
|
|
454
|
+
item = me.item,
|
|
455
|
+
info = item.elementInfo,
|
|
456
|
+
type = item.dataType,
|
|
457
|
+
el = item.element,
|
|
458
|
+
isoDate = null;
|
|
459
|
+
|
|
460
|
+
if (typeof value == 'string' && (/^\d{4}-\d{2}-\d{2}/.test(value))) // iso string date
|
|
461
|
+
{
|
|
462
|
+
isoDate = new Date(value);
|
|
463
|
+
if ($lib.isDate(isoDate) && !isNaN(isoDate.getTime()))
|
|
464
|
+
value = isoDate;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if ($lib.isDate(value))
|
|
468
|
+
{
|
|
469
|
+
let format,
|
|
470
|
+
date = isoDate || value;
|
|
471
|
+
|
|
472
|
+
if (isNaN(date.getTime()))
|
|
473
|
+
return '';
|
|
474
|
+
|
|
475
|
+
if (info.isInput && el.type == 'date')
|
|
476
|
+
format = 'YYYY-MM-DD'; // use default date format yyyy-mm-dd
|
|
477
|
+
else if (type == 'date')
|
|
478
|
+
format = $bindary.dateFormat.replace(core.timeRegEx, ''); // remove time portion from date-format
|
|
479
|
+
|
|
480
|
+
return core.formatDate(date, format);
|
|
481
|
+
}
|
|
482
|
+
else if (typeof value == 'number' && type?.startsWith('number'))
|
|
483
|
+
{
|
|
484
|
+
const match = type.match(/^number(?:\((\d+)\))?$/),
|
|
485
|
+
precision = match?.[1] != null ? parseInt(match[1]) : $bindary.decimalPrecision;
|
|
486
|
+
|
|
487
|
+
return $lib.formatNumber(value, false, true, precision, null, $bindary.decimalSeparator);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return value;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
clearInputEvents()
|
|
494
|
+
{
|
|
495
|
+
let me = this, item = me.item,
|
|
496
|
+
element = item.element;
|
|
497
|
+
|
|
498
|
+
if ($lib.has(element, 'blur', core.eventHandler))
|
|
499
|
+
$lib.off(element, 'blur', core.eventHandler);
|
|
500
|
+
|
|
501
|
+
if ($lib.has(element, 'change', core.eventHandler))
|
|
502
|
+
$lib.off(element, 'change', core.eventHandler);
|
|
503
|
+
|
|
504
|
+
if ($lib.has(element, 'input', me.deferDataBind))
|
|
505
|
+
$lib.off(element, 'input', me.deferDataBind);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
bindInputEvents()
|
|
509
|
+
{
|
|
510
|
+
let me = this, item = me.item,
|
|
511
|
+
element = item.element;
|
|
512
|
+
|
|
513
|
+
if (!item.inputBind)
|
|
514
|
+
return;
|
|
515
|
+
|
|
516
|
+
let tree = me.treeState;
|
|
517
|
+
|
|
518
|
+
// Attach listeners in next event cycle to avoid infinite event call loop when the update came from dataBind().
|
|
519
|
+
// The library event handler uses forEach, which will always retrieve a new value because of the remove/add action
|
|
520
|
+
$lib.defer(function (element, tree)
|
|
521
|
+
{
|
|
522
|
+
let me = this, item = me.item;
|
|
523
|
+
|
|
524
|
+
if (element.isContentEditable)
|
|
525
|
+
$lib.on(element, 'blur', core.eventHandler, [me.dataBind.bind(me, false), item, tree, [], true, null], me, true);
|
|
526
|
+
else
|
|
527
|
+
$lib.on(element, 'change', core.eventHandler, [me.dataBind.bind(me, false), item, tree, [], true, null], me, true);
|
|
528
|
+
|
|
529
|
+
if ((($bindary.liveBind && item.liveBind !== false) || item.liveBind) && element.type != 'hidden')
|
|
530
|
+
$lib.on(element, 'input', me.deferDataBind, [tree], me, true);
|
|
531
|
+
|
|
532
|
+
}.bind(me, element, tree));
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
deferDataBind(tree, e)
|
|
536
|
+
{
|
|
537
|
+
const me = this,
|
|
538
|
+
element = me.item.element,
|
|
539
|
+
itemDelay = Number(me.item.liveBind),
|
|
540
|
+
delay = (!isNaN(itemDelay) && itemDelay >= 0) ? itemDelay : ($bindary.liveBindDelay || 0),
|
|
541
|
+
updateFn = function (tree)
|
|
542
|
+
{
|
|
543
|
+
core.eventHandler(this.dataBind.bind(this, true), this.item, tree, [], true, null);
|
|
544
|
+
}.bind(me, tree);
|
|
545
|
+
|
|
546
|
+
if (core.liveBindTimers.has(element))
|
|
547
|
+
clearTimeout(core.liveBindTimers.get(element));
|
|
548
|
+
|
|
549
|
+
const timerId = setTimeout(updateFn, delay);
|
|
550
|
+
core.liveBindTimers.set(element, timerId);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
dataBind(live)
|
|
554
|
+
{
|
|
555
|
+
let me = this, item = me.item,
|
|
556
|
+
info = item.elementInfo,
|
|
557
|
+
el = item.element,
|
|
558
|
+
value = core.getElementValue(item),
|
|
559
|
+
state = info.isCheck || info.isRadio ? `${el.checked}:${value}` : value;
|
|
560
|
+
|
|
561
|
+
if (state === el._bindaryLastState)
|
|
562
|
+
return;
|
|
563
|
+
|
|
564
|
+
if (core.fireEvent('preDataBind', [item, el, function () { item.dataBind(live); }]) !== false)
|
|
565
|
+
item.dataBind(live);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
postRender()
|
|
569
|
+
{
|
|
570
|
+
let me = this, item = me.item;
|
|
571
|
+
|
|
572
|
+
if (item.children && item.children.length)
|
|
573
|
+
$bindary.renderView(me.update, item.children);
|
|
574
|
+
|
|
575
|
+
if (item.elementInfo && item.elementInfo.isSelect && item.dataKey)
|
|
576
|
+
me.setSelectValue(); // set select value when all options are rendered
|
|
577
|
+
|
|
578
|
+
if (me.inRepeat)
|
|
579
|
+
core.rendered.push(item); // set rendered state after all repeat-elements are rendered
|
|
580
|
+
else
|
|
581
|
+
item.isRendered = true;
|
|
582
|
+
|
|
583
|
+
if (item.component && item.context?.postRender)
|
|
584
|
+
item.context.postRender(item); // invoke postRender method on component if exists
|
|
585
|
+
|
|
586
|
+
if (core.call(item.postRender, [item]) === false)
|
|
587
|
+
item.element.style.display = 'none';
|
|
588
|
+
|
|
589
|
+
item.key = item.index = item.value = null; // clear
|
|
590
|
+
me.next(); // fetch next
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
setSelectValue()
|
|
594
|
+
{
|
|
595
|
+
|
|
596
|
+
let me = this, item = me.item;
|
|
597
|
+
let dataKey = item.dataKey;
|
|
598
|
+
$lib('#' + item.id).value = item.getDataValue(dataKey, item.context);
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
})();
|
|
602
|
+
|
|
603
|
+
var Renderer = componyx.bindary_modules.Renderer;
|
|
604
|
+
|
|
605
|
+
export { Renderer as default };
|