PluginProbe
seQura / 3.0.0
seQura v3.0.0
4.3.4 4.3.3 4.3.2 4.3.1 trunk 2.0.0 2.0.10 2.0.11 2.0.12 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0.0 3.0.2 3.0.5 3.0.6 3.0.7 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 4.0.0 All 30 releases
sequra / assets / js / src / core / ValidationService.js

ValidationService.js in seQura 3.0.0, at assets/js/src/core/ValidationService.js

315 lines 9.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 if (!window.SequraFE) {
2 window.SequraFE = {};
3 }
4
5 (function () {
6 /**
7 * @typedef ValidationMessage
8 * @property {string} code The message code.
9 * @property {string} field The field name that the error is related to.
10 * @property {string} message The error message.
11 */
12
13 const validationRule = {
14 numeric: 'numeric',
15 integer: 'integer',
16 required: 'required',
17 greaterThanZero: 'greaterThanZero',
18 minValue: 'minValue',
19 maxValue: 'maxValue',
20 nonNegative: 'nonNegative',
21 greaterThanX: 'greaterThanX'
22 };
23
24 const { templateService, utilities, translationService } = SequraFE;
25
26 /**
27 * Validates if the input has a value. If the value is not set, adds an error class to the input element.
28 *
29 * @param {HTMLInputElement|HTMLSelectElement} input
30 * @param {string?} message
31 * @return {boolean}
32 */
33 const validateRequiredField = (input, message) => {
34 return validateField(input, !input.value?.trim() || (input.type === 'checkbox' && !input.checked), message);
35 };
36
37 /**
38 * Validates a numeric input.
39 *
40 * @param {HTMLInputElement} input
41 * @param {string?} message
42 * @return {boolean} Indication of the validity.
43 */
44 const validateNumber = (input, message) => {
45 const ruleset = input.dataset?.validationRule ? input.dataset.validationRule.split(',') : [];
46 let result = true;
47
48 if (!validateField(input, Number.isNaN(input.value), message)) {
49 return false;
50 }
51
52 const value = Number(input.value);
53 ruleset.forEach((rule) => {
54 if (!result) {
55 // break on first false rule
56 return;
57 }
58
59 let condition = false;
60 let subValue = null;
61 if (rule.includes('|')) {
62 [rule, subValue] = rule.split('|');
63 }
64
65 // condition should be positive for valid values
66 switch (rule) {
67 case validationRule.integer:
68 condition = Number.isInteger(value);
69 break;
70 case validationRule.greaterThanZero:
71 condition = value > 0;
72 break;
73 case validationRule.minValue:
74 condition = value >= Number(subValue);
75 break;
76 case validationRule.maxValue:
77 condition = value <= Number(subValue);
78 break;
79 case validationRule.nonNegative:
80 condition = value >= 0;
81 break;
82 case validationRule.required:
83 condition = !!input.value?.trim();
84 break;
85 case validationRule.greaterThanX:
86 condition = value >= Number(document.querySelector(`input[name="${subValue}"]`)?.value);
87 break;
88 default:
89 return;
90 }
91
92 if (!validateField(input, !condition, message)) {
93 result = false;
94 }
95 });
96
97 return result;
98 };
99
100 /**
101 * Validates if the input is a valid email. If not, adds the error class to the input element.
102 *
103 * @param {HTMLInputElement} input
104 * @param {string?} message
105 * @return {boolean}
106 */
107 const validateEmail = (input, message) => {
108 let regex =
109 /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
110
111 return validateField(input, !regex.test(String(input.value).toLowerCase()), message);
112 };
113
114 /**
115 * Validates if the input is a valid email. If not, adds the error class to the input element.
116 *
117 * @param {HTMLInputElement} input
118 * @param {boolean} required
119 * @param {string?} message
120 * @return {boolean}
121 */
122 const validateCssSelector = (input, required, message) => {
123 let isValid = false;
124 try {
125 document.querySelector(input.value);
126 isValid = true;
127 } catch {
128 isValid = !required && !input.value;
129 }
130
131 return validateField(input, !isValid, message);
132 };
133
134 /**
135 * Validates if the value is a valid date or duration following ISO 8601 format.
136 *
137 * @param {string} str
138 * @return {boolean}
139 */
140 const validateDateOrDuration = (str) => {
141 const regex = new RegExp(SequraFE.regex.dateOrDuration);
142 return regex.test(str) && 'P' !== str && !str.endsWith('T');
143 };
144
145 /**
146 * Validates if the value is a valid IP address
147 *
148 * @param {string} ip
149 * @return {boolean}
150 */
151 const validateIP = (ip) => {
152 const regex = new RegExp(SequraFE.regex.ip);
153 return regex.test(ip);
154 };
155
156 /**
157 * Validates if the value is a valid IP address
158 *
159 * @param {string[]} ipList
160 * @return {boolean}
161 */
162 const validateIPList = (ipList) => {
163
164 let isValid = true;
165 for (const ip of ipList) {
166 if (!validateIP(ip)) {
167 isValid = false;
168 break;
169 }
170 }
171 return isValid;
172 };
173
174 /**
175 * Validates if the input is a valid URL. If not, adds an error class to the input element.
176 *
177 * @param {HTMLInputElement} input
178 * @param {string?} message
179 * @return {boolean}
180 */
181 const validateUrl = (input, message) => {
182 let regex = /(https?:\/\/)([\w\-])+\.([a-zA-Z]{2,63})([\/\w-]*)*\/?\??([^#\n\r]*)?#?([^\n\r]*)/m;
183
184 return validateField(input, !regex.test(String(input.value).toLowerCase()), message);
185 };
186
187 /**
188 * Validates if the input field is longer than a specified number of characters.
189 * If so, adds an error class to the input element.
190 *
191 * @param {HTMLInputElement} input
192 * @param {string?} message
193 * @return {boolean}
194 */
195 const validateMaxLength = (input, message) => {
196 return validateField(input, input.dataset.maxLength && input.value.length > input.dataset.maxLength, message);
197 };
198
199 /**
200 * Handles validation errors. These errors come from the back end.
201 *
202 * @param {ValidationMessage[]} errors
203 */
204 const handleValidationErrors = (errors) => {
205 for (const error of errors) {
206 markFieldGroupInvalid(`[name=${error.field}]`, error.message);
207 }
208 };
209
210 /**
211 * Marks a field as invalid.
212 *
213 * @param {string} fieldSelector The field selector.
214 * @param {string} message The message to display.
215 * @param {Element} [parent] A parent element.
216 */
217 const markFieldGroupInvalid = (fieldSelector, message, parent) => {
218 if (!parent) {
219 parent = templateService.getMainPage();
220 }
221
222 const inputEl = parent.querySelector(fieldSelector);
223 inputEl && setError(inputEl, message);
224 };
225
226 /**
227 * Sets error for an input.
228 *
229 * @param {HTMLElement} element
230 * @param {string?} message
231 */
232 const setError = (element, message) => {
233 const parent = utilities.getAncestor(element, 'sq-field-wrapper');
234 parent && parent.classList.add('sqs--error');
235 if (message) {
236 let errorField = parent.querySelector('.sqp-input-error');
237 if (!errorField) {
238 errorField = SequraFE.elementGenerator.createElement('span', 'sqp-input-error', message);
239 parent.append(errorField);
240 }
241
242 errorField.innerHTML = translationService.translate(message);
243 }
244 };
245
246 /**
247 * Removes error from input form group element.
248 *
249 * @param {HTMLElement} element
250 */
251 const removeError = (element) => {
252 const parent = utilities.getAncestor(element, 'sq-field-wrapper');
253 parent && parent.classList.remove('sqs--error');
254 };
255
256
257 /**
258 * Validates the provided JSON string and marks field invalid if the JSON is invalid.
259 *
260 * @param {HTMLElement} element
261 * @param {string?} value JSON value.
262 * @param {string?} message
263 * @return {boolean}
264 */
265 const validateJson = (element, value, message) => {
266 try {
267 JSON.parse(value);
268 removeError(element);
269
270 return true;
271 } catch (e) {
272 setError(element, message);
273
274 return false;
275 }
276 };
277
278 /**
279 * Validates the condition against the input field and marks field invalid if the error condition is met.
280 *
281 * @param {HTMLElement} element
282 * @param {boolean} errorCondition Error condition.
283 * @param {string?} message
284 * @return {boolean}
285 */
286 const validateField = (element, errorCondition, message) => {
287 if (errorCondition) {
288 setError(element, message);
289
290 return false;
291 }
292
293 removeError(element);
294
295 return true;
296 };
297
298 SequraFE.validationService = {
299 setError,
300 removeError,
301 validateEmail,
302 validateDateOrDuration,
303 validateIP,
304 validateIPList,
305 validateNumber,
306 validateUrl,
307 validateMaxLength,
308 validateJson,
309 validateCssSelector,
310 validateField,
311 validateRequiredField,
312 handleValidationErrors
313 };
314 })();
315