From 4b4564aae48addcf1c03bc11232b7866ea33c51b Mon Sep 17 00:00:00 2001 From: Guillaume Potier Date: Tue, 22 Jan 2013 15:26:56 +0100 Subject: [PATCH 1/2] -[wip] html validators. min validator failing on Zepto --- dist/parsley-standalone.min.js | 23 ++++++++------- dist/parsley.extend.min.js | 2 +- dist/parsley.min.js | 23 ++++++++------- documentation.html | 6 ++++ i18n/messages.de.js | 3 ++ i18n/messages.fr.js | 12 ++++++-- i18n/messages.is.js | 3 ++ i18n/messages.nl.js | 3 ++ i18n/messages.no.js | 3 ++ parsley.js | 54 +++++++++++++++++++++++++++++----- tests/index.html | 10 +++++++ tests/tests.js | 31 +++++++++++++++++++ 12 files changed, 139 insertions(+), 34 deletions(-) diff --git a/dist/parsley-standalone.min.js b/dist/parsley-standalone.min.js index 782757c3b..8b7c66af6 100644 --- a/dist/parsley-standalone.min.js +++ b/dist/parsley-standalone.min.js @@ -1,4 +1,4 @@ -/* Parsley dist/parsley-standalone.min.js build version 1.1.1 http://parsleyjs.org */ +/* Parsley dist/parsley-standalone.min.js build version 1.1.2 http://parsleyjs.org */ var Zepto=function(){function b(c){return"[object Function]"==M.call(c)}function p(c){return c instanceof Object}function s(c){return p(c)&&c.__proto__==Object.prototype}function t(c){return c instanceof Array}function u(c){return"number"==typeof c.length}function a(c){return c.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function e(c){return c in y?y[c]:y[c]=RegExp("(^|\\s)"+c+"(\\s|$)")}function f(c){return"children"in c?x.call(c.children):d.map(c.childNodes,function(c){if(1==c.nodeType)return c})}function g(c,a,d){for(q in a)d&&s(a[q])?(s(c[q])||(c[q]={}),g(c[q],a[q],d)):a[q]!==m&&(c[q]=a[q])}function n(c,a){return a===m?d(c):d(c).filter(a)}function j(c,a,d,e){return b(a)?a.call(c,d,e):a}function k(c,a){var d=c.className,b=d&&d.baseVal!==m;if(a===m)return b?d.baseVal:d;b?d.baseVal=a:c.className=a}function z(c){var a;try{return c?"true"==c||("false"==c?!1:"null"==c?null:isNaN(a=Number(c))?/^[\[\{]/.test(c)?d.parseJSON(c): c:a):c}catch(b){return c}}function A(c,a){a(c);for(var d in c.childNodes)A(c.childNodes[d],a)}var m,q,d,v,w=[],x=w.slice,B=w.filter,l=window.document,h={},y={},D=l.defaultView.getComputedStyle,G={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},H=/^\s*<(\w+|!)[^>]*>/,N=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,I=/^(?:body|html)$/i,O="val css html text data width height offset".split(" "),E=l.createElement("table"),J=l.createElement("tr"), @@ -45,16 +45,17 @@ e){return void 0===e?b.isPlainObject(a)?this.each(function(e,g){b.each(a,functio required:"This value is required.",regexp:"This value seems to be invalid.",min:"This value should be greater than %s.",max:"This value should be lower than %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or less.",rangelength:"This value length is invalid. It should be between %s and %s characters long.",equalto:"This value should be the same."},validators:{notnull:function(a){return 0< a.length},notblank:function(a){return""!==a.replace(/^\s+/g,"").replace(/\s+$/g,"")},required:function(a){return"object"===typeof a?0=b},maxlength:function(a,b){return a.length<=b},rangelength:function(a,b){return this.minlength(a,b[0])&&this.maxlength(a,b[1])},min:function(a,b){return a>=b},max:function(a,b){return a<=b},range:function(a,b){return a>=b[0]&&a<=b[1]},equalto:function(a,e){return a===b(e).val()},remote:function(a, -e,f){var g={},n={};g[f.$element.attr("name")]=a;"undefined"!==typeof f.options.remoteDatatype&&(n={dataType:f.options.remoteDatatype});var j=function(a){f.updateConstraint("remote","isValid",a);f.manageValidationResult()};b.ajax(b.extend({},{url:e,data:g,async:f.async,method:f.options.remoteMethod||"GET",success:function(a){j("1"===a||"true"==a||"object"===typeof a&&"undefined"!==typeof a.success||/success/i.test(a))},error:function(){j(!1)}},n));f.async&&j(null);return null},mincheck:function(a, -b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var f in b)this.addValidator(f,b[f]);for(f in a)this.addMessage(f,a[f])},formatMesssage:function(a,b){if("object"===typeof b){for(var f in b)a=this.formatMesssage(a,b[f]);return a}return a.replace(/%s/i,b)},addValidator:function(a,b){this.validators[a]=b},addMessage:function(a,b){if("type"===a)for(var f in b)this.messages.type[f]= -b[f];else this.messages[a]=b}};var s=function(a,b,f){this.options=b;this.Validator=new p(b);this.init(a,f||"ParsleyField");return this};s.prototype={constructor:s,init:function(a,e){this.type=e;this.isValid=!0;this.element=a;this.validatedOnce=!1;this.$element=b(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=[];this.isRadioOrCheckbox=!1;this.hash=this.generateHash();this.errorClassHandler=this.options.errors.classHandler(a)||this.$element;if("undefined"!==typeof this.options.required|| -this.$element.hasClass("required")||"required"===this.$element.attr("required"))this.isRequired=this.options.required=!0;this.addConstraints();this.constraints.length&&this.bindValidationEvents()},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&this.constraints.push({name:a,requirements:this.options[a],isValid:null})},bindValidationEvents:function(){this.$element.addClass("parsley-validated");var a=this.options.trigger+(/key/i.test(this.options.trigger)? -"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,b.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"===a.type&&!/keyup/i.test(this.options.trigger)&& -!this.validatedOnce||b.length=b},maxlength:function(a,b){return a.length<=b},rangelength:function(a,b){return this.minlength(a,b[0])&&this.maxlength(a,b[1])},min:function(a,b){return new Number(a)>=new Number(b)},max:function(a,b){return new Number(a)<=new Number(b)},range:function(a,b){return a>=b[0]&&a<=b[1]}, +equalto:function(a,e){return a===b(e).val()},remote:function(a,e,f){var g={},n={};g[f.$element.attr("name")]=a;"undefined"!==typeof f.options.remoteDatatype&&(n={dataType:f.options.remoteDatatype});var j=function(a){f.updateConstraint("remote","isValid",a);f.manageValidationResult()};b.ajax(b.extend({},{url:e,data:g,async:f.async,method:f.options.remoteMethod||"GET",success:function(a){j("1"===a||"true"==a||"object"===typeof a&&"undefined"!==typeof a.success||/success/i.test(a))},error:function(){j(!1)}}, +n));f.async&&j(null);return null},mincheck:function(a,b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var f in b)this.addValidator(f,b[f]);for(f in a)this.addMessage(f,a[f])},formatMesssage:function(a,b){if("object"===typeof b){for(var f in b)a=this.formatMesssage(a,b[f]);return a}return a.replace(/%s/i,b)},addValidator:function(a,b){this.validators[a]=b}, +addMessage:function(a,b){if("type"===a)for(var f in b)this.messages.type[f]=b[f];else this.messages[a]=b}};var s=function(a,b,f){this.options=b;this.Validator=new p(b);this.init(a,f||"ParsleyField");return this};s.prototype={constructor:s,init:function(a,e){this.type=e;this.isValid=!0;this.element=a;this.validatedOnce=!1;this.$element=b(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=[];this.isRadioOrCheckbox=!1;this.hash=this.generateHash();this.errorClassHandler=this.options.errors.classHandler(a)|| +this.$element;this.bindHtml5Constraints();this.addConstraints();this.constraints.length&&this.bindValidationEvents()},bindHtml5Constraints:function(){if(this.$element.hasClass("required")||this.$element.attr("required"))this.options.required=!0;"undefined"!==typeof this.$element.attr("type")&&RegExp(this.$element.attr("type"),"i").test("email url number range")&&(this.options.type=this.$element.attr("type"),RegExp(this.options.type,"i").test("number range")&&(this.options.type="number","undefined"!== +typeof this.$element.attr("min")&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&(this.options.max=this.$element.attr("max"))))},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&(this.constraints.push({name:a,requirements:this.options[a],isValid:null}),"required"===a&&(this.isRequired=!0))},bindValidationEvents:function(){this.$element.addClass("parsley-validated");var a=this.options.trigger+ +(/key/i.test(this.options.trigger)?"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,b.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"=== +a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||b.length=b},maxwords:function(a,b){a=a.replace(/(^\s*)|(\s*$)/gi,"");a=a.replace(/[ ]{2,}/gi," ");a=a.replace(/\n /,"\n");a=a.split(" ").length;return a<=b},rangewords:function(a,b){a=a.replace(/(^\s*)|(\s*$)/gi,"");a=a.replace(/[ ]{2,}/gi," ");a=a.replace(/\n /,"\n");a=a.split(" ").length; return a>=b[0]&&a<=b[1]},greaterthan:function(a,b){return new Number(a)>new Number(c(b).val())},lessthan:function(a,b){return new Number(a)=b},maxlength:function(a,b){return a.length<=b},rangelength:function(a,b){return this.minlength(a,b[0])&&this.maxlength(a,b[1])},min:function(a,b){return a>=b},max:function(a,b){return a<=b},range:function(a,b){return a>=b[0]&&a<=b[1]},equalto:function(a,b){return a===d(b).val()},remote:function(a, -b,c){var e={},f={};e[c.$element.attr("name")]=a;"undefined"!==typeof c.options.remoteDatatype&&(f={dataType:c.options.remoteDatatype});var l=function(a){c.updateConstraint("remote","isValid",a);c.manageValidationResult()};d.ajax(d.extend({},{url:b,data:e,async:c.async,method:c.options.remoteMethod||"GET",success:function(a){l("1"===a||"true"==a||"object"===typeof a&&"undefined"!==typeof a.success||/success/i.test(a))},error:function(){l(!1)}},f));c.async&&l(null);return null},mincheck:function(a, -b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var c in b)this.addValidator(c,b[c]);for(c in a)this.addMessage(c,a[c])},formatMesssage:function(a,b){if("object"===typeof b){for(var c in b)a=this.formatMesssage(a,b[c]);return a}return a.replace(/%s/i,b)},addValidator:function(a,b){this.validators[a]=b},addMessage:function(a,b){if("type"===a)for(var c in b)this.messages.type[c]= -b[c];else this.messages[a]=b}};var h=function(a,b,c){this.options=b;this.Validator=new k(b);this.init(a,c||"ParsleyField");return this};h.prototype={constructor:h,init:function(a,b){this.type=b;this.isValid=!0;this.element=a;this.validatedOnce=!1;this.$element=d(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=[];this.isRadioOrCheckbox=!1;this.hash=this.generateHash();this.errorClassHandler=this.options.errors.classHandler(a)||this.$element;if("undefined"!==typeof this.options.required|| -this.$element.hasClass("required")||"required"===this.$element.attr("required"))this.isRequired=this.options.required=!0;this.addConstraints();this.constraints.length&&this.bindValidationEvents()},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&this.constraints.push({name:a,requirements:this.options[a],isValid:null})},bindValidationEvents:function(){this.$element.addClass("parsley-validated");var a=this.options.trigger+(/key/i.test(this.options.trigger)? -"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,d.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"===a.type&&!/keyup/i.test(this.options.trigger)&& -!this.validatedOnce||b.length=b},maxlength:function(a,b){return a.length<=b},rangelength:function(a,b){return this.minlength(a,b[0])&&this.maxlength(a,b[1])},min:function(a,b){return new Number(a)>=new Number(b)},max:function(a,b){return new Number(a)<=new Number(b)},range:function(a,b){return a>=b[0]&&a<=b[1]}, +equalto:function(a,b){return a===d(b).val()},remote:function(a,b,c){var e={},f={};e[c.$element.attr("name")]=a;"undefined"!==typeof c.options.remoteDatatype&&(f={dataType:c.options.remoteDatatype});var l=function(a){c.updateConstraint("remote","isValid",a);c.manageValidationResult()};d.ajax(d.extend({},{url:b,data:e,async:c.async,method:c.options.remoteMethod||"GET",success:function(a){l("1"===a||"true"==a||"object"===typeof a&&"undefined"!==typeof a.success||/success/i.test(a))},error:function(){l(!1)}}, +f));c.async&&l(null);return null},mincheck:function(a,b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var c in b)this.addValidator(c,b[c]);for(c in a)this.addMessage(c,a[c])},formatMesssage:function(a,b){if("object"===typeof b){for(var c in b)a=this.formatMesssage(a,b[c]);return a}return a.replace(/%s/i,b)},addValidator:function(a,b){this.validators[a]=b}, +addMessage:function(a,b){if("type"===a)for(var c in b)this.messages.type[c]=b[c];else this.messages[a]=b}};var h=function(a,b,c){this.options=b;this.Validator=new k(b);this.init(a,c||"ParsleyField");return this};h.prototype={constructor:h,init:function(a,b){this.type=b;this.isValid=!0;this.element=a;this.validatedOnce=!1;this.$element=d(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=[];this.isRadioOrCheckbox=!1;this.hash=this.generateHash();this.errorClassHandler=this.options.errors.classHandler(a)|| +this.$element;this.bindHtml5Constraints();this.addConstraints();this.constraints.length&&this.bindValidationEvents()},bindHtml5Constraints:function(){if(this.$element.hasClass("required")||this.$element.attr("required"))this.options.required=!0;"undefined"!==typeof this.$element.attr("type")&&RegExp(this.$element.attr("type"),"i").test("email url number range")&&(this.options.type=this.$element.attr("type"),RegExp(this.options.type,"i").test("number range")&&(this.options.type="number","undefined"!== +typeof this.$element.attr("min")&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&(this.options.max=this.$element.attr("max"))))},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&(this.constraints.push({name:a,requirements:this.options[a],isValid:null}),"required"===a&&(this.isRequired=!0))},bindValidationEvents:function(){this.$element.addClass("parsley-validated");var a=this.options.trigger+ +(/key/i.test(this.options.trigger)?"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,d.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"=== +a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||b.lengthBasic constraints Min data-min="6" + type="number" min="6" Validates that a given number is greater than some minimum number. @@ -529,6 +530,7 @@

Basic constraints

Max data-max="100" + type="number" max="100" Validates that a given number is less than some maximum number. @@ -554,6 +556,7 @@

Basic constraints

Range data-range="[6, 100]" + type="range" min="6" max="100" Validates that a given number is between some minimum and maximum number. @@ -736,6 +739,7 @@

Type constraints

Email data-type="email" + type="email" Validates that a value is a valid email address. @@ -761,6 +765,7 @@

Type constraints

Url data-type="url" + type="url" Validates that a value is a valid url. @@ -836,6 +841,7 @@

Type constraints

Number data-type="number" + type="number" Validates that a value is a valid number. diff --git a/i18n/messages.de.js b/i18n/messages.de.js index 435e9a3a3..cc32a47ce 100644 --- a/i18n/messages.de.js +++ b/i18n/messages.de.js @@ -3,6 +3,7 @@ window.ParsleyConfig = window.ParsleyConfig || {}; (function ($) { window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, { messages: { + // parsley ////////////////////////////////////// defaultMessage: "Die Eingabe scheint nicht korrekt zu sein." , type: { email: "Die Eingabe muss eine gültige E-Mail-Adresse sein." @@ -24,6 +25,8 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , maxlength: "Die Eingabe ist zu lang. Es dürfen höchstens %s Zeichen eingegeben werden." , rangelength: "Die Länge der Eingabe ist ungültig. Es müssen zwischen %s und %s Zeichen eingegeben werden." , equalto: "Die Eingabe darf nicht identisch sein." + + // parsley.extend /////////////////////////////// } }); }(window.jQuery || window.Zepto)); diff --git a/i18n/messages.fr.js b/i18n/messages.fr.js index 7e9010716..5ef78e80c 100644 --- a/i18n/messages.fr.js +++ b/i18n/messages.fr.js @@ -3,7 +3,8 @@ window.ParsleyConfig = window.ParsleyConfig || {}; (function ($) { window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, { messages: { - defaultMessage: "Cette valeur semble non valide." + // parsley ////////////////////////////////////// + defaultMessage: "Cette valeur semble invalide." , type: { email: "Cette valeur n'est pas une adresse email valide." , url: "Cette valeur n'est pas une URL valide." @@ -13,8 +14,8 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , dateIso: "Cette valeur n'est pas une date valide (YYYY-MM-DD)." , alphanum: "Cette valeur doit être alphanumérique." } - , notnull: "Cette valeur ne peux pas être nulle." - , notblank: "Cette valeur ne peux pas être vide." + , notnull: "Cette valeur ne peut pas être nulle." + , notblank: "Cette valeur ne peut pas être vide." , required: "Ce champ est requis." , regexp: "Cette valeur semble non valide." , min: "Cette valeur ne doit pas être inféreure à %s." @@ -24,6 +25,11 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , maxlength: "Cette chaîne est trop longue. Elle doit avoir au maximum %s caractères." , rangelength: "Cette valeur doit contenir entre %s et %s caractères." , equalto: "Cette valeur devrait être identique." + + // parsley.extend /////////////////////////////// + , minwords: "Cette valeur doit contenir plus de %s mots." + , maxwords: "Cette valeur ne peut pas dépasser %s mots." + , rangewords: "Cette valeur doit comprendre %s à %s mots." } }); }(window.jQuery || window.Zepto)); diff --git a/i18n/messages.is.js b/i18n/messages.is.js index 024050fca..3d60fde02 100644 --- a/i18n/messages.is.js +++ b/i18n/messages.is.js @@ -3,6 +3,7 @@ window.ParsleyConfig = window.ParsleyConfig || {}; (function ($) { window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, { messages: { + // parsley ////////////////////////////////////// defaultMessage: "Þetta gildi virðist vera ógilt." , type: { email: "Þetta ætti að vera gilt netfang." @@ -24,6 +25,8 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , maxlength: "Þetta gildi er of langt. Það ætti að innihalda %s stafi eða færri." , rangelength: "Þetta gildi er ógilt. Það ætti að vera %s-%s stafir að lengd." , equalto: "Þetta gildi ætti að vera eins." + + // parsley.extend /////////////////////////////// } }); }(window.jQuery || window.Zepto)); diff --git a/i18n/messages.nl.js b/i18n/messages.nl.js index 9bcbac1ac..f740376f7 100644 --- a/i18n/messages.nl.js +++ b/i18n/messages.nl.js @@ -3,6 +3,7 @@ window.ParsleyConfig = window.ParsleyConfig || {}; (function ($) { window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, { messages: { + // parsley ////////////////////////////////////// defaultMessage: "Deze waarde lijkt onjuist." , type: { email: "Dit lijkt geen geldig e-mail adres te zijn." @@ -24,6 +25,8 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , maxlength: "Deze waarde is te lang. Deze mag maximaal %s karakters lang zijn." , rangelength: "Deze waarde moet tussen %s en %s karakters lang zijn." , equalto: "Deze waardes moeten identiek zijn." + + // parsley.extend /////////////////////////////// } }); }(window.jQuery || window.Zepto)); \ No newline at end of file diff --git a/i18n/messages.no.js b/i18n/messages.no.js index ac316d43d..9d2559f1a 100644 --- a/i18n/messages.no.js +++ b/i18n/messages.no.js @@ -3,6 +3,7 @@ window.ParsleyConfig = window.ParsleyConfig || {}; (function ($) { window.ParsleyConfig = $.extend( true, {}, window.ParsleyConfig, { messages: { + // parsley ////////////////////////////////////// defaultMessage: "Denne verdien er ikke gyldig." , type: { email: "Denne verdien må være en gyldig e-post." @@ -24,6 +25,8 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , maxlength: "Denne verdien er for lang. Den må ikke være lenger enn %s tegn." , rangelength: "Denne verdien har feil lengde. Lengden må være mellom %s og %s tegn." , equalto: "Denne verdien må være lik." + + // parsley.extend /////////////////////////////// } }); }(window.jQuery || window.Zepto)); diff --git a/parsley.js b/parsley.js index a8505c42d..9e77dce25 100644 --- a/parsley.js +++ b/parsley.js @@ -129,11 +129,11 @@ } , min: function ( val, min ) { - return val >= min; + return new Number( val ) >= new Number( min ); } , max: function ( val, max ) { - return val <= max; + return new Number( val ) <= new Number( max ); } , range: function ( val, arrayRange ) { @@ -234,7 +234,7 @@ return message; } - return message.replace(new RegExp("%s", "i"), args); + return message.replace(new RegExp( "%s", "i" ), args); } /** @@ -312,10 +312,7 @@ this.hash = this.generateHash(); this.errorClassHandler = this.options.errors.classHandler( element ) || this.$element; - // a field is required if data-required="true" or class="required" or required="required" - if ( 'undefined' !== typeof this.options[ 'required' ] || this.$element.hasClass( 'required' ) || this.$element.attr( 'required' ) === 'required' ) { - this.isRequired = this.options[ 'required' ] = true; - } + this.bindHtml5Constraints(); // bind validators to field this.addConstraints(); @@ -326,6 +323,36 @@ } } + /** + * Bind some extra html5 types / validators + * + * @method bindHtml5Constraints + */ + , bindHtml5Constraints: function () { + // add html5 required support + class required support + if ( this.$element.hasClass( 'required' ) || this.$element.attr( 'required' ) ) { + this.options.required = true; + } + + // add html5 supported types & options + if ( 'undefined' !== typeof this.$element.attr( 'type' ) && new RegExp( this.$element.attr( 'type' ), "i" ).test( "email url number range" ) ) { + this.options.type = this.$element.attr( 'type' ); + + // number and range types could have min and/or max values + if ( new RegExp( this.options.type, "i" ).test( "number range" ) ) { + this.options.type = "number"; + + if ( 'undefined' !== typeof this.$element.attr( 'min' ) ) { + this.options.min = this.$element.attr( 'min' ); + } + + if ( 'undefined' !== typeof this.$element.attr( 'max' ) ) { + this.options.max = this.$element.attr( 'max' ); + } + } + } + } + /** * Attach field validators functions passed through data-api * @@ -339,6 +366,10 @@ , requirements: this.options[ constraint ] , isValid: null } ); + + if ( constraint === "required" ) { + this.isRequired = true; + } } } } @@ -470,6 +501,13 @@ return isValid; } + /** + * Check if value has changed since previous validation + * + * @method needsValidation + * @param value + * @return {Boolean} + */ , needsValidation: function ( val ) { if ( this.val === val && this.validatedOnce ) { return false; @@ -589,7 +627,7 @@ * @method reset */ , reset: function () { - this.isValid = true; + this.isValid = null; this.removeErrors(); this.errorClassHandler.removeClass( this.options.successClass ).removeClass( this.options.errorClass ); } diff --git a/tests/index.html b/tests/index.html index 5647046b6..418e8656e 100644 --- a/tests/index.html +++ b/tests/index.html @@ -62,17 +62,27 @@ + + + + + + + + + + diff --git a/tests/tests.js b/tests/tests.js index 64ad15529..3859bcdda 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -200,6 +200,15 @@ var testSuite = function () { triggerSubmitValidation( '#required-html5', ' foo' ); expect( $( '#required-html5' ).hasClass( 'parsley-success' ) ).to.be( true ); } ) + it ( 'required - html5-api bis', function () { + triggerSubmitValidation( '#required-html5-bis', '' ); + expect( $( '#required-html5-bis' ).hasClass( 'parsley-error' ) ).to.be( true ); + expect( getErrorMessage( '#required-html5-bis', 'required') ).to.be( 'This value is required.' ); + triggerSubmitValidation( '#required-html5-bis', ' ' ); + expect( $( '#required-html5-bis' ).hasClass( 'parsley-error' ) ).to.be( true ); + triggerSubmitValidation( '#required-html5-bis', ' foo' ); + expect( $( '#required-html5-bis' ).hasClass( 'parsley-success' ) ).to.be( true ); + } ) it ( 'minlength', function () { triggerSubmitValidation( '#minlength', '12345' ); expect( $( '#minlength' ).hasClass( 'parsley-error' ) ).to.be( true ); @@ -228,6 +237,14 @@ var testSuite = function () { triggerSubmitValidation( '#min', '12' ); expect( $( '#min' ).hasClass( 'parsley-success' ) ).to.be( true ); } ) + it ( 'min html5', function () { + triggerSubmitValidation( '#min-html5', 12 ); + expect( $( '#min-html5' ).hasClass( 'parsley-success' ) ).to.be( true ); + } ) + it ( 'max html5', function () { + triggerSubmitValidation( '#max-html5', 8 ); + expect( $( '#max-html5' ).hasClass( 'parsley-success' ) ).to.be( true ); + } ) it ( 'max', function () { triggerSubmitValidation( '#max', '12' ); expect( $( '#max' ).hasClass( 'parsley-error' ) ).to.be( true ); @@ -263,6 +280,8 @@ var testSuite = function () { , { url: "foo", expected: false, strict: false } , { url: "foo:bar", expected: false, strict: false } , { url: "foo://bar", expected: false, strict: false } + + // absolutely finish by false to test error message , { url: "ého", expected: false, strict: false } ]; @@ -274,6 +293,10 @@ var testSuite = function () { triggerSubmitValidation( '#typeurl', 'foo' ); expect( getErrorMessage( '#typeurl', 'type') ).to.be( 'This value should be a valid url.' ); } ) + it ( 'url html5', function () { + $( '#typeurl-html5' ).val( "http://foo.bar" ); + expect( $( '#typeurl-html5' ).parsley( 'validate' ) ).to.be( true ); + } ) it ( 'url strict + global config overriding type message', function () { for ( var i in urls ) { $( '#typeurlstrict' ).val( urls[i].url ); @@ -295,6 +318,14 @@ var testSuite = function () { triggerSubmitValidation( '#typeemail', 'foo.bar@bar.com.ext' ); expect( $( '#typeemail' ).hasClass( 'parsley-success' ) ).to.be( true ); } ) + it ( 'email html5', function () { + triggerSubmitValidation( '#typeemail-html5', 'foo@bar.com' ); + expect( $( '#typeemail-html5' ).hasClass( 'parsley-success' ) ).to.be( true ); + } ) + it ( 'range html5', function () { + triggerSubmitValidation( '#typerange-html5', 8 ); + expect( $( '#typerange-html5' ).hasClass( 'parsley-success' ) ).to.be( true ); + } ) it ( 'digits', function () { triggerSubmitValidation( '#typedigits', 'foo' ); expect( $( '#typedigits' ).hasClass( 'parsley-error' ) ).to.be( true ); From d3f4eb956a6f3636deeb7cf16190e73b843fd65f Mon Sep 17 00:00:00 2001 From: Guillaume Potier Date: Tue, 22 Jan 2013 23:36:32 +0100 Subject: [PATCH 2/2] - fixed test suite for html5 types validation + added new parsley.extend validator messages in fr --- dist/parsley-standalone.min.js | 28 ++++++++++++++-------------- dist/parsley.min.js | 28 ++++++++++++++-------------- i18n/messages.fr.js | 8 +++++--- parsley.extend.js | 6 +++--- parsley.js | 5 +++-- 5 files changed, 39 insertions(+), 36 deletions(-) diff --git a/dist/parsley-standalone.min.js b/dist/parsley-standalone.min.js index 8b7c66af6..24ff082d9 100644 --- a/dist/parsley-standalone.min.js +++ b/dist/parsley-standalone.min.js @@ -50,17 +50,17 @@ equalto:function(a,e){return a===b(e).val()},remote:function(a,e,f){var g={},n={ n));f.async&&j(null);return null},mincheck:function(a,b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var f in b)this.addValidator(f,b[f]);for(f in a)this.addMessage(f,a[f])},formatMesssage:function(a,b){if("object"===typeof b){for(var f in b)a=this.formatMesssage(a,b[f]);return a}return a.replace(/%s/i,b)},addValidator:function(a,b){this.validators[a]=b}, addMessage:function(a,b){if("type"===a)for(var f in b)this.messages.type[f]=b[f];else this.messages[a]=b}};var s=function(a,b,f){this.options=b;this.Validator=new p(b);this.init(a,f||"ParsleyField");return this};s.prototype={constructor:s,init:function(a,e){this.type=e;this.isValid=!0;this.element=a;this.validatedOnce=!1;this.$element=b(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=[];this.isRadioOrCheckbox=!1;this.hash=this.generateHash();this.errorClassHandler=this.options.errors.classHandler(a)|| this.$element;this.bindHtml5Constraints();this.addConstraints();this.constraints.length&&this.bindValidationEvents()},bindHtml5Constraints:function(){if(this.$element.hasClass("required")||this.$element.attr("required"))this.options.required=!0;"undefined"!==typeof this.$element.attr("type")&&RegExp(this.$element.attr("type"),"i").test("email url number range")&&(this.options.type=this.$element.attr("type"),RegExp(this.options.type,"i").test("number range")&&(this.options.type="number","undefined"!== -typeof this.$element.attr("min")&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&(this.options.max=this.$element.attr("max"))))},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&(this.constraints.push({name:a,requirements:this.options[a],isValid:null}),"required"===a&&(this.isRequired=!0))},bindValidationEvents:function(){this.$element.addClass("parsley-validated");var a=this.options.trigger+ -(/key/i.test(this.options.trigger)?"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,b.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"=== -a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||b.length",errorElem:"
  • "},listeners:{onFieldValidate:function(){return!1},onFormSubmit:function(){},onFieldError:function(){}, -onFieldSuccess:function(){}}};b(window).on("load",function(){b.fn.parsley.defaults=b.extend(!0,{},b.fn.parsley.defaults,"undefined"!==typeof window.ParsleyConfig?ParsleyConfig:{});b('[data-validate="parsley"]').each(function(){b(this).parsley()})})}(window.jQuery||window.Zepto); +typeof this.$element.attr("min")&&this.$element.attr("min").length&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&this.$element.attr("max").length&&(this.options.max=this.$element.attr("max"))))},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&(this.constraints.push({name:a,requirements:this.options[a],isValid:null}),"required"===a&&(this.isRequired=!0))},bindValidationEvents:function(){this.$element.addClass("parsley-validated"); +var a=this.options.trigger+(/key/i.test(this.options.trigger)?"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,b.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b= +this.getVal();if("keyup"===a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||b.length",errorElem:"
  • "},listeners:{onFieldValidate:function(){return!1},onFormSubmit:function(){},onFieldError:function(){},onFieldSuccess:function(){}}};b(window).on("load",function(){b.fn.parsley.defaults=b.extend(!0,{},b.fn.parsley.defaults,"undefined"!==typeof window.ParsleyConfig?ParsleyConfig:{});b('[data-validate="parsley"]').each(function(){b(this).parsley()})})}(window.jQuery||window.Zepto); diff --git a/dist/parsley.min.js b/dist/parsley.min.js index 8616aff37..f465fa122 100644 --- a/dist/parsley.min.js +++ b/dist/parsley.min.js @@ -8,17 +8,17 @@ equalto:function(a,b){return a===d(b).val()},remote:function(a,b,c){var e={},f={ f));c.async&&l(null);return null},mincheck:function(a,b){return this.minlength(a,b)},maxcheck:function(a,b){return this.maxlength(a,b)},rangecheck:function(a,b){return this.rangelength(a,b)}},init:function(a){var b=a.validators;a=a.messages;for(var c in b)this.addValidator(c,b[c]);for(c in a)this.addMessage(c,a[c])},formatMesssage:function(a,b){if("object"===typeof b){for(var c in b)a=this.formatMesssage(a,b[c]);return a}return a.replace(/%s/i,b)},addValidator:function(a,b){this.validators[a]=b}, addMessage:function(a,b){if("type"===a)for(var c in b)this.messages.type[c]=b[c];else this.messages[a]=b}};var h=function(a,b,c){this.options=b;this.Validator=new k(b);this.init(a,c||"ParsleyField");return this};h.prototype={constructor:h,init:function(a,b){this.type=b;this.isValid=!0;this.element=a;this.validatedOnce=!1;this.$element=d(a);this.val=this.$element.val();this.isRequired=!1;this.constraints=[];this.isRadioOrCheckbox=!1;this.hash=this.generateHash();this.errorClassHandler=this.options.errors.classHandler(a)|| this.$element;this.bindHtml5Constraints();this.addConstraints();this.constraints.length&&this.bindValidationEvents()},bindHtml5Constraints:function(){if(this.$element.hasClass("required")||this.$element.attr("required"))this.options.required=!0;"undefined"!==typeof this.$element.attr("type")&&RegExp(this.$element.attr("type"),"i").test("email url number range")&&(this.options.type=this.$element.attr("type"),RegExp(this.options.type,"i").test("number range")&&(this.options.type="number","undefined"!== -typeof this.$element.attr("min")&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&(this.options.max=this.$element.attr("max"))))},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&(this.constraints.push({name:a,requirements:this.options[a],isValid:null}),"required"===a&&(this.isRequired=!0))},bindValidationEvents:function(){this.$element.addClass("parsley-validated");var a=this.options.trigger+ -(/key/i.test(this.options.trigger)?"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,d.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b=this.getVal();if("keyup"=== -a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||b.length",errorElem:"
  • "},listeners:{onFieldValidate:function(){return!1},onFormSubmit:function(){},onFieldError:function(){}, -onFieldSuccess:function(){}}};d(window).on("load",function(){d.fn.parsley.defaults=d.extend(!0,{},d.fn.parsley.defaults,"undefined"!==typeof window.ParsleyConfig?ParsleyConfig:{});d('[data-validate="parsley"]').each(function(){d(this).parsley()})})}(window.jQuery||window.Zepto); +typeof this.$element.attr("min")&&this.$element.attr("min").length&&(this.options.min=this.$element.attr("min")),"undefined"!==typeof this.$element.attr("max")&&this.$element.attr("max").length&&(this.options.max=this.$element.attr("max"))))},addConstraints:function(){for(var a in this.options)"function"===typeof this.Validator.validators[a.toLowerCase()]&&(this.constraints.push({name:a,requirements:this.options[a],isValid:null}),"required"===a&&(this.isRequired=!0))},bindValidationEvents:function(){this.$element.addClass("parsley-validated"); +var a=this.options.trigger+(/key/i.test(this.options.trigger)?"":" keyup");this.options.remote&&(a+=/change/i.test(a)?"":" change");if(a)this.$element.on(a.split(" ").join("."+this.type+" "),!1,d.proxy(this.eventValidation,this))},generateHash:function(){for(var a="",b=0;5>b;b++)a+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(Math.floor(52*Math.random()));return a},getHash:function(){return this.hash},getVal:function(){return this.$element.val()},eventValidation:function(a){var b= +this.getVal();if("keyup"===a.type&&!/keyup/i.test(this.options.trigger)&&!this.validatedOnce||b.length",errorElem:"
  • "},listeners:{onFieldValidate:function(){return!1},onFormSubmit:function(){},onFieldError:function(){},onFieldSuccess:function(){}}};d(window).on("load",function(){d.fn.parsley.defaults=d.extend(!0,{},d.fn.parsley.defaults,"undefined"!==typeof window.ParsleyConfig?ParsleyConfig:{});d('[data-validate="parsley"]').each(function(){d(this).parsley()})})}(window.jQuery||window.Zepto); diff --git a/i18n/messages.fr.js b/i18n/messages.fr.js index 5ef78e80c..eac322201 100644 --- a/i18n/messages.fr.js +++ b/i18n/messages.fr.js @@ -27,9 +27,11 @@ window.ParsleyConfig = window.ParsleyConfig || {}; , equalto: "Cette valeur devrait être identique." // parsley.extend /////////////////////////////// - , minwords: "Cette valeur doit contenir plus de %s mots." - , maxwords: "Cette valeur ne peut pas dépasser %s mots." - , rangewords: "Cette valeur doit comprendre %s à %s mots." + , minwords: "Cette valeur doit contenir plus de %s mots." + , maxwords: "Cette valeur ne peut pas dépasser %s mots." + , rangewords: "Cette valeur doit comprendre %s à %s mots." + , greaterthan: "Cette valeur doit être plus grande que %s." + , lessthan: "Cette valeur doit être plus petite que %s." } }); }(window.jQuery || window.Zepto)); diff --git a/parsley.extend.js b/parsley.extend.js index 14d013532..0d8e55ffb 100644 --- a/parsley.extend.js +++ b/parsley.extend.js @@ -39,9 +39,9 @@ window.ParsleyConfig = window.ParsleyConfig || {}; } } , messages: { - minwords: "This value should have %s words at least." - , maxwords: "This value should have %s words maximum." - , rangewords: "This value should have between %s and %s words." + minwords: "This value should have %s words at least." + , maxwords: "This value should have %s words maximum." + , rangewords: "This value should have between %s and %s words." , greaterthan: "This value should be greater than %s." , lessthan: "This value should be less than %s." } diff --git a/parsley.js b/parsley.js index 9e77dce25..ea1fe0656 100644 --- a/parsley.js +++ b/parsley.js @@ -342,11 +342,12 @@ if ( new RegExp( this.options.type, "i" ).test( "number range" ) ) { this.options.type = "number"; - if ( 'undefined' !== typeof this.$element.attr( 'min' ) ) { + // double condition to support jQuery and Zepto.. :( + if ( 'undefined' !== typeof this.$element.attr( 'min' ) && this.$element.attr( 'min' ).length ) { this.options.min = this.$element.attr( 'min' ); } - if ( 'undefined' !== typeof this.$element.attr( 'max' ) ) { + if ( 'undefined' !== typeof this.$element.attr( 'max' ) && this.$element.attr( 'max' ).length ) { this.options.max = this.$element.attr( 'max' ); } }