/**
* Form input validation module
* @module formValidation
* @requires module:util
*/
import { checkValue, checkTimeInput, parseAge } from './util.js'
/**
* Set up event listeners for form validation
* @param {FormValidationConfig[]} config configuration for setup
* @returns {String} space-delimited list of all selectors used
*/
export default function setup(config){
let fields = "";
for ( let item of config ) {
fields += `${item.selector}, `;
// Remove 'invalid' class on focus
$(item.selector).on("focus", e => {
$(e.target).removeClass("invalid");
})
// Handle items with an itemType
if ( item.inputType ) {
if ( item.inputType === "age" ) {
$(item.selector).on("focusout", e => {
if( $(e.target).val() !== "" ) {
validateAge(e.target, item);
}
})
} else if ( item.inputType === "time" ) {
$(item.selector).on("focusout", e => {
if( $(e.target).val() !== "" ) {
validateTime(e.target, item);
}
})
}
} else if ( item.max ) {
// Handle items with a range
$( item.selector ).on("focusout", e => {
if( $( e.target ).val() !== "" ) {
validateRange(e.target, item);
}
});
} else if ( item.match ) {
// Handle items with a RegExp match
$(item.selector).on("focusout", e => {
if( $(e.target).val() !== "" ) {
validateMatch(e.target, item);
}
});
}
}
// Remove trailing comma-space
return fields.slice(0,-2);
};
/**
* Form validation configuration parameters. Must have either an inputType,
* a 'match' property, or a 'min' and 'max' property
* @typedef {Object} FormValidationConfig
* @property {String} selector jQuery selector of inputs to validate
* @property {Number} [min] Minimum valid numeric input
* @property {Number} [max] Maximum valid numeric input
* @property {RegExp} [match] Regular expression that matches valid input
* @property {String} [inputType] Type of input if not a match or min/max validation
*/
/**
* Callback for validating age input. Adds 'invalid' class to DOM element if
* input is invalid or removes if valid.
* @requires module:util
* @param {HTMLElement} el DOM element
* @param {FormValidationConfig} item Current element's validation configuration
* @returns {HTMLElement} The original DOM element, for chaining
*/
function validateAge(el, item){
let yearsOld = parseAge( $(el).val() );
const validatedAge = checkValue(yearsOld, item.min, item.max);
if ( validatedAge === 0 ) {
$(el).addClass("invalid");
} else {
$(el).removeClass("invalid");
}
return el;
};
/**
* Callback for validating time input. Adds 'invalid' class to DOM element if
* input is invalid. If valid, replaces input value with correctly formatted
* time input string and removes 'invalid' class.
* @requires module:util
* @param {HTMLElement} el DOM element
* @param {FormValidationConfig} item Current element's validation configuration
* @returns {HTMLElement} The original DOM element, for chaining
*/
function validateTime(el, item){
let x = $(el).val();
let corrected = checkTimeInput(x);
if ( corrected === "" ) {
$(el).addClass("invalid");
} else {
$(el).val(corrected);
$(el).removeClass('invalid');
$(el).removeClass('invalid');
}
return el;
};
/**
* Callback for validating numerical input with defined minimum and maximum.
* Adds 'invalid' class to DOM element if input is invalid, otherwise removes
* 'invalid' class.
* @param {HTMLElement} el DOM element
* @param {FormValidationConfig} item Current element's validation configuration
* @returns {HTMLElement} The original DOM element, for chaining
*/
function validateRange(el, item){
if ( checkValue(+$(el).val(), item.min, item.max) === 0 ) {
$(el).addClass("invalid");
} else {
$(el).removeClass('invalid');
}
return el;
};
/**
* Callback for validating input against a regular expression. Adds 'invalid'
* class to DOM element if input is invalid, otherwise removes 'invalid' class.
* @param {HTMLElement} el DOM element
* @param {FormValidationConfig} item Current element's validation configuration
* @returns {HTMLElement} The original DOM element, for chaining
*/
function validateMatch(el, item){
if ( ! item.match.test($(el).val())) {
$(el).addClass("invalid");
} else {
$(el).removeClass('invalid');
}
return el;
}