import { datePattern, datePlaceholder, timePattern, timePlaceholder } from "./date";
import { datePickerParams } from "./datePickerParams";
/**
* @typedef {object} validation
* @description Provides input and parameter check methods
* @property {array} error - Stores errors in array
* @property {function} addError - Add an error object to error attribute
* @property {object} allowedLength - Provides allowed lengths.
* Contains dateInput, id, label attributes.
* These attributes contain an object having the min and max attributes.
* @property {object} allowedType - Provides allowed type (return of typeof).
* Contains eventFuntion attribute
* @property {function} checkColor - Checks that the color passed in parameter corresponds to the accepted format
* @property {function} checkFormat - Checks that the requested format matches the accepted format
* @property {function} checkId - Checks that id passed in parameter corresponds to the accepted format
* @property {function} checkInputValue - Checks that input value passed in parameter corresponds to the accepted format
* @property {function} checkLabel - Checks that label passed in parameter corresponds to the accepted format
* @property {function} checkLimits - Checks that deadlines passed in parameter corresponds to the accepted format
* @property {function} checkString - Checks length and format of string parameter
* @property {function} checkType - Checks if type is allowed
* @property {function} clearError - clear error attribute and error message displayed
* @property {object} formats - Provides format control functions and information
* @property {function} regExpTest - Apply RegExp test function
*/
export const validation = {
error: [],
/**
* Add an error object to error attribute
* @memberof validation
* @param {string} what - What is the problem element ?
* @param {*} why - Why it throws an error ?
* @param {*} output - Where should it show error message ?
* @returns {boolean} false
*/
addError: (what, why, output) => {
const errorObject = { what, why, output }
if(!validation.error.includes(errorObject)){ validation.error.push(errorObject) }
return false
},
allowedLength: {
color: { max: 23, min: 3 },
date: { max: 10, min: 10 },
dateTime: { max: 16, min: 16 },
id: { max: 25, min: 2 },
label: { max: 60, min: 4 },
time: {max: 5, min: 5}
},
allowedType: { eventFunction: "function" },
/**
* Checks that the color passed in parameter corresponds to the accepted format
* @memberof validation
* @param {string} color
* @param {string} output - error box id
* @returns {boolean} checkResult
* @see validation.checkString
*/
checkColor: (color, output) => validation.checkString(color, "color", output),
/**
* Checks that the requested format matches the accepted format
* @memberof validation
* @param {string} format
* @returns {boolean}
*/
checkFormat: (format) => (validation.formats.pattern[format] && validation.formats.placeholder[format]) ? true : false,
/**
* Checks that id passed in parameter corresponds to the accepted format
* @memberof validation
* @param {string} datePickerId
* @param {string} output - error box id
* @returns {boolean} checkResult
* @see validation.checkString
*/
checkId: (datePickerId, output) => validation.checkString(datePickerId, "id", output),
/**
* Checks that input value passed in parameter corresponds to the accepted format
* @memberof validation
* @param {string} value - date format : YYYY-MM-DD
* @param {string} output - error box id
* @param {string} type - accept date, dateTime, ...
* @param {object} limits - deadlines object
* @param {boolean} strictValidation - true : apply strict validation
* @returns {boolean} checkResult
* @see validation.checkString
*/
checkInputValue: (value, output, type, limits = false, strictValidation = false) => validation.checkString(value, type, output, limits, strictValidation),
/**
* Checks that label passed in parameter corresponds to the accepted format
* @memberof validation
* @param {string} datePickerLabel
* @param {string} output - error box id
* @returns {boolean} checkResult
* @see validation.checkString
*/
checkLabel: (datePickerLabel, output) => validation.checkString(datePickerLabel, "label", output),
/**
* Checks that deadlines passed in parameter corresponds to the accepted format
* @memberof validation
* @param {string} date
* @param {object} limits - deadlines object
* @param {boolean} strictValidation - true : apply strict validation
* @returns {boolean} checkResult
*/
checkLimits: (date, limits, strictValidation = false) => {
const dateSplit = date.split("-")
date = parseInt(
dateSplit[0].length === 4
? `${dateSplit[0]}${dateSplit[1]}${dateSplit[2]}`
: `${dateSplit[2]}${dateSplit[1]}${dateSplit[0]}`
)
if(limits.max){
const maxSplit = limits.max.split("-")
const max = parseInt(
maxSplit[0].length === 4
? `${maxSplit[0]}${maxSplit[1]}${maxSplit[2]}`
: `${maxSplit[2]}${maxSplit[1]}${maxSplit[0]}`
)
if(date > max) { return false }
}
if(strictValidation && limits.min){
const minSplit = limits.min.split("-")
const min = parseInt(
minSplit[0].length === 4
? `${minSplit[0]}${minSplit[1]}${minSplit[2]}`
: `${minSplit[2]}${minSplit[1]}${minSplit[0]}`
)
if(date < min) { return false }
}
return true
},
/**
* Checks length and format of string parameter
* @memberof validation
* @param {string} string
* @param {string} stringName - accept dateInput, id or label
* @param {string} output - error box id
* @param {object} limits - deadlines object
* @param {boolean} strictValidation - true : apply strict validation
* @returns {boolean}
*/
checkString: (string, stringName, output, limits, strictValidation = false) => {
const stringLength = string.length
const searchLetter = stringName === "date" || stringName === "dateTime" || stringName === "time"
? true : false
if(limits && stringName === "date" && !validation.checkLimits(string, limits, strictValidation)){
return validation.addError(stringName, "outOfBounds", output)
}
if(searchLetter && !strictValidation){
if( /[a-zA-Z?,;!§%*$£&+_()\/]/.test(string) ){
return validation.addError(stringName, "wrongFormat", output)
}
if(stringLength < validation.allowedLength[stringName].min){ return false }
}
if(stringLength > validation.allowedLength[stringName].max){
return validation.addError(stringName, "tooLong", output)
}
if(stringLength < validation.allowedLength[stringName].min){
return validation.addError(stringName, "tooShort", output)
}
if(!validation.regExpTest(string, stringName, output)){
return validation.addError(stringName, "wrongFormat", output)
}
return string
},
/**
* Checks if type is allowed
* @memberof validation
* @param {string} itemToCheck
* @param {string} itemName
* @param {string} output - error box id
* @returns {boolean} checkResult
*/
checkType: (itemToCheck, itemName, output) => {
if(typeof itemToCheck !== validation.allowedType[itemName]){
return validation.addError(itemName, "wrongType", output)
}
return true
},
/**
* clear error attribute and error message displayed
* @memberof validation
*/
clearError: () => { validation.error = [] },
formats: {
/**
* Provide expected formats as an object
* @memberof validation
* @param {string} type - accept date, time, ...
* @param {string} outputFormat - corresponding to DatePicker parameter
* @returns {object} formatObject
*/
get: (type, outputFormat = "number") => {
let langOpt = 0
if(type !== "time"){
switch(validation.formats.lang){
case "de":
langOpt = 3
break
case "es": case "it":
langOpt = 2
break
case "fr":
langOpt = 1
break
default: break
}
}
return validation.formats.getObject(
outputFormat === "number" ? validation.formats.output[outputFormat] : validation.formats.output[outputFormat][type],
validation.formats.pattern[type][langOpt],
validation.formats.placeholder[type][langOpt],
validation.formats.regExp[type][langOpt]
)
},
/**
* Provide formats object
* @memberof validation
* @param {string} output
* @param {string} pattern
* @param {string} placeholder
* @param {string} regExp
* @param {object} expectedLenght
* @returns {object} formatsObject
*/
getObject: (output, pattern, placeholder, regExp, expectedLenght) => { return { output, pattern, placeholder, regExp, expectedLenght }},
/**
* Provide options object
* @memberof validation
* @param {boolean} time
* @returns {object} optionsObject
*/
getOptions: (time = false) => {
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
return time ? { hour: 'numeric', minute: 'numeric', ...options } : options
},
/**
* Store language defined to navigator
* @memberof validation
*/
lang: navigator.language.substring(0,2),
/**
* Stores functions to get input value correctly formatted
* @memberof validation
*/
output: {
/**
* Stores functions to get input value in array format
*/
array: {
/**
* Provide date in array format
* @param {string} date
* @returns {array} dateArray
* @example [ {number} year, {number} month, {number} day ]
*/
date: (date) => date && date.split(date.indexOf("-") > 0 ? "-" : "."),
/**
* Provide date time in array format
* @param {string} dateTime
* @returns {array} dateTimeArray
* @example [ {number} year, {number} month, {number} day, {number} hour, {number} minute ]
*/
dateTime: (dateTime) => {
if(dateTime){
const dateTimeArray = dateTime.split(" ")
return [ ...validation.formats.output.array.date(dateTimeArray[0]), ...validation.formats.output.array.time(dateTimeArray[1])]
}
},
/**
* Provide time in array format
* @param {string} time
* @returns {array} timeArray
* @example [ {number} hour, {number} minute ]
*/
time: (time) => time && time.split(":"),
},
/**
* Stores functions to get input value in object format
*/
dateObject: {
/**
* Provide date in object format
* @param {string} date
* @returns {object} Date
*/
date: (date) => date && validation.formats.output.dateObject.fct(date, "date"),
/**
* Provide dateTime in object format
* @param {string} dateTime
* @returns {object} Date
*/
dateTime: (dateTime) => dateTime && validation.formats.output.dateObject.fct(dateTime, "dateTime"),
/**
* Provide date in object format
* @param {string} date
* @param {string} type
* @returns {object} Date
*/
fct: (date, type) => {
if(!date){ return false }
date = validation.formats.output.array[type](date)
return type === "time" ? { hour: date[0], minute: date[1] }
: type === "date" ? new Date(
date[validation.formats.lang === "en" ? 0 : 2],
parseInt(date[1]) - 1,
date[validation.formats.lang === "en" ? 2 : 0]
) : new Date(
date[validation.formats.lang === "en" ? 0 : 2],
parseInt(date[1]) - 1,
date[validation.formats.lang === "en" ? 2 : 0],
date[3] && date[3],
date[4] && date[4]
)
},
/**
* Provide time in object format
* @param {string} time
* @returns {object} Date
*/
time: (time) => time && validation.formats.output.dateObject.fct(time, "time")
},
number: "number",
/**
* Stores functions to get input value in string format
*/
string: {
/**
* Provide date in string format
* @param {string} date
* @returns {string} date
*/
date: (date) => date && validation.formats.output.string.fct(date, false),
/**
* Provide dateTime in string format
* @param {string} dateTime
* @returns {string} dateTime
*/
dateTime: (date) => date && validation.formats.output.string.fct(date, true),
/**
* Provide date in string format
* @param {string} date
* @param {boolean} isDateTime
* @returns {string} date
*/
fct: (date, isDateTime = false) => new Intl.DateTimeFormat(
undefined,
validation.formats.getOptions(isDateTime)).format(
validation.formats.output.dateObject[isDateTime ? "dateTime" : "date"](date)
),
/**
* Provide time in string format
* @param {string} time
* @returns {string} time
*/
time: (date) => date && date.toLocalTimeString()
}
},
/**
* Stores input pattern corresponding to the expected format
* @memberof validation
*/
pattern: {
date: datePattern,
dateTime: [
datePattern[0] +" "+ timePattern,
datePattern[1] +" "+ timePattern,
datePattern[2] +" "+ timePattern,
datePattern[3] +" "+ timePattern
],
time: [timePattern]
},
/**
* Stores input placeholder corresponding to the expected format
* @memberof validation
*/
placeholder: {
date: datePlaceholder,
dateTime: [
datePlaceholder[0] +" "+ timePlaceholder,
datePlaceholder[1] +" "+ timePlaceholder,
datePlaceholder[2] +" "+ timePlaceholder,
datePlaceholder[3] +" "+ timePlaceholder
],
time: [timePlaceholder]
},
/**
* Stores regExp parameter to control the expected format
* @memberof validation
*/
regExp: {
date: [/^\d{4}-\d{2}-\d{2}$/, /^\d{2}-\d{2}-\d{4}$/, /^\d{1}-\d{1}-\d{4}$/, /^\d{1}.\d{1}.\d{4}$/],
dateTime: [
/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}$/,
/^\d{2}-\d{2}-\d{4}\s\d{2}:\d{2}$/,
/^\d{1}-\d{1}-\d{4}\s\d{2}:\d{2}$/,
/^\d{1}.\d{1}.\d{4}\s\d{2}:\d{2}$/
],
time: /^\s\d{2}:\d{2}/
}
},
/**
* Applies the test function of regExp
* @memberof validation
* @param {string} string - value to check
* @param {string} stringName
* @param {string} output
* @returns {boolean} testFunctionResult
*/
regExpTest(string, stringName, output){
const regVal = stringName === "id" ? ["^[a-zA-Z0-9-]+$", "g"]
: stringName === "label" ? ["^[a-zA-Z0-9 -/']+$", "g"]
: stringName === "color" ? ["^[rh#][a-zA-Z0-9]+$", "g"]
: datePickerParams.format[output].regExp
const regEx = Array.isArray(regVal) ? new RegExp(regVal[0], regVal[1]) : new RegExp(regVal)
return regEx.test(string)
}
};
Source