@syncfusion/ej2-inputs 30.2.4 → 31.1.17

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 (110) hide show
  1. package/dist/ej2-inputs.min.js +2 -2
  2. package/dist/ej2-inputs.umd.min.js +2 -2
  3. package/dist/ej2-inputs.umd.min.js.map +1 -1
  4. package/dist/es6/ej2-inputs.es2015.js +1 -1
  5. package/dist/es6/ej2-inputs.es2015.js.map +1 -1
  6. package/dist/es6/ej2-inputs.es5.js +1 -1
  7. package/dist/es6/ej2-inputs.es5.js.map +1 -1
  8. package/dist/global/ej2-inputs.min.js +2 -2
  9. package/dist/global/ej2-inputs.min.js.map +1 -1
  10. package/dist/global/index.d.ts +1 -1
  11. package/dist/ts/color-picker/color-picker-model.d.ts +186 -0
  12. package/dist/ts/color-picker/color-picker.d.ts +398 -0
  13. package/dist/ts/color-picker/color-picker.ts +2209 -0
  14. package/dist/ts/color-picker/index.d.ts +5 -0
  15. package/dist/ts/color-picker/index.ts +5 -0
  16. package/dist/ts/common/index.d.ts +4 -0
  17. package/dist/ts/common/index.ts +4 -0
  18. package/dist/ts/common/signature-base.d.ts +340 -0
  19. package/dist/ts/common/signature-base.ts +1170 -0
  20. package/dist/ts/form-validator/form-validator-model.d.ts +121 -0
  21. package/dist/ts/form-validator/form-validator.d.ts +312 -0
  22. package/dist/ts/form-validator/form-validator.ts +1068 -0
  23. package/dist/ts/form-validator/index.d.ts +5 -0
  24. package/dist/ts/form-validator/index.ts +5 -0
  25. package/dist/ts/index.d.ts +18 -0
  26. package/dist/ts/index.ts +18 -0
  27. package/dist/ts/input/index.d.ts +4 -0
  28. package/dist/ts/input/index.ts +4 -0
  29. package/dist/ts/input/input.d.ts +345 -0
  30. package/dist/ts/input/input.ts +1277 -0
  31. package/dist/ts/maskedtextbox/base/index.d.ts +4 -0
  32. package/dist/ts/maskedtextbox/base/index.ts +4 -0
  33. package/dist/ts/maskedtextbox/base/mask-base.d.ts +134 -0
  34. package/dist/ts/maskedtextbox/base/mask-base.ts +1207 -0
  35. package/dist/ts/maskedtextbox/index.d.ts +5 -0
  36. package/dist/ts/maskedtextbox/index.ts +5 -0
  37. package/dist/ts/maskedtextbox/maskedtextbox/index.d.ts +5 -0
  38. package/dist/ts/maskedtextbox/maskedtextbox/index.ts +5 -0
  39. package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox-model.d.ts +167 -0
  40. package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.d.ts +307 -0
  41. package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.ts +709 -0
  42. package/dist/ts/numerictextbox/index.d.ts +5 -0
  43. package/dist/ts/numerictextbox/index.ts +5 -0
  44. package/dist/ts/numerictextbox/numerictextbox-model.d.ts +228 -0
  45. package/dist/ts/numerictextbox/numerictextbox.d.ts +431 -0
  46. package/dist/ts/numerictextbox/numerictextbox.ts +1672 -0
  47. package/dist/ts/otp-input/index.d.ts +5 -0
  48. package/dist/ts/otp-input/index.ts +5 -0
  49. package/dist/ts/otp-input/otp-input-model.d.ts +165 -0
  50. package/dist/ts/otp-input/otp-input.d.ts +365 -0
  51. package/dist/ts/otp-input/otp-input.ts +924 -0
  52. package/dist/ts/rating/index.d.ts +5 -0
  53. package/dist/ts/rating/index.ts +5 -0
  54. package/dist/ts/rating/rating-model.d.ts +239 -0
  55. package/dist/ts/rating/rating.d.ts +416 -0
  56. package/dist/ts/rating/rating.ts +1101 -0
  57. package/dist/ts/signature/index.d.ts +5 -0
  58. package/dist/ts/signature/index.ts +5 -0
  59. package/dist/ts/signature/signature-model.d.ts +131 -0
  60. package/dist/ts/signature/signature.d.ts +167 -0
  61. package/dist/ts/signature/signature.ts +266 -0
  62. package/dist/ts/slider/index.d.ts +5 -0
  63. package/dist/ts/slider/index.ts +5 -0
  64. package/dist/ts/slider/slider-model.d.ts +401 -0
  65. package/dist/ts/slider/slider.d.ts +721 -0
  66. package/dist/ts/slider/slider.ts +3497 -0
  67. package/dist/ts/smart-textarea/caret-helper.d.ts +17 -0
  68. package/dist/ts/smart-textarea/caret-helper.ts +95 -0
  69. package/dist/ts/smart-textarea/index.d.ts +5 -0
  70. package/dist/ts/smart-textarea/index.ts +5 -0
  71. package/dist/ts/smart-textarea/smart-textarea-model.d.ts +44 -0
  72. package/dist/ts/smart-textarea/smart-textarea.d.ts +80 -0
  73. package/dist/ts/smart-textarea/smart-textarea.ts +518 -0
  74. package/dist/ts/speech-to-text/index.d.ts +5 -0
  75. package/dist/ts/speech-to-text/index.ts +5 -0
  76. package/dist/ts/speech-to-text/speech-to-text-model.d.ts +270 -0
  77. package/dist/ts/speech-to-text/speech-to-text.d.ts +487 -0
  78. package/dist/ts/speech-to-text/speech-to-text.ts +1008 -0
  79. package/dist/ts/textarea/index.d.ts +5 -0
  80. package/dist/ts/textarea/index.ts +5 -0
  81. package/dist/ts/textarea/textarea-model.d.ts +161 -0
  82. package/dist/ts/textarea/textarea.d.ts +237 -0
  83. package/dist/ts/textarea/textarea.ts +812 -0
  84. package/dist/ts/textbox/index.d.ts +5 -0
  85. package/dist/ts/textbox/index.ts +5 -0
  86. package/dist/ts/textbox/textbox-model.d.ts +155 -0
  87. package/dist/ts/textbox/textbox.d.ts +288 -0
  88. package/dist/ts/textbox/textbox.ts +872 -0
  89. package/dist/ts/uploader/index.d.ts +5 -0
  90. package/dist/ts/uploader/index.ts +5 -0
  91. package/dist/ts/uploader/uploader-model.d.ts +555 -0
  92. package/dist/ts/uploader/uploader.d.ts +1216 -0
  93. package/dist/ts/uploader/uploader.ts +4391 -0
  94. package/package.json +62 -12
  95. package/src/input/input.js +1 -1
  96. package/styles/bootstrap5.3-lite.css +3 -3
  97. package/styles/bootstrap5.3.css +5 -5
  98. package/styles/input/_layout.scss +0 -1
  99. package/styles/input/tailwind3.css +0 -1
  100. package/styles/tailwind-dark-lite.css +3 -3
  101. package/styles/tailwind-dark.css +5 -5
  102. package/styles/tailwind-lite.css +3 -3
  103. package/styles/tailwind.css +5 -5
  104. package/styles/tailwind3-lite.css +0 -1
  105. package/styles/tailwind3.css +0 -1
  106. package/styles/uploader/_bootstrap5.3-definition.scss +1 -1
  107. package/styles/uploader/_tailwind-definition.scss +1 -1
  108. package/styles/uploader/bootstrap5.3.css +5 -5
  109. package/styles/uploader/tailwind-dark.css +5 -5
  110. package/styles/uploader/tailwind.css +5 -5
@@ -0,0 +1,1277 @@
1
+ /* eslint-disable valid-jsdoc, jsdoc/require-jsdoc, jsdoc/require-returns, jsdoc/require-param */
2
+ import { createElement, attributes, addClass, removeClass, detach, classList } from '@syncfusion/ej2-base';
3
+ import { closest, formatUnit, isNullOrUndefined, remove } from '@syncfusion/ej2-base';
4
+ const CLASSNAMES: ClassNames = {
5
+ RTL: 'e-rtl',
6
+ DISABLE: 'e-disabled',
7
+ INPUT: 'e-input',
8
+ TEXTAREA: 'e-multi-line-input',
9
+ INPUTGROUP: 'e-input-group',
10
+ FLOATINPUT: 'e-float-input',
11
+ FLOATLINE: 'e-float-line',
12
+ FLOATTEXT: 'e-float-text',
13
+ FLOATTEXTCONTENT: 'e-float-text-content',
14
+ CLEARICON: 'e-clear-icon',
15
+ CLEARICONHIDE: 'e-clear-icon-hide',
16
+ LABELTOP: 'e-label-top',
17
+ LABELBOTTOM: 'e-label-bottom',
18
+ NOFLOATLABEL: 'e-no-float-label',
19
+ INPUTCUSTOMTAG: 'e-input-custom-tag',
20
+ FLOATCUSTOMTAG: 'e-float-custom-tag'
21
+ };
22
+
23
+ /* eslint-disable no-inner-declarations */
24
+
25
+ /**
26
+ * Defines floating label type of the input and decides how the label should float on the input.
27
+ */
28
+ export type FloatLabelType = 'Never' | 'Always' | 'Auto';
29
+
30
+ /**
31
+ * Defines the constant attributes for the input element container.
32
+ */
33
+ export const containerAttributes: string[] = ['title', 'style', 'class'];
34
+
35
+ /**
36
+ * Defines the constant focus class for the input element.
37
+ */
38
+ export const TEXTBOX_FOCUS: string = 'e-input-focus';
39
+
40
+ /**
41
+ * Base for Input creation through util methods.
42
+ */
43
+ // eslint-disable-next-line @typescript-eslint/no-namespace
44
+ export namespace Input {
45
+ let privateInputObj: InputObject = {
46
+ container: null,
47
+ buttons: [],
48
+ clearButton: null
49
+ };
50
+ let floatType: string;
51
+ let isBindClearAction: boolean = true;
52
+ /**
53
+ * Create a wrapper to input element with multiple span elements and set the basic properties to input based components.
54
+ * ```
55
+ * E.g : Input.createInput({ element: element, floatLabelType : "Auto", properties: { placeholder: 'Search' } });
56
+ * ```
57
+ *
58
+ */
59
+ export function createInput(args: InputArgs, internalCreateElement ?: createElementParams): InputObject {
60
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers = {};
61
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
62
+ let inputObject: InputObject = { container: null, buttons: [], clearButton: null };
63
+ floatType = args.floatLabelType;
64
+ isBindClearAction = args.bindClearAction;
65
+ if (isNullOrUndefined(args.floatLabelType ) || args.floatLabelType === 'Never' ) {
66
+ inputObject.container = createInputContainer(args, CLASSNAMES.INPUTGROUP, CLASSNAMES.INPUTCUSTOMTAG, 'span', makeElement);
67
+ args.element.parentNode.insertBefore(inputObject.container, args.element);
68
+ addClass([args.element], CLASSNAMES.INPUT);
69
+ inputObject.container.appendChild(args.element);
70
+ } else {
71
+ createFloatingInput(args, inputObject, makeElement);
72
+ }
73
+ bindInitialEvent(args);
74
+ if (!isNullOrUndefined(args.properties) && !isNullOrUndefined(args.properties.showClearButton) &&
75
+ args.properties.showClearButton) {
76
+ setClearButton(args.properties.showClearButton, args.element, inputObject, true, makeElement);
77
+ inputObject.clearButton.setAttribute('role', 'button');
78
+ if (inputObject.container.classList.contains(CLASSNAMES.FLOATINPUT)) {
79
+ addClass([inputObject.container], CLASSNAMES.INPUTGROUP);
80
+ }
81
+ }
82
+ if (!isNullOrUndefined(args.buttons)) {
83
+ for (let i: number = 0; i < args.buttons.length; i++) {
84
+ inputObject.buttons.push(appendSpan(args.buttons[i as number], inputObject.container, makeElement));
85
+ }
86
+ }
87
+ if (!isNullOrUndefined(args.element) && args.element.tagName === 'TEXTAREA') {
88
+ addClass([inputObject.container], CLASSNAMES.TEXTAREA);
89
+ }
90
+ validateInputType(inputObject.container, args.element);
91
+ inputObject = setPropertyValue(args, inputObject);
92
+ createSpanElement(inputObject.container, makeElement);
93
+ privateInputObj = inputObject;
94
+ return inputObject;
95
+ }
96
+
97
+ function bindFocusEventHandler(args: InputArgs): void {
98
+ const parent: HTMLElement = getParentNode(args.element);
99
+ if (parent.classList.contains('e-input-group') || parent.classList.contains('e-outline') || parent.classList.contains('e-filled')) {
100
+ parent.classList.add('e-input-focus');
101
+ }
102
+ if (args.floatLabelType !== 'Never') {
103
+ setTimeout(() => {
104
+ Input.calculateWidth(args.element, parent);
105
+ }, 80);
106
+ }
107
+ }
108
+
109
+ function bindBlurEventHandler (args: InputArgs): void {
110
+ const parent: HTMLElement = getParentNode(args.element);
111
+ if (parent.classList.contains('e-input-group') || parent.classList.contains('e-outline') || parent.classList.contains('e-filled')) {
112
+ parent.classList.remove('e-input-focus');
113
+ }
114
+ if (args.floatLabelType !== 'Never') {
115
+ setTimeout(() => {
116
+ Input.calculateWidth(args.element, parent);
117
+ }, 80);
118
+ }
119
+ }
120
+
121
+ function bindInputEventHandler (args: InputArgs): void {
122
+ checkInputValue(args.floatLabelType, args.element as HTMLInputElement);
123
+ }
124
+
125
+ export function bindInitialEvent(args: InputArgs): void {
126
+ checkInputValue(args.floatLabelType, args.element as HTMLInputElement);
127
+ const focusHandler: () => void = () => bindFocusEventHandler(args);
128
+ const blurHandler: () => void = () => bindBlurEventHandler(args);
129
+ const inputHandler: () => void = () => bindInputEventHandler(args);
130
+
131
+ args.element.addEventListener('focus', focusHandler);
132
+ args.element.addEventListener('blur', blurHandler);
133
+ args.element.addEventListener('input', inputHandler);
134
+
135
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputFocusHandler'] = { focusHandler };
136
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputBlurHandler'] = { blurHandler };
137
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputHandler'] = { inputHandler };
138
+ }
139
+
140
+ function unbindInitialEvent(args: InputArgs): void {
141
+ if (!isNullOrUndefined(args.element)) {
142
+ if (!isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers)) {
143
+ if (!isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputFocusHandler'])
144
+ && !isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputBlurHandler'])
145
+ && !isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputHandler'])) {
146
+ const focusHandler: any = (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputFocusHandler'].focusHandler;
147
+ const blurHandler: any = (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputBlurHandler'].blurHandler;
148
+ const inputHandler: any = (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputHandler'].inputHandler;
149
+ args.element.removeEventListener('focus', focusHandler);
150
+ args.element.removeEventListener('blur', blurHandler);
151
+ args.element.removeEventListener('input', inputHandler);
152
+
153
+ // Clean up stored bound functions
154
+ delete (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputFocusHandler'];
155
+ delete (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputBlurHandler'];
156
+ delete (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['inputHandler'];
157
+ }
158
+ }
159
+ }
160
+ }
161
+ function checkInputValue(floatLabelType: string, inputElement: HTMLInputElement): void {
162
+ const inputValue: string = inputElement.value;
163
+ const inputParent: HTMLElement = inputElement.parentElement;
164
+ const grandParent: HTMLElement = inputParent && inputParent.parentElement;
165
+ if (inputValue !== '' && !isNullOrUndefined(inputValue)) {
166
+ if (inputParent && inputParent.classList.contains('e-input-group')) {
167
+ inputParent.classList.add('e-valid-input');
168
+ }
169
+ else if (grandParent && grandParent.classList.contains('e-input-group')) {
170
+ grandParent.classList.add('e-valid-input');
171
+ }
172
+ } else if (floatLabelType !== 'Always') {
173
+ if (inputParent && inputParent.classList.contains('e-input-group')) {
174
+ inputParent.classList.remove('e-valid-input');
175
+ }
176
+ else if (grandParent && grandParent.classList.contains('e-input-group')) {
177
+ grandParent.classList.remove('e-valid-input');
178
+ }
179
+ }
180
+ }
181
+
182
+ function _focusFn (): void {
183
+ const label: HTMLElement = <HTMLElement> getParentNode(this).getElementsByClassName('e-float-text')[0];
184
+ if (!isNullOrUndefined(label)) {
185
+ addClass ([label], CLASSNAMES.LABELTOP);
186
+ if (label.classList.contains(CLASSNAMES.LABELBOTTOM)) {
187
+ removeClass([label], CLASSNAMES.LABELBOTTOM);
188
+ }
189
+ }
190
+ }
191
+
192
+ function _blurFn (): void {
193
+ const parent: HTMLElement = getParentNode(this);
194
+ if ((parent.getElementsByTagName('textarea')[0]) ? parent.getElementsByTagName('textarea')[0].value === '' :
195
+ parent.getElementsByTagName('input')[0].value === '') {
196
+ const label: HTMLElement = <HTMLElement> parent.getElementsByClassName('e-float-text')[0];
197
+ if (!isNullOrUndefined(label)) {
198
+ if (label.classList.contains(CLASSNAMES.LABELTOP)) {
199
+ removeClass([label], CLASSNAMES.LABELTOP);
200
+ }
201
+ addClass([label], CLASSNAMES.LABELBOTTOM);
202
+ }
203
+ }
204
+ }
205
+
206
+ export function wireFloatingEvents(element: HTMLInputElement | HTMLTextAreaElement): void {
207
+ element.addEventListener('focus', _focusFn);
208
+ element.addEventListener('blur', _blurFn);
209
+ }
210
+ function unwireFloatingEvents(element: HTMLElement): void {
211
+ if (!isNullOrUndefined(element)) {
212
+ element.removeEventListener('focus', _focusFn);
213
+ element.removeEventListener('blur', _blurFn);
214
+ }
215
+ }
216
+ function inputEventHandler (args: InputArgs): void {
217
+ validateLabel(args.element, args.floatLabelType);
218
+ }
219
+ function blurEventHandler (args: InputArgs): void {
220
+ validateLabel(args.element, args.floatLabelType);
221
+ }
222
+ function createFloatingInput(args: InputArgs, inputObject: InputObject, internalCreateElement ?: createElementParams): void {
223
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
224
+ if (args.floatLabelType === 'Auto') {
225
+ wireFloatingEvents(args.element);
226
+ }
227
+ if (isNullOrUndefined(inputObject.container)) {
228
+ inputObject.container = createInputContainer(args, CLASSNAMES.FLOATINPUT, CLASSNAMES.FLOATCUSTOMTAG, 'div', makeElement);
229
+ inputObject.container.classList.add(CLASSNAMES.INPUTGROUP);
230
+ if (args.element.parentNode) {
231
+ args.element.parentNode.insertBefore(inputObject.container, args.element);
232
+ }
233
+ } else {
234
+ if (!isNullOrUndefined(args.customTag)) {
235
+ inputObject.container.classList.add(CLASSNAMES.FLOATCUSTOMTAG);
236
+ }
237
+ inputObject.container.classList.add(CLASSNAMES.FLOATINPUT);
238
+ }
239
+ const floatLinelement: HTMLElement = makeElement('span', { className: CLASSNAMES.FLOATLINE });
240
+ const floatLabelElement: HTMLElement = makeElement('label', { className: CLASSNAMES.FLOATTEXT });
241
+ if (!isNullOrUndefined(args.element.id) && args.element.id !== '') {
242
+ floatLabelElement.id = 'label_' + args.element.id.replace(/ /g, '_');
243
+ attributes(args.element, { 'aria-labelledby': floatLabelElement.id });
244
+ }
245
+ if (!isNullOrUndefined(args.element.placeholder) && args.element.placeholder !== '') {
246
+ floatLabelElement.innerText = encodePlaceHolder(args.element.placeholder);
247
+ args.element.removeAttribute('placeholder');
248
+ }
249
+ if (!isNullOrUndefined(args.properties) && !isNullOrUndefined(args.properties.placeholder) &&
250
+ args.properties.placeholder !== '') {
251
+ floatLabelElement.innerText = encodePlaceHolder(args.properties.placeholder);
252
+ }
253
+ if (!floatLabelElement.innerText) {
254
+ inputObject.container.classList.add(CLASSNAMES.NOFLOATLABEL);
255
+ }
256
+ if (inputObject.container.classList.contains('e-float-icon-left')) {
257
+ const inputWrap: HTMLElement = inputObject.container.querySelector('.e-input-in-wrap') as HTMLElement;
258
+ inputWrap.appendChild(args.element);
259
+ inputWrap.appendChild(floatLinelement);
260
+ inputWrap.appendChild(floatLabelElement);
261
+ } else {
262
+ inputObject.container.appendChild(args.element);
263
+ inputObject.container.appendChild(floatLinelement);
264
+ inputObject.container.appendChild(floatLabelElement);
265
+ }
266
+ updateLabelState(args.element.value, floatLabelElement);
267
+ if (args.floatLabelType === 'Always') {
268
+ if (floatLabelElement.classList.contains(CLASSNAMES.LABELBOTTOM)) {
269
+ removeClass([floatLabelElement], CLASSNAMES.LABELBOTTOM);
270
+ }
271
+ addClass([floatLabelElement], CLASSNAMES.LABELTOP);
272
+ }
273
+ if (args.floatLabelType === 'Auto') {
274
+ const inputFloatHandler: () => void = () => inputEventHandler(args);
275
+ const blurFloatHandler: () => void = () => blurEventHandler(args);
276
+
277
+ // Add event listeners using the defined functions
278
+ args.element.addEventListener('input', inputFloatHandler);
279
+ args.element.addEventListener('blur', blurFloatHandler);
280
+
281
+ // Store the event handler functions to remove them later
282
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatInputHandler'] = { inputFloatHandler };
283
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatBlurHandler'] = { blurFloatHandler };
284
+ } else {
285
+ unWireFloatLabelEvents(args);
286
+ }
287
+ if (!isNullOrUndefined(args.element.getAttribute('id'))) {
288
+ floatLabelElement.setAttribute('for', args.element.getAttribute('id'));
289
+ }
290
+ }
291
+ function unWireFloatLabelEvents(args: InputArgs): void {
292
+ if (!isNullOrUndefined(args.element) &&
293
+ !isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers)
294
+ && !isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatInputHandler'])
295
+ && !isNullOrUndefined((args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatBlurHandler'])) {
296
+ const inputFloatHandler: any =
297
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatInputHandler'].inputFloatHandler;
298
+ const blurFloatHandler: any =
299
+ (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatBlurHandler'].blurFloatHandler;
300
+
301
+ // Remove the event listeners using the defined functions
302
+ args.element.removeEventListener('input', inputFloatHandler);
303
+ args.element.removeEventListener('blur', blurFloatHandler);
304
+
305
+ // Clean up stored event handler functions
306
+ delete (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatInputHandler'];
307
+ delete (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['floatBlurHandler'];
308
+ }
309
+ }
310
+
311
+ function checkFloatLabelType(type: string , container: HTMLElement): void {
312
+ if (type === 'Always' && container.classList.contains('e-outline')) {
313
+ container.classList.add('e-valid-input');
314
+ }
315
+ }
316
+
317
+ function setPropertyValue(args: InputArgs, inputObject: InputObject): InputObject {
318
+ if (!isNullOrUndefined(args.properties)) {
319
+ for (const prop of Object.keys(args.properties)) {
320
+ switch (prop) {
321
+ case 'cssClass':
322
+ setCssClass(args.properties.cssClass, [inputObject.container]);
323
+ checkFloatLabelType(args.floatLabelType, inputObject.container);
324
+ break;
325
+ case 'enabled':
326
+ setEnabled(args.properties.enabled, args.element, args.floatLabelType, inputObject.container);
327
+ break;
328
+ case 'enableRtl':
329
+ setEnableRtl(args.properties.enableRtl, [inputObject.container]);
330
+ break;
331
+ case 'placeholder':
332
+ setPlaceholder(args.properties.placeholder, args.element);
333
+ break;
334
+ case 'readonly':
335
+ setReadonly(args.properties.readonly, args.element);
336
+ break;
337
+ }
338
+ }
339
+ }
340
+ return inputObject;
341
+ }
342
+
343
+ function updateIconState(value: string | number, button: HTMLElement, readonly?: boolean): void {
344
+ if (!isNullOrUndefined(button)){
345
+ if (value && !readonly) {
346
+ removeClass([button], CLASSNAMES.CLEARICONHIDE);
347
+ }
348
+ else{
349
+ addClass([button], CLASSNAMES.CLEARICONHIDE);
350
+ }
351
+ }
352
+
353
+ }
354
+
355
+ function updateLabelState(value: string | number, label: HTMLElement, element: HTMLElement = null): void {
356
+ if (value) {
357
+ addClass([label], CLASSNAMES.LABELTOP);
358
+ if (label.classList.contains(CLASSNAMES.LABELBOTTOM)) {
359
+ removeClass([label], CLASSNAMES.LABELBOTTOM);
360
+ }
361
+ } else {
362
+ const isNotFocused : boolean = element != null ? element !== document.activeElement : true;
363
+ if (isNotFocused) {
364
+ if (label.classList.contains(CLASSNAMES.LABELTOP)) {
365
+ removeClass([label], CLASSNAMES.LABELTOP);
366
+ }
367
+ addClass([label], CLASSNAMES.LABELBOTTOM);
368
+ }
369
+ }
370
+ }
371
+
372
+ function getParentNode(element: HTMLInputElement | HTMLElement): HTMLElement {
373
+ let parentNode: HTMLElement = isNullOrUndefined(<HTMLElement>element.parentNode) ? <HTMLElement>element
374
+ : <HTMLElement>element.parentNode;
375
+ if (parentNode && parentNode.classList.contains('e-input-in-wrap')) {
376
+ parentNode = <HTMLElement>parentNode.parentNode;
377
+ }
378
+ return parentNode;
379
+ }
380
+
381
+ /**
382
+ * To create clear button.
383
+ */
384
+ function createClearButton(element: HTMLInputElement | HTMLTextAreaElement, inputObject?: InputObject ,
385
+ initial ?: boolean, internalCreateElement ?: createElementParams ): HTMLElement {
386
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
387
+ const button: HTMLElement = <HTMLElement>makeElement('span', { className: CLASSNAMES.CLEARICON });
388
+ const container: HTMLElement = inputObject.container;
389
+ if (!isNullOrUndefined(initial)) {
390
+ container.appendChild(button);
391
+ } else {
392
+ const baseElement: HTMLElement = inputObject.container.classList.contains(CLASSNAMES.FLOATINPUT) ?
393
+ inputObject.container.querySelector('.' + CLASSNAMES.FLOATTEXT) as HTMLElement : element;
394
+ baseElement.insertAdjacentElement('afterend', button);
395
+ }
396
+ addClass([button], CLASSNAMES.CLEARICONHIDE);
397
+ wireClearBtnEvents(element, button, container);
398
+ button.setAttribute('aria-label', 'close');
399
+ return button;
400
+ }
401
+ function clickHandler (event: MouseEvent, element: HTMLInputElement | HTMLTextAreaElement, button: HTMLElement): any {
402
+ if (!(element.classList.contains(CLASSNAMES.DISABLE) || element.readOnly)) {
403
+ event.preventDefault();
404
+ if (element !== document.activeElement) {
405
+ element.focus();
406
+ }
407
+ element.value = '';
408
+ addClass([button], CLASSNAMES.CLEARICONHIDE);
409
+ }
410
+ }
411
+
412
+ function inputHandler (element: HTMLInputElement | HTMLTextAreaElement, button: HTMLElement): any {
413
+ updateIconState(element.value, button);
414
+ }
415
+
416
+ function focusHandler (element: HTMLInputElement | HTMLTextAreaElement, button: HTMLElement): any {
417
+ updateIconState(element.value, button, element.readOnly);
418
+ }
419
+
420
+ function blurHandler (element: HTMLInputElement | HTMLTextAreaElement, button: HTMLElement): any {
421
+ setTimeout (() => {
422
+ if (!isNullOrUndefined(button)){
423
+ addClass([button], CLASSNAMES.CLEARICONHIDE);
424
+ button = !isNullOrUndefined(element) && element.classList.contains('e-combobox') ? null : button ;
425
+ }
426
+ }, 200);
427
+ }
428
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
429
+ export function wireClearBtnEvents(element: HTMLInputElement | HTMLTextAreaElement, button: HTMLElement, container: HTMLElement): void {
430
+ if (isBindClearAction === undefined || isBindClearAction) {
431
+ const clickHandlerEvent: (e: MouseEvent) => void = (e: MouseEvent): void => clickHandler(e, element, button);
432
+ button.addEventListener('click', clickHandlerEvent);
433
+ (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearClickHandler'] = { clickHandlerEvent };
434
+ }
435
+
436
+ const inputHandlerEvent: () => void = (): void => inputHandler(element, button);
437
+ const focusHandlerEvent: () => void = (): void => focusHandler(element, button);
438
+ const blurHandlerEvent: () => void = (): void => blurHandler(element, button);
439
+
440
+ element.addEventListener('input', inputHandlerEvent);
441
+ element.addEventListener('focus', focusHandlerEvent);
442
+ element.addEventListener('blur', blurHandlerEvent);
443
+
444
+ // Store the bound functions to remove them later
445
+ (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearInputHandler'] = { inputHandlerEvent };
446
+ (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearFocusHandler'] = { focusHandlerEvent };
447
+ (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearBlurHandler'] = { blurHandlerEvent };
448
+ }
449
+ function unWireClearBtnEvents(element: HTMLInputElement | HTMLTextAreaElement, button: HTMLElement): void {
450
+ if (!isNullOrUndefined(element) &&
451
+ !isNullOrUndefined((element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers)) {
452
+ if (!isNullOrUndefined((element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearClickHandler'])) {
453
+ const clickHandlerEvent: any = (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearClickHandler'].clickHandlerEvent;
454
+ if (isBindClearAction === undefined || isBindClearAction) {
455
+ if (!isNullOrUndefined(button)) {
456
+ button.removeEventListener('click', clickHandlerEvent);
457
+ }
458
+ }
459
+ delete (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearClickHandler'];
460
+ }
461
+ if (!isNullOrUndefined((element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearInputHandler'])
462
+ && !isNullOrUndefined((element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearFocusHandler'])
463
+ && !isNullOrUndefined((element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearBlurHandler'])) {
464
+ const inputHandlerEvent: any = (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearInputHandler'].inputHandlerEvent;
465
+ const focusHandlerEvent: any = (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearFocusHandler'].focusHandlerEvent;
466
+ const blurHandlerEvent: any = (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearBlurHandler'].blurHandlerEvent;
467
+
468
+
469
+ element.removeEventListener('input', inputHandlerEvent);
470
+ element.removeEventListener('focus', focusHandlerEvent);
471
+ element.removeEventListener('blur', blurHandlerEvent);
472
+
473
+ // Clean up stored Event functions
474
+
475
+ delete (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearInputHandler'];
476
+ delete (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearFocusHandler'];
477
+ delete (element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers['clearBlurHandler'];
478
+ }
479
+ }
480
+ }
481
+ export function destroy(args: InputArgs, button: HTMLElement = null): void {
482
+ unbindInitialEvent(args);
483
+ if (args.floatLabelType === 'Auto'){
484
+ unWireFloatLabelEvents(args);
485
+ }
486
+ if (args.properties.showClearButton) {
487
+ unWireClearBtnEvents(args.element, button);
488
+ }
489
+ if (!isNullOrUndefined(args.buttons)) {
490
+ _internalRipple(false, null, args.buttons as any);
491
+ }
492
+ unwireFloatingEvents(args.element);
493
+ if (!isNullOrUndefined(args.element)) {
494
+ delete (args.element as HTMLInputElement & { __eventHandlers?: any }).__eventHandlers;
495
+ if (args.element.classList.contains(CLASSNAMES.INPUT)) {
496
+ args.element.classList.remove(CLASSNAMES.INPUT);
497
+ }
498
+ }
499
+ privateInputObj = null;
500
+ }
501
+ function validateLabel(element: HTMLInputElement | HTMLTextAreaElement, floatLabelType: string) : void {
502
+ const parent: HTMLElement = getParentNode(element);
503
+ if (parent.classList.contains(CLASSNAMES.FLOATINPUT) && floatLabelType === 'Auto') {
504
+ const label: HTMLElement = <HTMLElement> getParentNode(element).getElementsByClassName('e-float-text')[0];
505
+ updateLabelState(element.value, label, element);
506
+ }
507
+ }
508
+
509
+ /**
510
+ * To create input box contianer.
511
+ */
512
+ function createInputContainer(args: InputArgs, className: string, tagClass: string, tag: string,
513
+ internalCreateElement ?: createElementParams): HTMLElement {
514
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
515
+ let container: HTMLElement;
516
+ if (!isNullOrUndefined(args.customTag)) {
517
+ container = makeElement(args.customTag , { className: className} );
518
+ container.classList.add(tagClass);
519
+ } else {
520
+ container = makeElement(tag, { className: className });
521
+ }
522
+ container.classList.add('e-control-wrapper');
523
+ return container;
524
+ }
525
+
526
+ function encodePlaceHolder(placeholder: string): string {
527
+ if (placeholder == null || placeholder === '') {
528
+ return '';
529
+ }
530
+ const decoded: string = decodeHtmlEntities(placeholder);
531
+ return decoded;
532
+ }
533
+
534
+ function decodeHtmlEntities(str: string): string {
535
+ const entityMap: { [key: string]: string } = {
536
+ '&amp;': '&',
537
+ // eslint-disable-next-line quotes
538
+ '&quot;': '"', // tslint:disable-line:quotemark
539
+ // eslint-disable-next-line quotes
540
+ '&#39;': "'", // tslint:disable-line:quotemark
541
+ '&lt;': '<',
542
+ '&gt;': '>',
543
+ '&eacute;': 'é'// tslint:disable-line:comma-dangle
544
+ };
545
+ // tslint:disable-next-line:typedef
546
+ // tslint-disable-next-line security/detect-object-injection
547
+ return str.replace(/&[a-zA-Z#0-9]+;/g, (entity: string) => entityMap[entity as string] || entity);
548
+ }
549
+
550
+ /**
551
+ * Sets the value to the input element.
552
+ * ```
553
+ * E.g : Input.setValue('content', element, "Auto", true );
554
+ * ```
555
+ *
556
+ * @param {string} value - Specify the value of the input element.
557
+ * @param {HTMLInputElement | HTMLTextAreaElement} element - The element on which the specified value is updated.
558
+ * @param {string} floatLabelType - Specify the float label type of the input element.
559
+ * @param {boolean} clearButton - Boolean value to specify whether the clear icon is enabled / disabled on the input.
560
+ */
561
+ export function setValue(value: string, element: HTMLInputElement | HTMLTextAreaElement,
562
+ floatLabelType ?: string, clearButton?: boolean): void {
563
+ element.value = value;
564
+ if (floatLabelType !== 'Never') {
565
+ calculateWidth(element, element.parentElement);
566
+ }
567
+ if ((!isNullOrUndefined(floatLabelType)) && floatLabelType === 'Auto') {
568
+ validateLabel(element, floatLabelType);
569
+ }
570
+ if (!isNullOrUndefined(clearButton) && clearButton ) {
571
+ const parentElement: HTMLElement = <HTMLElement> getParentNode(element);
572
+ if (!isNullOrUndefined(parentElement)) {
573
+ const button: HTMLElement = <HTMLElement> parentElement.getElementsByClassName(CLASSNAMES.CLEARICON)[0];
574
+ if (!isNullOrUndefined(button)) {
575
+ if (element.value && !isNullOrUndefined(parentElement) && parentElement.classList.contains('e-input-focus')) {
576
+ removeClass([button], CLASSNAMES.CLEARICONHIDE);
577
+ } else {
578
+ addClass([button], CLASSNAMES.CLEARICONHIDE);
579
+ }
580
+ }
581
+ }
582
+ }
583
+ checkInputValue(floatLabelType, element as HTMLInputElement);
584
+ }
585
+
586
+ /**
587
+ * Sets the single or multiple cssClass to wrapper of input element.
588
+ * ```
589
+ * E.g : Input.setCssClass('e-custom-class', [element]);
590
+ * ```
591
+ *
592
+ * @param {string} cssClass - Css class names which are needed to add.
593
+ * @param {Element[] | NodeList} elements - The elements which are needed to add / remove classes.
594
+ * @param {string} oldClass
595
+ * - Css class names which are needed to remove. If old classes are need to remove, can give this optional parameter.
596
+ */
597
+ export function setCssClass(cssClass: string, elements: Element[] | NodeList, oldClass?: string): void {
598
+ if (!isNullOrUndefined(oldClass) && oldClass !== '') {
599
+ removeClass(elements, oldClass.split(' '));
600
+ }
601
+ if (!isNullOrUndefined(cssClass) && cssClass !== '') {
602
+ addClass(elements, cssClass.split(' '));
603
+ }
604
+ }
605
+ /**
606
+ * Set the width to the placeholder when it overflows on the button such as spinbutton, clearbutton, icon etc
607
+ * ```
608
+ * E.g : Input.calculateWidth(element, container);
609
+ * ```
610
+ *
611
+ * @param {any} element - Input element which is need to add.
612
+ * @param {HTMLElement} container - The parent element which is need to get the label span to calculate width
613
+ */
614
+ export function calculateWidth(element: any, container: HTMLElement, moduleName?: string): void {
615
+ if (moduleName !== 'multiselect' && !_isElementVisible(element)) {
616
+ return;
617
+ }
618
+ const elementWidth : number | Element = moduleName === 'multiselect' ? element : element.clientWidth - parseInt(getComputedStyle(element, null).getPropertyValue('padding-left'), 10);
619
+ if ( !isNullOrUndefined(container) && !isNullOrUndefined(container.getElementsByClassName('e-float-text-content')[0])) {
620
+ if (container.getElementsByClassName('e-float-text-content')[0].classList.contains('e-float-text-overflow')) {
621
+ container.getElementsByClassName('e-float-text-content')[0].classList.remove('e-float-text-overflow');
622
+ }
623
+ if (elementWidth as number < container.getElementsByClassName('e-float-text-content')[0].clientWidth || elementWidth === container.getElementsByClassName('e-float-text-content')[0].clientWidth) {
624
+ container.getElementsByClassName('e-float-text-content')[0].classList.add('e-float-text-overflow');
625
+ }
626
+ }
627
+ }
628
+
629
+ /**
630
+ * Set the width to the wrapper of input element.
631
+ * ```
632
+ * E.g : Input.setWidth('200px', container);
633
+ * ```
634
+ *
635
+ * @param {number | string} width - Width value which is need to add.
636
+ * @param {HTMLElement} container - The element on which the width is need to add.
637
+ */
638
+ export function setWidth(width: number | string, container: HTMLElement): void {
639
+ if (typeof width === 'number') {
640
+ container.style.width = formatUnit(width);
641
+ } else if (typeof width === 'string') {
642
+ container.style.width = (width.match(/px|%|em/)) ? <string>(width) : <string>(formatUnit(width));
643
+ }
644
+ calculateWidth(container.firstChild as HTMLElement, container);
645
+ }
646
+
647
+ /**
648
+ * Set the placeholder attribute to the input element.
649
+ * ```
650
+ * E.g : Input.setPlaceholder('Search here', element);
651
+ * ```
652
+ *
653
+ * @param {string} placeholder - Placeholder value which is need to add.
654
+ * @param {HTMLInputElement | HTMLTextAreaElement} element - The element on which the placeholder is need to add.
655
+ */
656
+ export function setPlaceholder(placeholder: string, element: HTMLInputElement | HTMLTextAreaElement): void {
657
+ placeholder = encodePlaceHolder(placeholder);
658
+ const parentElement: HTMLElement = getParentNode(element);
659
+ if (parentElement.classList.contains(CLASSNAMES.FLOATINPUT)) {
660
+ if (!isNullOrUndefined(placeholder) && placeholder !== '') {
661
+ const floatTextContent: Element = parentElement.getElementsByClassName('e-float-text-content')[0];
662
+ if (floatTextContent && floatTextContent.children[0]) {
663
+ floatTextContent.children[0].textContent = placeholder;
664
+ } else {
665
+ const floatText: Element = parentElement.getElementsByClassName(CLASSNAMES.FLOATTEXT)[0];
666
+ if (!isNullOrUndefined(floatText)) {
667
+ floatText.textContent = placeholder;
668
+ }
669
+ }
670
+ parentElement.classList.remove(CLASSNAMES.NOFLOATLABEL);
671
+ element.removeAttribute('placeholder');
672
+ } else {
673
+ parentElement.classList.add(CLASSNAMES.NOFLOATLABEL);
674
+ const floatTextContent: Element = parentElement.getElementsByClassName('e-float-text-content')[0];
675
+ if (floatTextContent && floatTextContent.children[0]) {
676
+ floatTextContent.children[0].textContent = '';
677
+ } else {
678
+ const floatText: Element = parentElement.getElementsByClassName(CLASSNAMES.FLOATTEXT)[0];
679
+ if (!isNullOrUndefined(floatText)) {
680
+ floatText.textContent = '';
681
+ }
682
+ }
683
+ }
684
+ } else {
685
+ if (!isNullOrUndefined(placeholder) && placeholder !== '') {
686
+ attributes(element, { 'placeholder': placeholder});
687
+ } else {
688
+ element.removeAttribute('placeholder');
689
+ }
690
+ }
691
+ }
692
+ /**
693
+ * Set the read only attribute to the input element
694
+ * ```
695
+ * E.g : Input.setReadonly(true, element);
696
+ * ```
697
+ *
698
+ * @param {boolean} isReadonly
699
+ * - Boolean value to specify whether to set read only. Setting "True" value enables read only.
700
+ * @param {HTMLInputElement | HTMLTextAreaElement} element
701
+ * - The element which is need to enable read only.
702
+ */
703
+ export function setReadonly(isReadonly: boolean, element: HTMLInputElement | HTMLTextAreaElement, floatLabelType ?: string): void {
704
+ if (isReadonly) {
705
+ attributes(element, { readonly: '' });
706
+ } else {
707
+ element.removeAttribute('readonly');
708
+ }
709
+ if (!isNullOrUndefined(floatLabelType)) {
710
+ validateLabel(element, floatLabelType);
711
+ }
712
+ }
713
+ /**
714
+ * Displays the element direction from right to left when its enabled.
715
+ * ```
716
+ * E.g : Input.setEnableRtl(true, [inputObj.container]);
717
+ * ```
718
+ *
719
+ * @param {boolean} isRtl
720
+ * - Boolean value to specify whether to set RTL. Setting "True" value enables the RTL mode.
721
+ * @param {Element[] | NodeList} elements
722
+ * - The elements that are needed to enable/disable RTL.
723
+ */
724
+ export function setEnableRtl(isRtl: boolean, elements: Element[] | NodeList): void {
725
+ if (isRtl) {
726
+ addClass(elements, CLASSNAMES.RTL);
727
+ } else {
728
+ removeClass(elements, CLASSNAMES.RTL);
729
+ }
730
+ }
731
+ /**
732
+ * Enables or disables the given input element.
733
+ * ```
734
+ * E.g : Input.setEnabled(false, element);
735
+ * ```
736
+ *
737
+ * @param {boolean} isEnable
738
+ * - Boolean value to specify whether to enable or disable.
739
+ * @param {HTMLInputElement | HTMLTextAreaElement} element
740
+ * - Element to be enabled or disabled.
741
+ */
742
+ export function setEnabled(isEnable: boolean, element: HTMLInputElement | HTMLTextAreaElement, floatLabelType ?: string ,
743
+ inputContainer?: HTMLElement ): void {
744
+ const disabledAttrs: { [key: string]: string } = { 'disabled': '', 'aria-disabled': 'true' };
745
+ const considerWrapper: boolean = isNullOrUndefined(inputContainer) ? false : true;
746
+ if (isEnable) {
747
+ element.classList.remove(CLASSNAMES.DISABLE);
748
+ removeAttributes(disabledAttrs, element);
749
+ if (considerWrapper) {
750
+ removeClass( [inputContainer], CLASSNAMES.DISABLE);
751
+ }
752
+ } else {
753
+ element.classList.add(CLASSNAMES.DISABLE);
754
+ addAttributes(disabledAttrs, element);
755
+ if (considerWrapper) {
756
+ addClass( [inputContainer], CLASSNAMES.DISABLE);
757
+ }
758
+ }
759
+ if (!isNullOrUndefined(floatLabelType)) {
760
+ validateLabel(element, floatLabelType);
761
+ }
762
+ }
763
+
764
+ export function setClearButton (isClear: boolean, element: HTMLInputElement | HTMLTextAreaElement,
765
+ inputObject: InputObject, initial ?: boolean, internalCreateElement ?: createElementParams ): void {
766
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
767
+ if (isClear) {
768
+ inputObject.clearButton = createClearButton (element, inputObject, initial, makeElement);
769
+ } else {
770
+ remove(inputObject.clearButton);
771
+ inputObject.clearButton = null;
772
+ }
773
+ }
774
+ /**
775
+ * Removing the multiple attributes from the given element such as "disabled","id" , etc.
776
+ * ```
777
+ * E.g : Input.removeAttributes({ 'disabled': 'disabled', 'aria-disabled': 'true' }, element);
778
+ * ```
779
+ *
780
+ * @param {string} attrs
781
+ * - Array of attributes which are need to removed from the element.
782
+ * @param {HTMLInputElement | HTMLElement} element
783
+ * - Element on which the attributes are needed to be removed.
784
+ */
785
+ export function removeAttributes(attrs: { [key: string]: string }, element: HTMLInputElement | HTMLElement): void {
786
+ for (const key of Object.keys(attrs)) {
787
+ const parentElement: HTMLElement = getParentNode(element);
788
+ if (key === 'disabled') {
789
+ element.classList.remove(CLASSNAMES.DISABLE);
790
+ }
791
+ if (key === 'disabled' && parentElement.classList.contains(CLASSNAMES.INPUTGROUP)) {
792
+ parentElement.classList.remove(CLASSNAMES.DISABLE);
793
+ }
794
+ if (key === 'placeholder' && parentElement.classList.contains(CLASSNAMES.FLOATINPUT)) {
795
+ parentElement.getElementsByClassName(CLASSNAMES.FLOATTEXT)[0].textContent = '';
796
+ } else {
797
+ element.removeAttribute(key);
798
+ }
799
+ }
800
+ }
801
+ /**
802
+ * Adding the multiple attributes to the given element such as "disabled","id" , etc.
803
+ * ```
804
+ * E.g : Input.addAttributes({ 'id': 'inputpopup' }, element);
805
+ * ```
806
+ *
807
+ * @param {string} attrs
808
+ * - Array of attributes which is added to element.
809
+ * @param {HTMLInputElement | HTMLElement} element
810
+ * - Element on which the attributes are needed to be added.
811
+ */
812
+ export function addAttributes(attrs: { [key: string]: string }, element: HTMLInputElement | HTMLElement): void {
813
+ for (const key of Object.keys(attrs)) {
814
+ const parentElement: HTMLElement = getParentNode(element);
815
+ if (key === 'disabled') {
816
+ element.classList.add(CLASSNAMES.DISABLE);
817
+ }
818
+ if (key === 'disabled' && parentElement.classList.contains(CLASSNAMES.INPUTGROUP)) {
819
+ parentElement.classList.add(CLASSNAMES.DISABLE);
820
+ }
821
+ if (key === 'placeholder' && parentElement.classList.contains(CLASSNAMES.FLOATINPUT)) {
822
+ parentElement.getElementsByClassName(CLASSNAMES.FLOATTEXT)[0].textContent = attrs[`${key}`];
823
+ } else {
824
+ element.setAttribute(key, attrs[`${key}`]);
825
+ }
826
+ }
827
+ }
828
+ export function removeFloating(input: InputObject): void {
829
+ const container: HTMLElement = input.container;
830
+ if (!isNullOrUndefined(container) && container.classList.contains(CLASSNAMES.FLOATINPUT)) {
831
+ const inputEle: HTMLElement = container.querySelector('textarea') ? <HTMLElement>container.querySelector('textarea') :
832
+ <HTMLElement>container.querySelector('input');
833
+ const placeholder: string = container.querySelector('.' + CLASSNAMES.FLOATTEXT).textContent;
834
+ const clearButton: boolean = container.querySelector('.e-clear-icon') !== null;
835
+ detach(container.querySelector('.' + CLASSNAMES.FLOATLINE));
836
+ detach(container.querySelector('.' + CLASSNAMES.FLOATTEXT));
837
+ classList(container, [CLASSNAMES.INPUTGROUP], [CLASSNAMES.FLOATINPUT]);
838
+ unwireFloatingEvents(inputEle);
839
+ attributes(inputEle, { 'placeholder': placeholder });
840
+ inputEle.classList.add(CLASSNAMES.INPUT);
841
+ if (!clearButton && inputEle.tagName === 'INPUT') {
842
+ inputEle.removeAttribute('required');
843
+ }
844
+ }
845
+ }
846
+ export function addFloating(input: HTMLInputElement | HTMLTextAreaElement, type: FloatLabelType | string, placeholder: string,
847
+ internalCreateElement ?: createElementParams): void {
848
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
849
+ const container: HTMLElement = <HTMLElement>closest(input, '.' + CLASSNAMES.INPUTGROUP);
850
+ floatType = type;
851
+ let customTag: string = container.tagName;
852
+ customTag = customTag !== 'DIV' && customTag !== 'SPAN' ? customTag : null;
853
+ const args: InputArgs = {element: input, floatLabelType: type ,
854
+ customTag: customTag, properties : {placeholder : placeholder } };
855
+ if (type !== 'Never') {
856
+ let iconEle: HTMLElement = <HTMLElement>container.querySelector('.e-clear-icon');
857
+ const inputObj: InputObject = { container: container};
858
+ input.classList.remove(CLASSNAMES.INPUT);
859
+ createFloatingInput(args, inputObj, makeElement);
860
+ createSpanElement(inputObj.container, makeElement);
861
+ calculateWidth(args.element, inputObj.container);
862
+ const isPrependIcon: boolean = container.classList.contains('e-float-icon-left');
863
+ if (isNullOrUndefined(iconEle)) {
864
+ if (isPrependIcon) {
865
+ const inputWrap: HTMLElement = container.querySelector('.e-input-in-wrap')as HTMLElement;
866
+ iconEle = inputWrap.querySelector('.e-input-group-icon') as HTMLElement;
867
+ } else {
868
+ iconEle = container.querySelector('.e-input-group-icon') as HTMLElement;
869
+ }
870
+ }
871
+ if (isNullOrUndefined(iconEle)) {
872
+ if (isPrependIcon) {
873
+ iconEle = container.querySelector('.e-input-group-icon') as HTMLElement;
874
+ }
875
+ } else {
876
+ const floatLine: HTMLElement = <HTMLElement>container.querySelector('.' + CLASSNAMES.FLOATLINE);
877
+ const floatText: HTMLElement = <HTMLElement>container.querySelector('.' + CLASSNAMES.FLOATTEXT);
878
+ const wrapper: HTMLElement = isPrependIcon ? container.querySelector('.e-input-in-wrap') as HTMLElement : container;
879
+ wrapper.insertBefore(input, iconEle);
880
+ wrapper.insertBefore(floatLine, iconEle);
881
+ wrapper.insertBefore(floatText, iconEle);
882
+ }
883
+ } else {
884
+ unWireFloatLabelEvents(args);
885
+ }
886
+ checkFloatLabelType(type, input.parentElement);
887
+ }
888
+ /**
889
+ * Create the span inside the label and add the label text into the span textcontent
890
+ * ```
891
+ * E.g : Input.createSpanElement(inputObject, makeElement);
892
+ * ```
893
+ *
894
+ * @param {Element} inputObject
895
+ * - Element which is need to get the label
896
+ * @param {createElementParams} makeElement
897
+ * - Element which is need to create the span
898
+ */
899
+ export function createSpanElement(inputObject: Element, makeElement: createElementParams): void {
900
+ if (inputObject.classList.contains('e-outline') && inputObject.getElementsByClassName('e-float-text')[0]) {
901
+ const labelSpanElement: HTMLElement = makeElement('span', { className: CLASSNAMES.FLOATTEXTCONTENT });
902
+ labelSpanElement.innerHTML = inputObject.getElementsByClassName('e-float-text')[0].innerHTML;
903
+ inputObject.getElementsByClassName('e-float-text')[0].innerHTML = '';
904
+ inputObject.getElementsByClassName('e-float-text')[0].appendChild(labelSpanElement);
905
+ }
906
+ }
907
+
908
+ /**
909
+ * Enable or Disable the ripple effect on the icons inside the Input. Ripple effect is only applicable for material theme.
910
+ * ```
911
+ * E.g : Input.setRipple(true, [inputObjects]);
912
+ * ```
913
+ *
914
+ * @param {boolean} isRipple
915
+ * - Boolean value to specify whether to enable the ripple effect.
916
+ * @param {InputObject[]} inputObj
917
+ * - Specify the collection of input objects.
918
+ */
919
+ export function setRipple (isRipple: boolean, inputObj: InputObject[]): void {
920
+ for (let i: number = 0 ; i < inputObj.length ; i++ ) {
921
+ _internalRipple(isRipple, inputObj[parseInt(i.toString(), 10)].container);
922
+ }
923
+ }
924
+
925
+ function _internalRipple(isRipple: boolean, container: HTMLElement, button?: HTMLElement): void {
926
+ const argsButton: HTMLElement[] = [];
927
+ argsButton.push(button);
928
+ const buttons : Element[] = isNullOrUndefined(button) ?
929
+ <NodeListOf<Element> & Element[]>container.querySelectorAll('.e-input-group-icon') : argsButton;
930
+ if ( isRipple && buttons.length > 0) {
931
+ for ( let index: number = 0 ; index < buttons.length; index++ ) {
932
+ buttons[parseInt(index.toString(), 10)].addEventListener('mousedown', _onMouseDownRipple , false);
933
+ buttons[parseInt(index.toString(), 10)].addEventListener('mouseup', _onMouseUpRipple , false);
934
+ }
935
+ } else if (buttons.length > 0) {
936
+ for ( let index: number = 0 ; index < buttons.length; index++ ) {
937
+ buttons[parseInt(index.toString(), 10)].removeEventListener('mousedown', _onMouseDownRipple, this);
938
+ buttons[parseInt(index.toString(), 10)].removeEventListener('mouseup', _onMouseUpRipple, this);
939
+ }
940
+ }
941
+ }
942
+
943
+ function _onMouseRipple (container?: HTMLElement, button?: Element): void {
944
+ if (!container.classList.contains('e-disabled') && !container.querySelector('input').readOnly ) {
945
+ button.classList.add('e-input-btn-ripple');
946
+ }
947
+ }
948
+
949
+ function _isElementVisible(element: any): boolean {
950
+ if (!element) {
951
+ return false;
952
+ }
953
+ // Check if the element or any of its parents are hidden using display: none
954
+ let currentElement: any = element;
955
+ while (currentElement && currentElement !== document.body) {
956
+ const style: CSSStyleDeclaration = window.getComputedStyle(currentElement);
957
+ if (style.display === 'none') {
958
+ return false;
959
+ }
960
+ currentElement = currentElement.parentElement;
961
+ }
962
+ // If none of the elements have display: none, the element is considered visible
963
+ return true;
964
+ }
965
+
966
+ function _onMouseDownRipple(): void {
967
+ const ele: HTMLElement = null || this;
968
+ let parentEle: HTMLElement = this.parentElement;
969
+ while (!parentEle.classList.contains('e-input-group')) {
970
+ parentEle = parentEle.parentElement;
971
+ }
972
+ _onMouseRipple(parentEle , ele);
973
+ }
974
+
975
+ function _onMouseUpRipple (): void {
976
+ const ele: HTMLElement = null || this;
977
+ setTimeout(
978
+ () => {
979
+ ele.classList.remove('e-input-btn-ripple');
980
+ },
981
+ 500);
982
+ }
983
+ function createIconEle(iconClass: string, makeElement: createElementParams): HTMLElement {
984
+ const button: HTMLElement = <HTMLElement>makeElement('span', { className: iconClass });
985
+ button.classList.add('e-input-group-icon');
986
+ return button;
987
+ }
988
+
989
+ /**
990
+ * Creates a new span element with the given icons added and append it in container element.
991
+ * ```
992
+ * E.g : Input.addIcon('append', 'e-icon-spin', inputObj.container, inputElement);
993
+ * ```
994
+ *
995
+ * @param {string} position - Specify the icon placement on the input.Possible values are append and prepend.
996
+ * @param {string | string[]} icons - Icon classes which are need to add to the span element which is going to created.
997
+ * Span element acts as icon or button element for input.
998
+ * @param {HTMLElement} container - The container on which created span element is going to append.
999
+ * @param {HTMLElement} input - The inputElement on which created span element is going to prepend.
1000
+ */
1001
+ export function addIcon(position: string, icons: string | string[], container: HTMLElement,
1002
+ input: HTMLElement, internalCreate?: createElementParams): void {
1003
+ const result: string[] = typeof(icons) === 'string' ? icons.split(',')
1004
+ : icons;
1005
+ if (position.toLowerCase() === 'append') {
1006
+ for (const icon of result) {
1007
+ appendSpan(icon, container, internalCreate);
1008
+ }
1009
+ } else {
1010
+ for (const icon of result) {
1011
+ prependSpan(icon, container, input, internalCreate);
1012
+ }
1013
+ }
1014
+ if (container.getElementsByClassName('e-input-group-icon')[0] && container.getElementsByClassName('e-float-text-overflow')[0]) {
1015
+ container.getElementsByClassName('e-float-text-overflow')[0].classList.add('e-icon');
1016
+ }
1017
+ }
1018
+
1019
+ /**
1020
+ * Creates a new span element with the given icons added and prepend it in input element.
1021
+ * ```
1022
+ * E.g : Input.prependSpan('e-icon-spin', inputObj.container, inputElement);
1023
+ * ```
1024
+ *
1025
+ * @param {string} iconClass - Icon classes which are need to add to the span element which is going to created.
1026
+ * Span element acts as icon or button element for input.
1027
+ * @param {HTMLElement} container - The container on which created span element is going to append.
1028
+ * @param {HTMLElement} inputElement - The inputElement on which created span element is going to prepend.
1029
+ */
1030
+ export function prependSpan(iconClass: string, container: HTMLElement,
1031
+ inputElement: HTMLElement, internalCreateElement?: createElementParams): HTMLElement {
1032
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
1033
+ const button: HTMLElement = createIconEle(iconClass, makeElement);
1034
+ container.classList.add('e-float-icon-left');
1035
+ let innerWrapper: HTMLElement = container.querySelector('.e-input-in-wrap');
1036
+ if (isNullOrUndefined(innerWrapper)) {
1037
+ innerWrapper = <HTMLElement>makeElement('span', { className: 'e-input-in-wrap' });
1038
+ inputElement.parentNode.insertBefore(innerWrapper, inputElement);
1039
+ const result: NodeListOf<Element> = container.querySelectorAll(inputElement.tagName + ' ~ *');
1040
+ innerWrapper.appendChild(inputElement);
1041
+ for (let i: number = 0; i < result.length; i++) {
1042
+ const element: Element = result[parseInt(i.toString(), 10)];
1043
+ const parentElement: HTMLElement = innerWrapper.parentElement;
1044
+ if (!(element.classList.contains('e-float-line')) || (!(parentElement && parentElement.classList.contains('e-filled')) && parentElement)) {
1045
+ innerWrapper.appendChild(element);
1046
+ }
1047
+ }
1048
+ }
1049
+ innerWrapper.parentNode.insertBefore(button, innerWrapper);
1050
+ _internalRipple(true, container, button);
1051
+ return button;
1052
+ }
1053
+
1054
+ /**
1055
+ * Creates a new span element with the given icons added and append it in container element.
1056
+ * ```
1057
+ * E.g : Input.appendSpan('e-icon-spin', inputObj.container);
1058
+ * ```
1059
+ *
1060
+ * @param {string} iconClass - Icon classes which are need to add to the span element which is going to created.
1061
+ * Span element acts as icon or button element for input.
1062
+ * @param {HTMLElement} container - The container on which created span element is going to append.
1063
+ */
1064
+ export function appendSpan(iconClass: string, container: HTMLElement, internalCreateElement ?: createElementParams): HTMLElement {
1065
+ const makeElement: createElementParams = !isNullOrUndefined(internalCreateElement) ? internalCreateElement : createElement;
1066
+ const button: HTMLElement = createIconEle(iconClass, makeElement);
1067
+ const wrap: HTMLElement = (container.classList.contains('e-float-icon-left')) ? container.querySelector('.e-input-in-wrap') :
1068
+ container;
1069
+ wrap.appendChild(button);
1070
+ _internalRipple(true, container, button);
1071
+ return button;
1072
+ }
1073
+
1074
+ export function validateInputType (containerElement : HTMLElement, input : HTMLInputElement | HTMLTextAreaElement) : void {
1075
+ if (input.type === 'hidden') {
1076
+ containerElement.classList.add('e-hidden');
1077
+ } else if (containerElement.classList.contains('e-hidden')) {
1078
+ containerElement.classList.remove('e-hidden');
1079
+ }
1080
+ }
1081
+
1082
+ export function updateHTMLAttributesToElement
1083
+ (htmlAttributes : {[key: string]: string}, element: HTMLInputElement | HTMLTextAreaElement): void {
1084
+ if ( !isNullOrUndefined(htmlAttributes)) {
1085
+ for (const key of Object.keys(htmlAttributes)) {
1086
+ if (containerAttributes.indexOf(key) < 0 ) {
1087
+ element.setAttribute(key, htmlAttributes[`${key}`]);
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ export function updateCssClass (newClass : string, oldClass : string, container: HTMLElement): void
1094
+ {
1095
+ setCssClass(getInputValidClassList(newClass), [container], getInputValidClassList(oldClass));
1096
+ }
1097
+
1098
+ export function getInputValidClassList(inputClassName: string): string {
1099
+ let result: string = inputClassName;
1100
+ if (!isNullOrUndefined(inputClassName) && inputClassName !== '') {
1101
+ result = (inputClassName.replace(/\s+/g, ' ')).trim();
1102
+ }
1103
+ return result;
1104
+ }
1105
+
1106
+ export function updateHTMLAttributesToWrapper(htmlAttributes : {[key: string]: string}, container: HTMLElement): void {
1107
+ if (!isNullOrUndefined(htmlAttributes)) {
1108
+ for (const key of Object.keys(htmlAttributes)) {
1109
+ if (containerAttributes.indexOf(key) > -1) {
1110
+ if (key === 'class') {
1111
+ const updatedClassValues: string = this.getInputValidClassList(htmlAttributes[`${key}`]);
1112
+ if (updatedClassValues !== '') {
1113
+ addClass([container], updatedClassValues.split(' '));
1114
+ }
1115
+ } else if (key === 'style') {
1116
+ let setStyle: string = container.getAttribute(key);
1117
+ setStyle = !isNullOrUndefined(setStyle) ? (setStyle + htmlAttributes[`${key}`]) :
1118
+ htmlAttributes[`${key}`];
1119
+ container.setAttribute(key, setStyle);
1120
+ } else {
1121
+ container.setAttribute(key, htmlAttributes[`${key}`]);
1122
+ }
1123
+ }
1124
+ }
1125
+ }
1126
+ }
1127
+
1128
+ export function isBlank(inputString: string): boolean {
1129
+ return (!inputString || /^\s*$/.test(inputString));
1130
+ }
1131
+ }
1132
+ /* eslint-enable no-inner-declarations */
1133
+
1134
+ interface ClassNames {
1135
+ RTL: string
1136
+ DISABLE: string
1137
+ INPUT: string
1138
+ TEXTAREA: string
1139
+ INPUTGROUP: string
1140
+ FLOATINPUT: string
1141
+ FLOATLINE: string
1142
+ FLOATTEXT: string
1143
+ FLOATTEXTCONTENT: string
1144
+ CLEARICON: string
1145
+ CLEARICONHIDE: string
1146
+ LABELTOP: string
1147
+ LABELBOTTOM: string
1148
+ NOFLOATLABEL: string
1149
+ INPUTCUSTOMTAG: string
1150
+ FLOATCUSTOMTAG: string
1151
+ }
1152
+ export interface InputObject {
1153
+ container?: HTMLElement
1154
+ buttons?: HTMLElement[]
1155
+ clearButton?: HTMLElement
1156
+ }
1157
+ /**
1158
+ * Arguments to create input element for input text boxes utility.These properties are optional.
1159
+ */
1160
+ export interface InputArgs {
1161
+ /**
1162
+ * Element which is needed to add to the container.
1163
+ * ```
1164
+ * E.g : Input.createInput({ element: element });
1165
+ * ```
1166
+ */
1167
+ element: HTMLInputElement | HTMLTextAreaElement
1168
+ /**
1169
+ * ```
1170
+ * E.g : Input.createInput({ element: element, buttons: ['e-icon-up', 'e-icon-down'] });
1171
+ * ```
1172
+ * Specifies the icon classes for span element which will be append to the container.
1173
+ */
1174
+ buttons?: string[]
1175
+ /**
1176
+ * ```
1177
+ * E.g : Input.createInput({ element: element, customTag: 'ej2-custom-input' });
1178
+ * ```
1179
+ * Specifies the custom tag which is acts as container to the input.
1180
+ */
1181
+ customTag?: string
1182
+ /**
1183
+ * ```
1184
+ * E.g : Input.createInput({ element: element, floatLabelType : "Always" });
1185
+ * ```
1186
+ * Specifies how the floating label works.
1187
+ * Possible values are:
1188
+ * * Never - Never float the label in the input when the placeholder is available.
1189
+ * * Always - The floating label will always float above the input.
1190
+ * * Auto - The floating label will float above the input after focusing or entering a value in the input.
1191
+ */
1192
+ floatLabelType ?: FloatLabelType | string
1193
+ /**
1194
+ * ```
1195
+ * E.g : Input.createInput({ element: element, customTag: 'ej2-custom-input' ,bindClearAction: false });
1196
+ * ```
1197
+ * Specifies whether to bind the clear button action in input base or not.
1198
+ */
1199
+ bindClearAction?: boolean
1200
+ /**
1201
+ * ```
1202
+ * E.g : Input.createInput({ element: element, properties: { readonly: true, placeholder: 'Search here' } });
1203
+ * ```
1204
+ * To specifies the properties such as readonly,enable rtl,etc.
1205
+ */
1206
+ properties?: {
1207
+ readonly?: boolean
1208
+ placeholder?: string
1209
+ cssClass?: string
1210
+ enableRtl?: boolean
1211
+ enabled?: boolean
1212
+ showClearButton?: boolean
1213
+ }
1214
+ }
1215
+ /**
1216
+ * Default required properties for input components.
1217
+ */
1218
+ export interface IInput {
1219
+ /**
1220
+ * Sets the placeholder value to input.
1221
+ */
1222
+ placeholder: string
1223
+ /**
1224
+ * Sets the css class value to input.
1225
+ */
1226
+ cssClass: string
1227
+ /**
1228
+ * Sets the enabled value to input.
1229
+ */
1230
+ enabled?: boolean
1231
+ /**
1232
+ * Sets the readonly value to input.
1233
+ */
1234
+ readonly: boolean
1235
+ /**
1236
+ * Sets the enable rtl value to input.
1237
+ */
1238
+ enableRtl: boolean
1239
+ /**
1240
+ * Specifies whether to display the Clear button in the input.
1241
+ */
1242
+ showClearButton?: boolean
1243
+ /**
1244
+ * Specifies how the floating label works.
1245
+ * Possible values are:
1246
+ * * Never - Never float the label in the input when the placeholder is available.
1247
+ * * Always - The floating label will always float above the input.
1248
+ * * Auto - The floating label will float above the input after focusing or entering a value in the input.
1249
+ */
1250
+ floatLabelType?: FloatLabelType | string
1251
+ /**
1252
+ * Sets the change event mapping function to input.
1253
+ */
1254
+ change: Function
1255
+ }
1256
+
1257
+ export type createElementParams = (
1258
+ tag: string,
1259
+ prop?: { id?: string; className?: string; innerHTML?: string; styles?: string; attrs?: { [key: string]: string } }
1260
+ ) => HTMLElement;
1261
+
1262
+ /**
1263
+ * Defines the argument for the focus event.
1264
+ */
1265
+ export interface FocusEventArgs {
1266
+ model?: Object
1267
+
1268
+ }
1269
+
1270
+ /**
1271
+ * Defines the argument for the blur event.
1272
+ */
1273
+ export interface BlurEventArgs {
1274
+ model?: Object
1275
+
1276
+ }
1277
+ /* eslint-enable valid-jsdoc, jsdoc/require-jsdoc, jsdoc/require-returns, jsdoc/require-param */