# sequra/3.1.0/assets/js/src/core/ValidationService.js

seQura, version 3.1.0. 315 lines.

- Page: https://pluginprobe.com/plugins/sequra/3.1.0/code/assets/js/src/core/ValidationService.js
- Raw: https://pluginprobe.com/plugins/sequra/3.1.0/raw/assets/js/src/core/ValidationService.js
- Modified: 2024-10-29T15:19:22+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/sequra/3.1.0/code/assets/js/src/core/ValidationService.js#L10-L20`.

```javascript
if (!window.SequraFE) {
    window.SequraFE = {};
}

(function () {
    /**
     * @typedef ValidationMessage
     * @property {string} code The message code.
     * @property {string} field The field name that the error is related to.
     * @property {string} message The error message.
     */

    const validationRule = {
        numeric: 'numeric',
        integer: 'integer',
        required: 'required',
        greaterThanZero: 'greaterThanZero',
        minValue: 'minValue',
        maxValue: 'maxValue',
        nonNegative: 'nonNegative',
        greaterThanX: 'greaterThanX'
    };

    const { templateService, utilities, translationService } = SequraFE;

    /**
     * Validates if the input has a value. If the value is not set, adds an error class to the input element.
     *
     * @param {HTMLInputElement|HTMLSelectElement} input
     * @param {string?} message
     * @return {boolean}
     */
    const validateRequiredField = (input, message) => {
        return validateField(input, !input.value?.trim() || (input.type === 'checkbox' && !input.checked), message);
    };

    /**
     * Validates a numeric input.
     *
     * @param {HTMLInputElement} input
     * @param {string?} message
     * @return {boolean} Indication of the validity.
     */
    const validateNumber = (input, message) => {
        const ruleset = input.dataset?.validationRule ? input.dataset.validationRule.split(',') : [];
        let result = true;

        if (!validateField(input, Number.isNaN(input.value), message)) {
            return false;
        }

        const value = Number(input.value);
        ruleset.forEach((rule) => {
            if (!result) {
                // break on first false rule
                return;
            }

            let condition = false;
            let subValue = null;
            if (rule.includes('|')) {
                [rule, subValue] = rule.split('|');
            }

            // condition should be positive for valid values
            switch (rule) {
                case validationRule.integer:
                    condition = Number.isInteger(value);
                    break;
                case validationRule.greaterThanZero:
                    condition = value > 0;
                    break;
                case validationRule.minValue:
                    condition = value >= Number(subValue);
                    break;
                case validationRule.maxValue:
                    condition = value <= Number(subValue);
                    break;
                case validationRule.nonNegative:
                    condition = value >= 0;
                    break;
                case validationRule.required:
                    condition = !!input.value?.trim();
                    break;
                case validationRule.greaterThanX:
                    condition = value >= Number(document.querySelector(`input[name="${subValue}"]`)?.value);
                    break;
                default:
                    return;
            }

            if (!validateField(input, !condition, message)) {
                result = false;
            }
        });

        return result;
    };

    /**
     * Validates if the input is a valid email. If not, adds the error class to the input element.
     *
     * @param {HTMLInputElement} input
     * @param {string?} message
     * @return {boolean}
     */
    const validateEmail = (input, message) => {
        let regex =
            /^(([^<>()\[\]\\.,;:\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,}))$/;

        return validateField(input, !regex.test(String(input.value).toLowerCase()), message);
    };

    /**
     * Validates if the input is a valid email. If not, adds the error class to the input element.
     *
     * @param {HTMLInputElement} input
     * @param {boolean} required
     * @param {string?} message
     * @return {boolean}
     */
    const validateCssSelector = (input, required, message) => {
        let isValid = false;
        try {
            document.querySelector(input.value);
            isValid = true;
        } catch {
            isValid = !required && !input.value;
        }

        return validateField(input, !isValid, message);
    };

    /**
     * Validates if the value is a valid date or duration following ISO 8601 format.
     *
     * @param {string} str
     * @return {boolean}
     */
    const validateDateOrDuration = (str) => {
        const regex = new RegExp(SequraFE.regex.dateOrDuration);
        return regex.test(str) && 'P' !== str && !str.endsWith('T');
    };

    /**
     * Validates if the value is a valid IP address
     *
     * @param {string} ip
     * @return {boolean}
     */
    const validateIP = (ip) => {
        const regex = new RegExp(SequraFE.regex.ip);
        return regex.test(ip);
    };

    /**
     * Validates if the value is a valid IP address
     *
     * @param {string[]} ipList
     * @return {boolean}
     */
    const validateIPList = (ipList) => {

        let isValid = true;
        for (const ip of ipList) {
            if (!validateIP(ip)) {
                isValid = false;
                break;
            }
        }
        return isValid;
    };

    /**
     * Validates if the input is a valid URL. If not, adds an error class to the input element.
     *
     * @param {HTMLInputElement} input
     * @param {string?} message
     * @return {boolean}
     */
    const validateUrl = (input, message) => {
        let regex = /(https?:\/\/)([\w\-])+\.([a-zA-Z]{2,63})([\/\w-]*)*\/?\??([^#\n\r]*)?#?([^\n\r]*)/m;

        return validateField(input, !regex.test(String(input.value).toLowerCase()), message);
    };

    /**
     * Validates if the input field is longer than a specified number of characters.
     * If so, adds an error class to the input element.
     *
     * @param {HTMLInputElement} input
     * @param {string?} message
     * @return {boolean}
     */
    const validateMaxLength = (input, message) => {
        return validateField(input, input.dataset.maxLength && input.value.length > input.dataset.maxLength, message);
    };

    /**
     * Handles validation errors. These errors come from the back end.
     *
     * @param {ValidationMessage[]} errors
     */
    const handleValidationErrors = (errors) => {
        for (const error of errors) {
            markFieldGroupInvalid(`[name=${error.field}]`, error.message);
        }
    };

    /**
     * Marks a field as invalid.
     *
     * @param {string} fieldSelector The field selector.
     * @param {string} message The message to display.
     * @param {Element} [parent] A parent element.
     */
    const markFieldGroupInvalid = (fieldSelector, message, parent) => {
        if (!parent) {
            parent = templateService.getMainPage();
        }

        const inputEl = parent.querySelector(fieldSelector);
        inputEl && setError(inputEl, message);
    };

    /**
     * Sets error for an input.
     *
     * @param {HTMLElement} element
     * @param {string?} message
     */
    const setError = (element, message) => {
        const parent = utilities.getAncestor(element, 'sq-field-wrapper');
        parent && parent.classList.add('sqs--error');
        if (message) {
            let errorField = parent.querySelector('.sqp-input-error');
            if (!errorField) {
                errorField = SequraFE.elementGenerator.createElement('span', 'sqp-input-error', message);
                parent.append(errorField);
            }

            errorField.innerHTML = translationService.translate(message);
        }
    };

    /**
     * Removes error from input form group element.
     *
     * @param {HTMLElement} element
     */
    const removeError = (element) => {
        const parent = utilities.getAncestor(element, 'sq-field-wrapper');
        parent && parent.classList.remove('sqs--error');
    };


    /**
     * Validates the provided JSON string and marks field invalid if the JSON is invalid.
     *
     * @param {HTMLElement} element
     * @param {string?} value JSON value.
     * @param {string?} message
     * @return {boolean}
     */
    const validateJson = (element, value, message) => {
        try {
            JSON.parse(value);
            removeError(element);

            return true;
        } catch (e) {
            setError(element, message);

            return false;
        }
    };

    /**
     * Validates the condition against the input field and marks field invalid if the error condition is met.
     *
     * @param {HTMLElement} element
     * @param {boolean} errorCondition Error condition.
     * @param {string?} message
     * @return {boolean}
     */
    const validateField = (element, errorCondition, message) => {
        if (errorCondition) {
            setError(element, message);

            return false;
        }

        removeError(element);

        return true;
    };

    SequraFE.validationService = {
        setError,
        removeError,
        validateEmail,
        validateDateOrDuration,
        validateIP,
        validateIPList,
        validateNumber,
        validateUrl,
        validateMaxLength,
        validateJson,
        validateCssSelector,
        validateField,
        validateRequiredField,
        handleValidationErrors
    };
})();

```
