@syncfusion/ej2-inputs 31.1.17 → 31.1.21
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/dist/ej2-inputs.min.js +2 -2
- package/dist/ej2-inputs.umd.min.js +2 -2
- package/dist/ej2-inputs.umd.min.js.map +1 -1
- package/dist/es6/ej2-inputs.es2015.js +11 -3
- package/dist/es6/ej2-inputs.es2015.js.map +1 -1
- package/dist/es6/ej2-inputs.es5.js +11 -3
- package/dist/es6/ej2-inputs.es5.js.map +1 -1
- package/dist/global/ej2-inputs.min.js +2 -2
- package/dist/global/ej2-inputs.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/package.json +11 -61
- package/src/color-picker/color-picker.js +4 -3
- package/src/textbox/textbox.js +7 -0
- package/styles/bootstrap4-lite.css +2 -2
- package/styles/bootstrap4.css +2 -2
- package/styles/bootstrap5-dark-lite.css +2 -2
- package/styles/bootstrap5-dark.css +2 -2
- package/styles/bootstrap5-lite.css +2 -2
- package/styles/bootstrap5.css +2 -2
- package/styles/input/_bootstrap4-definition.scss +1 -1
- package/styles/input/_bootstrap5-definition.scss +1 -1
- package/styles/input/bootstrap4.css +2 -2
- package/styles/input/bootstrap5-dark.css +2 -2
- package/styles/input/bootstrap5.css +2 -2
- package/dist/ts/color-picker/color-picker-model.d.ts +0 -186
- package/dist/ts/color-picker/color-picker.d.ts +0 -398
- package/dist/ts/color-picker/color-picker.ts +0 -2209
- package/dist/ts/color-picker/index.d.ts +0 -5
- package/dist/ts/color-picker/index.ts +0 -5
- package/dist/ts/common/index.d.ts +0 -4
- package/dist/ts/common/index.ts +0 -4
- package/dist/ts/common/signature-base.d.ts +0 -340
- package/dist/ts/common/signature-base.ts +0 -1170
- package/dist/ts/form-validator/form-validator-model.d.ts +0 -121
- package/dist/ts/form-validator/form-validator.d.ts +0 -312
- package/dist/ts/form-validator/form-validator.ts +0 -1068
- package/dist/ts/form-validator/index.d.ts +0 -5
- package/dist/ts/form-validator/index.ts +0 -5
- package/dist/ts/index.d.ts +0 -18
- package/dist/ts/index.ts +0 -18
- package/dist/ts/input/index.d.ts +0 -4
- package/dist/ts/input/index.ts +0 -4
- package/dist/ts/input/input.d.ts +0 -345
- package/dist/ts/input/input.ts +0 -1277
- package/dist/ts/maskedtextbox/base/index.d.ts +0 -4
- package/dist/ts/maskedtextbox/base/index.ts +0 -4
- package/dist/ts/maskedtextbox/base/mask-base.d.ts +0 -134
- package/dist/ts/maskedtextbox/base/mask-base.ts +0 -1207
- package/dist/ts/maskedtextbox/index.d.ts +0 -5
- package/dist/ts/maskedtextbox/index.ts +0 -5
- package/dist/ts/maskedtextbox/maskedtextbox/index.d.ts +0 -5
- package/dist/ts/maskedtextbox/maskedtextbox/index.ts +0 -5
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox-model.d.ts +0 -167
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.d.ts +0 -307
- package/dist/ts/maskedtextbox/maskedtextbox/maskedtextbox.ts +0 -709
- package/dist/ts/numerictextbox/index.d.ts +0 -5
- package/dist/ts/numerictextbox/index.ts +0 -5
- package/dist/ts/numerictextbox/numerictextbox-model.d.ts +0 -228
- package/dist/ts/numerictextbox/numerictextbox.d.ts +0 -431
- package/dist/ts/numerictextbox/numerictextbox.ts +0 -1672
- package/dist/ts/otp-input/index.d.ts +0 -5
- package/dist/ts/otp-input/index.ts +0 -5
- package/dist/ts/otp-input/otp-input-model.d.ts +0 -165
- package/dist/ts/otp-input/otp-input.d.ts +0 -365
- package/dist/ts/otp-input/otp-input.ts +0 -924
- package/dist/ts/rating/index.d.ts +0 -5
- package/dist/ts/rating/index.ts +0 -5
- package/dist/ts/rating/rating-model.d.ts +0 -239
- package/dist/ts/rating/rating.d.ts +0 -416
- package/dist/ts/rating/rating.ts +0 -1101
- package/dist/ts/signature/index.d.ts +0 -5
- package/dist/ts/signature/index.ts +0 -5
- package/dist/ts/signature/signature-model.d.ts +0 -131
- package/dist/ts/signature/signature.d.ts +0 -167
- package/dist/ts/signature/signature.ts +0 -266
- package/dist/ts/slider/index.d.ts +0 -5
- package/dist/ts/slider/index.ts +0 -5
- package/dist/ts/slider/slider-model.d.ts +0 -401
- package/dist/ts/slider/slider.d.ts +0 -721
- package/dist/ts/slider/slider.ts +0 -3497
- package/dist/ts/smart-textarea/caret-helper.d.ts +0 -17
- package/dist/ts/smart-textarea/caret-helper.ts +0 -95
- package/dist/ts/smart-textarea/index.d.ts +0 -5
- package/dist/ts/smart-textarea/index.ts +0 -5
- package/dist/ts/smart-textarea/smart-textarea-model.d.ts +0 -44
- package/dist/ts/smart-textarea/smart-textarea.d.ts +0 -80
- package/dist/ts/smart-textarea/smart-textarea.ts +0 -518
- package/dist/ts/speech-to-text/index.d.ts +0 -5
- package/dist/ts/speech-to-text/index.ts +0 -5
- package/dist/ts/speech-to-text/speech-to-text-model.d.ts +0 -270
- package/dist/ts/speech-to-text/speech-to-text.d.ts +0 -487
- package/dist/ts/speech-to-text/speech-to-text.ts +0 -1008
- package/dist/ts/textarea/index.d.ts +0 -5
- package/dist/ts/textarea/index.ts +0 -5
- package/dist/ts/textarea/textarea-model.d.ts +0 -161
- package/dist/ts/textarea/textarea.d.ts +0 -237
- package/dist/ts/textarea/textarea.ts +0 -812
- package/dist/ts/textbox/index.d.ts +0 -5
- package/dist/ts/textbox/index.ts +0 -5
- package/dist/ts/textbox/textbox-model.d.ts +0 -155
- package/dist/ts/textbox/textbox.d.ts +0 -288
- package/dist/ts/textbox/textbox.ts +0 -872
- package/dist/ts/uploader/index.d.ts +0 -5
- package/dist/ts/uploader/index.ts +0 -5
- package/dist/ts/uploader/uploader-model.d.ts +0 -555
- package/dist/ts/uploader/uploader.d.ts +0 -1216
- package/dist/ts/uploader/uploader.ts +0 -4391
|
@@ -1,1068 +0,0 @@
|
|
|
1
|
-
import { selectAll, select, createElement, Base, EmitType, detach } from '@syncfusion/ej2-base';
|
|
2
|
-
import { extend, isNullOrUndefined, IKeyValue, EventHandler } from '@syncfusion/ej2-base';
|
|
3
|
-
import { Property, NotifyPropertyChanges, INotifyPropertyChanged, Event, onIntlChange } from '@syncfusion/ej2-base';
|
|
4
|
-
import { Internationalization, L10n } from '@syncfusion/ej2-base';
|
|
5
|
-
import { FormValidatorModel } from './form-validator-model';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* global declarations
|
|
9
|
-
*/
|
|
10
|
-
export const regex: { [key: string]: RegExp } = {
|
|
11
|
-
/* eslint-disable no-useless-escape */
|
|
12
|
-
EMAIL: new RegExp('^[A-Za-z0-9._%+-]{1,}@[A-Za-z0-9._%+-]{1,}([.]{1}[a-zA-Z0-9]{2,}' +
|
|
13
|
-
'|[.]{1}[a-zA-Z0-9]{2,4}[.]{1}[a-zA-Z0-9]{2,4})$'),
|
|
14
|
-
/* eslint-disable-next-line security/detect-unsafe-regex */
|
|
15
|
-
URL: /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/m,
|
|
16
|
-
DATE_ISO: new RegExp('^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$'),
|
|
17
|
-
DIGITS: new RegExp('^[0-9]*$'),
|
|
18
|
-
PHONE: new RegExp('^[+]?[0-9]{9,13}$'),
|
|
19
|
-
CREDITCARD: new RegExp('^\\d{13,16}$')
|
|
20
|
-
/* eslint-enable no-useless-escape */
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* ErrorOption values
|
|
25
|
-
*
|
|
26
|
-
* @private
|
|
27
|
-
*/
|
|
28
|
-
export enum ErrorOption {
|
|
29
|
-
/**
|
|
30
|
-
* Defines the error message.
|
|
31
|
-
*/
|
|
32
|
-
Message,
|
|
33
|
-
/**
|
|
34
|
-
* Defines the error element type.
|
|
35
|
-
*/
|
|
36
|
-
Label
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* FormValidator class enables you to validate the form fields based on your defined rules
|
|
41
|
-
* ```html
|
|
42
|
-
* <form id='formId'>
|
|
43
|
-
* <input type='text' name='Name' />
|
|
44
|
-
* <input type='text' name='Age' />
|
|
45
|
-
* </form>
|
|
46
|
-
* <script>
|
|
47
|
-
* let formObject = new FormValidator('#formId', {
|
|
48
|
-
* rules: { Name: { required: true }, Age: { range: [18, 30] } };
|
|
49
|
-
* });
|
|
50
|
-
* formObject.validate();
|
|
51
|
-
* </script>
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
|
-
@NotifyPropertyChanges
|
|
55
|
-
export class FormValidator extends Base<HTMLFormElement> implements INotifyPropertyChanged {
|
|
56
|
-
private validated: string[] = [];
|
|
57
|
-
private errorRules: ErrorRule[] = [];
|
|
58
|
-
private allowSubmit: boolean = false;
|
|
59
|
-
private required: string = 'required';
|
|
60
|
-
private infoElement: HTMLElement = null;
|
|
61
|
-
private inputElement: HTMLInputElement = null;
|
|
62
|
-
private selectQuery: string = 'input:not([type=reset]):not([type=button]), select, textarea';
|
|
63
|
-
private inputElements: HTMLInputElement[];
|
|
64
|
-
private l10n: L10n;
|
|
65
|
-
private internationalization: Internationalization;
|
|
66
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
-
private localyMessage: any = {};
|
|
68
|
-
/**
|
|
69
|
-
* default locale variable
|
|
70
|
-
*/
|
|
71
|
-
@Property('')
|
|
72
|
-
public locale: string;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Ignores input fields based on the class name
|
|
77
|
-
*
|
|
78
|
-
* @default 'e-hidden'
|
|
79
|
-
*/
|
|
80
|
-
@Property('e-hidden')
|
|
81
|
-
public ignore: string;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Maps the input fields with validation rules
|
|
85
|
-
*
|
|
86
|
-
* @default {}
|
|
87
|
-
*/
|
|
88
|
-
@Property()
|
|
89
|
-
public rules: { [name: string]: { [rule: string]: Object } };
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Sets the defined css class to error fields
|
|
93
|
-
*
|
|
94
|
-
* @default 'e-error'
|
|
95
|
-
*/
|
|
96
|
-
@Property('e-error')
|
|
97
|
-
public errorClass: string;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Sets the defined css class to valid fields
|
|
101
|
-
*
|
|
102
|
-
* @default 'e-valid'
|
|
103
|
-
*/
|
|
104
|
-
@Property('e-valid')
|
|
105
|
-
public validClass: string;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Specify HTML element for error
|
|
109
|
-
*
|
|
110
|
-
* @default 'label'
|
|
111
|
-
*/
|
|
112
|
-
@Property('label')
|
|
113
|
-
public errorElement: string;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Specify HTML element for error container
|
|
117
|
-
*
|
|
118
|
-
* @default 'div'
|
|
119
|
-
*/
|
|
120
|
-
@Property('div')
|
|
121
|
-
public errorContainer: string;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Option to display the error
|
|
125
|
-
*
|
|
126
|
-
* @default ErrorOption.Label
|
|
127
|
-
* @deprecated
|
|
128
|
-
*/
|
|
129
|
-
@Property(ErrorOption.Label)
|
|
130
|
-
public errorOption: ErrorOption;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Triggers when a field's focused out
|
|
134
|
-
*
|
|
135
|
-
* @event focusout
|
|
136
|
-
*/
|
|
137
|
-
@Event()
|
|
138
|
-
public focusout: EmitType<Event>;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Trigger when keyup is triggered in any fields
|
|
142
|
-
*
|
|
143
|
-
* @event keyup
|
|
144
|
-
*/
|
|
145
|
-
@Event()
|
|
146
|
-
public keyup: EmitType<KeyboardEvent>;
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Triggers when a check box field is clicked
|
|
150
|
-
*
|
|
151
|
-
* @event click
|
|
152
|
-
*/
|
|
153
|
-
@Event()
|
|
154
|
-
public click: EmitType<Event>;
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Trigger when a select/drop-down field is changed
|
|
158
|
-
*
|
|
159
|
-
* @event change
|
|
160
|
-
*/
|
|
161
|
-
@Event()
|
|
162
|
-
public change: EmitType<Event>;
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Triggers before form is being submitted
|
|
166
|
-
*
|
|
167
|
-
* @event submit
|
|
168
|
-
*/
|
|
169
|
-
@Event()
|
|
170
|
-
public submit: EmitType<Event>;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Triggers before validation starts
|
|
174
|
-
*
|
|
175
|
-
* @event validationBegin
|
|
176
|
-
*/
|
|
177
|
-
@Event()
|
|
178
|
-
public validationBegin: EmitType<Object | ValidArgs>;
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Triggers after validation is completed
|
|
182
|
-
*
|
|
183
|
-
* @event validationComplete
|
|
184
|
-
*/
|
|
185
|
-
@Event()
|
|
186
|
-
public validationComplete: EmitType<Object | FormEventArgs>;
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Assigns the custom function to place the error message in the page.
|
|
190
|
-
*
|
|
191
|
-
* @event customPlacement
|
|
192
|
-
*/
|
|
193
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
194
|
-
@Event()
|
|
195
|
-
public customPlacement: EmitType<HTMLElement | any>;
|
|
196
|
-
|
|
197
|
-
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Add validation rules to the corresponding input element based on `name` attribute.
|
|
201
|
-
*
|
|
202
|
-
* @param {string} name `name` of form field.
|
|
203
|
-
* @param {Object} rules Validation rules for the corresponding element.
|
|
204
|
-
* @returns {void}
|
|
205
|
-
*/
|
|
206
|
-
public addRules(name: string, rules: Object): void {
|
|
207
|
-
if (name) {
|
|
208
|
-
// eslint-disable-next-line no-prototype-builtins
|
|
209
|
-
if (this.rules.hasOwnProperty(name)) {
|
|
210
|
-
extend(this.rules[`${name}`], rules, {});
|
|
211
|
-
} else {
|
|
212
|
-
this.rules[`${name}`] = <IKeyValue>rules;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Remove validation to the corresponding field based on name attribute.
|
|
219
|
-
* When no parameter is passed, remove all the validations in the form.
|
|
220
|
-
*
|
|
221
|
-
* @param {string} name Input name attribute value.
|
|
222
|
-
* @param {string[]} rules List of validation rules need to be remove from the corresponding element.
|
|
223
|
-
* @returns {void}
|
|
224
|
-
*/
|
|
225
|
-
public removeRules(name?: string, rules?: string[]): void {
|
|
226
|
-
if (!name && !rules) {
|
|
227
|
-
this.rules = {};
|
|
228
|
-
} else if (this.rules[`${name}`] && !rules) {
|
|
229
|
-
delete this.rules[`${name}`];
|
|
230
|
-
} else if (!isNullOrUndefined(this.rules[`${name}`] && rules)) {
|
|
231
|
-
for (let i: number = 0; i < rules.length; i++) {
|
|
232
|
-
delete this.rules[`${name}`][rules[parseInt(i.toString(), 10)]];
|
|
233
|
-
}
|
|
234
|
-
} else {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Validate the current form values using defined rules.
|
|
241
|
-
* Returns `true` when the form is valid otherwise `false`
|
|
242
|
-
*
|
|
243
|
-
* @param {string} selected - Optional parameter to validate specified element.
|
|
244
|
-
* @returns {boolean} - Returns form validation status.
|
|
245
|
-
*/
|
|
246
|
-
public validate(selected?: string): boolean {
|
|
247
|
-
const rules: string[] = Object.keys(this.rules);
|
|
248
|
-
if (selected && rules.length) {
|
|
249
|
-
this.validateRules(selected);
|
|
250
|
-
//filter the selected element it don't have any valid input element
|
|
251
|
-
return rules.indexOf(selected) !== -1 && this.errorRules.filter((data: ErrorRule) => {
|
|
252
|
-
return data.name === selected;
|
|
253
|
-
}).length === 0;
|
|
254
|
-
} else {
|
|
255
|
-
this.errorRules = [];
|
|
256
|
-
for (const name of rules) {
|
|
257
|
-
this.validateRules(name);
|
|
258
|
-
}
|
|
259
|
-
return this.errorRules.length === 0;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Reset the value of all the fields in form.
|
|
265
|
-
*
|
|
266
|
-
* @returns {void}
|
|
267
|
-
*/
|
|
268
|
-
public reset(): void {
|
|
269
|
-
this.element.reset();
|
|
270
|
-
this.clearForm();
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Get input element by name.
|
|
275
|
-
*
|
|
276
|
-
* @param {string} name - Input element name attribute value.
|
|
277
|
-
* @returns {HTMLInputElement} - Returns the input element.
|
|
278
|
-
*/
|
|
279
|
-
public getInputElement(name: string): HTMLInputElement {
|
|
280
|
-
this.inputElement = <HTMLInputElement>(select('[name="' + name + '"]', this.element));
|
|
281
|
-
return this.inputElement;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Destroy the form validator object and error elements.
|
|
286
|
-
*
|
|
287
|
-
* @returns {void}
|
|
288
|
-
*/
|
|
289
|
-
public destroy(): void {
|
|
290
|
-
this.reset();
|
|
291
|
-
this.unwireEvents();
|
|
292
|
-
this.rules = {};
|
|
293
|
-
const elements: HTMLElement[] = selectAll('.' + this.errorClass + ', .' + this.validClass, this.element);
|
|
294
|
-
for (const element of elements) {
|
|
295
|
-
detach(element);
|
|
296
|
-
}
|
|
297
|
-
super.destroy();
|
|
298
|
-
this.infoElement = null;
|
|
299
|
-
onIntlChange.off('notifyExternalChange', this.afterLocalization);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Specifies the default messages for validation rules.
|
|
304
|
-
*
|
|
305
|
-
* @default { List of validation message }
|
|
306
|
-
*/
|
|
307
|
-
public defaultMessages: { [rule: string]: string } = {
|
|
308
|
-
required: 'This field is required.',
|
|
309
|
-
email: 'Please enter a valid email address.',
|
|
310
|
-
url: 'Please enter a valid URL.',
|
|
311
|
-
date: 'Please enter a valid date.',
|
|
312
|
-
dateIso: 'Please enter a valid date ( ISO ).',
|
|
313
|
-
creditcard: 'Please enter valid card number',
|
|
314
|
-
number: 'Please enter a valid number.',
|
|
315
|
-
digits: 'Please enter only digits.',
|
|
316
|
-
maxLength: 'Please enter no more than {0} characters.',
|
|
317
|
-
minLength: 'Please enter at least {0} characters.',
|
|
318
|
-
rangeLength: 'Please enter a value between {0} and {1} characters long.',
|
|
319
|
-
range: 'Please enter a value between {0} and {1}.',
|
|
320
|
-
max: 'Please enter a value less than or equal to {0}.',
|
|
321
|
-
min: 'Please enter a value greater than or equal to {0}.',
|
|
322
|
-
regex: 'Please enter a correct value.',
|
|
323
|
-
tel: 'Please enter a valid phone number.',
|
|
324
|
-
pattern: 'Please enter a correct pattern value.',
|
|
325
|
-
equalTo: 'Please enter the valid match text'
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* @param {FormValidatorModel} newProp - Returns the dynamic property value of the component.
|
|
330
|
-
* @param {FormValidatorModel} oldProp - Returns the previous property value of the component.
|
|
331
|
-
* @returns {void}
|
|
332
|
-
* @private
|
|
333
|
-
*/
|
|
334
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
335
|
-
public onPropertyChanged(newProp: FormValidatorModel, oldProp?: FormValidatorModel): void {
|
|
336
|
-
for (const prop of Object.keys(newProp)) {
|
|
337
|
-
switch (prop) {
|
|
338
|
-
case 'locale':
|
|
339
|
-
this.localeFunc();
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* @private
|
|
347
|
-
* @returns {void}
|
|
348
|
-
*/
|
|
349
|
-
public localeFunc(): void {
|
|
350
|
-
for (const key of Object.keys(this.defaultMessages)) {
|
|
351
|
-
this.l10n.setLocale(this.locale);
|
|
352
|
-
const value: string = this.l10n.getConstant(key);
|
|
353
|
-
this.localyMessage[`${key}`] = value;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* @private
|
|
360
|
-
* @returns {string} - Returns the component name.
|
|
361
|
-
*/
|
|
362
|
-
public getModuleName(): string {
|
|
363
|
-
return 'formvalidator';
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* @param {any} args - Specifies the culture name.
|
|
368
|
-
* @returns {void}
|
|
369
|
-
* @private
|
|
370
|
-
*/
|
|
371
|
-
public afterLocalization(args: any): void {
|
|
372
|
-
this.locale = args.locale;
|
|
373
|
-
this.localeFunc();
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Allows you to refresh the form validator base events to the elements inside the form.
|
|
378
|
-
*
|
|
379
|
-
* @returns {void}
|
|
380
|
-
*/
|
|
381
|
-
public refresh(): void {
|
|
382
|
-
this.unwireEvents();
|
|
383
|
-
this.inputElements = <HTMLInputElement[]>selectAll(this.selectQuery, this.element);
|
|
384
|
-
this.wireEvents();
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Initializes the FormValidator.
|
|
389
|
-
*
|
|
390
|
-
* @param {string | HTMLFormElement} element - Specifies the element to render as component.
|
|
391
|
-
* @param {FormValidatorModel} options - Specifies the FormValidator model.
|
|
392
|
-
* @private
|
|
393
|
-
*/
|
|
394
|
-
public constructor(element: string | HTMLFormElement, options?: FormValidatorModel) {
|
|
395
|
-
super(options, element);
|
|
396
|
-
if (typeof this.rules === 'undefined') {
|
|
397
|
-
this.rules = {};
|
|
398
|
-
}
|
|
399
|
-
this.l10n = new L10n('formValidator', this.defaultMessages, this.locale);
|
|
400
|
-
if (this.locale) {
|
|
401
|
-
this.localeFunc();
|
|
402
|
-
}
|
|
403
|
-
onIntlChange.on('notifyExternalChange', this.afterLocalization, this);
|
|
404
|
-
|
|
405
|
-
element = typeof element === 'string' ? <HTMLFormElement>select(element, document) : element;
|
|
406
|
-
// Set novalidate to prevent default HTML5 form validation
|
|
407
|
-
if (this.element != null) {
|
|
408
|
-
this.element.setAttribute('novalidate', '');
|
|
409
|
-
this.inputElements = <HTMLInputElement[]>selectAll(this.selectQuery, this.element);
|
|
410
|
-
this.createHTML5Rules();
|
|
411
|
-
this.wireEvents();
|
|
412
|
-
} else {
|
|
413
|
-
return undefined;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
private clearForm(): void {
|
|
418
|
-
this.errorRules = [];
|
|
419
|
-
this.validated = [];
|
|
420
|
-
const elements: HTMLElement[] = selectAll(this.selectQuery, this.element);
|
|
421
|
-
for (const element of elements) {
|
|
422
|
-
const input: HTMLInputElement = <HTMLInputElement>element;
|
|
423
|
-
input.removeAttribute('aria-invalid');
|
|
424
|
-
const inputParent: HTMLElement = input.parentElement;
|
|
425
|
-
const grandParent: HTMLElement = inputParent.parentElement;
|
|
426
|
-
if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
|
|
427
|
-
(input.classList.contains('e-input') && inputParent.classList.contains('e-input-group'))) {
|
|
428
|
-
inputParent.classList.remove(this.errorClass);
|
|
429
|
-
}
|
|
430
|
-
else if ((grandParent != null) && (grandParent.classList.contains('e-control-wrapper') ||
|
|
431
|
-
grandParent.classList.contains('e-wrapper'))) {
|
|
432
|
-
grandParent.classList.remove(this.errorClass);
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
input.classList.remove(this.errorClass);
|
|
436
|
-
}
|
|
437
|
-
if (input.name.length > 0) {
|
|
438
|
-
this.getInputElement(input.name);
|
|
439
|
-
this.getErrorElement(input.name);
|
|
440
|
-
this.hideMessage(input.name);
|
|
441
|
-
}
|
|
442
|
-
if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
|
|
443
|
-
(input.classList.contains('e-input') && inputParent.classList.contains('e-input-group'))) {
|
|
444
|
-
inputParent.classList.remove(this.validClass);
|
|
445
|
-
}
|
|
446
|
-
else if ((grandParent != null) && (grandParent.classList.contains('e-control-wrapper') ||
|
|
447
|
-
grandParent.classList.contains('e-wrapper'))) {
|
|
448
|
-
grandParent.classList.remove(this.validClass);
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
input.classList.remove(this.validClass);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
private createHTML5Rules(): void {
|
|
457
|
-
const defRules: string[] = ['required', 'validateHidden', 'regex', 'rangeLength', 'maxLength', 'minLength', 'dateIso', 'digits',
|
|
458
|
-
'pattern', 'data-val-required', 'type', 'data-validation', 'min', 'max', 'range', 'equalTo', 'data-val-minlength-min',
|
|
459
|
-
'data-val-equalto-other', 'data-val-maxlength-max', 'data-val-range-min', 'data-val-regex-pattern', 'data-val-length-max',
|
|
460
|
-
'data-val-creditcard', 'data-val-phone'];
|
|
461
|
-
const acceptedTypes: string[] = ['hidden', 'email', 'url', 'date', 'number', 'tel'];
|
|
462
|
-
for (const input of (this.inputElements)) {
|
|
463
|
-
// Default attribute rules
|
|
464
|
-
const allRule: { [key: string]: Object } = {};
|
|
465
|
-
for (let rule of defRules) {
|
|
466
|
-
if (input.getAttribute(rule) !== null) {
|
|
467
|
-
switch (rule) {
|
|
468
|
-
case 'required':
|
|
469
|
-
this.defRule(input, allRule, rule, input.required);
|
|
470
|
-
break;
|
|
471
|
-
case 'data-validation':
|
|
472
|
-
rule = input.getAttribute(rule);
|
|
473
|
-
this.defRule(input, allRule, rule, true);
|
|
474
|
-
break;
|
|
475
|
-
case 'type':
|
|
476
|
-
if (acceptedTypes.indexOf(input.type) !== -1) {
|
|
477
|
-
this.defRule(input, allRule, input.type, true);
|
|
478
|
-
}
|
|
479
|
-
break;
|
|
480
|
-
case 'rangeLength':
|
|
481
|
-
case 'range':
|
|
482
|
-
this.defRule(input, allRule, rule, JSON.parse(input.getAttribute(rule)));
|
|
483
|
-
break;
|
|
484
|
-
case 'equalTo': {
|
|
485
|
-
const id: string = input.getAttribute(rule);
|
|
486
|
-
this.defRule(input, allRule, rule, id);
|
|
487
|
-
}
|
|
488
|
-
break;
|
|
489
|
-
default:
|
|
490
|
-
if (input.getAttribute('data-val') === 'true') {
|
|
491
|
-
this.annotationRule(input, allRule, rule, input.getAttribute(rule));
|
|
492
|
-
} else {
|
|
493
|
-
this.defRule(input, allRule, rule, input.getAttribute(rule));
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
//adding pattern type validation
|
|
499
|
-
if (Object.keys(allRule).length !== 0) {
|
|
500
|
-
this.addRules(input.name, allRule);
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
private annotationRule(input: HTMLInputElement, ruleCon: { [key: string]: Object }, ruleName: string, value: Object): void {
|
|
506
|
-
const annotationRule: string[] = ruleName.split('-');
|
|
507
|
-
const rulesList: string[] = ['required', 'creditcard', 'phone', 'maxlength', 'minlength', 'range', 'regex', 'equalto'];
|
|
508
|
-
const ruleFirstName: string = annotationRule[annotationRule.length - 1];
|
|
509
|
-
const ruleSecondName: string = annotationRule[annotationRule.length - 2];
|
|
510
|
-
if (rulesList.indexOf(ruleFirstName) !== -1) {
|
|
511
|
-
switch (ruleFirstName) {
|
|
512
|
-
case 'required':
|
|
513
|
-
this.defRule(input, ruleCon, 'required', value);
|
|
514
|
-
break;
|
|
515
|
-
case 'creditcard':
|
|
516
|
-
this.defRule(input, ruleCon, 'creditcard', value);
|
|
517
|
-
break;
|
|
518
|
-
case 'phone':
|
|
519
|
-
this.defRule(input, ruleCon, 'tel', value);
|
|
520
|
-
break;
|
|
521
|
-
}
|
|
522
|
-
} else if (rulesList.indexOf(ruleSecondName) !== -1) {
|
|
523
|
-
switch (ruleSecondName) {
|
|
524
|
-
case 'maxlength':
|
|
525
|
-
this.defRule(input, ruleCon, 'maxLength', value);
|
|
526
|
-
break;
|
|
527
|
-
case 'minlength':
|
|
528
|
-
this.defRule(input, ruleCon, 'minLength', value);
|
|
529
|
-
break;
|
|
530
|
-
case 'range': {
|
|
531
|
-
const minvalue: string = input.getAttribute('data-val-range-min');
|
|
532
|
-
const maxvalue: string = input.getAttribute('data-val-range-max');
|
|
533
|
-
this.defRule(input, ruleCon, 'range', [minvalue, maxvalue]);
|
|
534
|
-
}
|
|
535
|
-
break;
|
|
536
|
-
case 'equalto': {
|
|
537
|
-
const id: string[] = input.getAttribute(ruleName).split('.');
|
|
538
|
-
this.defRule(input, ruleCon, 'equalTo', id[id.length - 1]);
|
|
539
|
-
}
|
|
540
|
-
break;
|
|
541
|
-
case 'regex':
|
|
542
|
-
this.defRule(input, ruleCon, 'regex', value);
|
|
543
|
-
break;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
private defRule(input: HTMLInputElement, ruleCon: { [key: string]: Object }, ruleName: string, value: Object): void {
|
|
549
|
-
const message: string = input.getAttribute('data-' + ruleName + '-message');
|
|
550
|
-
const annotationMessage: string = input.getAttribute('data-val-' + ruleName);
|
|
551
|
-
let customMessage: string;
|
|
552
|
-
if (this.rules[input.name] && ruleName !== 'validateHidden' && ruleName !== 'hidden') {
|
|
553
|
-
this.getInputElement(input.name);
|
|
554
|
-
customMessage = this.getErrorMessage(this.rules[input.name][`${ruleName}`], ruleName);
|
|
555
|
-
}
|
|
556
|
-
if (message) {
|
|
557
|
-
value = [value, message];
|
|
558
|
-
} else if (annotationMessage) {
|
|
559
|
-
value = [value, annotationMessage];
|
|
560
|
-
} else if (customMessage) {
|
|
561
|
-
value = [value, customMessage];
|
|
562
|
-
}
|
|
563
|
-
ruleCon[`${ruleName}`] = value;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// Wire events to the form elements
|
|
567
|
-
private wireEvents(): void {
|
|
568
|
-
for (const input of (this.inputElements)) {
|
|
569
|
-
if (FormValidator.isCheckable(input)) {
|
|
570
|
-
EventHandler.add(input, 'click', this.clickHandler, this);
|
|
571
|
-
} else if (input.tagName === 'SELECT') {
|
|
572
|
-
EventHandler.add(input, 'change', this.changeHandler, this);
|
|
573
|
-
} else {
|
|
574
|
-
EventHandler.add(input, 'focusout', this.focusOutHandler, this);
|
|
575
|
-
EventHandler.add(input, 'keyup', this.keyUpHandler, this);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
EventHandler.add(this.element, 'submit', this.submitHandler, this);
|
|
579
|
-
EventHandler.add(this.element, 'reset', this.resetHandler, this);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// UnWire events to the form elements
|
|
583
|
-
private unwireEvents(): void {
|
|
584
|
-
for (const input of (this.inputElements)) {
|
|
585
|
-
EventHandler.clearEvents(input);
|
|
586
|
-
}
|
|
587
|
-
EventHandler.remove(this.element, 'submit', this.submitHandler);
|
|
588
|
-
EventHandler.remove(this.element, 'reset', this.resetHandler);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// Handle input element focusout event
|
|
592
|
-
private focusOutHandler(e: Event): void {
|
|
593
|
-
this.trigger('focusout', e);
|
|
594
|
-
//FormValidator.triggerCallback(this.focusout, e);
|
|
595
|
-
const element: HTMLInputElement = <HTMLInputElement>e.target;
|
|
596
|
-
if (this.rules[element.name]) {
|
|
597
|
-
if (this.rules[element.name][this.required] || element.value.length > 0) {
|
|
598
|
-
this.validate(element.name);
|
|
599
|
-
} else if (this.validated.indexOf(element.name) === -1) {
|
|
600
|
-
this.validated.push(element.name);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// Handle input element keyup event
|
|
606
|
-
private keyUpHandler(e: KeyboardEvent): void {
|
|
607
|
-
this.trigger('keyup', e);
|
|
608
|
-
const element: HTMLInputElement = <HTMLInputElement>e.target;
|
|
609
|
-
// List of keys need to prevent while validation
|
|
610
|
-
const excludeKeys: number[] = [16, 17, 18, 20, 35, 36, 37, 38, 39, 40, 45, 144, 225];
|
|
611
|
-
if (e.which === 9 && (!this.rules[element.name] || (this.rules[element.name] && !this.rules[element.name][this.required]))) {
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
if (this.validated.indexOf(element.name) !== -1 && this.rules[element.name] && excludeKeys.indexOf(e.which) === -1) {
|
|
615
|
-
this.validate(element.name);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Handle input click event
|
|
620
|
-
private clickHandler(e: Event): void {
|
|
621
|
-
this.trigger('click', e);
|
|
622
|
-
const element: HTMLInputElement = <HTMLInputElement>e.target;
|
|
623
|
-
// If element type is not submit allow validation
|
|
624
|
-
if (element.type !== 'submit') {
|
|
625
|
-
this.validate(element.name);
|
|
626
|
-
} else if (element.getAttribute('formnovalidate') !== null) {
|
|
627
|
-
// Prevent form validation, if submit button has formnovalidate attribute
|
|
628
|
-
this.allowSubmit = true;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// Handle input change event
|
|
633
|
-
private changeHandler(e: Event): void {
|
|
634
|
-
this.trigger('change', e);
|
|
635
|
-
const element: HTMLInputElement = <HTMLInputElement>e.target;
|
|
636
|
-
this.validate(element.name);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
// Handle form submit event
|
|
640
|
-
private submitHandler(e: Event): void {
|
|
641
|
-
this.trigger('submit', e);
|
|
642
|
-
//FormValidator.triggerCallback(this.submit, e);
|
|
643
|
-
// Prevent form submit if validation failed
|
|
644
|
-
if (!this.allowSubmit && !this.validate()) {
|
|
645
|
-
e.preventDefault();
|
|
646
|
-
} else {
|
|
647
|
-
this.allowSubmit = false;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Handle form reset
|
|
652
|
-
private resetHandler(): void {
|
|
653
|
-
this.clearForm();
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// Validate each rule based on input element name
|
|
657
|
-
private validateRules(name: string): void {
|
|
658
|
-
if (!this.rules[`${name}`]) {
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
const rules: string[] = Object.keys(this.rules[`${name}`]);
|
|
662
|
-
let hiddenType: boolean = false;
|
|
663
|
-
let validateHiddenType: boolean = false;
|
|
664
|
-
const vhPos: number = rules.indexOf('validateHidden');
|
|
665
|
-
const hPos: number = rules.indexOf('hidden');
|
|
666
|
-
this.getInputElement(name);
|
|
667
|
-
if (hPos !== -1) {
|
|
668
|
-
hiddenType = true;
|
|
669
|
-
}
|
|
670
|
-
if (vhPos !== -1) {
|
|
671
|
-
validateHiddenType = true;
|
|
672
|
-
}
|
|
673
|
-
if (!hiddenType || (hiddenType && validateHiddenType)) {
|
|
674
|
-
if (vhPos !== -1) {
|
|
675
|
-
rules.splice(vhPos, 1);
|
|
676
|
-
}
|
|
677
|
-
if (hPos !== -1) {
|
|
678
|
-
rules.splice((hPos - 1), 1);
|
|
679
|
-
}
|
|
680
|
-
this.getErrorElement(name);
|
|
681
|
-
for (const rule of rules) {
|
|
682
|
-
const errorMessage: string = this.getErrorMessage(this.rules[`${name}`][`${rule}`], rule);
|
|
683
|
-
const errorRule: ErrorRule = { name: name, message: errorMessage };
|
|
684
|
-
const eventArgs: FormEventArgs = {
|
|
685
|
-
inputName: name,
|
|
686
|
-
element: this.inputElement,
|
|
687
|
-
message: errorMessage
|
|
688
|
-
};
|
|
689
|
-
if (!this.isValid(name, rule) && !this.inputElement.classList.contains(this.ignore)) {
|
|
690
|
-
this.removeErrorRules(name);
|
|
691
|
-
this.errorRules.push(errorRule);
|
|
692
|
-
// Set aria attributes to invalid elements
|
|
693
|
-
this.inputElement.setAttribute('aria-invalid', 'true');
|
|
694
|
-
this.inputElement.setAttribute('aria-describedby', this.inputElement.id + '-info');
|
|
695
|
-
const inputParent: HTMLElement = this.inputElement.parentElement;
|
|
696
|
-
const grandParent: HTMLElement = inputParent.parentElement;
|
|
697
|
-
if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
|
|
698
|
-
(this.inputElement.classList.contains('e-input') && inputParent.classList.contains('e-input-group'))) {
|
|
699
|
-
inputParent.classList.add(this.errorClass);
|
|
700
|
-
inputParent.classList.remove(this.validClass);
|
|
701
|
-
}
|
|
702
|
-
else if ((grandParent != null) && (grandParent.classList.contains('e-control-wrapper') ||
|
|
703
|
-
grandParent.classList.contains('e-wrapper'))) {
|
|
704
|
-
grandParent.classList.add(this.errorClass);
|
|
705
|
-
grandParent.classList.remove(this.validClass);
|
|
706
|
-
}
|
|
707
|
-
else {
|
|
708
|
-
this.inputElement.classList.add(this.errorClass);
|
|
709
|
-
this.inputElement.classList.remove(this.validClass);
|
|
710
|
-
}
|
|
711
|
-
if (!this.infoElement) {
|
|
712
|
-
this.createErrorElement(name, errorRule.message, this.inputElement);
|
|
713
|
-
} else {
|
|
714
|
-
this.showMessage(errorRule);
|
|
715
|
-
}
|
|
716
|
-
eventArgs.errorElement = this.infoElement;
|
|
717
|
-
eventArgs.status = 'failure';
|
|
718
|
-
if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
|
|
719
|
-
(this.inputElement.classList.contains('e-input') && inputParent.classList.contains('e-input-group'))) {
|
|
720
|
-
inputParent.classList.add(this.errorClass);
|
|
721
|
-
inputParent.classList.remove(this.validClass);
|
|
722
|
-
}
|
|
723
|
-
else if ((grandParent != null) && (grandParent.classList.contains('e-control-wrapper') ||
|
|
724
|
-
grandParent.classList.contains('e-wrapper'))) {
|
|
725
|
-
grandParent.classList.add(this.errorClass);
|
|
726
|
-
grandParent.classList.remove(this.validClass);
|
|
727
|
-
}
|
|
728
|
-
else {
|
|
729
|
-
this.inputElement.classList.add(this.errorClass);
|
|
730
|
-
this.inputElement.classList.remove(this.validClass);
|
|
731
|
-
}
|
|
732
|
-
this.optionalValidationStatus(name, eventArgs);
|
|
733
|
-
this.trigger('validationComplete', eventArgs);
|
|
734
|
-
// Set aria-required to required rule elements
|
|
735
|
-
if (rule === 'required') {
|
|
736
|
-
this.inputElement.setAttribute('aria-required', 'true');
|
|
737
|
-
}
|
|
738
|
-
break;
|
|
739
|
-
} else {
|
|
740
|
-
this.hideMessage(name);
|
|
741
|
-
eventArgs.status = 'success';
|
|
742
|
-
this.trigger('validationComplete', eventArgs);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
} else {
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
// Update the optional validation status
|
|
751
|
-
private optionalValidationStatus(name: string, refer: FormEventArgs): void {
|
|
752
|
-
if (!this.rules[`${name}`][this.required] && !this.inputElement.value.length && !isNullOrUndefined(this.infoElement)) {
|
|
753
|
-
this.infoElement.innerHTML = this.inputElement.value;
|
|
754
|
-
this.infoElement.setAttribute('aria-invalid', 'false');
|
|
755
|
-
refer.status = '';
|
|
756
|
-
this.hideMessage(name);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// Check the input element whether it's value satisfy the validation rule or not
|
|
761
|
-
private isValid(name: string, rule: string): boolean {
|
|
762
|
-
const params: Object = this.rules[`${name}`][`${rule}`];
|
|
763
|
-
const param: Object = (params instanceof Array && typeof params[1] === 'string') ? params[0] : params;
|
|
764
|
-
const currentRule: { [key: string]: Object } = <IKeyValue>this.rules[`${name}`][`${rule}`];
|
|
765
|
-
const dateFormat: string = ((rule === 'min' || rule === 'max') && this.rules['' + name].date &&
|
|
766
|
-
typeof (this.rules['' + name].date) === 'string') ? this.rules['' + name].date as string : null;
|
|
767
|
-
const args: ValidArgs = { value: this.inputElement.value,
|
|
768
|
-
param: param, element: this.inputElement, formElement: this.element, format: dateFormat, culture: this.locale };
|
|
769
|
-
this.trigger('validationBegin', args);
|
|
770
|
-
if (!args.param && rule === 'required') {
|
|
771
|
-
return true;
|
|
772
|
-
}
|
|
773
|
-
if (currentRule && typeof currentRule[0] === 'function') {
|
|
774
|
-
const fn: () => boolean = <() => boolean>currentRule[0];
|
|
775
|
-
return fn.call(this, { element: this.inputElement, value: this.inputElement.value });
|
|
776
|
-
} else if (FormValidator.isCheckable(this.inputElement)) {
|
|
777
|
-
if (rule !== 'required') {
|
|
778
|
-
return true;
|
|
779
|
-
}
|
|
780
|
-
return selectAll('input[name="' + name + '"]:checked', this.element).length > 0;
|
|
781
|
-
} else {
|
|
782
|
-
return FormValidator.checkValidator[`${rule}`](args);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// Return default error message or custom error message
|
|
787
|
-
private getErrorMessage(ruleValue: Object, rule: string): string {
|
|
788
|
-
let message: string = this.inputElement.getAttribute('data-' + rule + '-message') ?
|
|
789
|
-
this.inputElement.getAttribute('data-' + rule + '-message') :
|
|
790
|
-
(ruleValue instanceof Array && typeof ruleValue[1] === 'string') ? ruleValue[1] :
|
|
791
|
-
(Object.keys(this.localyMessage).length !== 0) ? this.localyMessage[`${rule}`] : this.defaultMessages[`${rule}`];
|
|
792
|
-
const formats: string[] = message.match(/{(\d)}/g);
|
|
793
|
-
if (!isNullOrUndefined(formats)) {
|
|
794
|
-
for (let i: number = 0; i < formats.length; i++) {
|
|
795
|
-
const value: string = ruleValue instanceof Array ? ruleValue[parseInt(i.toString(), 10)] : ruleValue;
|
|
796
|
-
message = message.replace(formats[parseInt(i.toString(), 10)], value);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
return message;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
// Create error element based on name and error message
|
|
803
|
-
private createErrorElement(name: string, message: string, input: HTMLInputElement): void {
|
|
804
|
-
let errorElement: HTMLElement = createElement(this.errorElement, {
|
|
805
|
-
className: this.errorClass,
|
|
806
|
-
innerHTML: message,
|
|
807
|
-
attrs: { for: name }
|
|
808
|
-
});
|
|
809
|
-
// Create message design if errorOption is message
|
|
810
|
-
if (this.errorOption === ErrorOption.Message) {
|
|
811
|
-
errorElement.classList.remove(this.errorClass);
|
|
812
|
-
errorElement.classList.add('e-message');
|
|
813
|
-
errorElement = createElement(this.errorContainer, { className: this.errorClass, innerHTML: errorElement.outerHTML });
|
|
814
|
-
}
|
|
815
|
-
errorElement.id = this.inputElement.name + '-info';
|
|
816
|
-
|
|
817
|
-
// Append error message into MVC error message element
|
|
818
|
-
if (this.element.querySelector('[data-valmsg-for="' + input.id + '"]')) {
|
|
819
|
-
this.element.querySelector('[data-valmsg-for="' + input.id + '"]').appendChild(errorElement);
|
|
820
|
-
} else if (input.hasAttribute('data-msg-containerid') === true) {
|
|
821
|
-
// Append error message into custom div element
|
|
822
|
-
const containerId: string = input.getAttribute('data-msg-containerid');
|
|
823
|
-
const divElement: Element = select('#' + containerId, this.element);
|
|
824
|
-
divElement.appendChild(errorElement);
|
|
825
|
-
} else if (this.customPlacement != null) {
|
|
826
|
-
// Call custom placement function if customPlacement is not null
|
|
827
|
-
this.customPlacement.call(this, this.inputElement, errorElement);
|
|
828
|
-
} else {
|
|
829
|
-
const inputParent: HTMLElement = this.inputElement.parentElement;
|
|
830
|
-
const grandParent: HTMLElement = inputParent.parentElement;
|
|
831
|
-
if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper')) {
|
|
832
|
-
grandParent.insertBefore(errorElement, inputParent.nextSibling);
|
|
833
|
-
}
|
|
834
|
-
else if (grandParent.classList.contains('e-control-wrapper') || grandParent.classList.contains('e-wrapper')) {
|
|
835
|
-
grandParent.parentElement.insertBefore(errorElement, grandParent.nextSibling);
|
|
836
|
-
}
|
|
837
|
-
else {
|
|
838
|
-
inputParent.insertBefore(errorElement, this.inputElement.nextSibling);
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
errorElement.style.display = 'block';
|
|
842
|
-
this.getErrorElement(name);
|
|
843
|
-
this.validated.push(name);
|
|
844
|
-
this.checkRequired(name);
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// Get error element by name
|
|
848
|
-
private getErrorElement(name: string): HTMLElement {
|
|
849
|
-
this.infoElement = <HTMLElement>select(this.errorElement + '.' + this.errorClass, this.inputElement.parentElement);
|
|
850
|
-
if (!this.infoElement) {
|
|
851
|
-
this.infoElement = (<HTMLElement>select(this.errorElement + '.' + this.errorClass + '[for="' + name + '"]', this.element));
|
|
852
|
-
}
|
|
853
|
-
return this.infoElement;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// Remove existing rule from errorRules object
|
|
857
|
-
private removeErrorRules(name: string): void {
|
|
858
|
-
for (let i: number = 0; i < this.errorRules.length; i++) {
|
|
859
|
-
const rule: ErrorRule = this.errorRules[parseInt(i.toString(), 10)];
|
|
860
|
-
if (rule.name === name) {
|
|
861
|
-
this.errorRules.splice(i, 1);
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
// Show error message to the input element
|
|
867
|
-
private showMessage(errorRule: ErrorRule): void {
|
|
868
|
-
this.infoElement.style.display = 'block';
|
|
869
|
-
this.infoElement.innerHTML = errorRule.message;
|
|
870
|
-
this.checkRequired(errorRule.name);
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
// Hide error message based on input name
|
|
874
|
-
private hideMessage(name: string): void {
|
|
875
|
-
if (this.infoElement) {
|
|
876
|
-
this.infoElement.style.display = 'none';
|
|
877
|
-
this.removeErrorRules(name);
|
|
878
|
-
const inputParent: HTMLElement = this.inputElement.parentElement;
|
|
879
|
-
const grandParent: HTMLElement = inputParent.parentElement;
|
|
880
|
-
if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
|
|
881
|
-
(this.inputElement.classList.contains('e-input') && inputParent.classList.contains('e-input-group'))) {
|
|
882
|
-
inputParent.classList.add(this.validClass);
|
|
883
|
-
inputParent.classList.remove(this.errorClass);
|
|
884
|
-
}
|
|
885
|
-
else if ((grandParent != null) && (grandParent.classList.contains('e-control-wrapper') || grandParent.classList.contains('e-wrapper'))) {
|
|
886
|
-
grandParent.classList.add(this.validClass);
|
|
887
|
-
grandParent.classList.remove(this.errorClass);
|
|
888
|
-
}
|
|
889
|
-
else {
|
|
890
|
-
this.inputElement.classList.add(this.validClass);
|
|
891
|
-
this.inputElement.classList.remove(this.errorClass);
|
|
892
|
-
}
|
|
893
|
-
this.inputElement.setAttribute('aria-invalid', 'false');
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// Check whether the input element have required rule and its value is not empty
|
|
898
|
-
private checkRequired(name: string): void {
|
|
899
|
-
if (!this.rules[`${name}`][this.required] && !this.inputElement.value.length && !isNullOrUndefined(this.infoElement)) {
|
|
900
|
-
this.infoElement.innerHTML = this.inputElement.value;
|
|
901
|
-
this.infoElement.setAttribute('aria-invalid', 'false');
|
|
902
|
-
this.hideMessage(name);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
// List of function to validate the rules
|
|
907
|
-
private static checkValidator: Validator = {
|
|
908
|
-
required: (option: ValidArgs): boolean => {
|
|
909
|
-
return !isNaN(Date.parse(option.value)) ? !isNaN(new Date(option.value).getTime()) : option.value.toString().length > 0;
|
|
910
|
-
},
|
|
911
|
-
email: (option: ValidArgs): boolean => {
|
|
912
|
-
return regex.EMAIL.test(option.value);
|
|
913
|
-
},
|
|
914
|
-
url: (option: ValidArgs): boolean => {
|
|
915
|
-
return regex.URL.test(option.value);
|
|
916
|
-
},
|
|
917
|
-
dateIso: (option: ValidArgs): boolean => {
|
|
918
|
-
return regex.DATE_ISO.test(option.value);
|
|
919
|
-
},
|
|
920
|
-
tel: (option: ValidArgs): boolean => {
|
|
921
|
-
return regex.PHONE.test(option.value);
|
|
922
|
-
},
|
|
923
|
-
creditcard: (option: ValidArgs): boolean => {
|
|
924
|
-
return regex.CREDITCARD.test(option.value);
|
|
925
|
-
},
|
|
926
|
-
number: (option: ValidArgs): boolean => {
|
|
927
|
-
return !isNaN(Number(option.value)) && String(option.value).indexOf(' ') === -1;
|
|
928
|
-
},
|
|
929
|
-
digits: (option: ValidArgs): boolean => {
|
|
930
|
-
return regex.DIGITS.test(option.value);
|
|
931
|
-
},
|
|
932
|
-
maxLength: (option: ValidArgs): boolean => {
|
|
933
|
-
return option.value.length <= Number(option.param);
|
|
934
|
-
},
|
|
935
|
-
minLength: (option: ValidArgs): boolean => {
|
|
936
|
-
return option.value.length >= Number(option.param);
|
|
937
|
-
},
|
|
938
|
-
rangeLength: (option: ValidArgs): boolean => {
|
|
939
|
-
const param: number[] = <number[]>option.param;
|
|
940
|
-
return option.value.length >= param[0] && option.value.length <= param[1];
|
|
941
|
-
},
|
|
942
|
-
range: (option: ValidArgs): boolean => {
|
|
943
|
-
const param: number[] = <number[]>option.param;
|
|
944
|
-
return !isNaN(Number(option.value)) && Number(option.value) >= param[0] && Number(option.value) <= param[1];
|
|
945
|
-
},
|
|
946
|
-
date: (option: ValidArgs): boolean => {
|
|
947
|
-
if (!isNullOrUndefined(option.param) && (typeof (option.param) === 'string' && option.param !== '')) {
|
|
948
|
-
const globalize: Internationalization = option.culture && option.culture !== '' ? new Internationalization(option.culture) : new Internationalization;
|
|
949
|
-
const dateOptions: { format: string, type: string, skeleton: string } = { format: option.param.toString(), type: 'dateTime', skeleton: 'yMd' };
|
|
950
|
-
const dateValue: Date = globalize.parseDate(option.value, dateOptions);
|
|
951
|
-
return (!isNullOrUndefined(dateValue) && dateValue instanceof Date && !isNaN(+dateValue));
|
|
952
|
-
}
|
|
953
|
-
else {
|
|
954
|
-
return !isNaN(new Date(option.value).getTime());
|
|
955
|
-
}
|
|
956
|
-
},
|
|
957
|
-
max: (option: ValidArgs): boolean => {
|
|
958
|
-
if (!isNaN(Number(option.value))) {
|
|
959
|
-
// Maximum rule validation for number
|
|
960
|
-
return +option.value <= +option.param;
|
|
961
|
-
}
|
|
962
|
-
// Maximum rule validation for date
|
|
963
|
-
if (option.format && option.format !== '') {
|
|
964
|
-
const globalize: Internationalization = option.culture && option.culture !== '' ? new Internationalization(option.culture) : new Internationalization;
|
|
965
|
-
const dateOptions: { format: string, type: string, skeleton: string } = { format: option.format.toString(), type: 'dateTime', skeleton: 'yMd' };
|
|
966
|
-
const dateValue: Date = globalize.parseDate(option.value, dateOptions);
|
|
967
|
-
const maxValue: Date = (typeof(option.param) === 'string') ? globalize.parseDate(JSON.parse(JSON.stringify(option.param)), dateOptions) : (option.param as Date);
|
|
968
|
-
return new Date(dateValue).getTime() <= new Date(maxValue).getTime();
|
|
969
|
-
} else {
|
|
970
|
-
return new Date(option.value).getTime() <= new Date(JSON.parse(JSON.stringify(option.param))).getTime();
|
|
971
|
-
}
|
|
972
|
-
},
|
|
973
|
-
min: (option: ValidArgs): boolean => {
|
|
974
|
-
if (!isNaN(Number(option.value))) {
|
|
975
|
-
// Minimum rule validation for number
|
|
976
|
-
return +option.value >= +option.param;
|
|
977
|
-
} else if ((option.value).indexOf(',') !== -1) {
|
|
978
|
-
const uNum: string = (option.value).replace(/,/g, '');
|
|
979
|
-
return parseFloat(uNum) >= Number(option.param); // Convert option.param to a number
|
|
980
|
-
} else {
|
|
981
|
-
// Minimum rule validation for date
|
|
982
|
-
if (option.format && option.format !== '') {
|
|
983
|
-
const globalize: Internationalization = option.culture && option.culture !== '' ? new Internationalization(option.culture) : new Internationalization;
|
|
984
|
-
const dateOptions: { format: string, type: string, skeleton: string } = { format: option.format.toString(), type: 'dateTime', skeleton: 'yMd' };
|
|
985
|
-
const dateValue: Date = globalize.parseDate(option.value, dateOptions);
|
|
986
|
-
const minValue: Date = (typeof(option.param) === 'string') ? globalize.parseDate(JSON.parse(JSON.stringify(option.param)), dateOptions) : (option.param as Date);
|
|
987
|
-
return new Date(dateValue).getTime() >= new Date(minValue).getTime();
|
|
988
|
-
} else {
|
|
989
|
-
return new Date(option.value).getTime() >= new Date(JSON.parse(JSON.stringify(option.param))).getTime();
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
},
|
|
993
|
-
regex: (option: ValidArgs): boolean => {
|
|
994
|
-
/* eslint-disable-next-line security/detect-non-literal-regexp */
|
|
995
|
-
return new RegExp(<string>option.param).test(option.value);
|
|
996
|
-
},
|
|
997
|
-
equalTo: (option: ValidArgs): boolean => {
|
|
998
|
-
const compareTo: HTMLInputElement = <HTMLInputElement>option.formElement.querySelector('#' + option.param);
|
|
999
|
-
option.param = compareTo.value;
|
|
1000
|
-
return option.param === option.value;
|
|
1001
|
-
}
|
|
1002
|
-
};
|
|
1003
|
-
|
|
1004
|
-
// Return boolean result if the input have checkable or submit types
|
|
1005
|
-
private static isCheckable(input: Element): boolean {
|
|
1006
|
-
const inputType: string = input.getAttribute('type');
|
|
1007
|
-
return inputType && (inputType === 'checkbox' || inputType === 'radio' || inputType === 'submit');
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
interface Validator {
|
|
1012
|
-
[rule: string]: (value: ValidArgs) => boolean
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
export interface ValidArgs {
|
|
1016
|
-
/**
|
|
1017
|
-
* Returns the value in input element.
|
|
1018
|
-
*/
|
|
1019
|
-
value: string
|
|
1020
|
-
/**
|
|
1021
|
-
* Returns the rule mapped for the input.
|
|
1022
|
-
*/
|
|
1023
|
-
param?: Object
|
|
1024
|
-
/**
|
|
1025
|
-
* Returns the input element.
|
|
1026
|
-
*/
|
|
1027
|
-
element?: HTMLElement
|
|
1028
|
-
/**
|
|
1029
|
-
* Returns the current form element.
|
|
1030
|
-
*/
|
|
1031
|
-
formElement?: HTMLFormElement,
|
|
1032
|
-
/**
|
|
1033
|
-
* Returns the date format mapped for the input.
|
|
1034
|
-
*/
|
|
1035
|
-
format? : string,
|
|
1036
|
-
/**
|
|
1037
|
-
* Returns the culture for the input.
|
|
1038
|
-
*/
|
|
1039
|
-
culture? : string,
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
interface ErrorRule {
|
|
1043
|
-
name: string
|
|
1044
|
-
message: string
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
export interface FormEventArgs {
|
|
1048
|
-
/**
|
|
1049
|
-
* Returns the name of the input element.
|
|
1050
|
-
*/
|
|
1051
|
-
inputName: string
|
|
1052
|
-
/**
|
|
1053
|
-
* Returns the error message.
|
|
1054
|
-
*/
|
|
1055
|
-
message: string
|
|
1056
|
-
/**
|
|
1057
|
-
* Returns the input element.
|
|
1058
|
-
*/
|
|
1059
|
-
element: HTMLInputElement
|
|
1060
|
-
/**
|
|
1061
|
-
* Returns the status input element.
|
|
1062
|
-
*/
|
|
1063
|
-
status?: string
|
|
1064
|
-
/**
|
|
1065
|
-
* Returns the error element for corresponding input.
|
|
1066
|
-
*/
|
|
1067
|
-
errorElement?: HTMLElement
|
|
1068
|
-
}
|