Source: validate.js

"use strict";
// SPDX-License-Identifier: GPL-3.0-or-later
// myMPD (c) 2018-2024 Juergen Mang <mail@jcgames.de>
// https://github.com/jcorporation/mympd

/** @module validate_js */

/**
 * Highlight the input element with the invalid value
 * @param {string} prefix prefix for the input fields
 * @param {object} obj the jsonrpc error object
 * @returns {boolean} true if input element was found, else false
 */
function highlightInvalidInput(prefix, obj) {
    if (obj.error.data.path === undefined) {
        return false;
    }
    // try to find the input element
    const id = ucFirst(obj.error.data.path.split('.').pop());
    const el = document.querySelector('#' + prefix + id + 'Input');
    if (el) {
        let col = el.closest('.col-sm-8');
        if (col === null) {
            col = el.parentNode;
        }
        setIsInvalid(el);
        // append error message if there is no client-side invalid feedback defined
        if (col.querySelector('.invalid-feedback') === null) {
            const invalidServerEl = col.querySelector('.invalid-server');
            if (invalidServerEl === null) {
                // Create new invalid feedback element
                col.appendChild(
                    elCreateTextTn('div', {"class": ["invalid-feedback", "invalid-server"]}, tn(obj.error.message, obj.error.data))
                );
                return true;
            }
        }
        const invalidServerEl = col.querySelector('.invalid-server');
        if (invalidServerEl !== null) {
            // Update invalid feedback from server
            invalidServerEl.textContent = tn(obj.error.message, obj.error.data);
        }
        return true;
    }
    logWarn('Element not found: #' + prefix + id + 'Input');
    return false;
}

/**
 * Removes all is-invalid classes
 * @param {Element} el element
 * @returns {void}
 */
function removeIsInvalid(el) {
    const els = el.querySelectorAll('.is-invalid');
    for (let i = 0, j = els.length; i < j; i++) {
        els[i].classList.remove('is-invalid');
    }
}

/**
 * Marks an element as invalid
 * @param {string} id element id
 * @returns {void}
 */
function setIsInvalidId(id) {
    setIsInvalid(elGetById(id));
}

/**
 * Marks an element as invalid
 * @param {Element} el element
 * @returns {void}
 */
function setIsInvalid(el) {
    //set is-invalid also on parent node
    el.classList.add('is-invalid');
    const col = el.closest('.col-sm-8');
    col.classList.add('is-invalid');
    col.firstElementChild.classList.add('is-invalid');
}

/**
 * Checks if string is a valid uri (not empty)
 * @param {string} uri uri to check 
 * @returns {boolean} true = valid uri, else false
 */
function isValidUri(uri) {
    if (uri === '' ||
        uri === undefined ||
        uri === null ||
        uri.match(/^\s*$/) !== null)
    {
        return false;
    }
    return true;
}

/**
 * Checks if string is a stream uri
 * @param {string} uri uri to check
 * @returns {boolean} true = stream uri, else false
 */
function isStreamUri(uri) {
    if (uri === undefined) {
        return false;
    }
    if (uri.indexOf('://') > -1) {
        return true;
    }
    return false;
}

/**
 * Checks if string is a http uri
 * @param {string} uri uri to check
 * @returns {boolean} true = http uri, else false
 */
function isHttpUri(uri) {
    if (uri.indexOf('http://') === 0 ||
        uri.indexOf('https://') === 0)
    {
        return true;
    }
    return false;
}

/**
 * Checks if the value of the input element is a valid playlist name
 * @param {Element} el input element
 * @returns {boolean} true = valid playlist name, else false
 */
//eslint-disable-next-line no-unused-vars
function validatePlistEl(el) {
    if (validatePlist(el.value) === false) {
        setIsInvalid(el);
        return false;
    }
    return true;
}

/**
 * Checks if the string is a valid playlist name
 * @param {string} str input element
 * @returns {boolean} true = valid playlist name, else false
 */
function validatePlist(str) {
    if (str === '') {
        return false;
    }
    if (str.match(/\/|\r|\n|"|'/) === null) {
        return true;
    }
    return false;
}

/**
 * Checks if the the value of the input element is an unsigned integer
 * @param {Element} el input element
 * @returns {boolean} true = unsigned integer, else false
 */
//eslint-disable-next-line no-unused-vars
function validateUintEl(el) {
    const value = el.value.replace(/[\d]/g, '');
    if (value !== '') {
        setIsInvalid(el);
        return false;
    }
    return true;
}

/**
 * Checks if the the value of the input element is a float
 * @param {Element} el input element
 * @returns {boolean} true = float, else false
 */
//eslint-disable-next-line no-unused-vars
function validateFloatEl(el) {
    const value = el.value.replace(/[\d-.]/g, '');
    if (value !== '') {
        setIsInvalid(el);
        return false;
    }
    return true;
}

/**
 * Checks if the the value of the input element is a valid stream uri
 * @param {Element} el input element
 * @returns {boolean} true = valid stream uri, else false
 */
function validateStreamEl(el) {
    if (el.value.length === 0) {
        return true;
    }
    if (isStreamUri(el.value) === true) {
        return true;
    }
    setIsInvalid(el);
    return false;
}

/**
 * Checks if the the value of the input element is a hex color
 * @param {Element} el input element
 * @returns {boolean} true = valid stream uri, else false
 */
//eslint-disable-next-line no-unused-vars
function validateColorEl(el) {
    if (el.value.match(/^#[a-f\d]+$/i) !== null) {
        return true;
    }
    setIsInvalid(el);
    return false;
}