@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,576 @@
|
|
|
1
|
+
/*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
|
|
2
|
+
import '../Base/Base.js';
|
|
3
|
+
import '../Base/Library.js';
|
|
4
|
+
|
|
5
|
+
(function (window)
|
|
6
|
+
{
|
|
7
|
+
/**
|
|
8
|
+
* FormField class.
|
|
9
|
+
* @class
|
|
10
|
+
* @memberof componyx.UI
|
|
11
|
+
* @augments componyx.UI.base.Component
|
|
12
|
+
* @param {String} id The id of the component.
|
|
13
|
+
* @param {Object|HTMLElement} properties The properties used to initialize the component or the container element.
|
|
14
|
+
* @returns {Object} An instance of the component.
|
|
15
|
+
*/
|
|
16
|
+
componyx.UI.FormField = function (id, properties)
|
|
17
|
+
{
|
|
18
|
+
// define private properties
|
|
19
|
+
let _instance = this,
|
|
20
|
+
_formElements = 'input:not([type="hidden"]):not([type="file"]), textarea, select',
|
|
21
|
+
_labelDisplayOption = componyx.UI.FormField.LabelDisplayOption,
|
|
22
|
+
_tooltipIcon,
|
|
23
|
+
_classOption =
|
|
24
|
+
{
|
|
25
|
+
INLINE: 'inline',
|
|
26
|
+
REQUIRED: 'required',
|
|
27
|
+
BORDERLESS: 'borderless',
|
|
28
|
+
TRANSPARENT: 'lucent',
|
|
29
|
+
SWITCH: 'switch',
|
|
30
|
+
TOOLTIP_ICON: 'icon ico-question-mark',
|
|
31
|
+
CONTENT_WRAPPER: 'field-content-wrapper',
|
|
32
|
+
DISABLED: 'disabled'
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// define public properties
|
|
36
|
+
/**
|
|
37
|
+
* Gets or sets the css class which is appended to the formfield class when inline is enabled.
|
|
38
|
+
* @type {String}
|
|
39
|
+
*/
|
|
40
|
+
this.cssClassInline = '';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Gets or sets the css class which is appended to the formfield class when required is enabled.
|
|
44
|
+
* @type {String}
|
|
45
|
+
*/
|
|
46
|
+
this.cssClassRequired = '';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets or sets the css class which is appended to the formfield class when borderless is enabled.
|
|
50
|
+
* @type {String}
|
|
51
|
+
*/
|
|
52
|
+
this.cssClassBorderless = '';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Gets or sets the css class which is appended to the formfield class when transparent is enabled.
|
|
56
|
+
* @type {String}
|
|
57
|
+
*/
|
|
58
|
+
this.cssClassTransparent = '';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gets or sets the css class which is appended to the formfield class when switch is enabled.
|
|
62
|
+
* @type {String}
|
|
63
|
+
*/
|
|
64
|
+
this.cssClassSwitch = '';
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets or sets the css class of the form field label element.
|
|
68
|
+
* @type {String}
|
|
69
|
+
*/
|
|
70
|
+
this.cssClassLabel = '';
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Gets or sets the css class of the form field tooltip icon element.
|
|
74
|
+
* @type {String}
|
|
75
|
+
*/
|
|
76
|
+
this.cssClassTooltipIcon = '';
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Gets or sets the css class of the form field content wrapper element when wrapFieldContent is set to true or the field root element is not an input field and the label display is set to above/floating/inside.
|
|
80
|
+
* @type {String}
|
|
81
|
+
*/
|
|
82
|
+
this.cssClassContentWrapper = '';
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Gets or sets the text label.
|
|
86
|
+
* @type {String}
|
|
87
|
+
*/
|
|
88
|
+
this.label = '';
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Gets or sets a value indicating whether the formfield is displayed as inline or block element.
|
|
92
|
+
* @type {Boolean}
|
|
93
|
+
*/
|
|
94
|
+
this.inline = false;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gets or sets a value indicating if the form field is required.
|
|
98
|
+
* @type {Boolean}
|
|
99
|
+
*/
|
|
100
|
+
this.required = false;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Gets or sets a value indicating if the form field is rendered without the top, left and right borders.
|
|
104
|
+
* @type {Boolean}
|
|
105
|
+
*/
|
|
106
|
+
this.borderless = true;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets or sets a value indicating if the checkbox or radio field must be rendered transparent.
|
|
110
|
+
* @type {Boolean}
|
|
111
|
+
*/
|
|
112
|
+
this.transparent = false;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Gets or sets a value indicating if the form field must be rendered as switch control. This option has effect only when the field is an input of type checkbox.
|
|
116
|
+
* @type {Boolean}
|
|
117
|
+
*/
|
|
118
|
+
this.switch = false;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Gets or sets a value indicating if the form field content is placed inside a wrapper element.
|
|
122
|
+
* @type {Boolean}
|
|
123
|
+
*/
|
|
124
|
+
this.wrapFieldContent = false;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Gets or sets a value indicating if the form field is disabled.
|
|
128
|
+
* @type {Boolean}
|
|
129
|
+
*/
|
|
130
|
+
this.disabled = false;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Gets or sets a value indicating whether the label is displayed automatically, inside, above, before or after the form input field.
|
|
134
|
+
* @type {componyx.UI.FormField.LabelDisplayOption}
|
|
135
|
+
*/
|
|
136
|
+
this.labelDisplay = _labelDisplayOption.AUTO;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Gets or sets the tooltip manager used to display tooltips.
|
|
140
|
+
* @type {String|null}
|
|
141
|
+
*/
|
|
142
|
+
this.tooltipManagerId = null;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Gets or sets the id of the tooltip to show.
|
|
146
|
+
* @type {String|null}
|
|
147
|
+
*/
|
|
148
|
+
this.tooltipId = null;
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
// inherit base instance members
|
|
152
|
+
$base.Component.apply(this, [id, properties]);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Enables or disables the inline state of the form field.
|
|
156
|
+
* @param {Boolean} enable A value indicating if the option should be enabled or disabled.
|
|
157
|
+
*/
|
|
158
|
+
this.setInline = function (enable)
|
|
159
|
+
{
|
|
160
|
+
setCss(enable, _instance.cssClassInline || _classOption.INLINE);
|
|
161
|
+
_instance.inline = enable || false;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Enables or disables the required state of the form field.
|
|
166
|
+
* @param {Boolean} enable A value indicating if the option should be enabled or disabled.
|
|
167
|
+
*/
|
|
168
|
+
this.setRequired = function (enable)
|
|
169
|
+
{
|
|
170
|
+
setCss(enable, _instance.cssClassRequired || _classOption.REQUIRED);
|
|
171
|
+
_instance.required = enable || false;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Enables or disables the borderless field style.
|
|
176
|
+
* @param {Boolean} enable A value indicating if the option should be enabled or disabled.
|
|
177
|
+
*/
|
|
178
|
+
this.setBorderless = function (enable)
|
|
179
|
+
{
|
|
180
|
+
setCss(enable, _instance.cssClassBorderless || _classOption.BORDERLESS);
|
|
181
|
+
_instance.borderless = enable || false;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Enables or disables the transparent field style.
|
|
186
|
+
* @param {Boolean} enable A value indicating if the option should be enabled or disabled.
|
|
187
|
+
*/
|
|
188
|
+
this.setTransparent = function (enable)
|
|
189
|
+
{
|
|
190
|
+
setCss(enable, _instance.cssClassTransparent || _classOption.TRANSPARENT);
|
|
191
|
+
_instance.transparent = enable || false;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Enables or disables the switch field style.
|
|
196
|
+
* @param {Boolean} enable A value indicating if the option should be enabled or disabled.
|
|
197
|
+
*/
|
|
198
|
+
this.setSwitch = function (enable)
|
|
199
|
+
{
|
|
200
|
+
setCss(enable, _instance.cssClassSwitch || _classOption.SWITCH);
|
|
201
|
+
_instance.switch = enable || false;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Sets the label display type (inside above before after).
|
|
206
|
+
* @param {componyx.UI.FormField.LabelDisplayOption} display The label display option.
|
|
207
|
+
*/
|
|
208
|
+
this.setLabelDisplay = function (display)
|
|
209
|
+
{
|
|
210
|
+
var field = _instance.element.firstElementChild;
|
|
211
|
+
$lib.removeClass(_instance.element, 'inside above before after');
|
|
212
|
+
|
|
213
|
+
if (display == _labelDisplayOption.AUTO)
|
|
214
|
+
{
|
|
215
|
+
var name = (field) ? field.nodeName.toLowerCase() : '';
|
|
216
|
+
|
|
217
|
+
if (!isFormElement(field) || (name == 'input' && ' checkbox radio text password email search url tel '.indexOf(' ' + field.type + ' ') == -1))
|
|
218
|
+
{
|
|
219
|
+
$lib.addClass(_instance.element, _labelDisplayOption.getName(_labelDisplayOption.ABOVE));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (name == 'input' && (field.type == 'checkbox' || field.type == 'radio'))
|
|
224
|
+
$lib.addClass(_instance.element, _labelDisplayOption.getName(_labelDisplayOption.AFTER));
|
|
225
|
+
else
|
|
226
|
+
setInsideDisplay(_labelDisplayOption.FLOATING);
|
|
227
|
+
}
|
|
228
|
+
else if (display <= _labelDisplayOption.INSIDE)
|
|
229
|
+
{
|
|
230
|
+
setInsideDisplay(display);
|
|
231
|
+
}
|
|
232
|
+
else
|
|
233
|
+
$lib.addClass(_instance.element, _labelDisplayOption.getName(display));
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Adds the content template for the label.
|
|
239
|
+
* @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The label template content.
|
|
240
|
+
*/
|
|
241
|
+
this.setLabelTemplate = function (content)
|
|
242
|
+
{
|
|
243
|
+
_instance.addTemplate('Label', content, false);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Adds the content template for the field.
|
|
248
|
+
* @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The field template content.
|
|
249
|
+
*/
|
|
250
|
+
this.setFieldTemplate = function (content)
|
|
251
|
+
{
|
|
252
|
+
_instance.addTemplate('Field', content, false);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Updates the label.
|
|
257
|
+
* @param {HTMLElement|HTMLElement[]|DocumentFragment|String} content The label template content.
|
|
258
|
+
*/
|
|
259
|
+
this.updateLabel = function (content)
|
|
260
|
+
{
|
|
261
|
+
let label = _instance.element.querySelector(':scope > label'),
|
|
262
|
+
b = _instance.element.querySelector(':scope > b');
|
|
263
|
+
|
|
264
|
+
if (!label)
|
|
265
|
+
return;
|
|
266
|
+
|
|
267
|
+
label.innerHTML = '';
|
|
268
|
+
_instance.addTemplate('Label', content, false);
|
|
269
|
+
_instance.applyTemplate(label, 'Label');
|
|
270
|
+
|
|
271
|
+
if (b)
|
|
272
|
+
{
|
|
273
|
+
b.setAttribute('title', label.textContent);
|
|
274
|
+
bindLabelEvent(b);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
_instance.updateTooltip();
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Links the label to the nested input by setting htmlFor and, if necessary, assigning an ID to the input.
|
|
282
|
+
* Adds a placeholder attribute if missing to support CSS styling.
|
|
283
|
+
*/
|
|
284
|
+
this.linkLabelToInput = function ()
|
|
285
|
+
{
|
|
286
|
+
const guid = `${_instance.id}_${$lib.guid()}`,
|
|
287
|
+
label = _instance.element.querySelector(':scope > label'),
|
|
288
|
+
formEl = getFormElement();
|
|
289
|
+
|
|
290
|
+
if (label && formEl)
|
|
291
|
+
{
|
|
292
|
+
if (!formEl.id)
|
|
293
|
+
formEl.id = guid;
|
|
294
|
+
|
|
295
|
+
label.htmlFor = formEl.id;
|
|
296
|
+
|
|
297
|
+
if (!formEl.hasAttribute('placeholder'))
|
|
298
|
+
formEl.setAttribute('placeholder', ''); // placeholder is required for css :placeholder-shown to work
|
|
299
|
+
|
|
300
|
+
const observer = new MutationObserver(() =>
|
|
301
|
+
{
|
|
302
|
+
if (formEl.id)
|
|
303
|
+
{
|
|
304
|
+
label.htmlFor = formEl.id;
|
|
305
|
+
observer.disconnect(); // fire once, then done
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
observer.observe(formEl, { attributes: true, attributeFilter: ['id'] });
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Recreates the tooltip icon for the element and updates its trigger in the tooltip manager.
|
|
315
|
+
*/
|
|
316
|
+
this.updateTooltip = function ()
|
|
317
|
+
{
|
|
318
|
+
if (_instance.tooltipManagerId)
|
|
319
|
+
{
|
|
320
|
+
const tooltipManager = $UI.store[_instance.tooltipManagerId];
|
|
321
|
+
|
|
322
|
+
if (_tooltipIcon)
|
|
323
|
+
{
|
|
324
|
+
tooltipManager.removeTrigger(_tooltipIcon);
|
|
325
|
+
_tooltipIcon.remove();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (_instance.tooltipId)
|
|
329
|
+
{
|
|
330
|
+
_tooltipIcon = $lib.element({ container: _instance.element.querySelector(':scope > label'), tag: 'i', attrs: { class: _instance.cssClassTooltipIcon || _classOption.TOOLTIP_ICON } });
|
|
331
|
+
tooltipManager.addTrigger(_tooltipIcon, _instance.tooltipId);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Disables the form field.
|
|
338
|
+
*/
|
|
339
|
+
this.disable = function ()
|
|
340
|
+
{
|
|
341
|
+
_instance.element.inert = true;
|
|
342
|
+
_instance.disabled = true;
|
|
343
|
+
setCss(true, _classOption.DISABLED);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Enables the form field.
|
|
348
|
+
*/
|
|
349
|
+
this.enable = function ()
|
|
350
|
+
{
|
|
351
|
+
_instance.element.inert = false;
|
|
352
|
+
_instance.disabled = false;
|
|
353
|
+
setCss(false, _classOption.DISABLED);
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Renders the component
|
|
358
|
+
*/
|
|
359
|
+
this.render = function ()
|
|
360
|
+
{
|
|
361
|
+
if (_instance.renderState != $base.static.RenderState.RENDERING)
|
|
362
|
+
{
|
|
363
|
+
// call base render and return
|
|
364
|
+
$base.methods.render.call(_instance, preRender, 'form-field');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// render logic after loading resources
|
|
369
|
+
draw();
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Handles the post render procedure.
|
|
374
|
+
*/
|
|
375
|
+
this.postRender = function ()
|
|
376
|
+
{
|
|
377
|
+
if (_instance.renderState != $base.static.RenderState.RENDERING) // extra safety to never execute a postRender when the component state is incorrect
|
|
378
|
+
return;
|
|
379
|
+
|
|
380
|
+
_instance.updateTooltip();
|
|
381
|
+
$base.methods.postRender.call(_instance);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
function preRender()
|
|
385
|
+
{
|
|
386
|
+
// initialize script and css
|
|
387
|
+
return ['FormField'];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function draw()
|
|
391
|
+
{
|
|
392
|
+
let label = document.createElement('label'),
|
|
393
|
+
element = _instance.element;
|
|
394
|
+
|
|
395
|
+
if (_instance.cssClassLabel)
|
|
396
|
+
$lib.addClass(label, _instance.cssClassLabel);
|
|
397
|
+
|
|
398
|
+
_instance.applyTemplate(element, 'Field');
|
|
399
|
+
|
|
400
|
+
if (_instance.hasTemplate('Label'))
|
|
401
|
+
_instance.applyTemplate(label, 'Label');
|
|
402
|
+
else if (_instance.label)
|
|
403
|
+
label.textContent = _instance.label;
|
|
404
|
+
|
|
405
|
+
let firstChild = element.firstElementChild,
|
|
406
|
+
isFormEl = isFormElement(firstChild);
|
|
407
|
+
|
|
408
|
+
if (isFormEl && isCheckOrRadio(firstChild))
|
|
409
|
+
{
|
|
410
|
+
let b = element.appendChild(document.createElement('b'));
|
|
411
|
+
b.setAttribute('title', label.textContent);
|
|
412
|
+
bindLabelEvent(b);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
_instance.setInline(_instance.inline);
|
|
416
|
+
_instance.setRequired(_instance.required);
|
|
417
|
+
_instance.setBorderless(_instance.borderless);
|
|
418
|
+
_instance.setTransparent(_instance.transparent);
|
|
419
|
+
_instance.setSwitch(_instance.switch);
|
|
420
|
+
_instance.setLabelDisplay(_instance.labelDisplay);
|
|
421
|
+
_instance.element.inert = false; // make sure we remove a possible inert attribute from previous render
|
|
422
|
+
|
|
423
|
+
if (_instance.disabled)
|
|
424
|
+
_instance.disable();
|
|
425
|
+
|
|
426
|
+
if (_instance.wrapFieldContent || (!isFormEl && ($lib.hasClass(_instance.element, 'above') || $lib.hasClass(_instance.element, 'floating') || $lib.hasClass(_instance.element, 'inside')))) // put content inside flex column
|
|
427
|
+
{
|
|
428
|
+
let content = getFieldContent(),
|
|
429
|
+
wrapper = $lib.element({ container: _instance.element, attrs: { class: _instance.cssClassContentWrapper || _classOption.CONTENT_WRAPPER } } );
|
|
430
|
+
|
|
431
|
+
$lib.surround(wrapper, content);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
element.appendChild(label);
|
|
435
|
+
_instance.linkLabelToInput();
|
|
436
|
+
_instance.postRender();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function getFieldContent()
|
|
440
|
+
{
|
|
441
|
+
var content = document.createDocumentFragment(),
|
|
442
|
+
element = _instance.element.firstChild, next;
|
|
443
|
+
|
|
444
|
+
while (element)
|
|
445
|
+
{
|
|
446
|
+
next = element.nextSibling;
|
|
447
|
+
content.appendChild(element);
|
|
448
|
+
|
|
449
|
+
element = next;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return content;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function bindLabelEvent(el)
|
|
456
|
+
{
|
|
457
|
+
if (!$lib.has(el, 'click', pretendLabelClick))
|
|
458
|
+
$lib.on(el, 'click', pretendLabelClick);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function pretendLabelClick(e)
|
|
462
|
+
{
|
|
463
|
+
var el = getFormElement();
|
|
464
|
+
|
|
465
|
+
if (!el)
|
|
466
|
+
return;
|
|
467
|
+
|
|
468
|
+
e.stopPropagation(); // input will bubble click event
|
|
469
|
+
el.focus();
|
|
470
|
+
(el.click) ? el.click() : $lib.fireEvent(el, 'click', true, true);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function isFormElement(el)
|
|
474
|
+
{
|
|
475
|
+
if (!el || !el.nodeName) return false;
|
|
476
|
+
|
|
477
|
+
const tag = el.nodeName.toLowerCase();
|
|
478
|
+
|
|
479
|
+
if (tag === 'input')
|
|
480
|
+
{
|
|
481
|
+
const type = (el.getAttribute('type') || '').toLowerCase();
|
|
482
|
+
return type !== 'hidden';
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return tag === 'textarea' || tag === 'select';
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function getFormElement()
|
|
489
|
+
{
|
|
490
|
+
const elements = Array.from(_instance.element.querySelectorAll(_formElements)),
|
|
491
|
+
cssClass = '.form-field';
|
|
492
|
+
|
|
493
|
+
return elements.find(el =>
|
|
494
|
+
{
|
|
495
|
+
let nearestFormField = el.closest(cssClass);
|
|
496
|
+
|
|
497
|
+
if (!nearestFormField) return false;
|
|
498
|
+
|
|
499
|
+
while (nearestFormField)
|
|
500
|
+
{
|
|
501
|
+
if (nearestFormField === _instance.element)
|
|
502
|
+
return true; // Input belongs to this component
|
|
503
|
+
|
|
504
|
+
if ($UI.elementStore.has(nearestFormField))
|
|
505
|
+
return false; // Input is inside a child form-field component, skip
|
|
506
|
+
|
|
507
|
+
nearestFormField = nearestFormField.parentElement?.closest(cssClass); // Not registered, move up to the next form-field ancestor
|
|
508
|
+
}
|
|
509
|
+
return false;
|
|
510
|
+
}) || null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function isCheckOrRadio(el)
|
|
514
|
+
{
|
|
515
|
+
return (el.nodeName.toLowerCase() === 'input' && (el.type == 'checkbox' || el.type == 'radio'));
|
|
516
|
+
}
|
|
517
|
+
function setInsideDisplay(display)
|
|
518
|
+
{
|
|
519
|
+
let formEl = getFormElement(),
|
|
520
|
+
ph = 'placeholder';
|
|
521
|
+
|
|
522
|
+
if (!formEl)
|
|
523
|
+
return;
|
|
524
|
+
|
|
525
|
+
if (!formEl.hasAttribute(ph))
|
|
526
|
+
formEl.setAttribute(ph, ''); // placeholder is required for css :placeholder-shown to work
|
|
527
|
+
|
|
528
|
+
if (formEl.getAttribute(ph) === '' && (formEl.nodeName === 'TEXTAREA' || formEl.nodeName === 'INPUT'))
|
|
529
|
+
$lib.addClass(_instance.element, _labelDisplayOption.getName(display).replace('_', ' '));
|
|
530
|
+
else
|
|
531
|
+
$lib.addClass(_instance.element, _labelDisplayOption.getName(_labelDisplayOption.ABOVE));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function setCss(enable, css)
|
|
535
|
+
{
|
|
536
|
+
if (enable)
|
|
537
|
+
$lib.addClass(_instance.element, css);
|
|
538
|
+
else
|
|
539
|
+
$lib.removeClass(_instance.element, css);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* @see {@link componyx.UI.base.methods}
|
|
545
|
+
*/
|
|
546
|
+
componyx.UI.FormField.prototype = Object.create($base.methods);
|
|
547
|
+
componyx.UI.FormField.prototype.constructor = componyx.UI.FormField;
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* LabelDisplayOption
|
|
551
|
+
* @readonly
|
|
552
|
+
* @enum {number}
|
|
553
|
+
*/
|
|
554
|
+
componyx.UI.FormField.LabelDisplayOption =
|
|
555
|
+
{
|
|
556
|
+
/** The label display depends on the field type: displayed after when the field is a checkbox or radiobutton,
|
|
557
|
+
displayed floating when the field is a basic textual input and displayed above for all other field types. */
|
|
558
|
+
AUTO: 0,
|
|
559
|
+
/** the label is displayed inside the field when empty and not focused otherwise it will be displayed above the field. */
|
|
560
|
+
FLOATING: 1,
|
|
561
|
+
/** the label is displayed inside the field and will be cleared when the input field gets focus, allowing placeholder to become visible. */
|
|
562
|
+
INSIDE: 2,
|
|
563
|
+
/** the label is displayed above the field. */
|
|
564
|
+
ABOVE: 3,
|
|
565
|
+
/** the label is displayed before the field. */
|
|
566
|
+
BEFORE: 4,
|
|
567
|
+
/** the label is displayed after the field. */
|
|
568
|
+
AFTER: 5,
|
|
569
|
+
|
|
570
|
+
getName: function (value) { return $base.static.getKeyByValue(this, value).toLowerCase(); }
|
|
571
|
+
};
|
|
572
|
+
})();
|
|
573
|
+
|
|
574
|
+
const FormField = componyx.UI.FormField;
|
|
575
|
+
|
|
576
|
+
export { FormField };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
|
|
2
|
+
.form-field.theme.theme-default input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(:disabled):focus,
|
|
3
|
+
.form-field.theme.theme-default textarea:not(:disabled):focus,
|
|
4
|
+
.form-field.theme.theme-default select:not(:disabled):focus
|
|
5
|
+
{
|
|
6
|
+
box-shadow: inset 0px -2px 0px 0px var(--cui-button-selected-bg-color);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* checkbox and radiobutton */
|
|
10
|
+
.form-field.theme.theme-default > input + b
|
|
11
|
+
{
|
|
12
|
+
background-color: var(--cui-button-bg-color);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.form-field.theme.theme-default > input[type="checkbox"]:disabled ~ b::before,
|
|
16
|
+
.form-field.theme.theme-default > input[type="radio"]:disabled ~ b::before,
|
|
17
|
+
.form-field.theme.theme-default.lucent > input[type="radio"] ~ b::before,
|
|
18
|
+
.form-field.theme.theme-default.lucent > input[type="checkbox"] ~ b::before
|
|
19
|
+
{
|
|
20
|
+
border-color: var(--cui-button-basic-text-color);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.form-field.theme.theme-default > input[type="radio"]:checked ~ b::before
|
|
24
|
+
{
|
|
25
|
+
background-color: var(--cui-button-text-color);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.form-field.theme.theme-default.lucent > input ~ b
|
|
29
|
+
{
|
|
30
|
+
background-color: var(--cui-color-surface);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.form-field.theme.theme-default:not(.lucent):hover:not(.switch) > input:not(:disabled) ~ b
|
|
34
|
+
{
|
|
35
|
+
background-color: var(--cui-button-hover-bg-color);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.form-field.theme.theme-default:not(.lucent):hover:not(.switch) > input:not(:disabled) ~ b::before
|
|
39
|
+
{
|
|
40
|
+
border-color: var(--cui-button-hover-text-color);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.form-field.theme.theme-default > input:focus:not(:disabled) ~ b
|
|
44
|
+
{
|
|
45
|
+
box-shadow: inset 0 -12px 0px -8px var(--cui-focus-box-shadow-color);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.form-field.theme.theme-default:not(.lucent) > input[type="checkbox"]:checked:not(:disabled) ~ b::before,
|
|
49
|
+
.form-field.theme.theme-default:not(.lucent) > input[type="radio"]:checked:not(:disabled) ~ b::before
|
|
50
|
+
{
|
|
51
|
+
border-color: var(--cui-button-text-color);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* switch */
|
|
55
|
+
.form-field.theme.switch > input ~ b
|
|
56
|
+
{
|
|
57
|
+
background-color: var(--cui-button-basic-hover-bg-color);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.form-field.theme.theme-default.switch > input:checked ~ b
|
|
61
|
+
{
|
|
62
|
+
background-color: var(--cui-button-bg-color);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.form-field.theme.theme-default.switch > input:checked ~ b::before
|
|
66
|
+
{
|
|
67
|
+
color: var(--cui-button-bg-color);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.form-field.theme.theme-default.switch > input ~ b::before
|
|
71
|
+
{
|
|
72
|
+
background-color: var(--cui-knob-color);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* readonly */
|
|
76
|
+
.form-field.theme.theme-default input[readonly],
|
|
77
|
+
.form-field.theme.theme-default textarea[readonly],
|
|
78
|
+
.form-field.theme.theme-default select[readonly],
|
|
79
|
+
.form-field.theme.theme-default .readonly
|
|
80
|
+
{
|
|
81
|
+
background-color: var(--cui-readonly-bg-color);
|
|
82
|
+
cursor: default;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* disabled */
|
|
86
|
+
.form-field.theme.theme-default input:disabled,
|
|
87
|
+
.form-field.theme.theme-default textarea:disabled,
|
|
88
|
+
.form-field.theme.theme-default select:disabled,
|
|
89
|
+
.form-field.theme.theme-default > input:disabled ~ b,
|
|
90
|
+
.form-field.theme.theme-default.switch > input:disabled ~ b::before
|
|
91
|
+
{
|
|
92
|
+
background-color: var(--cui-disabled-bg-color);
|
|
93
|
+
color: var(--cui-disabled-text-color);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.form-field.theme.theme-default.required label::before
|
|
97
|
+
{
|
|
98
|
+
color: var(--cui-negative-text-color);
|
|
99
|
+
}
|