@jdlien/validator 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/validator.js +1 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Validator
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Validator is a utility class that you can use to add validation to your application that works much like native HTML5 form validation provided by browsers, but it is much more powerful, flexible, and customizable.
|
|
6
|
+
|
|
7
|
+
It is meant to validate user input in forms, and it includes the following built-in validators:
|
|
8
|
+
|
|
9
|
+
- `required`
|
|
10
|
+
- `minlength`
|
|
11
|
+
- `maxlength`
|
|
12
|
+
- `pattern`
|
|
13
|
+
- `number`
|
|
14
|
+
- `integer`
|
|
15
|
+
- `tel` (North-American Phone Numbers)
|
|
16
|
+
- `email`
|
|
17
|
+
- `postal` (Canadian Postal Codes)
|
|
18
|
+
- `color`
|
|
19
|
+
- `date`
|
|
20
|
+
- `date-range`
|
|
21
|
+
- `time`
|
|
22
|
+
- `url`
|
|
23
|
+
|
|
24
|
+
It is easy to add your own custom validators, and you can easily add your own custom error messages for each field or any given validation for the whole class.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @jdlien/validator
|
|
30
|
+
|
|
31
|
+
# or
|
|
32
|
+
|
|
33
|
+
yarn add @jdlien/validator
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Basic Usage
|
|
37
|
+
|
|
38
|
+
Create a form as you normally would, speciyfing parameters for each input to control how Validator will check the input. You can use the data-type attribute instead of type if you do not want users to be limited by the browser's built-in input fields.
|
|
39
|
+
|
|
40
|
+
Then create a new Validator instance and pass it the form element as the first argument. An optional second argument allows you to pass in options.
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<form id="myForm">
|
|
44
|
+
<input
|
|
45
|
+
type="text"
|
|
46
|
+
name="name"
|
|
47
|
+
required
|
|
48
|
+
data-min-length="2"
|
|
49
|
+
data-max-length="20"
|
|
50
|
+
data-error-default="Please enter a name."
|
|
51
|
+
/>
|
|
52
|
+
<div id="name-error"></div>
|
|
53
|
+
|
|
54
|
+
<input type="text" data-type="email" name="email" required />
|
|
55
|
+
<div id="email-error"></div>
|
|
56
|
+
|
|
57
|
+
<input type="text" data-type="tel" name="phone" />
|
|
58
|
+
<div id="phone-error"></div>
|
|
59
|
+
|
|
60
|
+
<input type="submit" value="Submit" />
|
|
61
|
+
</form>
|
|
62
|
+
|
|
63
|
+
<!-- Include the validator.js file if you are not using a module bundler -->
|
|
64
|
+
<script src="./dist/validator.js"></script>
|
|
65
|
+
<script>
|
|
66
|
+
const form = document.getElementById('myForm')
|
|
67
|
+
const validator = new Validator(form)
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
When Validator is initialized, it will disable the built-in browser validation and show error messages from Validator in the divs with the id of the input name + `-error`.
|
|
72
|
+
|
|
73
|
+
You can also pass in a custom default error message for a field using `data-error-default`.
|
|
74
|
+
|
|
75
|
+
## Demo
|
|
76
|
+
|
|
77
|
+
For a working demo, see the [demo page](./demo.html).
|
|
78
|
+
|
|
79
|
+
## Contributing
|
|
80
|
+
|
|
81
|
+
Install dev dependencies:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm install
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
You may get an error like
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Module did not self-register: '...\node_modules\canvas\build\Release\canvas.node'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If that happens, you
|
|
94
|
+
need to install the canvas module manually: `bash npm rebuild canvas --update-binary `
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(m,c){typeof exports=="object"&&typeof module<"u"?module.exports=c():typeof define=="function"&&define.amd?define(c):(m=typeof globalThis<"u"?globalThis:m||self,m.Validator=c())})(this,function(){"use strict";var W=Object.defineProperty;var B=(m,c,f)=>c in m?W(m,c,{enumerable:!0,configurable:!0,writable:!0,value:f}):m[c]=f;var d=(m,c,f)=>(B(m,typeof c!="symbol"?c+"":c,f),f);function m(r){return r instanceof HTMLInputElement||r instanceof HTMLSelectElement||r instanceof HTMLTextAreaElement}function c(r,e){typeof e=="string"&&(e=[e]);const t=r.dataset.type||"",s=r.type||"";return!!(e.includes(t)||e.includes(s))}function f(r){const e=parseInt(r);if(typeof r=="number"||!isNaN(e))return e-1;const t=new Date(`1 ${r} 2000`).getMonth();if(!isNaN(t))return t;const s={ja:0,en:0,fe:1,fé:1,ap:3,ab:3,av:3,mai:4,juin:5,juil:6,au:7,ag:7,ao:7,se:8,o:9,n:10,d:11};for(const i in s)if(r.toLowerCase().startsWith(i))return s[i];throw new Error("Invalid month name: "+r)}function v(r){return typeof r=="string"&&(r=parseInt(r.replace(/\D/g,""))),r>99?r:r<(new Date().getFullYear()+20)%100?r+2e3:r+1900}function p(r){if(r instanceof Date)return r;r=r.trim().toLowerCase();let e=0,t=0,s=0,i=0,a=0,n=0;const l=new RegExp(/\d{1,2}\:\d\d(?:\:\d\ds?)?\s?(?:[a|p]m?)?/gi);if(l.test(r)){const h=r.match(l)[0];r=r.replace(h,"").trim();const g=R(h);if(g!==null&&({hour:i,minute:a,second:n}=g),r.length<=2){const y=new Date;return new Date(y.getFullYear(),y.getMonth(),y.getDate(),i,a,n)}}const u=/(^|\b)(mo|tu|we|th|fr|sa|su|lu|mard|mer|jeu|ve|dom)[\w]*\.?/gi;r=r.replace(u,"").trim();const o=new Date(new Date().setHours(0,0,0,0));if(/(now|today)/.test(r))return o;if(r.includes("tomorrow"))return new Date(o.setDate(o.getDate()+1));r.length===8&&(r=r.replace(/(\d\d\d\d)(\d\d)(\d\d)/,"$1-$2-$3")),r.length===6&&(r=r.replace(/(\d\d)(\d\d)(\d\d)/,v(r.slice(0,2))+"-$2-$3"));try{({year:e,month:t,day:s}=M(r))}catch{return new Date("")}return new Date(e,t-1,s,i,a,n)}function M(r){function e(n,l=[null,null,null]){const u=o=>o.filter(h=>!l.includes(h));return n===0||n>31?u(["y"]):n>12?u(["d","y"]):n>=1||n<=12?u(["m","d","y"]):[]}const t=r.split(/[\s-/:.,]+/).filter(n=>n!=="");if(t.length<3){if(r.match(/\d{4}/)!==null)throw new Error("Invalid Date");t.unshift(String(new Date().getFullYear()))}const s={year:0,month:0,day:0};function i(n,l){n==="year"?s.year=v(l):s[n]=l}let a=0;for(;!(s.year&&s.month&&s.day);){e:for(const n of t){if(a++,/^[a-zA-Zé]+$/.test(n)){s.month||i("month",f(n)+1);continue}if(/^'\d\d$/.test(n)||/^\d{3,5}$/.test(n)){s.year||i("year",parseInt(n.replace(/'/,"")));continue}const l=parseInt(n);if(isNaN(l))throw console.error(`not date because ${n} isNaN`),new Error("Invalid Date");const u=e(l,[s.year?"y":null,s.month?"m":null,s.day?"d":null]);if(u.length==1)for(let o=0;o<u.length;o++){if(u[o]==="m"&&!s.month){i("month",l);continue e}if(u[o]==="d"&&!s.day){i("day",l);continue e}if(u[o]==="y"&&!s.year){i("year",l);continue e}}a>3&&(!s.month&&u.includes("m")?i("month",l):!s.day&&u.includes("d")?i("day",l):!s.year&&u.includes("y")&&i("year",l))}if(a>6)throw new Error("Invalid Date")}if(s.year&&s.month&&s.day)return s;throw new Error("Invalid Date")}function R(r){if(r=r.trim().toLowerCase(),r==="now"){const o=new Date;return{hour:o.getHours(),minute:o.getMinutes(),second:o.getSeconds()}}const e=r.match(/(\d{3,4})/);if(e){const o=e[1].length,h=e[1].slice(0,o==3?1:2),g=e[1].slice(-2);r=r.replace(e[1],h+":"+g)}const t=new RegExp(/^(\d{1,2})(?::(\d{1,2}))?\s*(?:(a|p)m?)?$/i);if(t.test(r)){const o=r.match(t);if(o===null)return null;r=o[1]+":"+(o[2]||"00")+(o[3]||"")}const s=new RegExp(/^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?\s*(?:(a|p)m?)?$/i);if(!s.test(r))return null;const i=r.match(s);if(i===null)return null;const a=parseInt(i[1]),n=parseInt(i[2]),l=i[3]?parseInt(i[3]):0,u=i[4];return isNaN(a)||isNaN(n)||isNaN(l)?null:u==="p"&&a<12?{hour:a+12,minute:n,second:l}:u==="a"&&a===12?{hour:0,minute:n,second:l}:a<0||a>23||n<0||n>59||l<0||l>59?null:{hour:a,minute:n,second:l}}function S(r,e="h:mm A"){const t=R(r);if(t){const s=new Date;return s.setHours(t.hour),s.setMinutes(t.minute),s.setSeconds(t.second),s.setMilliseconds(0),w(s,e)}return""}function w(r,e="YYYY-MM-DD"){if(r=p(r),isNaN(r.getTime()))return"";const t={y:r.getFullYear(),M:r.getMonth(),D:r.getDate(),W:r.getDay(),H:r.getHours(),m:r.getMinutes(),s:r.getSeconds(),ms:r.getMilliseconds()},s=(o,h=2)=>(o+"").padStart(h,"0"),i=()=>t.H%12||12,a=o=>o<12?"AM":"PM",n=o=>"January|February|March|April|May|June|July|August|September|October|November|December".split("|")[o];function l(o,h=0){const g="Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday".split("|");return h?g[o].slice(0,h):g[o]}const u={YY:String(t.y).slice(-2),YYYY:t.y,M:t.M+1,MM:s(t.M+1),MMMM:n(t.M),MMM:n(t.M).slice(0,3),D:String(t.D),DD:s(t.D),d:String(t.W),dd:l(t.W,2),ddd:l(t.W,3),dddd:l(t.W),H:String(t.H),HH:s(t.H),h:i(),hh:s(i()),A:a(t.H),a:a(t.H).toLowerCase(),m:String(t.m),mm:s(t.m),s:String(t.s),ss:s(t.s),SSS:s(t.ms,3)};return e.replace(/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,(o,h)=>h||u[o])}function x(r,e){const t=p(r);return isNaN(t.getTime())?"":((!e||e.length===0)&&(e="YYYY-MMM-DD"),w(t,e))}function C(r){let e=p(r);return e==null?!1:!isNaN(e.getTime())}function D(r,e){return!(e==="past"&&r>new Date||e==="future"&&r.getTime()<new Date().setHours(0,0,0,0))}function A(r){let e=R(r);return e===null?!1:!isNaN(e.hour)&&!isNaN(e.minute)&&!isNaN(e.second)}function H(r){if(r.length>255||!new RegExp(/^.+@.+\.[a-zA-Z0-9]{2,}$/).test(r))return!1;let t="";return t+="^([a-zA-Z0-9!#$%'*+/=?^_`{|}~-]+",t+="(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*",t+="|",t+='"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*"',t+=")@(",t+="(",t+="(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+",t+="[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?",t+=")",t+=")$",new RegExp(t).test(r)}function N(r){return r=r.replace(/^[^2-90]+/g,""),r=r.replace(/(\d\d\d).*?(\d\d\d).*?(\d\d\d\d)(.*)/,"$1-$2-$3$4"),r}function k(r){return/^\d\d\d-\d\d\d-\d\d\d\d$/.test(r)}function T(r){return r.replace(/[^0-9]/g,"")}function O(r){return/^\-?\d*\.?\d*$/.test(r)}function I(r){return r.replace(/[^\-0-9.]/g,"").replace(/(^-)|(-)/g,(e,t)=>t?"-":"").replace(/(\..*)\./g,"$1")}function _(r){return/^\-?\d*$/.test(r)}function $(r){return r=r.trim(),new RegExp("^(?:[a-z+]+:)?//","i").test(r)?r:"https://"+r}function P(r){return new RegExp("^(?:[-a-z+]+:)?//","i").test(r)}function V(r){return r=r.replace(/[^0-9]/g,"").replace(/(.{5})(.*)/,"$1-$2").trim(),r.length===6&&(r=r.replace(/-/,"")),r}function U(r){return new RegExp(/^\d{5}(-\d{4})?$/).test(r)}function Y(r){return r=r.toUpperCase().replace(/[^A-Z0-9]/g,"").replace(/(.{3})\s*(.*)/,"$1 $2").trim(),r}function q(r){return new RegExp(/^[ABCEGHJKLMNPRSTVXY][0-9][ABCEGHJKLMNPRSTVWXYZ] ?[0-9][ABCEGHJKLMNPRSTVWXYZ][0-9]$/).test(r)}function L(r){return["transparent","currentColor"].includes(r)?!0:typeof r!="string"||!r.trim()?!1:typeof CSS=="object"&&typeof CSS.supports=="function"?CSS.supports("color",r):F(r)}function F(r){const e=new RegExp(/^rgba?\(\s*(\d{1,3}%?,\s*){2}\d{1,3}%?\s*(?:,\s*(\.\d+|0+(\.\d+)?|1(\.0+)?|0|1\.0|\d{1,2}(\.\d*)?%|100%))?\s*\)$/),t=new RegExp(/^hsla?\(\s*\d+(deg|grad|rad|turn)?,\s*\d{1,3}%,\s*\s*\d{1,3}%(?:,\s*(\.\d+|0+(\.\d+)?|1(\.0+)?|0|1\.0|\d{1,2}(\.\d*)?%|100%))?\s*\)$/),s=new RegExp(/^rgba?\(\s*(\d{1,3}%?\s+){2}\d{1,3}%?\s*(?:\s*\/\s*(\.\d+|0+(\.\d+)?|1(\.0+)?|0|1\.0|\d{1,2}(\.\d*)?%|100%))?\s*\)$/),i=new RegExp(/^hsla?\(\s*\d+(deg|grad|rad|turn)?\s+\d{1,3}%\s+\s*\d{1,3}%(?:\s*\/\s*(\.\d+|0+(\.\d+)?|1(\.0+)?|0|1\.0|\d{1,2}(\.\d*)?%|100%))?\s*\)$/),a=new RegExp(/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i);let n="aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|rebeccapurple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen";const l=new RegExp(`^(${n})$`,"i");return e.test(r)||t.test(r)||s.test(r)||i.test(r)||a.test(r)||l.test(r)}let E=null;const b=new Map;function z(r){if(r=r.trim().toLowerCase(),r==="transparent")return"transparent";if(b.has(r))return b.get(r);E===null&&(E=document.createElement("canvas"),E.willReadFrequently=!0);let e=E.getContext("2d");if(!e)throw new Error("Can't get context from colorCanvas");e.fillStyle=r,e.fillRect(0,0,1,1);let t=e.getImageData(0,0,1,1).data,s="#"+("000000"+(t[0]<<16|t[1]<<8|t[2]).toString(16)).slice(-6);return b.set(r,s),s}function Z(r){let e={valid:!1,error:!1,messages:[]};return typeof r=="boolean"?{valid:r,error:!1,messages:[]}:(typeof r.valid=="boolean"&&(e.valid=r.valid),typeof r.message=="string"&&(e.messages=[r.message]),typeof r.messages=="string"&&(e.messages=[r.messages]),Array.isArray(r.messages)&&(e.messages=r.messages),r.error===!0&&(e.error=!0),e)}class G extends Event{constructor(t){super("validationSuccess",{cancelable:!0});d(this,"submitEvent");this.submitEvent=t}}class j extends Event{constructor(t){super("validationError",{cancelable:!0});d(this,"submitEvent");this.submitEvent=t}}class K{constructor(e,t={}){d(this,"form");d(this,"inputs",[]);d(this,"inputErrors",{});d(this,"messages",{ERROR_MAIN:"There is a problem with your submission.",ERROR_GENERIC:"Enter a valid value.",ERROR_REQUIRED:"This field is required.",OPTION_REQUIRED:"An option must be selected.",CHECKED_REQUIRED:"This must be checked.",ERROR_MAXLENGTH:"This must be ${val} characters or fewer.",ERROR_MINLENGTH:"This must be at least ${val} characters.",ERROR_NUMBER:"This must be a number.",ERROR_INTEGER:"This must be a whole number.",ERROR_TEL:"This is not a valid telephone number.",ERROR_EMAIL:"This is not a valid email address.",ERROR_ZIP:"This is not a valid zip code.",ERROR_POSTAL:"This is not a valid postal code.",ERROR_DATE:"This is not a valid date.",ERROR_DATE_PAST:"The date must be in the past.",ERROR_DATE_FUTURE:"The date must be in the future.",ERROR_DATE_RANGE:"The date is outside the allowed range.",ERROR_TIME:"This is not a valid time.",ERROR_TIME_RANGE:"The time is outside the allowed range.",ERROR_URL:"This is not a valid URL.",ERROR_COLOR:"This is not a valid CSS colour.",ERROR_CUSTOM_VALIDATION:"There was a problem validating this field."});d(this,"debug");d(this,"autoInit");d(this,"preventSubmit",!1);d(this,"hiddenClasses");d(this,"errorMainClasses");d(this,"errorInputClasses");d(this,"dispatchTimeout",0);d(this,"originalNoValidate",!1);d(this,"validationSuccessCallback");d(this,"validationErrorCallback");d(this,"submitHandlerRef",this.submitHandler.bind(this));d(this,"inputInputHandlerRef",this.inputInputHandler.bind(this));d(this,"inputChangeHandlerRef",this.inputChangeHandler.bind(this));d(this,"inputKeydownHandlerRef",this.inputKeydownHandler.bind(this));d(this,"inputHandlers",{number:{parse:I,isValid:O,error:this.messages.ERROR_NUMBER},integer:{parse:T,isValid:_,error:this.messages.ERROR_INTEGER},tel:{parse:N,isValid:k,error:this.messages.ERROR_TEL},email:{parse:e=>e.trim(),isValid:H,error:this.messages.ERROR_EMAIL},zip:{parse:V,isValid:U,error:this.messages.ERROR_ZIP},postal:{parse:Y,isValid:q,error:this.messages.ERROR_POSTAL},url:{parse:$,isValid:P,error:this.messages.ERROR_URL},date:{parse:x,isValid:C,error:this.messages.ERROR_DATE},time:{parse:S,isValid:A,error:this.messages.ERROR_TIME},color:{parse:e=>e.trim().toLowerCase(),isValid:L,error:this.messages.ERROR_COLOR}});d(this,"isSubmitting",!1);if(!e)throw new Error("Validator requires a form to be passed as the first argument.");if(!(e instanceof HTMLFormElement))throw new Error("form argument must be an instance of HTMLFormElement");this.form=e,(e.dataset.preventSubmit===""||e.dataset.preventSubmit)&&(this.preventSubmit=!0),Object.assign(this.messages,t.messages||{}),this.debug=t.debug||!1,this.autoInit=t.autoInit!==!1,this.preventSubmit=t.preventSubmit===!1?!1:this.preventSubmit,this.hiddenClasses=t.hiddenClasses||"hidden opacity-0",this.errorMainClasses=t.errorMainClasses||"m-2 border border-red-500 bg-red-100 p-3 dark:bg-red-900/80 text-center",this.errorInputClasses=t.errorInputClasses||"border-red-600 dark:border-red-500",this.validationSuccessCallback=t.validationSuccessCallback||(()=>{}),this.validationErrorCallback=t.validationErrorCallback||(()=>{}),this.autoInit&&this.init(),new MutationObserver(()=>this.autoInit&&this.init()).observe(e,{childList:!0})}addEventListeners(){this.form.addEventListener("submit",this.submitHandlerRef),this.form.addEventListener("input",this.inputInputHandlerRef),this.form.addEventListener("change",this.inputChangeHandlerRef),this.form.addEventListener("keydown",this.inputKeydownHandlerRef),this.form.addEventListener("remove",this.destroy,{once:!0})}removeEventListeners(){this.form.removeEventListener("submit",this.submitHandlerRef),this.form.removeEventListener("input",this.inputInputHandlerRef),this.form.removeEventListener("change",this.inputChangeHandlerRef),this.form.removeEventListener("keydown",this.inputKeydownHandlerRef),this.form.removeEventListener("remove",this.destroy)}init(){this.inputs=Array.from(this.form.elements),this.inputs.forEach(e=>{!e.name&&!e.id&&(e.id=`vl-input-${Math.random().toString(36).slice(2)}`),this.inputErrors[e.name||e.id]=[]}),this.originalNoValidate=this.form.hasAttribute("novalidate"),this.form.setAttribute("novalidate","novalidate"),this.removeEventListeners(),this.addEventListeners()}getErrorEl(e){const t=document.getElementById(e.name+"-error");return t||document.getElementById(e.id+"-error")||null}addErrorMain(e){const t=document.createElement("div");t.id="form-error-main",this.errorMainClasses.split(" ").forEach(s=>{t.classList.add(s)}),e?t.innerHTML=e:t.innerHTML=this.messages.ERROR_MAIN,this.form.appendChild(t)}addInputError(e,t=e.dataset.errorDefault||this.messages.ERROR_GENERIC){const s=e.name||e.id;this.debug&&console.log("Invalid value for "+s+": "+t),s in this.inputErrors||(this.inputErrors[s]=[]),this.inputErrors[s].includes(t)||this.inputErrors[s].push(t)}showInputErrors(e){if(!e||!e.name&&!e.id)return;const t=e.name||e.id,s=t in this.inputErrors?this.inputErrors[t]:[];if(!s.length)return;e.setAttribute("aria-invalid","true"),this.errorInputClasses.split(" ").forEach(a=>{e.classList.add(a)});let i=this.getErrorEl(e);i&&(i.innerHTML=s.join("<br>"),this.hiddenClasses.split(" ").forEach(a=>{i&&i.classList.remove(a)}))}showFormErrors(){if(this.inputs.forEach(e=>this.showInputErrors(e)),Object.values(this.inputErrors).some(e=>Array.isArray(e)&&e.length)){const e=this.form.querySelectorAll("#form-error-main");e.length?e.forEach(t=>{t.innerHTML||(t.innerHTML=this.messages.ERROR_MAIN),this.hiddenClasses.split(" ").forEach(s=>{t.classList.remove(s)})}):this.addErrorMain()}}clearInputErrors(e){this.inputErrors[e.name||e.id]=[],e.removeAttribute("aria-invalid");let t=this.getErrorEl(e);t&&(this.errorInputClasses.split(" ").forEach(s=>{e.classList.remove(s)}),this.hiddenClasses.split(" ").forEach(s=>{t&&t.classList.add(s)}),t.textContent="")}clearFormErrors(){this.form.querySelectorAll("#form-error-main").forEach(e=>{this.hiddenClasses.split(" ").forEach(t=>{e.classList.add(t)})}),this.inputs.forEach(e=>this.clearInputErrors(e))}validateRequired(e){let t=!0;if(e.required&&(e.value===""||e instanceof HTMLInputElement&&["checkbox","radio"].includes(e.type)&&!e.checked))if(e instanceof HTMLInputElement&&["checkbox","radio"].includes(e.type)){let s=!1,i=e.name;const a=this.form.querySelectorAll(`input[name="${i}"]`);if(a.forEach(n=>{if(n instanceof HTMLInputElement&&n.checked===!0){s=!0;return}}),s===!1){t=!1;let n=a.length>1?this.messages.OPTION_REQUIRED:this.messages.CHECKED_REQUIRED;e.dataset.errorDefault&&(n=e.dataset.errorDefault),this.addInputError(e,n)}}else m(e)&&(t=!1,this.addInputError(e,e.dataset.errorDefault||this.messages.ERROR_REQUIRED));return t}validateLength(e){let t=!0;if((e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&e.value.length){let s=e.minLength>0?e.minLength:e.dataset.minLength?parseInt(e.dataset.minLength):0,i=e.maxLength>0&&e.maxLength<5e5?e.maxLength:e.dataset.maxLength?parseInt(e.dataset.maxLength):1/0;s>0&&e.value.length<s&&(t=!1,this.addInputError(e,this.messages.ERROR_MINLENGTH.replace("${val}",s.toString()))),e.value.length>i&&(t=!1,this.addInputError(e,this.messages.ERROR_MAXLENGTH.replace("${val}",i.toString())))}return t}validateInputType(e){const t=e.dataset.type||e.type,s=this.inputHandlers[e.type]||this.inputHandlers[t];if(s){const i=e.dataset.dateFormat||e.dataset.timeFormat,a=s.parse(e.value,i),n=["date","time","datetime-local","month","week"];if(a.length&&!n.includes(e.type)&&(e.value=a),!s.isValid(e.value))return this.addInputError(e,s.error),!1}return!0}validateDateRange(e){if(e.dataset.dateRange){const t=e.dataset.dateRange,s=p(e.value);if(!isNaN(s.getTime())&&!D(s,t)){let i=e.dataset.errorDefault||this.messages.ERROR_DATE_RANGE;return t==="past"?i=this.messages.ERROR_DATE_PAST:t==="future"&&(i=this.messages.ERROR_DATE_FUTURE),this.addInputError(e,i),!1}}return!0}validatePattern(e){const t=e.dataset.pattern||e instanceof HTMLInputElement&&e.pattern||null;return t&&!new RegExp(t).test(e.value)?(this.addInputError(e,e.dataset.message),!1):!0}async validateCustom(e){const t=e.dataset.validation;if(!t||typeof t!="string")return!0;const s=window[t];if(!s||typeof s!="function")return!0;let i;try{i=await Promise.resolve(s(e.value)),i=Z(i)}catch{return this.addInputError(e,this.messages.ERROR_CUSTOM_VALIDATION),!1}const a=i.messages.join("<br>")||this.messages.ERROR_CUSTOM_VALIDATION;return i.valid||this.addInputError(e,a),i.valid}async validateInput(e){if(!(e instanceof HTMLInputElement)||!e.value.length)return!0;let t=!0;return t=this.validateInputType(e)&&t,t=this.validateDateRange(e)&&t,t=this.validatePattern(e)&&t,t=await this.validateCustom(e)&&t,t}async validate(e){let t=!0;for(const s of this.inputs)t=this.validateRequired(s)&&t,t=this.validateLength(s)&&t,t=await this.validateInput(s)&&t;return t}async submitHandler(e){if(this.isSubmitting)return;e.preventDefault(),this.clearFormErrors();let t=await this.validate(e);this.showFormErrors();const s=new G(e),i=new j(e);t?(this.form.dispatchEvent(s),this.validationSuccessCallback&&this.validationSuccessCallback(e)):(this.form.dispatchEvent(i),this.validationErrorCallback&&this.validationErrorCallback(e)),t&&!this.preventSubmit&&(this.isSubmitting=!0,s.defaultPrevented||this.form.submit(),this.isSubmitting=!1)}async inputChangeHandler(e){e.target instanceof HTMLInputElement&&(this.clearInputErrors(e.target),await this.validateInput(e.target),this.showInputErrors(e.target))}inputInputHandler(e){const t=e.target;c(t,"integer")&&(t.value=T(t.value)),t.type!=="number"&&c(t,["number","float","decimal"])&&(t.value=I(t.value)),c(t,"color")&&this.syncColorInput(e)}syncColorInput(e){let t=e.target,s=t;t.type==="color"&&(s=this.form.querySelector(`#${t.id.replace(/-color/,"")}`));let i=this.form.querySelector(`#${s.id}-color-label`);if((t.dataset.type||"")==="color"){let a=this.form.querySelector(`input#${t.id}-color`);if(!a||!L(t.value))return;a.value=z(t.value)}t.type==="color"&&(s.value=t.value),i&&(i.style.backgroundColor=t.value),clearTimeout(this.dispatchTimeout),this.dispatchTimeout=window.setTimeout(()=>{s.dispatchEvent(new Event("change",{bubbles:!0}))},200)}inputKeydownHandler(e){e.target instanceof HTMLInputElement&&c(e.target,"integer")&&(e.key==="ArrowUp"?(e.preventDefault(),e.target.value===""&&(e.target.value="0"),e.target.value=(parseInt(e.target.value)+1).toString()):e.key==="ArrowDown"&&(parseInt(e.target.value)>0?e.target.value=(parseInt(e.target.value)-1).toString():e.target.value="0"))}destroy(){this.removeEventListeners(),this.originalNoValidate||this.form.removeAttribute("novalidate")}}return K});
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jdlien/validator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"module": "dist/validator.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/validator.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"description": "Validates and sanitizes the inputs in a form using native html attributes.",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "vite",
|
|
18
|
+
"build": "tsc && vite build",
|
|
19
|
+
"preview": "vite preview",
|
|
20
|
+
"test": "vitest",
|
|
21
|
+
"coverage": "vitest --coverage",
|
|
22
|
+
"tw": "tailwindcss -i demo-src.css -o demo.css -w -m"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/jdlien/validator.git"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"form",
|
|
33
|
+
"validation",
|
|
34
|
+
"front-end",
|
|
35
|
+
"validation",
|
|
36
|
+
"better",
|
|
37
|
+
"HTML",
|
|
38
|
+
"inputs",
|
|
39
|
+
"date",
|
|
40
|
+
"validation",
|
|
41
|
+
"time",
|
|
42
|
+
"validation",
|
|
43
|
+
"color",
|
|
44
|
+
"validation",
|
|
45
|
+
"required",
|
|
46
|
+
"field",
|
|
47
|
+
"validation"
|
|
48
|
+
],
|
|
49
|
+
"author": "JD Lien",
|
|
50
|
+
"license": "ISC",
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/jdlien/validator/issues"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/jdlien/validator#readme",
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@sheerun/mutationobserver-shim": "^0.3.3",
|
|
57
|
+
"@tailwindcss/forms": "^0.5.3",
|
|
58
|
+
"@types/jsdom": "^21.1.0",
|
|
59
|
+
"@vitest/coverage-c8": "^0.28.5",
|
|
60
|
+
"jsdom": "^21.1.0",
|
|
61
|
+
"jsdom-global": "^3.0.2",
|
|
62
|
+
"prettier": "^2.8.4",
|
|
63
|
+
"tailwindcss": "^3.2.7",
|
|
64
|
+
"typescript": "^4.9.3",
|
|
65
|
+
"vite": "^4.1.0",
|
|
66
|
+
"vitest": "^0.28.5"
|
|
67
|
+
},
|
|
68
|
+
"sideEffects": false
|
|
69
|
+
}
|