@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,685 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ await (async function ()
3
+ {
4
+ await import(`${$UI.getScriptResourcePath('Form.ComponentPanel')}`);
5
+ await import(`${$UI.getScriptResourcePath('Form.OptionsPanel')}`);
6
+ await import(`${$UI.getScriptResourcePath('Form.RulesPanel')}`);
7
+
8
+ componyx.UI.form_modules = componyx.UI.form_modules || {};
9
+ componyx.UI.form_modules.ConfigPanelManager = class ConfigPanelManger
10
+ {
11
+ #activeFieldSetId;
12
+ #activeFieldId;
13
+ #updateOptionsTimerId;
14
+ constructor(form)
15
+ {
16
+ this.form = form;
17
+ this.cf = form.componentFactory;
18
+ this.draggable = form.draggable;
19
+ this.panelBar = null;
20
+ this.labels = this.form.labels;
21
+ this.InputTypeOption = this.form.constructor.InputTypeOption;
22
+ this.classOption = form.classOption;
23
+ this.getCssClass = form.getCssClass;
24
+
25
+ this.expressionEngine = form.expressionEngine;
26
+ this.componentPanel = new componyx.UI.form_modules.ComponentPanel(form, this);
27
+ this.optionsPanel = new componyx.UI.form_modules.OptionsPanel(form, this);
28
+ this.rulesPanel = new componyx.UI.form_modules.RulesPanel(form, this);
29
+ }
30
+
31
+ destroy()
32
+ {
33
+ this.rulesPanel.destroy();
34
+ }
35
+
36
+ isFieldSetActive(fieldSet)
37
+ {
38
+ return this.#activeFieldSetId === fieldSet.id;
39
+ }
40
+
41
+ isFieldActive(field)
42
+ {
43
+ return this.#activeFieldId === field.id;
44
+ }
45
+
46
+ setActiveFieldSet(fieldSet)
47
+ {
48
+ this.#activeFieldSetId = fieldSet.id;
49
+ }
50
+
51
+ setActiveField(field)
52
+ {
53
+ this.#activeFieldId = field.id;
54
+ }
55
+
56
+ clearActive()
57
+ {
58
+ this.#activeFieldSetId = null;
59
+ this.#activeFieldId = null;
60
+ this.form.dataBinder.clearValueHandlers();
61
+ }
62
+
63
+ createPanelBar(container, id, cloneId, panels)
64
+ {
65
+ const panelBar = $UI.createComponent(componyx.UI.PanelBar, { id: id, containerElement: container });
66
+ panelBar.clone($UI.store[cloneId], this.form);
67
+
68
+ panelBar.events.onPostRender.priorityAdd(() => { this.form.isReady(); }, null, true);
69
+ panelBar.expandOnPointerEnter = false;
70
+ panelBar.showing = true;
71
+ panelBar.panels = panels;
72
+ this.panelBar = panelBar;
73
+ }
74
+
75
+ applyPanelTemplate(contentEl, templateId)
76
+ {
77
+ contentEl.innerHTML = '';
78
+ this.form.applyTemplate(contentEl, templateId, this.#getTemplateValues(templateId));
79
+ }
80
+
81
+ renderPanel(item, contentEl, fields = [], templateId, idPrefix = '', namePrefix = '')
82
+ {
83
+ this.applyPanelTemplate(contentEl, templateId);
84
+
85
+ for (const fieldDef of fields)
86
+ {
87
+ if (!fieldDef) continue;
88
+
89
+ let { id, name, label, type, value, options, checked, placeholder, config = {}, events, fieldElement, disableDataBinding } = fieldDef,
90
+ fullId = `${idPrefix}${id}`,
91
+ inputId = `${idPrefix}${id}_input`,
92
+ defaultPlaceholder = this.labels[id + 'Hint'],
93
+ element, input;
94
+
95
+ name = (name) ? name : namePrefix + id;
96
+
97
+ if (!(element = $lib(`#${fullId}`)))
98
+ continue;
99
+
100
+ if (!label)
101
+ label = this.labels[id]; // auto set label
102
+
103
+ if (!placeholder && defaultPlaceholder)
104
+ placeholder = defaultPlaceholder;
105
+
106
+ if ($lib.isEmpty(config.labelDisplay) && ' checkbox radio '.indexOf(` ${type} `) == -1)
107
+ {
108
+ config.labelDisplay = componyx.UI.FormField.LabelDisplayOption.ABOVE;
109
+ }
110
+
111
+ if (!type && fieldElement)
112
+ {
113
+ this.renderComponentField(contentEl, element, label, fieldElement, config);
114
+ continue;
115
+ }
116
+
117
+ if (Array.isArray(options) && options.length > 0)
118
+ {
119
+ const container = $lib.element({ attrs: { class: this.getCssClass(this.classOption.CONFIG_CHOICE_GROUP) } });
120
+ for (const opt of options)
121
+ {
122
+ inputId = `${fullId}_${opt.value}_input`;
123
+ input = type === 'radio' ? this.cf.createRadio(inputId, name, opt.value, opt.checked || false, opt.events) : this.cf.createCheckbox(inputId, name, opt.value, opt.checked || false, opt.events);
124
+ this.cf.createFormField(container, `${fullId}_${opt.value}_field`, '', opt.label || opt.value, input, { ...config, inline: true });
125
+
126
+ if (!disableDataBinding)
127
+ this.#setSettingAttribute(input);
128
+ }
129
+ this.cf.createFormField(contentEl, `${element.id}_field`, '', label, container, config);
130
+ }
131
+ else
132
+ {
133
+ if (type === 'checkbox' && checked === undefined && item[id] != null)
134
+ checked = item[id];
135
+ else if (type !== 'checkbox' && value === undefined && item[id] != null)
136
+ value = item[id];
137
+
138
+ switch (type)
139
+ {
140
+ case 'input':
141
+ input = this.cf.createTextInput(inputId, name, value, placeholder, events);
142
+ break;
143
+ case 'textarea':
144
+ input = this.cf.createTextarea(inputId, name, value, placeholder, events);
145
+ break;
146
+ case 'checkbox':
147
+ input = this.cf.createCheckbox(inputId, name, value, checked || false, events);
148
+ break;
149
+ default:
150
+ continue;
151
+ }
152
+
153
+ if (!disableDataBinding)
154
+ this.#setSettingAttribute(input);
155
+
156
+ this.cf.createFormField(contentEl, `${element.id}_field`, '', label, input, config);
157
+ }
158
+ }
159
+ }
160
+
161
+ renderComponentField(contentEl, element, label, fieldElement, config)
162
+ {
163
+ if (!config.events)
164
+ config.events = {};
165
+
166
+ config.events.onPostRender = (formField) =>
167
+ {
168
+ const componentId = formField.id.replace(/_field$/, '_input'),
169
+ component = $UI.store[componentId];
170
+
171
+ if (!component)
172
+ return;
173
+
174
+ if (component.renderState === $base.static.RenderState.RENDERED)
175
+ formField.linkLabelToInput();
176
+ else
177
+ component.events.onPostRender.priorityAdd(() => { formField.linkLabelToInput(); });
178
+ };
179
+
180
+ this.cf.createFormField(contentEl, `${element.id}_field`, '', label, fieldElement, config);
181
+ }
182
+
183
+ renderFieldSetPanel(fieldSet)
184
+ {
185
+ const panelId = 'FieldSetPanel',
186
+ templateId = fieldSet.panelTemplates?.[panelId] ?? panelId,
187
+ panel = this.panelBar.panels.find(p => p.id === panelId),
188
+ contentEl = panel.contentElement,
189
+ idPrefix = `${this.form.id}_${panelId}_`,
190
+ events = this.createBindingEvents(fieldSet),
191
+ selectLabelDisplay = (combo, args) => { this.form.setLabelDisplay(fieldSet, args.item.value); },
192
+ parentFieldSet = fieldSet.parent,
193
+ isRepeatable = (parentFieldSet && parentFieldSet.type === 'FieldSet');
194
+
195
+ this.renderPanel(fieldSet, contentEl, [
196
+ { id: 'id', label: this.labels.fieldSetId, type: 'input', value: fieldSet.id, disableDataBinding: true, config: { disabled: true } },
197
+ { id: 'layout', label: this.labels.fieldSetLayout, fieldElement: this.#createLayoutCombo(`${idPrefix}layout_input`, events) },
198
+ { id: 'labelDisplay', label: this.labels.fieldLabelDisplay, fieldElement: this.#createLabelDisplayCombo(`${idPrefix}labelDisplay_input`, { onItemSelect: selectLabelDisplay }, true) },
199
+ (isRepeatable) ? { id: 'repeatable', label: this.labels.fieldSetRepeatable, type: 'checkbox', config: { switch: true } } : null,
200
+ (isRepeatable) ? {
201
+ id: 'maxRepeats', label: this.labels.fieldSetMaxRepeats, fieldElement: this.cf.createNumericBox(this.form, `${idPrefix}maxRepeats_input`, this.form.panelMaxRepeatsNumericBoxId,
202
+ {
203
+ name: `maxRepeats`,
204
+ value: fieldSet.maxRepeats,
205
+ events
206
+ }).element
207
+ } : null,
208
+ (isRepeatable) ? { id: 'repeatLabel', label: this.labels.fieldSetRepeatLabel, type: 'input', value: fieldSet.repeatLabel } : null,
209
+ { id: 'tooltip', type: 'textarea' },
210
+ { id: 'lineBreak', type: 'checkbox', config: { switch: true } },
211
+ { id: 'visible', type: 'checkbox', config: { switch: true } },
212
+ { id: 'disabled', type: 'checkbox', config: { switch: true } }
213
+ ], templateId, idPrefix);
214
+
215
+ this.bindProperties(fieldSet, contentEl);
216
+ }
217
+
218
+ renderFieldTypePanel(field)
219
+ {
220
+ if (field.type === 'ContentField')
221
+ this.renderContentFieldPanel(field);
222
+ else if (field.type === 'SpacerField')
223
+ this.renderSpacerFieldPanel(field);
224
+ else
225
+ this.renderFieldPanel(field);
226
+ }
227
+
228
+ renderFieldPanel(field)
229
+ {
230
+ const panelId = 'FieldPanel',
231
+ templateId = field.panelTemplates?.[panelId] ?? panelId,
232
+ panel = this.panelBar.panels.find(p => p.id === panelId),
233
+ contentEl = panel.contentElement,
234
+ idPrefix = `${this.form.id}_${panelId}_`,
235
+ showPlaceholder = (field.inputType <= this.InputTypeOption.TEXTAREA || field.inputType == this.InputTypeOption.COMBOBOX || field.inputType == this.InputTypeOption.NUMERICBOX),
236
+ showValue = (field.inputType <= this.InputTypeOption.TEXTAREA),
237
+ events = this.createBindingEvents(field),
238
+ hasComponentPanel = (field.inputType >= this.InputTypeOption.MASKEDTEXTBOX),
239
+ hasRoles = this.form.fieldRoles?.length > 0;
240
+
241
+ let customConfigFields = [];
242
+ let fields = [
243
+ {
244
+ id: 'name', label: this.labels.fieldName, type: 'input', config: { required: true }, disableDataBinding: true,
245
+ events: {
246
+ input: (e) =>
247
+ {
248
+ const val = e.target.value,
249
+ duplicate = this.form.getFields().some(f => f.id !== field.id && f.name === val);
250
+
251
+ if (!val || duplicate)
252
+ e.target.classList.add('invalid');
253
+ else
254
+ e.target.classList.remove('invalid');
255
+ },
256
+ blur: (e) =>
257
+ {
258
+ const oldName = field.name,
259
+ val = e.target.value.trim(),
260
+ duplicate = this.form.getFields().some(f => f.id !== field.id && f.name === val);
261
+
262
+ e.target.classList.remove('invalid');
263
+
264
+ if (!val || duplicate)
265
+ e.target.value = field.name = field.id; // reset
266
+ else
267
+ {
268
+ field.name = val;
269
+
270
+ this.form.getFields().forEach(f =>
271
+ {
272
+ (f.ruleCases || []).forEach(ruleCase =>
273
+ {
274
+ (ruleCase.actions || []).forEach(action =>
275
+ {
276
+ if (action.expression)
277
+ {
278
+ const found = [];
279
+
280
+ this.expressionEngine.evaluate(action.expression, (token, startIndex) =>
281
+ {
282
+ if (token === oldName)
283
+ found.push({ startIndex, length: token.length });
284
+ });
285
+
286
+ if (found.length > 0)
287
+ {
288
+ // Sort found by descending startIndex to avoid messing up indexes during replacements
289
+ found.sort((a, b) => b.startIndex - a.startIndex);
290
+
291
+ let expr = action.expression;
292
+
293
+ for (const f of found)
294
+ {
295
+ expr = expr.substring(0, f.startIndex) + val + expr.substring(f.startIndex + f.length);
296
+ }
297
+
298
+ action.expression = expr;
299
+
300
+ if (f.id === field.id)
301
+ this.renderRulesPanel(field);
302
+ }
303
+ }
304
+ });
305
+ });
306
+ });
307
+ }
308
+
309
+ this.form.autoNameCandidates.delete(field.id);
310
+ this.form.save();
311
+ }
312
+ }
313
+ },
314
+ { id: 'labelDisplay', label: this.labels.fieldLabelDisplay, fieldElement: this.#createLabelDisplayCombo(`${idPrefix}labelDisplay_input`, events) },
315
+ (showPlaceholder) ? { id: 'placeholder', label: this.labels.fieldPlaceholder, type: 'input' } : null,
316
+ { id: 'tooltip', type: 'textarea' },
317
+ (showValue) ? { id: 'value', type: (field.inputType == this.InputTypeOption.TEXTAREA) ? 'textarea' : 'input' } : null,
318
+ (hasRoles) ? { id: 'role', label: this.labels.fieldRole, fieldElement: this.#createFieldRoleCombo(`${idPrefix}fieldRole_input`, field, events), config: { tooltipId: this.cf.addTooltip(`${idPrefix}role_tooltip`, { tooltip: this.labels.fieldRoleTooltip }) } } : null,
319
+ { id: 'width', label: this.labels.fieldWidth, fieldElement: this.#createFieldWidthCombo(`${idPrefix}fieldWidth_input`, field, events), config: { tooltipId: this.cf.addTooltip(`${idPrefix}width_tooltip`, { tooltip: this.labels.fieldWidthTooltip }) } },
320
+ { id: 'required', label: this.labels.validationRequired, type: 'checkbox', config: { switch: true } },
321
+ { id: 'lineBreak', type: 'checkbox', config: { switch: true } },
322
+ { id: 'visible', type: 'checkbox', config: { switch: true } },
323
+ { id: 'disabled', type: 'checkbox', config: { switch: true }, events: { onchange: (evt) => { this.setDisabled(`${idPrefix}readOnly_field`, evt.target.checked); } } },
324
+ (showValue) ? { id: 'readOnly', type: 'checkbox', config: { switch: true } } : null,
325
+ ];
326
+
327
+ if (field.customType)
328
+ {
329
+ const config = this.form.constructor.getCustomType(field.customType);
330
+
331
+ if (config)
332
+ customConfigFields = config.configGetter(this.form, field, panelId);
333
+ }
334
+
335
+ this.renderPanel(field, contentEl, [...fields, ...customConfigFields], templateId, idPrefix);
336
+
337
+ if (hasComponentPanel && this.labels.fieldMoreSettings)
338
+ {
339
+ this.cf.createButton(contentEl, `${idPrefix}_more_settings`, this.moreSettingsButtonId, {
340
+ hasIcon: false,
341
+ text: this.labels.fieldMoreSettings,
342
+ cssClass: this.getCssClass(this.classOption.MORE_SETTINGS),
343
+ primary: false,
344
+ command: () => { this.panelBar.expandPanel('ComponentPanel'); }
345
+ });
346
+ }
347
+
348
+ this.bindProperties(field, contentEl);
349
+ }
350
+
351
+ renderContentFieldPanel(field)
352
+ {
353
+ const panelId = 'ContentFieldPanel',
354
+ templateId = field.panelTemplates?.[panelId] ?? panelId,
355
+ panel = this.panelBar.panels.find(p => p.id === panelId),
356
+ contentEl = panel.contentElement,
357
+ idPrefix = `${this.form.id}_${panelId}_`,
358
+ events = this.createBindingEvents(field),
359
+ colorPickerId = this.form.colorPicker.id;
360
+
361
+ this.renderPanel(field, contentEl, [
362
+ { id: 'width', label: this.labels.fieldWidth, fieldElement: this.#createFieldWidthCombo(`${idPrefix}fieldWidth_input`, field, events), config: { tooltipId: this.cf.addTooltip(`${idPrefix}width_tooltip`, { tooltip: this.labels.fieldWidthTooltip }) } },
363
+ { id: 'margin', type: 'input' },
364
+ { id: 'padding', type: 'input' },
365
+ { id: 'borderWidth', fieldElement: this.cf.createNumericBox(this.form, `${idPrefix}borderWidth_input`, this.form.borderWidthNumericBoxId, { name: 'borderWidth', minValue: 0, maxValue: 25, value: field.borderWidth, events }).element },
366
+ { id: 'borderRadius', type: 'input' },
367
+ {
368
+ id: 'borderColor',
369
+ fieldElement: this.cf.createColorButton(this.form, `${idPrefix}borderColor_input`, this.form.borderColorButtonId, { colorPickerId, name: 'borderColor', value: field.borderColor, events }).element,
370
+ config: { labelDisplay: componyx.UI.FormField.LabelDisplayOption.AFTER }
371
+ },
372
+ {
373
+ id: 'backgroundColor',
374
+ fieldElement: this.cf.createColorButton(this.form, `${idPrefix}backgroundColor_input`, this.form.backgroundColorButtonId, { colorPickerId, name: 'backgroundColor', value: field.backgroundColor, events }).element,
375
+ config: { labelDisplay: componyx.UI.FormField.LabelDisplayOption.AFTER }
376
+ },
377
+ { id: 'lineBreak', type: 'checkbox', config: { switch: true } },
378
+ { id: 'visible', type: 'checkbox', config: { switch: true } },
379
+ ], templateId, idPrefix);
380
+
381
+ this.bindProperties(field, contentEl);
382
+ }
383
+
384
+ renderSpacerFieldPanel(field)
385
+ {
386
+ const panelId = 'SpacerFieldPanel',
387
+ templateId = field.panelTemplates?.[panelId] ?? panelId,
388
+ panel = this.panelBar.panels.find(p => p.id === panelId),
389
+ contentEl = panel.contentElement,
390
+ idPrefix = `${this.form.id}_${panelId}_`;
391
+
392
+ this.renderPanel(field, contentEl, [
393
+ { id: 'showDivider', type: 'checkbox', config: { switch: true } },
394
+ { id: 'height', type: 'input' }
395
+ ], templateId, idPrefix);
396
+
397
+ this.bindProperties(field, contentEl);
398
+ }
399
+
400
+ renderComponentPanel(field)
401
+ {
402
+ this.componentPanel.render(field);
403
+ }
404
+
405
+ renderOptionsPanel(field)
406
+ {
407
+ this.optionsPanel.render(field);
408
+ }
409
+
410
+ renderValidationPanel(field)
411
+ {
412
+ const panelId = 'ValidationPanel',
413
+ templateId = field.panelTemplates?.[panelId] ?? panelId,
414
+ panel = this.panelBar.panels.find(p => p.id === panelId),
415
+ contentEl = panel.contentElement,
416
+ idPrefix = `${this.form.id}_${panelId}_`,
417
+ namePrefix = 'validationSettings.',
418
+ settings = field.validationSettings || new this.form.constructor.ValidationSettings(),
419
+ events = this.createBindingEvents(field); // bind components
420
+
421
+ if (!settings.compareOperator)
422
+ settings.compareOperator = '==';
423
+
424
+ settings.parent = field;
425
+
426
+ this.renderPanel(field, contentEl, [
427
+ { id: 'required', label: this.labels.validationRequired, type: 'checkbox', config: { switch: true } },
428
+ { id: 'dataType', name: `${namePrefix}dataType`, label: this.labels.validationDataType, fieldElement: this.#createDataTypeCombo(idPrefix, namePrefix, events) },
429
+ { id: 'length', label: this.labels.validationLength, fieldElement: this.#createLengthField(idPrefix, namePrefix, events) },
430
+ { id: 'range', label: this.labels.validationRange, fieldElement: this.#createRangeField(idPrefix, namePrefix, events) },
431
+ { id: 'pattern', name: `${namePrefix}pattern`, label: this.labels.validationPattern, placeholder: this.labels.validationPatternHint, type: 'textarea' },
432
+ { id: 'compare', label: this.labels.validationCompare, fieldElement: this.#createCompareField(idPrefix, namePrefix, field, events), config: { disabled: this.form.getFields().length <= 1 } },
433
+ ], templateId, idPrefix);
434
+
435
+ this.bindProperties(field, contentEl);
436
+ }
437
+
438
+ renderRulesPanel(field)
439
+ {
440
+ this.rulesPanel.render(field);
441
+ }
442
+
443
+ createBindingEvents(item)
444
+ {
445
+ this.form.dataBinder.cancelUpdate();
446
+
447
+ return {
448
+ onPostRender: (component) =>
449
+ {
450
+ this.form.dataBinder.bindSettingProperties(item, component.element);
451
+ this.form.dataBinder.updateView(true);
452
+ }
453
+ };
454
+ }
455
+
456
+ bindProperties(item, contentEl)
457
+ {
458
+ this.form.dataBinder.bindSettingProperties(item, contentEl);
459
+ }
460
+
461
+ setDisabled(ids, disabled = true)
462
+ {
463
+ if (!Array.isArray(ids))
464
+ ids = [ids];
465
+
466
+ ids.forEach(id =>
467
+ {
468
+ const formField = $UI.store[id];
469
+
470
+ if (!formField)
471
+ return;
472
+
473
+ if (disabled)
474
+ formField.disable();
475
+ else
476
+ formField.enable();
477
+ });
478
+ }
479
+
480
+ toggleFieldDisplay(idPrefix, id, show)
481
+ {
482
+ const formField = $UI.store[idPrefix + id + '_field'];
483
+
484
+ if (show)
485
+ formField.show();
486
+ else
487
+ formField.hide();
488
+ }
489
+
490
+ createDataSourceCombo(id, inputType, name, events)
491
+ {
492
+ return this.cf.createComboBox(this.form, id, this.form.dataSourceComboBoxId,
493
+ {
494
+ name: name,
495
+ placeholder: this.labels.comboBoxDefaultHint,
496
+ allowInput: false,
497
+ itemList: this.form.dataSources
498
+ .filter(ds => [ds.inputType].flat().includes(inputType))
499
+ .map(ds => ({ id: ds.id, text: ds.label })),
500
+ events
501
+ }).element;
502
+ }
503
+
504
+ #setSettingAttribute(element)
505
+ {
506
+ element.setAttribute('data-ui-form-setting', '');
507
+ }
508
+
509
+ #createLayoutCombo(id, events)
510
+ {
511
+ return this.cf.createComboBox(this.form, id, this.form.layoutComboBoxId, {
512
+ name: 'layout',
513
+ placeholder: this.labels.comboBoxDefaultHint,
514
+ allowInput: false,
515
+ itemList: [{ id: '0', text: this.labels.fieldSetLayoutNone },
516
+ { id: '1', text: this.labels.fieldSetLayoutDefault },
517
+ { id: '2', text: this.labels.fieldSetLayoutBannered }],
518
+ events
519
+ }).element;
520
+ }
521
+
522
+ #createLabelDisplayCombo(id, events, isFieldSet = false)
523
+ {
524
+ const itemList = [{ id: '1', value: '3', text: this.labels.fieldLabelDisplayAbove },
525
+ { id: '2', value: '4', text: this.labels.fieldLabelDisplayBefore },
526
+ { id: '3', value: '1', text: this.labels.fieldLabelDisplayFloating },
527
+ { id: '4', value: '2', text: this.labels.fieldLabelDisplayInside }];
528
+
529
+ return this.cf.createComboBox(this.form, id, this.form.labelDisplayComboBoxId, {
530
+ name: 'labelDisplay',
531
+ placeholder: this.labels.comboBoxDefaultHint,
532
+ allowInput: false,
533
+ itemList: itemList,
534
+ events,
535
+ _disableDataBinding: isFieldSet
536
+ }).element;
537
+ }
538
+
539
+ #createFieldRoleCombo(id, field, events)
540
+ {
541
+ const fields = this.form.getFields(),
542
+ isCompatibleType = (fieldInputType, roleInputType) =>
543
+ {
544
+ if (!roleInputType) return true;
545
+
546
+ if (Array.isArray(roleInputType))
547
+ return roleInputType.includes(fieldInputType);
548
+
549
+ return roleInputType === fieldInputType;
550
+ },
551
+ assignedRoles = new Set(fields.filter(f => f.id !== field.id && f.role).map(f => f.role)),
552
+ itemList = this.form.fieldRoles
553
+ .filter(role =>
554
+ !assignedRoles.has(role.id) &&
555
+ isCompatibleType(field.inputType, role.inputType))
556
+ .map(role => ({ id: role.id, text: role.label }));
557
+
558
+ return this.cf.createComboBox(this.form, id, this.form.fieldWidthComboBoxId, {
559
+ name: 'role',
560
+ placeholder: this.labels.comboBoxDefaultHint,
561
+ allowInput: false,
562
+ value: field.role,
563
+ itemList: itemList,
564
+ disabled: !itemList.length,
565
+ events
566
+ }).element;
567
+ }
568
+
569
+ #createFieldWidthCombo(id, field, events)
570
+ {
571
+ return this.cf.createComboBox(this.form, id, this.form.fieldWidthComboBoxId, {
572
+ name: 'width',
573
+ placeholder: this.labels.fieldWidthHint,
574
+ allowInput: true,
575
+ allowCustomValue: true,
576
+ value: field.width,
577
+ itemList: [
578
+ { id: '1', text: this.labels.fieldWidth1PerRow, value: '100%' },
579
+ { id: '2', text: this.labels.fieldWidth2PerRow, value: '50%' },
580
+ { id: '3', text: this.labels.fieldWidth3PerRow, value: '33%' },
581
+ { id: '4', text: this.labels.fieldWidth4PerRow, value: '25%' },
582
+ { id: '5', text: this.labels.fieldWidthAuto, value: '' }],
583
+ events
584
+ }).element;
585
+ }
586
+
587
+ #createDataTypeCombo(idPrefix, namePrefix, events)
588
+ {
589
+ return this.cf.createComboBox(this.form, `${idPrefix}dataType_input`, this.form.dataTypeComboBoxId, {
590
+ name: `${namePrefix}dataType`,
591
+ placeholder: this.labels.comboBoxDefaultHint,
592
+ allowInput: false,
593
+ itemList: [{ id: '0', text: this.labels.validationDataTypeInteger },
594
+ { id: '1', text: this.labels.validationDataTypeFloat },
595
+ { id: '2', text: this.labels.validationDataTypeDateTime },
596
+ { id: '3', text: this.labels.validationDataTypeEmail },
597
+ { id: '4', text: this.labels.validationDataTypeURL },
598
+ { id: '5', text: this.labels.validationDataTypeSource }],
599
+ events
600
+ }).element;
601
+ }
602
+
603
+ #createCompareOperatorCombo(id, namePrefix, events)
604
+ {
605
+ return this.cf.createComboBox(this.form, id, this.form.compareOperatorComboBoxId, {
606
+ name: `${namePrefix}compareOperator`,
607
+ cssClass: this.getCssClass(this.classOption.COMBOBOX_VAL_COMPARE_OPERATOR),
608
+ allowInput: false,
609
+ disableClearButton: true,
610
+ itemList: [{ id: '0', value: '==', text: this.labels.operator_equal },
611
+ { id: '1', value: '<', text: this.labels.operator_less_than },
612
+ { id: '2', value: '<=', text: this.labels.operator_less_than_or_equal },
613
+ { id: '3', value: '>=', text: this.labels.operator_greater_than_or_equal },
614
+ { id: '4', value: '>', text: this.labels.operator_greater_than }],
615
+ events
616
+ }).element;
617
+ }
618
+
619
+ #createCompareFieldCombo(id, field, namePrefix, events)
620
+ {
621
+ const fields = this.form.getFields(),
622
+ itemList = fields.filter(f => f.id !== field.id).map(f => ({ id: f.id, text: f.name }));
623
+
624
+ return this.cf.createComboBox(this.form, id, this.form.compareFieldComboBoxId, {
625
+ name: `${namePrefix}compareFieldId`,
626
+ placeholder: this.labels.comboBoxDefaultHint,
627
+ cssClass: this.getCssClass(this.classOption.COMBOBOX_VAL_COMPARE_FIELD),
628
+ allowInput: false,
629
+ itemList,
630
+ events
631
+ }).element;
632
+ }
633
+
634
+ #createLengthField(idPrefix, namePrefix, events)
635
+ {
636
+ const container = $lib.element(),
637
+ minLength = this.cf.createNumericBox(this.form, `${idPrefix}min_length_input`, this.form.minLengthNumericBoxId, { name: namePrefix + 'minLength', placeholder: this.labels.validationMinLengthHint, events }).element,
638
+ maxLength = this.cf.createNumericBox(this.form, `${idPrefix}max_length_input`, this.form.maxLengthNumericBoxId, { name: namePrefix + 'maxLength', placeholder: this.labels.validationMaxLengthHint, events }).element;
639
+
640
+ container.appendChild(minLength);
641
+ container.appendChild(maxLength);
642
+ return container;
643
+ }
644
+
645
+ #createRangeField(idPrefix, namePrefix, events)
646
+ {
647
+ const container = $lib.element(),
648
+ minRange = this.cf.createNumericBox(this.form, `${idPrefix}min_range_input`, this.form.minRangeNumericBoxId, { name: namePrefix + 'minRange', placeholder: this.labels.validationMinRangeHint, events }).element,
649
+ maxRange = this.cf.createNumericBox(this.form, `${idPrefix}max_range_input`, this.form.maxRangeNumericBoxId, { name: namePrefix + 'maxRange', placeholder: this.labels.validationMaxRangeHint, events }).element;
650
+
651
+ container.appendChild(minRange);
652
+ container.appendChild(maxRange);
653
+ return container;
654
+ }
655
+
656
+ #createCompareField(idPrefix, namePrefix, field, events)
657
+ {
658
+ const container = $lib.element(),
659
+ compareOperatorEl = this.#createCompareOperatorCombo(`${idPrefix}compare_operator_input`, namePrefix, events),
660
+ compareFieldEl = this.#createCompareFieldCombo(`${idPrefix}compare_field_input`, field, namePrefix, events);
661
+
662
+ container.appendChild(compareOperatorEl);
663
+ container.appendChild(compareFieldEl);
664
+ return container;
665
+ }
666
+
667
+ #getTemplateValues(templateId)
668
+ {
669
+ let values = {},
670
+ idPrefix = `${this.form.id}_${templateId}_`,
671
+ templateTags = this.form.getTemplateTags(templateId);
672
+
673
+ $lib.each(templateTags, (tag) =>
674
+ {
675
+ values[tag] = `<div id="${idPrefix}${tag}"></div>`;
676
+ });
677
+
678
+ return values;
679
+ }
680
+ };
681
+ })();
682
+
683
+ var ConfigPanelManager = componyx.UI.form_modules.ConfigPanelManager;
684
+
685
+ export { ConfigPanelManager as default };