From b8ec1d42a1f826fbc7f24b85723300740a7fd1a8 Mon Sep 17 00:00:00 2001 From: Josh Heidenreich Date: Fri, 16 Apr 2021 12:31:05 +0930 Subject: [PATCH] Only validate onblur of the field, and only if it's been edited The process of editing the field (the 'input' event) will activate the field for validation, and then the blur event does the actual validation. This means that clicking into (or tabbing into) a field won't do anything if you then leave that field UNLESS if you actually enter some content into the field; once some input has occurred, then the field is active, and from then onwards the blur events will trigger validation. Not the most efficient code (especially for radio/checkbox) due to the double-events, but it works. Could be made better by removing the 'input' event handler upon first use. Tested on Firefox/Linux and Chrome/Linux, with entering fields, inputting fields, chrome autofill, etc. --- dist/pristine.js | 6 +++++- dist/pristine.min.js | 2 +- src/pristine.js | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dist/pristine.js b/dist/pristine.js index 0abfbc3..73f9dd9 100644 --- a/dist/pristine.js +++ b/dist/pristine.js @@ -142,7 +142,11 @@ }); self.live && input.addEventListener(!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'input' : 'change', function (e) { - self.validate(e.target); + e.target.active = true; + }.bind(self)); + + self.live && input.addEventListener(!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'blur' : 'change', function (e) { + e.target.active && self.validate(e.target); }.bind(self)); return input.pristine = { input: input, validators: fns, params: params, messages: messages, self: self }; diff --git a/dist/pristine.min.js b/dist/pristine.min.js index cc1cbee..3cd5285 100644 --- a/dist/pristine.min.js +++ b/dist/pristine.min.js @@ -1 +1 @@ -!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).Pristine=r()}(this,(function(){"use strict";var e={required:"This field is required",email:"This field requires a valid e-mail address",number:"This field requires a number",integer:"This field requires an integer value",url:"This field requires a valid website URL",tel:"This field requires a valid telephone number",maxlength:"This fields length must be < ${1}",minlength:"This fields length must be > ${1}",min:"Minimum value for this field is ${1}",max:"Maximum value for this field is ${1}",pattern:"Please match the requested format"};function r(e){var r=arguments;return this.replace(/\${([^{}]*)}/g,(function(e,t){return r[t]}))}function t(e){return e.pristine.self.form.querySelectorAll('input[name="'+e.getAttribute("name")+'"]:checked').length}var n={classTo:"form-group",errorClass:"has-danger",successClass:"has-success",errorTextParent:"form-group",errorTextTag:"div",errorTextClass:"text-help"},i=["required","min","max","minlength","maxlength","pattern"],s=/^(([^<>()\[\]\\.,;:\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,}))$/,a={},o=function(r,t){t.name=r,t.msg||(t.msg=e[r]),void 0===t.priority&&(t.priority=1),a[r]=t};function l(e,t,s){var o=this;function l(e,r,t,n){var i=a[t];if(i&&(e.push(i),n)){var s=n.split(",");s.unshift(null),r[t]=s}}function u(e){for(var t,n=[],i=!0,s=0;e.validators[s];s++){var a=e.validators[s],o=e.params[a.name]?e.params[a.name]:[];if(o[0]=e.input.value,!a.fn.apply(e.input,o)){if(i=!1,(t=a.msg)&&t.constructor&&t.call&&t.apply)n.push(a.msg(e.input.value,o));else{var l=e.messages[a.name]||a.msg;n.push(r.apply(l,o))}if(!0===a.halt)break}}return e.errors=n,i}function f(e){if(e.errorElements)return e.errorElements;var r=function(e,r){for(;(e=e.parentElement)&&!e.classList.contains(r););return e}(e.input,o.config.classTo),t=null,n=null;return(t=o.config.classTo===o.config.errorTextParent?r:r.querySelector("."+o.config.errorTextParent))&&((n=t.querySelector(".pristine-error"))||((n=document.createElement(o.config.errorTextTag)).className="pristine-error "+o.config.errorTextClass,t.appendChild(n),n.pristineDisplay=n.style.display)),e.errorElements=[r,n]}function c(e){var r=f(e),t=r[0],n=r[1];t&&(t.classList.remove(o.config.successClass),t.classList.add(o.config.errorClass)),n&&(n.innerHTML=e.errors.join("
"),n.style.display=n.pristineDisplay||"")}function p(e){var r=function(e){var r=f(e),t=r[0],n=r[1];return t&&(t.classList.remove(o.config.errorClass),t.classList.remove(o.config.successClass)),n&&(n.innerHTML="",n.style.display="none"),r}(e)[0];r&&r.classList.add(o.config.successClass)}return function(e,r,t){e.setAttribute("novalidate","true"),o.form=e,o.config=function(e,r){for(var t in r)t in e||(e[t]=r[t]);return e}(r||{},n),o.live=!(!1===t),o.fields=Array.from(e.querySelectorAll("input:not([type^=hidden]):not([type^=submit]), select, textarea")).map(function(e){var r=[],t={},n={};return[].forEach.call(e.attributes,(function(e){if(/^data-pristine-/.test(e.name)){var s=e.name.substr(14);if(s.endsWith("-message"))return void(n[s.slice(0,s.length-8)]=e.value);"type"===s&&(s=e.value),l(r,t,s,e.value)}else~i.indexOf(e.name)?l(r,t,e.name,e.value):"type"===e.name&&l(r,t,e.value)})),r.sort((function(e,r){return r.priority-e.priority})),o.live&&e.addEventListener(~["radio","checkbox"].indexOf(e.getAttribute("type"))?"change":"input",function(e){o.validate(e.target)}.bind(o)),e.pristine={input:e,validators:r,params:t,messages:n,self:o}}.bind(o))}(e,t,s),o.validate=function(e,r){r=e&&!0===r||!0===e;var t=o.fields;!0!==e&&!1!==e&&(e instanceof HTMLElement?t=[e.pristine]:(e instanceof NodeList||e instanceof(window.$||Array)||e instanceof Array)&&(t=Array.from(e).map((function(e){return e.pristine}))));for(var n=!0,i=0;t[i];i++){var s=t[i];u(s)?!r&&p(s):(n=!1,!r&&c(s))}return n},o.getErrors=function(e){if(!e){for(var r=[],t=0;t=parseInt(r)}}),o("maxlength",{fn:function(e,r){return!e||e.length<=parseInt(r)}}),o("min",{fn:function(e,r){return!e||("checkbox"===this.type?t(this)>=parseInt(r):parseFloat(e)>=parseFloat(r))}}),o("max",{fn:function(e,r){return!e||("checkbox"===this.type?t(this)<=parseInt(r):parseFloat(e)<=parseFloat(r))}}),o("pattern",{fn:function(e,r){var t=r.match(new RegExp("^/(.*?)/([gimy]*)$"));return!e||new RegExp(t[1],t[2]).test(e)}}),l.addValidator=function(e,r,t,n,i){o(e,{fn:r,msg:t,priority:n,halt:i})},l})); +!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).Pristine=r()}(this,(function(){"use strict";var e={required:"This field is required",email:"This field requires a valid e-mail address",number:"This field requires a number",integer:"This field requires an integer value",url:"This field requires a valid website URL",tel:"This field requires a valid telephone number",maxlength:"This fields length must be < ${1}",minlength:"This fields length must be > ${1}",min:"Minimum value for this field is ${1}",max:"Maximum value for this field is ${1}",pattern:"Please match the requested format"};function r(e){var r=arguments;return this.replace(/\${([^{}]*)}/g,(function(e,t){return r[t]}))}function t(e){return e.pristine.self.form.querySelectorAll('input[name="'+e.getAttribute("name")+'"]:checked').length}var n={classTo:"form-group",errorClass:"has-danger",successClass:"has-success",errorTextParent:"form-group",errorTextTag:"div",errorTextClass:"text-help"},i=["required","min","max","minlength","maxlength","pattern"],s=/^(([^<>()\[\]\\.,;:\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,}))$/,a={},o=function(r,t){t.name=r,t.msg||(t.msg=e[r]),void 0===t.priority&&(t.priority=1),a[r]=t};function l(e,t,s){var o=this;function l(e,r,t,n){var i=a[t];if(i&&(e.push(i),n)){var s=n.split(",");s.unshift(null),r[t]=s}}function u(e){for(var t,n=[],i=!0,s=0;e.validators[s];s++){var a=e.validators[s],o=e.params[a.name]?e.params[a.name]:[];if(o[0]=e.input.value,!a.fn.apply(e.input,o)){if(i=!1,(t=a.msg)&&t.constructor&&t.call&&t.apply)n.push(a.msg(e.input.value,o));else{var l=e.messages[a.name]||a.msg;n.push(r.apply(l,o))}if(!0===a.halt)break}}return e.errors=n,i}function f(e){if(e.errorElements)return e.errorElements;var r=function(e,r){for(;(e=e.parentElement)&&!e.classList.contains(r););return e}(e.input,o.config.classTo),t=null,n=null;return(t=o.config.classTo===o.config.errorTextParent?r:r.querySelector("."+o.config.errorTextParent))&&((n=t.querySelector(".pristine-error"))||((n=document.createElement(o.config.errorTextTag)).className="pristine-error "+o.config.errorTextClass,t.appendChild(n),n.pristineDisplay=n.style.display)),e.errorElements=[r,n]}function c(e){var r=f(e),t=r[0],n=r[1];t&&(t.classList.remove(o.config.successClass),t.classList.add(o.config.errorClass)),n&&(n.innerHTML=e.errors.join("
"),n.style.display=n.pristineDisplay||"")}function p(e){var r=function(e){var r=f(e),t=r[0],n=r[1];return t&&(t.classList.remove(o.config.errorClass),t.classList.remove(o.config.successClass)),n&&(n.innerHTML="",n.style.display="none"),r}(e)[0];r&&r.classList.add(o.config.successClass)}return function(e,r,t){e.setAttribute("novalidate","true"),o.form=e,o.config=function(e,r){for(var t in r)t in e||(e[t]=r[t]);return e}(r||{},n),o.live=!(!1===t),o.fields=Array.from(e.querySelectorAll("input:not([type^=hidden]):not([type^=submit]), select, textarea")).map(function(e){var r=[],t={},n={};return[].forEach.call(e.attributes,(function(e){if(/^data-pristine-/.test(e.name)){var s=e.name.substr(14);if(s.endsWith("-message"))return void(n[s.slice(0,s.length-8)]=e.value);"type"===s&&(s=e.value),l(r,t,s,e.value)}else~i.indexOf(e.name)?l(r,t,e.name,e.value):"type"===e.name&&l(r,t,e.value)})),r.sort((function(e,r){return r.priority-e.priority})),o.live&&e.addEventListener(~["radio","checkbox"].indexOf(e.getAttribute("type"))?"change":"input",function(e){e.target.active=!0}.bind(o)),o.live&&e.addEventListener(~["radio","checkbox"].indexOf(e.getAttribute("type"))?"change":"blur",function(e){e.target.active&&o.validate(e.target)}.bind(o)),e.pristine={input:e,validators:r,params:t,messages:n,self:o}}.bind(o))}(e,t,s),o.validate=function(e,r){r=e&&!0===r||!0===e;var t=o.fields;!0!==e&&!1!==e&&(e instanceof HTMLElement?t=[e.pristine]:(e instanceof NodeList||e instanceof(window.$||Array)||e instanceof Array)&&(t=Array.from(e).map((function(e){return e.pristine}))));for(var n=!0,i=0;t[i];i++){var s=t[i];u(s)?!r&&p(s):(n=!1,!r&&c(s))}return n},o.getErrors=function(e){if(!e){for(var r=[],t=0;t=parseInt(r)}}),o("maxlength",{fn:function(e,r){return!e||e.length<=parseInt(r)}}),o("min",{fn:function(e,r){return!e||("checkbox"===this.type?t(this)>=parseInt(r):parseFloat(e)>=parseFloat(r))}}),o("max",{fn:function(e,r){return!e||("checkbox"===this.type?t(this)<=parseInt(r):parseFloat(e)<=parseFloat(r))}}),o("pattern",{fn:function(e,r){var t=r.match(new RegExp("^/(.*?)/([gimy]*)$"));return!e||new RegExp(t[1],t[2]).test(e)}}),l.addValidator=function(e,r,t,n,i){o(e,{fn:r,msg:t,priority:n,halt:i})},l})); diff --git a/src/pristine.js b/src/pristine.js index 3a19a0b..8f6f3c5 100755 --- a/src/pristine.js +++ b/src/pristine.js @@ -76,7 +76,11 @@ export default function Pristine(form, config, live){ fns.sort( (a, b) => b.priority - a.priority); self.live && input.addEventListener((!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'input':'change'), function(e) { - self.validate(e.target); + e.target.active = true; + }.bind(self)); + + self.live && input.addEventListener((!~['radio', 'checkbox'].indexOf(input.getAttribute('type')) ? 'blur':'change'), function(e) { + e.target.active && self.validate(e.target); }.bind(self)); return input.pristine = {input, validators: fns, params, messages, self};