| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129 |
- /*!
- * Parsleyjs
- * Guillaume Potier - <guillaume@wisembly.com>
- * Version 2.0.3 - built Mon Jul 21 2014 11:58:33
- * MIT Licensed
- *
- */
- !(function (factory) {
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module depending on jQuery.
- define(['jquery'], factory);
- } else {
- // No AMD. Register plugin with global jQuery object.
- factory(jQuery);
- }
- }(function ($) {
- // small hack for requirejs if jquery is loaded through map and not path
- // see http://requirejs.org/docs/jquery.html
- if ('undefined' === typeof $ && 'undefined' !== typeof window.jQuery)
- $ = window.jQuery;
- var ParsleyUtils = {
- // Parsley DOM-API
- // returns object from dom attributes and values
- // if attr is given, returns bool if attr present in DOM or not
- attr: function ($element, namespace, checkAttr) {
- var
- attribute,
- obj = {},
- msie = this.msieversion(),
- regex = new RegExp('^' + namespace, 'i');
- if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
- return {};
- for (var i in $element[0].attributes) {
- attribute = $element[0].attributes[i];
- if ('undefined' !== typeof attribute && null !== attribute && (!msie || msie >= 8 || attribute.specified) && regex.test(attribute.name)) {
- if ('undefined' !== typeof checkAttr && new RegExp(checkAttr + '$', 'i').test(attribute.name))
- return true;
- obj[this.camelize(attribute.name.replace(namespace, ''))] = this.deserializeValue(attribute.value);
- }
- }
- return 'undefined' === typeof checkAttr ? obj : false;
- },
- setAttr: function ($element, namespace, attr, value) {
- $element[0].setAttribute(this.dasherize(namespace + attr), String(value));
- },
- // Recursive object / array getter
- get: function (obj, path) {
- var
- i = 0,
- paths = (path || '').split('.');
- while (this.isObject(obj) || this.isArray(obj)) {
- obj = obj[paths[i++]];
- if (i === paths.length)
- return obj;
- }
- return undefined;
- },
- hash: function (length) {
- return String(Math.random()).substring(2, length ? length + 2 : 9);
- },
- /** Third party functions **/
- // Underscore isArray
- isArray: function (mixed) {
- return Object.prototype.toString.call(mixed) === '[object Array]';
- },
- // Underscore isObject
- isObject: function (mixed) {
- return mixed === Object(mixed);
- },
- // Zepto deserialize function
- deserializeValue: function (value) {
- var num;
- try {
- return value ?
- value == "true" ||
- (value == "false" ? false :
- value == "null" ? null :
- !isNaN(num = Number(value)) ? num :
- /^[\[\{]/.test(value) ? $.parseJSON(value) :
- value)
- : value;
- } catch (e) { return value; }
- },
- // Zepto camelize function
- camelize: function (str) {
- return str.replace(/-+(.)?/g, function(match, chr) {
- return chr ? chr.toUpperCase() : '';
- });
- },
- // Zepto dasherize function
- dasherize: function (str) {
- return str.replace(/::/g, '/')
- .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
- .replace(/([a-z\d])([A-Z])/g, '$1_$2')
- .replace(/_/g, '-')
- .toLowerCase();
- },
- // http://support.microsoft.com/kb/167820
- // http://stackoverflow.com/questions/19999388/jquery-check-if-user-is-using-ie
- msieversion: function () {
- var
- ua = window.navigator.userAgent,
- msie = ua.indexOf('MSIE ');
- if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./))
- return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
- return 0;
- }
- };
- // All these options could be overriden and specified directly in DOM using
- // `data-parsley-` default DOM-API
- // eg: `inputs` can be set in DOM using `data-parsley-inputs="input, textarea"`
- // eg: `data-parsley-stop-on-first-failing-constraint="false"`
- var ParsleyDefaults = {
- // ### General
- // Default data-namespace for DOM API
- namespace: 'data-parsley-',
- // Supported inputs by default
- inputs: 'input, textarea, select',
- // Excluded inputs by default
- excluded: 'input[type=button], input[type=submit], input[type=reset], input[type=hidden]',
- // Stop validating field on highest priority failing constraint
- priorityEnabled: true,
- // ### UI
- // Enable\Disable error messages
- uiEnabled: true,
- // Key events threshold before validation
- validationThreshold: 3,
- // Focused field on form validation error. 'fist'|'last'|'none'
- focus: 'first',
- // `$.Event()` that will trigger validation. eg: `keyup`, `change`..
- trigger: false,
- // Class that would be added on every failing validation Parsley field
- errorClass: 'parsley-error',
- // Same for success validation
- successClass: 'parsley-success',
- // Return the `$element` that will receive these above success or error classes
- // Could also be (and given directly from DOM) a valid selector like `'#div'`
- classHandler: function (ParsleyField) {},
- // Return the `$element` where errors will be appended
- // Could also be (and given directly from DOM) a valid selector like `'#div'`
- errorsContainer: function (ParsleyField) {},
- // ul elem that would receive errors' list
- errorsWrapper: '<ul class="parsley-errors-list"></ul>',
- // li elem that would receive error message
- errorTemplate: '<li></li>'
- };
- var ParsleyAbstract = function() {};
- ParsleyAbstract.prototype = {
- asyncSupport: false,
- actualizeOptions: function () {
- this.options = this.OptionsFactory.get(this);
- return this;
- },
- // ParsleyValidator validate proxy function . Could be replaced by third party scripts
- validateThroughValidator: function (value, constraints, priority) {
- return window.ParsleyValidator.validate.apply(window.ParsleyValidator, [value, constraints, priority]);
- },
- // Subscribe an event and a handler for a specific field or a specific form
- // If on a ParsleyForm instance, it will be attached to form instance and also
- // To every field instance for this form
- subscribe: function (name, fn) {
- $.listenTo(this, name.toLowerCase(), fn);
- return this;
- },
- // Same as subscribe above. Unsubscribe an event for field, or form + its fields
- unsubscribe: function (name) {
- $.unsubscribeTo(this, name.toLowerCase());
- return this;
- },
- // Reset UI
- reset: function () {
- // Field case: just emit a reset event for UI
- if ('ParsleyForm' !== this.__class__)
- return $.emit('parsley:field:reset', this);
- // Form case: emit a reset event for each field
- for (var i = 0; i < this.fields.length; i++)
- $.emit('parsley:field:reset', this.fields[i]);
- $.emit('parsley:form:reset', this);
- },
- // Destroy Parsley instance (+ UI)
- destroy: function () {
- // Field case: emit destroy event to clean UI and then destroy stored instance
- if ('ParsleyForm' !== this.__class__) {
- this.$element.removeData('Parsley');
- this.$element.removeData('ParsleyFieldMultiple');
- $.emit('parsley:field:destroy', this);
- return;
- }
- // Form case: destroy all its fields and then destroy stored instance
- for (var i = 0; i < this.fields.length; i++)
- this.fields[i].destroy();
- this.$element.removeData('Parsley');
- $.emit('parsley:form:destroy', this);
- }
- };
- /*!
- * validator.js
- * Guillaume Potier - <guillaume@wisembly.com>
- * Version 0.5.8 - built Sun Mar 16 2014 17:18:21
- * MIT Licensed
- *
- */
- ( function ( exports ) {
- /**
- * Validator
- */
- var Validator = function ( options ) {
- this.__class__ = 'Validator';
- this.__version__ = '0.5.8';
- this.options = options || {};
- this.bindingKey = this.options.bindingKey || '_validatorjsConstraint';
- return this;
- };
- Validator.prototype = {
- constructor: Validator,
- /*
- * Validate string: validate( string, Assert, string ) || validate( string, [ Assert, Assert ], [ string, string ] )
- * Validate object: validate( object, Constraint, string ) || validate( object, Constraint, [ string, string ] )
- * Validate binded object: validate( object, string ) || validate( object, [ string, string ] )
- */
- validate: function ( objectOrString, AssertsOrConstraintOrGroup, group ) {
- if ( 'string' !== typeof objectOrString && 'object' !== typeof objectOrString )
- throw new Error( 'You must validate an object or a string' );
- // string / array validation
- if ( 'string' === typeof objectOrString || _isArray(objectOrString) )
- return this._validateString( objectOrString, AssertsOrConstraintOrGroup, group );
- // binded object validation
- if ( this.isBinded( objectOrString ) )
- return this._validateBindedObject( objectOrString, AssertsOrConstraintOrGroup );
- // regular object validation
- return this._validateObject( objectOrString, AssertsOrConstraintOrGroup, group );
- },
- bind: function ( object, constraint ) {
- if ( 'object' !== typeof object )
- throw new Error( 'Must bind a Constraint to an object' );
- object[ this.bindingKey ] = new Constraint( constraint );
- return this;
- },
- unbind: function ( object ) {
- if ( 'undefined' === typeof object._validatorjsConstraint )
- return this;
- delete object[ this.bindingKey ];
- return this;
- },
- isBinded: function ( object ) {
- return 'undefined' !== typeof object[ this.bindingKey ];
- },
- getBinded: function ( object ) {
- return this.isBinded( object ) ? object[ this.bindingKey ] : null;
- },
- _validateString: function ( string, assert, group ) {
- var result, failures = [];
- if ( !_isArray( assert ) )
- assert = [ assert ];
- for ( var i = 0; i < assert.length; i++ ) {
- if ( ! ( assert[ i ] instanceof Assert) )
- throw new Error( 'You must give an Assert or an Asserts array to validate a string' );
- result = assert[ i ].check( string, group );
- if ( result instanceof Violation )
- failures.push( result );
- }
- return failures.length ? failures : true;
- },
- _validateObject: function ( object, constraint, group ) {
- if ( 'object' !== typeof constraint )
- throw new Error( 'You must give a constraint to validate an object' );
- if ( constraint instanceof Constraint )
- return constraint.check( object, group );
- return new Constraint( constraint ).check( object, group );
- },
- _validateBindedObject: function ( object, group ) {
- return object[ this.bindingKey ].check( object, group );
- }
- };
- Validator.errorCode = {
- must_be_a_string: 'must_be_a_string',
- must_be_an_array: 'must_be_an_array',
- must_be_a_number: 'must_be_a_number',
- must_be_a_string_or_array: 'must_be_a_string_or_array'
- };
- /**
- * Constraint
- */
- var Constraint = function ( data, options ) {
- this.__class__ = 'Constraint';
- this.options = options || {};
- this.nodes = {};
- if ( data ) {
- try {
- this._bootstrap( data );
- } catch ( err ) {
- throw new Error( 'Should give a valid mapping object to Constraint', err, data );
- }
- }
- return this;
- };
- Constraint.prototype = {
- constructor: Constraint,
- check: function ( object, group ) {
- var result, failures = {};
- // check all constraint nodes if strict validation enabled. Else, only object nodes that have a constraint
- for ( var property in this.options.strict ? this.nodes : object ) {
- if ( this.options.strict ? this.has( property, object ) : this.has( property ) ) {
- result = this._check( property, object[ property ], group );
- // check returned an array of Violations or an object mapping Violations
- if ( ( _isArray( result ) && result.length > 0 ) || ( !_isArray( result ) && !_isEmptyObject( result ) ) )
- failures[ property ] = result;
- // in strict mode, get a violation for each constraint node not in object
- } else if ( this.options.strict ) {
- try {
- // we trigger here a HaveProperty Assert violation to have uniform Violation object in the end
- new Assert().HaveProperty( property ).validate( object );
- } catch ( violation ) {
- failures[ property ] = violation;
- }
- }
- }
- return _isEmptyObject(failures) ? true : failures;
- },
- add: function ( node, object ) {
- if ( object instanceof Assert || ( _isArray( object ) && object[ 0 ] instanceof Assert ) ) {
- this.nodes[ node ] = object;
- return this;
- }
- if ( 'object' === typeof object && !_isArray( object ) ) {
- this.nodes[ node ] = object instanceof Constraint ? object : new Constraint( object );
- return this;
- }
- throw new Error( 'Should give an Assert, an Asserts array, a Constraint', object );
- },
- has: function ( node, nodes ) {
- nodes = 'undefined' !== typeof nodes ? nodes : this.nodes;
- return 'undefined' !== typeof nodes[ node ];
- },
- get: function ( node, placeholder ) {
- return this.has( node ) ? this.nodes[ node ] : placeholder || null;
- },
- remove: function ( node ) {
- var _nodes = [];
- for ( var i in this.nodes )
- if ( i !== node )
- _nodes[ i ] = this.nodes[ i ];
- this.nodes = _nodes;
- return this;
- },
- _bootstrap: function ( data ) {
- if ( data instanceof Constraint )
- return this.nodes = data.nodes;
- for ( var node in data )
- this.add( node, data[ node ] );
- },
- _check: function ( node, value, group ) {
- // Assert
- if ( this.nodes[ node ] instanceof Assert )
- return this._checkAsserts( value, [ this.nodes[ node ] ], group );
- // Asserts
- if ( _isArray( this.nodes[ node ] ) )
- return this._checkAsserts( value, this.nodes[ node ], group );
- // Constraint -> check api
- if ( this.nodes[ node ] instanceof Constraint )
- return this.nodes[ node ].check( value, group );
- throw new Error( 'Invalid node', this.nodes[ node ] );
- },
- _checkAsserts: function ( value, asserts, group ) {
- var result, failures = [];
- for ( var i = 0; i < asserts.length; i++ ) {
- result = asserts[ i ].check( value, group );
- if ( 'undefined' !== typeof result && true !== result )
- failures.push( result );
- // Some asserts (Collection for example) could return an object
- // if ( result && ! ( result instanceof Violation ) )
- // return result;
- //
- // // Vast assert majority return Violation
- // if ( result instanceof Violation )
- // failures.push( result );
- }
- return failures;
- }
- };
- /**
- * Violation
- */
- var Violation = function ( assert, value, violation ) {
- this.__class__ = 'Violation';
- if ( ! ( assert instanceof Assert ) )
- throw new Error( 'Should give an assertion implementing the Assert interface' );
- this.assert = assert;
- this.value = value;
- if ( 'undefined' !== typeof violation )
- this.violation = violation;
- };
- Violation.prototype = {
- show: function () {
- var show = {
- assert: this.assert.__class__,
- value: this.value
- };
- if ( this.violation )
- show.violation = this.violation;
- return show;
- },
- __toString: function () {
- if ( 'undefined' !== typeof this.violation )
- this.violation = '", ' + this.getViolation().constraint + ' expected was ' + this.getViolation().expected;
- return this.assert.__class__ + ' assert failed for "' + this.value + this.violation || '';
- },
- getViolation: function () {
- var constraint, expected;
- for ( constraint in this.violation )
- expected = this.violation[ constraint ];
- return { constraint: constraint, expected: expected };
- }
- };
- /**
- * Assert
- */
- var Assert = function ( group ) {
- this.__class__ = 'Assert';
- this.__parentClass__ = this.__class__;
- this.groups = [];
- if ( 'undefined' !== typeof group )
- this.addGroup( group );
- return this;
- };
- Assert.prototype = {
- construct: Assert,
- check: function ( value, group ) {
- if ( group && !this.hasGroup( group ) )
- return;
- if ( !group && this.hasGroups() )
- return;
- try {
- return this.validate( value, group );
- } catch ( violation ) {
- return violation;
- }
- },
- hasGroup: function ( group ) {
- if ( _isArray( group ) )
- return this.hasOneOf( group );
- // All Asserts respond to "Any" group
- if ( 'Any' === group )
- return true;
- // Asserts with no group also respond to "Default" group. Else return false
- if ( !this.hasGroups() )
- return 'Default' === group;
- return -1 !== this.groups.indexOf( group );
- },
- hasOneOf: function ( groups ) {
- for ( var i = 0; i < groups.length; i++ )
- if ( this.hasGroup( groups[ i ] ) )
- return true;
- return false;
- },
- hasGroups: function () {
- return this.groups.length > 0;
- },
- addGroup: function ( group ) {
- if ( _isArray( group ) )
- return this.addGroups( group );
- if ( !this.hasGroup( group ) )
- this.groups.push( group );
- return this;
- },
- removeGroup: function ( group ) {
- var _groups = [];
- for ( var i = 0; i < this.groups.length; i++ )
- if ( group !== this.groups[ i ] )
- _groups.push( this.groups[ i ] );
- this.groups = _groups;
- return this;
- },
- addGroups: function ( groups ) {
- for ( var i = 0; i < groups.length; i++ )
- this.addGroup( groups[ i ] );
- return this;
- },
- /**
- * Asserts definitions
- */
- HaveProperty: function ( node ) {
- this.__class__ = 'HaveProperty';
- this.node = node;
- this.validate = function ( object ) {
- if ( 'undefined' === typeof object[ this.node ] )
- throw new Violation( this, object, { value: this.node } );
- return true;
- };
- return this;
- },
- Blank: function () {
- this.__class__ = 'Blank';
- this.validate = function ( value ) {
- if ( 'string' !== typeof value )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
- if ( '' !== value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- Callback: function ( fn ) {
- this.__class__ = 'Callback';
- this.arguments = Array.prototype.slice.call( arguments );
- if ( 1 === this.arguments.length )
- this.arguments = [];
- else
- this.arguments.splice( 0, 1 );
- if ( 'function' !== typeof fn )
- throw new Error( 'Callback must be instanciated with a function' );
- this.fn = fn;
- this.validate = function ( value ) {
- var result = this.fn.apply( this, [ value ].concat( this.arguments ) );
- if ( true !== result )
- throw new Violation( this, value, { result: result } );
- return true;
- };
- return this;
- },
- Choice: function ( list ) {
- this.__class__ = 'Choice';
- if ( !_isArray( list ) && 'function' !== typeof list )
- throw new Error( 'Choice must be instanciated with an array or a function' );
- this.list = list;
- this.validate = function ( value ) {
- var list = 'function' === typeof this.list ? this.list() : this.list;
- for ( var i = 0; i < list.length; i++ )
- if ( value === list[ i ] )
- return true;
- throw new Violation( this, value, { choices: list } );
- };
- return this;
- },
- Collection: function ( constraint ) {
- this.__class__ = 'Collection';
- this.constraint = 'undefined' !== typeof constraint ? new Constraint( constraint ) : false;
- this.validate = function ( collection, group ) {
- var result, validator = new Validator(), count = 0, failures = {}, groups = this.groups.length ? this.groups : group;
- if ( !_isArray( collection ) )
- throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
- for ( var i = 0; i < collection.length; i++ ) {
- result = this.constraint ?
- validator.validate( collection[ i ], this.constraint, groups ) :
- validator.validate( collection[ i ], groups );
- if ( !_isEmptyObject( result ) )
- failures[ count ] = result;
- count++;
- }
- return !_isEmptyObject( failures ) ? failures : true;
- };
- return this;
- },
- Count: function ( count ) {
- this.__class__ = 'Count';
- this.count = count;
- this.validate = function ( array ) {
- if ( !_isArray( array ) )
- throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
- var count = 'function' === typeof this.count ? this.count( array ) : this.count;
- if ( isNaN( Number( count ) ) )
- throw new Error( 'Count must be a valid interger', count );
- if ( count !== array.length )
- throw new Violation( this, array, { count: count } );
- return true;
- };
- return this;
- },
- Email: function () {
- this.__class__ = 'Email';
- this.validate = function ( value ) {
- var regExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
- if ( 'string' !== typeof value )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
- if ( !regExp.test( value ) )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- Eql: function ( eql ) {
- this.__class__ = 'Eql';
- if ( 'undefined' === typeof eql )
- throw new Error( 'Equal must be instanciated with an Array or an Object' );
- this.eql = eql;
- this.validate = function ( value ) {
- var eql = 'function' === typeof this.eql ? this.eql( value ) : this.eql;
- if ( !expect.eql( eql, value ) )
- throw new Violation( this, value, { eql: eql } );
- return true;
- };
- return this;
- },
- EqualTo: function ( reference ) {
- this.__class__ = 'EqualTo';
- if ( 'undefined' === typeof reference )
- throw new Error( 'EqualTo must be instanciated with a value or a function' );
- this.reference = reference;
- this.validate = function ( value ) {
- var reference = 'function' === typeof this.reference ? this.reference( value ) : this.reference;
- if ( reference !== value )
- throw new Violation( this, value, { value: reference } );
- return true;
- };
- return this;
- },
- GreaterThan: function ( threshold ) {
- this.__class__ = 'GreaterThan';
- if ( 'undefined' === typeof threshold )
- throw new Error( 'Should give a threshold value' );
- this.threshold = threshold;
- this.validate = function ( value ) {
- if ( '' === value || isNaN( Number( value ) ) )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
- if ( this.threshold >= value )
- throw new Violation( this, value, { threshold: this.threshold } );
- return true;
- };
- return this;
- },
- GreaterThanOrEqual: function ( threshold ) {
- this.__class__ = 'GreaterThanOrEqual';
- if ( 'undefined' === typeof threshold )
- throw new Error( 'Should give a threshold value' );
- this.threshold = threshold;
- this.validate = function ( value ) {
- if ( '' === value || isNaN( Number( value ) ) )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
- if ( this.threshold > value )
- throw new Violation( this, value, { threshold: this.threshold } );
- return true;
- };
- return this;
- },
- InstanceOf: function ( classRef ) {
- this.__class__ = 'InstanceOf';
- if ( 'undefined' === typeof classRef )
- throw new Error( 'InstanceOf must be instanciated with a value' );
- this.classRef = classRef;
- this.validate = function ( value ) {
- if ( true !== (value instanceof this.classRef) )
- throw new Violation( this, value, { classRef: this.classRef } );
- return true;
- };
- return this;
- },
- IPv4: function () {
- this.__class__ = 'IPv4';
- this.validate = function ( value ) {
- var regExp = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
- if ( 'string' !== typeof value )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
- if ( !regExp.test( value ) )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- Length: function ( boundaries ) {
- this.__class__ = 'Length';
- if ( !boundaries.min && !boundaries.max )
- throw new Error( 'Lenth assert must be instanciated with a { min: x, max: y } object' );
- this.min = boundaries.min;
- this.max = boundaries.max;
- this.validate = function ( value ) {
- if ( 'string' !== typeof value && !_isArray( value ) )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string_or_array } );
- if ( 'undefined' !== typeof this.min && this.min === this.max && value.length !== this.min )
- throw new Violation( this, value, { min: this.min, max: this.max } );
- if ( 'undefined' !== typeof this.max && value.length > this.max )
- throw new Violation( this, value, { max: this.max } );
- if ( 'undefined' !== typeof this.min && value.length < this.min )
- throw new Violation( this, value, { min: this.min } );
- return true;
- };
- return this;
- },
- LessThan: function ( threshold ) {
- this.__class__ = 'LessThan';
- if ( 'undefined' === typeof threshold )
- throw new Error( 'Should give a threshold value' );
- this.threshold = threshold;
- this.validate = function ( value ) {
- if ( '' === value || isNaN( Number( value ) ) )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
- if ( this.threshold <= value )
- throw new Violation( this, value, { threshold: this.threshold } );
- return true;
- };
- return this;
- },
- LessThanOrEqual: function ( threshold ) {
- this.__class__ = 'LessThanOrEqual';
- if ( 'undefined' === typeof threshold )
- throw new Error( 'Should give a threshold value' );
- this.threshold = threshold;
- this.validate = function ( value ) {
- if ( '' === value || isNaN( Number( value ) ) )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } );
- if ( this.threshold < value )
- throw new Violation( this, value, { threshold: this.threshold } );
- return true;
- };
- return this;
- },
- Mac: function () {
- this.__class__ = 'Mac';
- this.validate = function ( value ) {
- var regExp = /^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/i;
- if ( 'string' !== typeof value )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
- if ( !regExp.test( value ) )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- NotNull: function () {
- this.__class__ = 'NotNull';
- this.validate = function ( value ) {
- if ( null === value || 'undefined' === typeof value )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- NotBlank: function () {
- this.__class__ = 'NotBlank';
- this.validate = function ( value ) {
- if ( 'string' !== typeof value )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
- if ( '' === value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- Null: function () {
- this.__class__ = 'Null';
- this.validate = function ( value ) {
- if ( null !== value )
- throw new Violation( this, value );
- return true;
- };
- return this;
- },
- Range: function ( min, max ) {
- this.__class__ = 'Range';
- if ( 'undefined' === typeof min || 'undefined' === typeof max )
- throw new Error( 'Range assert expects min and max values' );
- this.min = min;
- this.max = max;
- this.validate = function ( value ) {
- try {
- // validate strings and objects with their Length
- if ( ( 'string' === typeof value && isNaN( Number( value ) ) ) || _isArray( value ) )
- new Assert().Length( { min: this.min, max: this.max } ).validate( value );
- // validate numbers with their value
- else
- new Assert().GreaterThanOrEqual( this.min ).validate( value ) && new Assert().LessThanOrEqual( this.max ).validate( value );
- return true;
- } catch ( violation ) {
- throw new Violation( this, value, violation.violation );
- }
- return true;
- };
- return this;
- },
- Regexp: function ( regexp, flag ) {
- this.__class__ = 'Regexp';
- if ( 'undefined' === typeof regexp )
- throw new Error( 'You must give a regexp' );
- this.regexp = regexp;
- this.flag = flag || '';
- this.validate = function ( value ) {
- if ( 'string' !== typeof value )
- throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } );
- if ( !new RegExp( this.regexp, this.flag ).test( value ) )
- throw new Violation( this, value, { regexp: this.regexp, flag: this.flag } );
- return true;
- };
- return this;
- },
- Required: function () {
- this.__class__ = 'Required';
- this.validate = function ( value ) {
- if ( 'undefined' === typeof value )
- throw new Violation( this, value );
- try {
- if ( 'string' === typeof value )
- new Assert().NotNull().validate( value ) && new Assert().NotBlank().validate( value );
- else if ( true === _isArray( value ) )
- new Assert().Length( { min: 1 } ).validate( value );
- } catch ( violation ) {
- throw new Violation( this, value );
- }
- return true;
- };
- return this;
- },
- // Unique() or Unique ( { key: foo } )
- Unique: function ( object ) {
- this.__class__ = 'Unique';
- if ( 'object' === typeof object )
- this.key = object.key;
- this.validate = function ( array ) {
- var value, store = [];
- if ( !_isArray( array ) )
- throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } );
- for ( var i = 0; i < array.length; i++ ) {
- value = 'object' === typeof array[ i ] ? array[ i ][ this.key ] : array[ i ];
- if ( 'undefined' === typeof value )
- continue;
- if ( -1 !== store.indexOf( value ) )
- throw new Violation( this, array, { value: value } );
- store.push( value );
- }
- return true;
- };
- return this;
- }
- };
- // expose to the world these awesome classes
- exports.Assert = Assert;
- exports.Validator = Validator;
- exports.Violation = Violation;
- exports.Constraint = Constraint;
- /**
- * Some useful object prototypes / functions here
- */
- // IE8<= compatibility
- // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
- if (!Array.prototype.indexOf)
- Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
- if (this === null) {
- throw new TypeError();
- }
- var t = Object(this);
- var len = t.length >>> 0;
- if (len === 0) {
- return -1;
- }
- var n = 0;
- if (arguments.length > 1) {
- n = Number(arguments[1]);
- if (n != n) { // shortcut for verifying if it's NaN
- n = 0;
- } else if (n !== 0 && n != Infinity && n != -Infinity) {
- n = (n > 0 || -1) * Math.floor(Math.abs(n));
- }
- }
- if (n >= len) {
- return -1;
- }
- var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
- for (; k < len; k++) {
- if (k in t && t[k] === searchElement) {
- return k;
- }
- }
- return -1;
- };
- // Test if object is empty, useful for Constraint violations check
- var _isEmptyObject = function ( obj ) {
- for ( var property in obj )
- return false;
- return true;
- };
- var _isArray = function ( obj ) {
- return Object.prototype.toString.call( obj ) === '[object Array]';
- };
- // https://github.com/LearnBoost/expect.js/blob/master/expect.js
- var expect = {
- eql: function ( actual, expected ) {
- if ( actual === expected ) {
- return true;
- } else if ( 'undefined' !== typeof Buffer && Buffer.isBuffer( actual ) && Buffer.isBuffer( expected ) ) {
- if ( actual.length !== expected.length ) return false;
- for ( var i = 0; i < actual.length; i++ )
- if ( actual[i] !== expected[i] ) return false;
- return true;
- } else if ( actual instanceof Date && expected instanceof Date ) {
- return actual.getTime() === expected.getTime();
- } else if ( typeof actual !== 'object' && typeof expected !== 'object' ) {
- // loosy ==
- return actual == expected;
- } else {
- return this.objEquiv(actual, expected);
- }
- },
- isUndefinedOrNull: function ( value ) {
- return value === null || typeof value === 'undefined';
- },
- isArguments: function ( object ) {
- return Object.prototype.toString.call(object) == '[object Arguments]';
- },
- keys: function ( obj ) {
- if ( Object.keys )
- return Object.keys( obj );
- var keys = [];
- for ( var i in obj )
- if ( Object.prototype.hasOwnProperty.call( obj, i ) )
- keys.push(i);
- return keys;
- },
- objEquiv: function ( a, b ) {
- if ( this.isUndefinedOrNull( a ) || this.isUndefinedOrNull( b ) )
- return false;
- if ( a.prototype !== b.prototype ) return false;
- if ( this.isArguments( a ) ) {
- if ( !this.isArguments( b ) )
- return false;
- return eql( pSlice.call( a ) , pSlice.call( b ) );
- }
- try {
- var ka = this.keys( a ), kb = this.keys( b ), key, i;
- if ( ka.length !== kb.length )
- return false;
- ka.sort();
- kb.sort();
- for ( i = ka.length - 1; i >= 0; i-- )
- if ( ka[ i ] != kb[ i ] )
- return false;
- for ( i = ka.length - 1; i >= 0; i-- ) {
- key = ka[i];
- if ( !this.eql( a[ key ], b[ key ] ) )
- return false;
- }
- return true;
- } catch ( e ) {
- return false;
- }
- }
- };
- // AMD Compliance
- if ( "function" === typeof define && define.amd ) {
- define( 'validator', [],function() { return exports; } );
- }
- } )( 'undefined' === typeof exports ? this[ 'undefined' !== typeof validatorjs_ns ? validatorjs_ns : 'Validator' ] = {} : exports );
- var ParsleyValidator = function (validators, catalog) {
- this.__class__ = 'ParsleyValidator';
- this.Validator = Validator;
- // Default Parsley locale is en
- this.locale = 'en';
- this.init(validators || {}, catalog || {});
- };
- ParsleyValidator.prototype = {
- init: function (validators, catalog) {
- this.catalog = catalog;
- for (var name in validators)
- this.addValidator(name, validators[name].fn, validators[name].priority, validators[name].requirementsTransformer);
- $.emit('parsley:validator:init');
- },
- // Set new messages locale if we have dictionary loaded in ParsleyConfig.i18n
- setLocale: function (locale) {
- if ('undefined' === typeof this.catalog[locale])
- throw new Error(locale + ' is not available in the catalog');
- this.locale = locale;
- return this;
- },
- // Add a new messages catalog for a given locale. Set locale for this catalog if set === `true`
- addCatalog: function (locale, messages, set) {
- if ('object' === typeof messages)
- this.catalog[locale] = messages;
- if (true === set)
- return this.setLocale(locale);
- return this;
- },
- // Add a specific message for a given constraint in a given locale
- addMessage: function (locale, name, message) {
- if ('undefined' === typeof this.catalog[locale])
- this.catalog[locale] = {};
- this.catalog[locale][name.toLowerCase()] = message;
- return this;
- },
- validate: function (value, constraints, priority) {
- return new this.Validator.Validator().validate.apply(new Validator.Validator(), arguments);
- },
- // Add a new validator
- addValidator: function (name, fn, priority, requirementsTransformer) {
- this.validators[name.toLowerCase()] = function (requirements) {
- return $.extend(new Validator.Assert().Callback(fn, requirements), {
- priority: priority,
- requirementsTransformer: requirementsTransformer
- });
- };
- return this;
- },
- updateValidator: function (name, fn, priority, requirementsTransformer) {
- return this.addValidator(name, fn, priority, requirementsTransformer);
- },
- removeValidator: function (name) {
- delete this.validators[name];
- return this;
- },
- getErrorMessage: function (constraint) {
- var message;
- // Type constraints are a bit different, we have to match their requirements too to find right error message
- if ('type' === constraint.name)
- message = this.catalog[this.locale][constraint.name][constraint.requirements];
- else
- message = this.formatMessage(this.catalog[this.locale][constraint.name], constraint.requirements);
- return '' !== message ? message : this.catalog[this.locale].defaultMessage;
- },
- // Kind of light `sprintf()` implementation
- formatMessage: function (string, parameters) {
- if ('object' === typeof parameters) {
- for (var i in parameters)
- string = this.formatMessage(string, parameters[i]);
- return string;
- }
- return 'string' === typeof string ? string.replace(new RegExp('%s', 'i'), parameters) : '';
- },
- // Here is the Parsley default validators list.
- // This is basically Validatorjs validators, with different API for some of them
- // and a Parsley priority set
- validators: {
- notblank: function () {
- return $.extend(new Validator.Assert().NotBlank(), { priority: 2 });
- },
- required: function () {
- return $.extend(new Validator.Assert().Required(), { priority: 512 });
- },
- type: function (type) {
- var assert;
- switch (type) {
- case 'email':
- assert = new Validator.Assert().Email();
- break;
- // range type just ensure we have a number here
- case 'range':
- case 'number':
- assert = new Validator.Assert().Regexp('^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$');
- break;
- case 'integer':
- assert = new Validator.Assert().Regexp('^-?\\d+$');
- break;
- case 'digits':
- assert = new Validator.Assert().Regexp('^\\d+$');
- break;
- case 'alphanum':
- assert = new Validator.Assert().Regexp('^\\w+$', 'i');
- break;
- case 'url':
- assert = new Validator.Assert().Regexp('(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)', 'i');
- break;
- default:
- throw new Error('validator type `' + type + '` is not supported');
- }
- return $.extend(assert, { priority: 256 });
- },
- pattern: function (regexp) {
- var flags = '';
- // Test if RegExp is literal, if not, nothing to be done, otherwise, we need to isolate flags and pattern
- if (!!(/^\/.*\/(?:[gimy]*)$/.test(regexp))) {
- // Replace the regexp literal string with the first match group: ([gimy]*)
- // If no flag is present, this will be a blank string
- flags = regexp.replace(/.*\/([gimy]*)$/, '$1');
- // Again, replace the regexp literal string with the first match group:
- // everything excluding the opening and closing slashes and the flags
- regexp = regexp.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1');
- }
- return $.extend(new Validator.Assert().Regexp(regexp, flags), { priority: 64 });
- },
- minlength: function (value) {
- return $.extend(new Validator.Assert().Length({ min: value }), {
- priority: 30,
- requirementsTransformer: function () {
- return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
- }
- });
- },
- maxlength: function (value) {
- return $.extend(new Validator.Assert().Length({ max: value }), {
- priority: 30,
- requirementsTransformer: function () {
- return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
- }
- });
- },
- length: function (array) {
- return $.extend(new Validator.Assert().Length({ min: array[0], max: array[1] }), { priority: 32 });
- },
- mincheck: function (length) {
- return this.minlength(length);
- },
- maxcheck: function (length) {
- return this.maxlength(length);
- },
- check: function (array) {
- return this.length(array);
- },
- min: function (value) {
- return $.extend(new Validator.Assert().GreaterThanOrEqual(value), {
- priority: 30,
- requirementsTransformer: function () {
- return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
- }
- });
- },
- max: function (value) {
- return $.extend(new Validator.Assert().LessThanOrEqual(value), {
- priority: 30,
- requirementsTransformer: function () {
- return 'string' === typeof value && !isNaN(value) ? parseInt(value, 10) : value;
- }
- });
- },
- range: function (array) {
- return $.extend(new Validator.Assert().Range(array[0], array[1]), {
- priority: 32,
- requirementsTransformer: function () {
- for (var i = 0; i < array.length; i++)
- array[i] = 'string' === typeof array[i] && !isNaN(array[i]) ? parseInt(array[i], 10) : array[i];
- return array;
- }
- });
- },
- equalto: function (value) {
- return $.extend(new Validator.Assert().EqualTo(value), {
- priority: 256,
- requirementsTransformer: function () {
- return $(value).length ? $(value).val() : value;
- }
- });
- }
- }
- };
- var ParsleyUI = function (options) {
- this.__class__ = 'ParsleyUI';
- };
- ParsleyUI.prototype = {
- listen: function () {
- $.listen('parsley:form:init', this, this.setupForm);
- $.listen('parsley:field:init', this, this.setupField);
- $.listen('parsley:field:validated', this, this.reflow);
- $.listen('parsley:form:validated', this, this.focus);
- $.listen('parsley:field:reset', this, this.reset);
- $.listen('parsley:form:destroy', this, this.destroy);
- $.listen('parsley:field:destroy', this, this.destroy);
- return this;
- },
- reflow: function (fieldInstance) {
- // If this field has not an active UI (case for multiples) don't bother doing something
- if ('undefined' === typeof fieldInstance._ui || false === fieldInstance._ui.active)
- return;
- // Diff between two validation results
- var diff = this._diff(fieldInstance.validationResult, fieldInstance._ui.lastValidationResult);
- // Then store current validation result for next reflow
- fieldInstance._ui.lastValidationResult = fieldInstance.validationResult;
- // Field have been validated at least once if here. Useful for binded key events..
- fieldInstance._ui.validatedOnce = true;
- // Handle valid / invalid / none field class
- this.manageStatusClass(fieldInstance);
- // Add, remove, updated errors messages
- this.manageErrorsMessages(fieldInstance, diff);
- // Triggers impl
- this.actualizeTriggers(fieldInstance);
- // If field is not valid for the first time, bind keyup trigger to ease UX and quickly inform user
- if ((diff.kept.length || diff.added.length) && 'undefined' === typeof fieldInstance._ui.failedOnce)
- this.manageFailingFieldTrigger(fieldInstance);
- },
- // Returns an array of field's error message(s)
- getErrorsMessages: function (fieldInstance) {
- // No error message, field is valid
- if (true === fieldInstance.validationResult)
- return [];
- var messages = [];
- for (var i = 0; i < fieldInstance.validationResult.length; i++)
- messages.push(this._getErrorMessage(fieldInstance, fieldInstance.validationResult[i].assert));
- return messages;
- },
- manageStatusClass: function (fieldInstance) {
- if (true === fieldInstance.validationResult)
- this._successClass(fieldInstance);
- else if (fieldInstance.validationResult.length > 0)
- this._errorClass(fieldInstance);
- else
- this._resetClass(fieldInstance);
- },
- manageErrorsMessages: function (fieldInstance, diff) {
- if ('undefined' !== typeof fieldInstance.options.errorsMessagesDisabled)
- return;
- // Case where we have errorMessage option that configure an unique field error message, regardless failing validators
- if ('undefined' !== typeof fieldInstance.options.errorMessage) {
- if ((diff.added.length || diff.kept.length)) {
- if (0 === fieldInstance._ui.$errorsWrapper.find('.parsley-custom-error-message').length)
- fieldInstance._ui.$errorsWrapper
- .append($(fieldInstance.options.errorTemplate)
- .addClass('parsley-custom-error-message'));
- return fieldInstance._ui.$errorsWrapper
- .addClass('filled')
- .find('.parsley-custom-error-message')
- .html(fieldInstance.options.errorMessage);
- }
- return fieldInstance._ui.$errorsWrapper
- .removeClass('filled')
- .find('.parsley-custom-error-message')
- .remove();
- }
- // Show, hide, update failing constraints messages
- for (var i = 0; i < diff.removed.length; i++)
- this.removeError(fieldInstance, diff.removed[i].assert.name, true);
- for (i = 0; i < diff.added.length; i++)
- this.addError(fieldInstance, diff.added[i].assert.name, undefined, diff.added[i].assert, true);
- for (i = 0; i < diff.kept.length; i++)
- this.updateError(fieldInstance, diff.kept[i].assert.name, undefined, diff.kept[i].assert, true);
- },
- // TODO: strange API here, intuitive for manual usage with addError(pslyInstance, 'foo', 'bar')
- // but a little bit complex for above internal usage, with forced undefined parametter..
- addError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
- fieldInstance._ui.$errorsWrapper
- .addClass('filled')
- .append($(fieldInstance.options.errorTemplate)
- .addClass('parsley-' + name)
- .html(message || this._getErrorMessage(fieldInstance, assert)));
- if (true !== doNotUpdateClass)
- this._errorClass(fieldInstance);
- },
- // Same as above
- updateError: function (fieldInstance, name, message, assert, doNotUpdateClass) {
- fieldInstance._ui.$errorsWrapper
- .addClass('filled')
- .find('.parsley-' + name)
- .html(message || this._getErrorMessage(fieldInstance, assert));
- if (true !== doNotUpdateClass)
- this._errorClass(fieldInstance);
- },
- // Same as above twice
- removeError: function (fieldInstance, name, doNotUpdateClass) {
- fieldInstance._ui.$errorsWrapper
- .removeClass('filled')
- .find('.parsley-' + name)
- .remove();
- // edge case possible here: remove a standard Parsley error that is still failing in fieldInstance.validationResult
- // but highly improbable cuz' manually removing a well Parsley handled error makes no sense.
- if (true !== doNotUpdateClass)
- this.manageStatusClass(fieldInstance);
- },
- focus: function (formInstance) {
- if (true === formInstance.validationResult || 'none' === formInstance.options.focus)
- return formInstance._focusedField = null;
- formInstance._focusedField = null;
- for (var i = 0; i < formInstance.fields.length; i++)
- if (true !== formInstance.fields[i].validationResult && formInstance.fields[i].validationResult.length > 0 && 'undefined' === typeof formInstance.fields[i].options.noFocus) {
- if ('first' === formInstance.options.focus) {
- formInstance._focusedField = formInstance.fields[i].$element;
- return formInstance._focusedField.focus();
- }
- formInstance._focusedField = formInstance.fields[i].$element;
- }
- if (null === formInstance._focusedField)
- return null;
- return formInstance._focusedField.focus();
- },
- _getErrorMessage: function (fieldInstance, constraint) {
- var customConstraintErrorMessage = constraint.name + 'Message';
- if ('undefined' !== typeof fieldInstance.options[customConstraintErrorMessage])
- return window.ParsleyValidator.formatMessage(fieldInstance.options[customConstraintErrorMessage], constraint.requirements);
- return window.ParsleyValidator.getErrorMessage(constraint);
- },
- _diff: function (newResult, oldResult, deep) {
- var
- added = [],
- kept = [];
- for (var i = 0; i < newResult.length; i++) {
- var found = false;
- for (var j = 0; j < oldResult.length; j++)
- if (newResult[i].assert.name === oldResult[j].assert.name) {
- found = true;
- break;
- }
- if (found)
- kept.push(newResult[i]);
- else
- added.push(newResult[i]);
- }
- return {
- kept: kept,
- added: added,
- removed: !deep ? this._diff(oldResult, newResult, true).added : []
- };
- },
- setupForm: function (formInstance) {
- formInstance.$element.on('submit.Parsley', false, $.proxy(formInstance.onSubmitValidate, formInstance));
- // UI could be disabled
- if (false === formInstance.options.uiEnabled)
- return;
- formInstance.$element.attr('novalidate', '');
- },
- setupField: function (fieldInstance) {
- var _ui = { active: false };
- // UI could be disabled
- if (false === fieldInstance.options.uiEnabled)
- return;
- _ui.active = true;
- // Give field its Parsley id in DOM
- fieldInstance.$element.attr(fieldInstance.options.namespace + 'id', fieldInstance.__id__);
- /** Generate important UI elements and store them in fieldInstance **/
- // $errorClassHandler is the $element that woul have parsley-error and parsley-success classes
- _ui.$errorClassHandler = this._manageClassHandler(fieldInstance);
- // $errorsWrapper is a div that would contain the various field errors, it will be appended into $errorsContainer
- _ui.errorsWrapperId = 'parsley-id-' + ('undefined' !== typeof fieldInstance.options.multiple ? 'multiple-' + fieldInstance.options.multiple : fieldInstance.__id__);
- _ui.$errorsWrapper = $(fieldInstance.options.errorsWrapper).attr('id', _ui.errorsWrapperId);
- // ValidationResult UI storage to detect what have changed bwt two validations, and update DOM accordingly
- _ui.lastValidationResult = [];
- _ui.validatedOnce = false;
- _ui.validationInformationVisible = false;
- // Store it in fieldInstance for later
- fieldInstance._ui = _ui;
- /** Mess with DOM now **/
- this._insertErrorWrapper(fieldInstance);
- // Bind triggers first time
- this.actualizeTriggers(fieldInstance);
- },
- // Determine which element will have `parsley-error` and `parsley-success` classes
- _manageClassHandler: function (fieldInstance) {
- // An element selector could be passed through DOM with `data-parsley-class-handler=#foo`
- if ('string' === typeof fieldInstance.options.classHandler && $(fieldInstance.options.classHandler).length)
- return $(fieldInstance.options.classHandler);
- // Class handled could also be determined by function given in Parsley options
- var $handler = fieldInstance.options.classHandler(fieldInstance);
- // If this function returned a valid existing DOM element, go for it
- if ('undefined' !== typeof $handler && $handler.length)
- return $handler;
- // Otherwise, if simple element (input, texatrea, select..) it will perfectly host the classes
- if ('undefined' === typeof fieldInstance.options.multiple || fieldInstance.$element.is('select'))
- return fieldInstance.$element;
- // But if multiple element (radio, checkbox), that would be their parent
- return fieldInstance.$element.parent();
- },
- _insertErrorWrapper: function (fieldInstance) {
- var $errorsContainer;
- if ('string' === typeof fieldInstance.options.errorsContainer) {
- if ($(fieldInstance.options.errorsContainer).length)
- return $(fieldInstance.options.errorsContainer).append(fieldInstance._ui.$errorsWrapper);
- else if (window.console && window.console.warn)
- window.console.warn('The errors container `' + fieldInstance.options.errorsContainer + '` does not exist in DOM');
- }
- else if ('function' === typeof fieldInstance.options.errorsContainer)
- $errorsContainer = fieldInstance.options.errorsContainer(fieldInstance);
- if ('undefined' !== typeof $errorsContainer && $errorsContainer.length)
- return $errorsContainer.append(fieldInstance._ui.$errorsWrapper);
- return 'undefined' === typeof fieldInstance.options.multiple ? fieldInstance.$element.after(fieldInstance._ui.$errorsWrapper) : fieldInstance.$element.parent().after(fieldInstance._ui.$errorsWrapper);
- },
- actualizeTriggers: function (fieldInstance) {
- var that = this;
- // Remove Parsley events already binded on this field
- if (fieldInstance.options.multiple)
- $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
- $(this).off('.Parsley');
- });
- else
- fieldInstance.$element.off('.Parsley');
- // If no trigger is set, all good
- if (false === fieldInstance.options.trigger)
- return;
- var triggers = fieldInstance.options.trigger.replace(/^\s+/g , '').replace(/\s+$/g , '');
- if ('' === triggers)
- return;
- // Bind fieldInstance.eventValidate if exists (for parsley.ajax for example), ParsleyUI.eventValidate otherwise
- if (fieldInstance.options.multiple)
- $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
- $(this).on(
- triggers.split(' ').join('.Parsley ') + '.Parsley',
- false,
- $.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : that.eventValidate, fieldInstance));
- });
- else
- fieldInstance.$element
- .on(
- triggers.split(' ').join('.Parsley ') + '.Parsley',
- false,
- $.proxy('function' === typeof fieldInstance.eventValidate ? fieldInstance.eventValidate : this.eventValidate, fieldInstance));
- },
- // Called through $.proxy with fieldInstance. `this` context is ParsleyField
- eventValidate: function(event) {
- // For keyup, keypress, keydown.. events that could be a little bit obstrusive
- // do not validate if val length < min threshold on first validation. Once field have been validated once and info
- // about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
- if (new RegExp('key').test(event.type))
- if (!this._ui.validationInformationVisible && this.getValue().length <= this.options.validationThreshold)
- return;
- this._ui.validatedOnce = true;
- this.validate();
- },
- manageFailingFieldTrigger: function (fieldInstance) {
- fieldInstance._ui.failedOnce = true;
- // Radio and checkboxes fields must bind every field multiple
- if (fieldInstance.options.multiple)
- $('[' + fieldInstance.options.namespace + 'multiple="' + fieldInstance.options.multiple + '"]').each(function () {
- if (!new RegExp('change', 'i').test($(this).parsley().options.trigger || ''))
- return $(this).on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
- });
- // Select case
- if (fieldInstance.$element.is('select'))
- if (!new RegExp('change', 'i').test(fieldInstance.options.trigger || ''))
- return fieldInstance.$element.on('change.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
- // All other inputs fields
- if (!new RegExp('keyup', 'i').test(fieldInstance.options.trigger || ''))
- return fieldInstance.$element.on('keyup.ParsleyFailedOnce', false, $.proxy(fieldInstance.validate, fieldInstance));
- },
- reset: function (parsleyInstance) {
- // Reset all event listeners
- parsleyInstance.$element.off('.Parsley');
- parsleyInstance.$element.off('.ParsleyFailedOnce');
- // Nothing to do if UI never initialized for this field
- if ('undefined' === typeof parsleyInstance._ui)
- return;
- if ('ParsleyForm' === parsleyInstance.__class__)
- return;
- // Reset all errors' li
- parsleyInstance._ui.$errorsWrapper.children().each(function () {
- $(this).remove();
- });
- // Reset validation class
- this._resetClass(parsleyInstance);
- // Reset validation flags and last validation result
- parsleyInstance._ui.validatedOnce = false;
- parsleyInstance._ui.lastValidationResult = [];
- parsleyInstance._ui.validationInformationVisible = false;
- },
- destroy: function (parsleyInstance) {
- this.reset(parsleyInstance);
- if ('ParsleyForm' === parsleyInstance.__class__)
- return;
- if ('undefined' !== typeof parsleyInstance._ui)
- parsleyInstance._ui.$errorsWrapper.remove();
- delete parsleyInstance._ui;
- },
- _successClass: function (fieldInstance) {
- fieldInstance._ui.validationInformationVisible = true;
- fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.errorClass).addClass(fieldInstance.options.successClass);
- },
- _errorClass: function (fieldInstance) {
- fieldInstance._ui.validationInformationVisible = true;
- fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).addClass(fieldInstance.options.errorClass);
- },
- _resetClass: function (fieldInstance) {
- fieldInstance._ui.$errorClassHandler.removeClass(fieldInstance.options.successClass).removeClass(fieldInstance.options.errorClass);
- }
- };
- var ParsleyOptionsFactory = function (defaultOptions, globalOptions, userOptions, namespace) {
- this.__class__ = 'OptionsFactory';
- this.__id__ = ParsleyUtils.hash(4);
- this.formOptions = null;
- this.fieldOptions = null;
- this.staticOptions = $.extend(true, {}, defaultOptions, globalOptions, userOptions, { namespace: namespace });
- };
- ParsleyOptionsFactory.prototype = {
- get: function (parsleyInstance) {
- if ('undefined' === typeof parsleyInstance.__class__)
- throw new Error('Parsley Instance expected');
- switch (parsleyInstance.__class__) {
- case 'Parsley':
- return this.staticOptions;
- case 'ParsleyForm':
- return this.getFormOptions(parsleyInstance);
- case 'ParsleyField':
- case 'ParsleyFieldMultiple':
- return this.getFieldOptions(parsleyInstance);
- default:
- throw new Error('Instance ' + parsleyInstance.__class__ + ' is not supported');
- }
- },
- getFormOptions: function (formInstance) {
- this.formOptions = ParsleyUtils.attr(formInstance.$element, this.staticOptions.namespace);
- // not deep extend, since formOptions is a 1 level deep object
- return $.extend({}, this.staticOptions, this.formOptions);
- },
- getFieldOptions: function (fieldInstance) {
- this.fieldOptions = ParsleyUtils.attr(fieldInstance.$element, this.staticOptions.namespace);
- if (null === this.formOptions && 'undefined' !== typeof fieldInstance.parent)
- this.formOptions = this.getFormOptions(fieldInstance.parent);
- // not deep extend, since formOptions and fieldOptions is a 1 level deep object
- return $.extend({}, this.staticOptions, this.formOptions, this.fieldOptions);
- }
- };
- var ParsleyForm = function (element, OptionsFactory) {
- this.__class__ = 'ParsleyForm';
- this.__id__ = ParsleyUtils.hash(4);
- if ('OptionsFactory' !== ParsleyUtils.get(OptionsFactory, '__class__'))
- throw new Error('You must give an OptionsFactory instance');
- this.OptionsFactory = OptionsFactory;
- this.$element = $(element);
- this.validationResult = null;
- this.options = this.OptionsFactory.get(this);
- };
- ParsleyForm.prototype = {
- onSubmitValidate: function (event) {
- this.validate(undefined, undefined, event);
- // prevent form submission if validation fails
- if (false === this.validationResult && event instanceof $.Event) {
- event.stopImmediatePropagation();
- event.preventDefault();
- }
- return this;
- },
- // @returns boolean
- validate: function (group, force, event) {
- this.submitEvent = event;
- this.validationResult = true;
- var fieldValidationResult = [];
- // Refresh form DOM options and form's fields that could have changed
- this._refreshFields();
- $.emit('parsley:form:validate', this);
- // loop through fields to validate them one by one
- for (var i = 0; i < this.fields.length; i++) {
- // do not validate a field if not the same as given validation group
- if (group && group !== this.fields[i].options.group)
- continue;
- fieldValidationResult = this.fields[i].validate(force);
- if (true !== fieldValidationResult && fieldValidationResult.length > 0 && this.validationResult)
- this.validationResult = false;
- }
- $.emit('parsley:form:validated', this);
- return this.validationResult;
- },
- // Iterate over refreshed fields, and stop on first failure
- isValid: function (group, force) {
- this._refreshFields();
- for (var i = 0; i < this.fields.length; i++) {
- // do not validate a field if not the same as given validation group
- if (group && group !== this.fields[i].options.group)
- continue;
- if (false === this.fields[i].isValid(force))
- return false;
- }
- return true;
- },
- _refreshFields: function () {
- return this.actualizeOptions()._bindFields();
- },
- _bindFields: function () {
- var self = this;
- this.fields = [];
- this.fieldsMappedById = {};
- this.$element.find(this.options.inputs).each(function () {
- var fieldInstance = new window.Parsley(this, {}, self);
- // Only add valid and not excluded `ParsleyField` and `ParsleyFieldMultiple` children
- if (('ParsleyField' === fieldInstance.__class__ || 'ParsleyFieldMultiple' === fieldInstance.__class__) && !fieldInstance.$element.is(fieldInstance.options.excluded))
- if ('undefined' === typeof self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__]) {
- self.fieldsMappedById[fieldInstance.__class__ + '-' + fieldInstance.__id__] = fieldInstance;
- self.fields.push(fieldInstance);
- }
- });
- return this;
- }
- };
- var ConstraintFactory = function (parsleyField, name, requirements, priority, isDomConstraint) {
- if (!new RegExp('ParsleyField').test(ParsleyUtils.get(parsleyField, '__class__')))
- throw new Error('ParsleyField or ParsleyFieldMultiple instance expected');
- if ('function' !== typeof window.ParsleyValidator.validators[name] &&
- 'Assert' !== window.ParsleyValidator.validators[name](requirements).__parentClass__)
- throw new Error('Valid validator expected');
- var getPriority = function (parsleyField, name) {
- if ('undefined' !== typeof parsleyField.options[name + 'Priority'])
- return parsleyField.options[name + 'Priority'];
- return ParsleyUtils.get(window.ParsleyValidator.validators[name](requirements), 'priority') || 2;
- };
- priority = priority || getPriority(parsleyField, name);
- // If validator have a requirementsTransformer, execute it
- if ('function' === typeof window.ParsleyValidator.validators[name](requirements).requirementsTransformer)
- requirements = window.ParsleyValidator.validators[name](requirements).requirementsTransformer();
- return $.extend(window.ParsleyValidator.validators[name](requirements), {
- name: name,
- requirements: requirements,
- priority: priority,
- groups: [priority],
- isDomConstraint: isDomConstraint || ParsleyUtils.attr(parsleyField.$element, parsleyField.options.namespace, name)
- });
- };
- var ParsleyField = function (field, OptionsFactory, parsleyFormInstance) {
- this.__class__ = 'ParsleyField';
- this.__id__ = ParsleyUtils.hash(4);
- this.$element = $(field);
- // If we have a parent `ParsleyForm` instance given, use its `OptionsFactory`, and save parent
- if ('undefined' !== typeof parsleyFormInstance) {
- this.parent = parsleyFormInstance;
- this.OptionsFactory = this.parent.OptionsFactory;
- this.options = this.OptionsFactory.get(this);
- // Else, take the `Parsley` one
- } else {
- this.OptionsFactory = OptionsFactory;
- this.options = this.OptionsFactory.get(this);
- }
- // Initialize some properties
- this.constraints = [];
- this.constraintsByName = {};
- this.validationResult = [];
- // Bind constraints
- this._bindConstraints();
- };
- ParsleyField.prototype = {
- // # Public API
- // Validate field and $.emit some events for mainly `ParsleyUI`
- // @returns validationResult:
- // - `true` if all constraint passes
- // - `[]` if not required field and empty (not validated)
- // - `[Violation, [Violation..]]` if there were validation errors
- validate: function (force) {
- this.value = this.getValue();
- // Field Validate event. `this.value` could be altered for custom needs
- $.emit('parsley:field:validate', this);
- $.emit('parsley:field:' + (this.isValid(force, this.value) ? 'success' : 'error'), this);
- // Field validated event. `this.validationResult` could be altered for custom needs too
- $.emit('parsley:field:validated', this);
- return this.validationResult;
- },
- // Just validate field. Do not trigger any event
- // Same @return as `validate()`
- isValid: function (force, value) {
- // Recompute options and rebind constraints to have latest changes
- this.refreshConstraints();
- // Sort priorities to validate more important first
- var priorities = this._getConstraintsSortedPriorities();
- // Value could be passed as argument, needed to add more power to 'parsley:field:validate'
- value = value || this.getValue();
- // If a field is empty and not required, leave it alone, it's just fine
- // Except if `data-parsley-validate-if-empty` explicitely added, useful for some custom validators
- if (0 === value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty && true !== force)
- return this.validationResult = [];
- // If we want to validate field against all constraints, just call Validator and let it do the job
- if (false === this.options.priorityEnabled)
- return true === (this.validationResult = this.validateThroughValidator(value, this.constraints, 'Any'));
- // Else, iterate over priorities one by one, and validate related asserts one by one
- for (var i = 0; i < priorities.length; i++)
- if (true !== (this.validationResult = this.validateThroughValidator(value, this.constraints, priorities[i])))
- return false;
- return true;
- },
- // @returns Parsley field computed value that could be overrided or configured in DOM
- getValue: function () {
- var value;
- // Value could be overriden in DOM
- if ('undefined' !== typeof this.options.value)
- value = this.options.value;
- else
- value = this.$element.val();
- // Handle wrong DOM or configurations
- if ('undefined' === typeof value || null === value)
- return '';
- // Use `data-parsley-trim-value="true"` to auto trim inputs entry
- if (true === this.options.trimValue)
- return value.replace(/^\s+|\s+$/g, '');
- return value;
- },
- // Actualize options that could have change since previous validation
- // Re-bind accordingly constraints (could be some new, removed or updated)
- refreshConstraints: function () {
- return this.actualizeOptions()._bindConstraints();
- },
- /**
- * Add a new constraint to a field
- *
- * @method addConstraint
- * @param {String} name
- * @param {Mixed} requirements optional
- * @param {Number} priority optional
- * @param {Boolean} isDomConstraint optional
- */
- addConstraint: function (name, requirements, priority, isDomConstraint) {
- name = name.toLowerCase();
- if ('function' === typeof window.ParsleyValidator.validators[name]) {
- var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);
- // if constraint already exist, delete it and push new version
- if ('undefined' !== this.constraintsByName[constraint.name])
- this.removeConstraint(constraint.name);
- this.constraints.push(constraint);
- this.constraintsByName[constraint.name] = constraint;
- }
- return this;
- },
- // Remove a constraint
- removeConstraint: function (name) {
- for (var i = 0; i < this.constraints.length; i++)
- if (name === this.constraints[i].name) {
- this.constraints.splice(i, 1);
- break;
- }
- return this;
- },
- // Update a constraint (Remove + re-add)
- updateConstraint: function (name, parameters, priority) {
- return this.removeConstraint(name)
- .addConstraint(name, parameters, priority);
- },
- // # Internals
- // Internal only.
- // Bind constraints from config + options + DOM
- _bindConstraints: function () {
- var constraints = [];
- // clean all existing DOM constraints to only keep javascript user constraints
- for (var i = 0; i < this.constraints.length; i++)
- if (false === this.constraints[i].isDomConstraint)
- constraints.push(this.constraints[i]);
- this.constraints = constraints;
- // then re-add Parsley DOM-API constraints
- for (var name in this.options)
- this.addConstraint(name, this.options[name]);
- // finally, bind special HTML5 constraints
- return this._bindHtml5Constraints();
- },
- // Internal only.
- // Bind specific HTML5 constraints to be HTML5 compliant
- _bindHtml5Constraints: function () {
- // html5 required
- if (this.$element.hasClass('required') || this.$element.attr('required'))
- this.addConstraint('required', true, undefined, true);
- // html5 pattern
- if ('string' === typeof this.$element.attr('pattern'))
- this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
- // range
- if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))
- this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
- // HTML5 min
- else if ('undefined' !== typeof this.$element.attr('min'))
- this.addConstraint('min', this.$element.attr('min'), undefined, true);
- // HTML5 max
- else if ('undefined' !== typeof this.$element.attr('max'))
- this.addConstraint('max', this.$element.attr('max'), undefined, true);
- // html5 types
- var type = this.$element.attr('type');
- if ('undefined' === typeof type)
- return this;
- // Small special case here for HTML5 number, that is in fact an integer validator
- if ('number' === type)
- return this.addConstraint('type', 'integer', undefined, true);
- // Regular other HTML5 supported types
- else if (new RegExp(type, 'i').test('email url range'))
- return this.addConstraint('type', type, undefined, true);
- return this;
- },
- // Internal only.
- // Field is required if have required constraint without `false` value
- _isRequired: function () {
- if ('undefined' === typeof this.constraintsByName.required)
- return false;
- return false !== this.constraintsByName.required.requirements;
- },
- // Internal only.
- // Sort constraints by priority DESC
- _getConstraintsSortedPriorities: function () {
- var priorities = [];
- // Create array unique of priorities
- for (var i = 0; i < this.constraints.length; i++)
- if (-1 === priorities.indexOf(this.constraints[i].priority))
- priorities.push(this.constraints[i].priority);
- // Sort them by priority DESC
- priorities.sort(function (a, b) { return b - a; });
- return priorities;
- }
- };
- var ParsleyMultiple = function () {
- this.__class__ = 'ParsleyFieldMultiple';
- };
- ParsleyMultiple.prototype = {
- // Add new `$element` sibling for multiple field
- addElement: function ($element) {
- this.$elements.push($element);
- return this;
- },
- // See `ParsleyField.refreshConstraints()`
- refreshConstraints: function () {
- var fieldConstraints;
- this.constraints = [];
- // Select multiple special treatment
- if (this.$element.is('select')) {
- this.actualizeOptions()._bindConstraints();
- return this;
- }
- // Gather all constraints for each input in the multiple group
- for (var i = 0; i < this.$elements.length; i++) {
- // Check if element have not been dynamically removed since last binding
- if (!$('html').has(this.$elements[i]).length) {
- this.$elements.splice(i, 1);
- continue;
- }
- fieldConstraints = this.$elements[i].data('ParsleyFieldMultiple').refreshConstraints().constraints;
- for (var j = 0; j < fieldConstraints.length; j++)
- this.addConstraint(fieldConstraints[j].name, fieldConstraints[j].requirements, fieldConstraints[j].priority, fieldConstraints[j].isDomConstraint);
- }
- return this;
- },
- // See `ParsleyField.getValue()`
- getValue: function () {
- // Value could be overriden in DOM
- if ('undefined' !== typeof this.options.value)
- return this.options.value;
- // Radio input case
- if (this.$element.is('input[type=radio]'))
- return $('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').val() || '';
- // checkbox input case
- if (this.$element.is('input[type=checkbox]')) {
- var values = [];
- $('[' + this.options.namespace + 'multiple="' + this.options.multiple + '"]:checked').each(function () {
- values.push($(this).val());
- });
- return values.length ? values : [];
- }
- // Select multiple case
- if (this.$element.is('select') && null === this.$element.val())
- return [];
- // Default case that should never happen
- return this.$element.val();
- },
- _init: function (multiple) {
- this.$elements = [this.$element];
- this.options.multiple = multiple;
- return this;
- }
- };
- var
- o = $({}),
- subscribed = {};
- // $.listen(name, callback);
- // $.listen(name, context, callback);
- $.listen = function (name) {
- if ('undefined' === typeof subscribed[name])
- subscribed[name] = [];
- if ('function' === typeof arguments[1])
- return subscribed[name].push({ fn: arguments[1] });
- if ('object' === typeof arguments[1] && 'function' === typeof arguments[2])
- return subscribed[name].push({ fn: arguments[2], ctxt: arguments[1] });
- throw new Error('Wrong parameters');
- };
- $.listenTo = function (instance, name, fn) {
- if ('undefined' === typeof subscribed[name])
- subscribed[name] = [];
- if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
- throw new Error('Must give Parsley instance');
- if ('string' !== typeof name || 'function' !== typeof fn)
- throw new Error('Wrong parameters');
- subscribed[name].push({ instance: instance, fn: fn });
- };
- $.unsubscribe = function (name, fn) {
- if ('undefined' === typeof subscribed[name])
- return;
- if ('string' !== typeof name || 'function' !== typeof fn)
- throw new Error('Wrong arguments');
- for (var i = 0; i < subscribed[name].length; i++)
- if (subscribed[name][i].fn === fn)
- return subscribed[name].splice(i, 1);
- };
- $.unsubscribeTo = function (instance, name) {
- if ('undefined' === typeof subscribed[name])
- return;
- if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
- throw new Error('Must give Parsley instance');
- for (var i = 0; i < subscribed[name].length; i++)
- if ('undefined' !== typeof subscribed[name][i].instance && subscribed[name][i].instance.__id__ === instance.__id__)
- return subscribed[name].splice(i, 1);
- };
- $.unsubscribeAll = function (name) {
- if ('undefined' === typeof subscribed[name])
- return;
- delete subscribed[name];
- };
- // $.emit(name [, arguments...]);
- // $.emit(name, instance [, arguments..]);
- $.emit = function (name, instance) {
- if ('undefined' === typeof subscribed[name])
- return;
- // loop through registered callbacks for this event
- for (var i = 0; i < subscribed[name].length; i++) {
- // if instance is not registered, simple emit
- if ('undefined' === typeof subscribed[name][i].instance) {
- subscribed[name][i].fn.apply('undefined' !== typeof subscribed[name][i].ctxt ? subscribed[name][i].ctxt : o, Array.prototype.slice.call(arguments, 1));
- continue;
- }
- // if instance registered but no instance given for the emit, continue
- if (!(instance instanceof ParsleyField) && !(instance instanceof ParsleyForm))
- continue;
- // if instance is registered and same id, emit
- if (subscribed[name][i].instance.__id__ === instance.__id__) {
- subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
- continue;
- }
- // if registered instance is a Form and fired one is a Field, loop over all its fields and emit if field found
- if (subscribed[name][i].instance instanceof ParsleyForm && instance instanceof ParsleyField)
- for (var j = 0; j < subscribed[name][i].instance.fields.length; j++)
- if (subscribed[name][i].instance.fields[j].__id__ === instance.__id__) {
- subscribed[name][i].fn.apply(o, Array.prototype.slice.call(arguments, 1));
- continue;
- }
- }
- };
- $.subscribed = function () { return subscribed; };
- // ParsleyConfig definition if not already set
- window.ParsleyConfig = window.ParsleyConfig || {};
- window.ParsleyConfig.i18n = window.ParsleyConfig.i18n || {};
- // Define then the messages
- window.ParsleyConfig.i18n.en = $.extend(window.ParsleyConfig.i18n.en || {}, {
- defaultMessage: "This value seems to be invalid.",
- type: {
- email: "This value should be a valid email.",
- url: "This value should be a valid url.",
- number: "This value should be a valid number.",
- integer: "This value should be a valid integer.",
- digits: "This value should be digits.",
- alphanum: "This value should be alphanumeric."
- },
- notblank: "This value should not be blank.",
- required: "This value is required.",
- pattern: "This value seems to be invalid.",
- min: "This value should be greater than or equal to %s.",
- max: "This value should be lower than or equal to %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 fewer.",
- length: "This value length is invalid. It should be between %s and %s characters long.",
- mincheck: "You must select at least %s choices.",
- maxcheck: "You must select %s choices or fewer.",
- check: "You must select between %s and %s choices.",
- equalto: "This value should be the same."
- });
- // If file is loaded after Parsley main file, auto-load locale
- if ('undefined' !== typeof window.ParsleyValidator)
- window.ParsleyValidator.addCatalog('en', window.ParsleyConfig.i18n.en, true);
- // Parsley.js 2.0.3
- // http://parsleyjs.org
- // (c) 20012-2014 Guillaume Potier, Wisembly
- // Parsley may be freely distributed under the MIT license.
- // ### Parsley factory
- var Parsley = function (element, options, parsleyFormInstance) {
- this.__class__ = 'Parsley';
- this.__version__ = '2.0.3';
- this.__id__ = ParsleyUtils.hash(4);
- // Parsley must be instanciated with a DOM element or jQuery $element
- if ('undefined' === typeof element)
- throw new Error('You must give an element');
- if ('undefined' !== typeof parsleyFormInstance && 'ParsleyForm' !== parsleyFormInstance.__class__)
- throw new Error('Parent instance must be a ParsleyForm instance');
- return this.init($(element), options, parsleyFormInstance);
- };
- Parsley.prototype = {
- init: function ($element, options, parsleyFormInstance) {
- if (!$element.length)
- throw new Error('You must bind Parsley on an existing element.');
- this.$element = $element;
- // If element have already been binded, returns its saved Parsley instance
- if (this.$element.data('Parsley')) {
- var savedparsleyFormInstance = this.$element.data('Parsley');
- // If saved instance have been binded without a ParsleyForm parent and there is one given in this call, add it
- if ('undefined' !== typeof parsleyFormInstance)
- savedparsleyFormInstance.parent = parsleyFormInstance;
- return savedparsleyFormInstance;
- }
- // Handle 'static' options
- this.OptionsFactory = new ParsleyOptionsFactory(ParsleyDefaults, ParsleyUtils.get(window, 'ParsleyConfig') || {}, options, this.getNamespace(options));
- this.options = this.OptionsFactory.get(this);
- // A ParsleyForm instance is obviously a `<form>` elem but also every node that is not an input and have `data-parsley-validate` attribute
- if (this.$element.is('form') || (ParsleyUtils.attr(this.$element, this.options.namespace, 'validate') && !this.$element.is(this.options.inputs)))
- return this.bind('parsleyForm');
- // Every other supported element and not excluded element is binded as a `ParsleyField` or `ParsleyFieldMultiple`
- else if (this.$element.is(this.options.inputs) && !this.$element.is(this.options.excluded))
- return this.isMultiple() ? this.handleMultiple(parsleyFormInstance) : this.bind('parsleyField', parsleyFormInstance);
- return this;
- },
- isMultiple: function () {
- return (this.$element.is('input[type=radio], input[type=checkbox]') && 'undefined' === typeof this.options.multiple) || (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple'));
- },
- // Multiples fields are a real nightmare :(
- // Maybe some refacto would be appreciated here..
- handleMultiple: function (parsleyFormInstance) {
- var
- that = this,
- name,
- multiple,
- parsleyMultipleInstance;
- // Get parsleyFormInstance options if exist, mixed with element attributes
- this.options = $.extend(this.options, parsleyFormInstance ? parsleyFormInstance.OptionsFactory.get(parsleyFormInstance) : {}, ParsleyUtils.attr(this.$element, this.options.namespace));
- // Handle multiple name
- if (this.options.multiple)
- multiple = this.options.multiple;
- else if ('undefined' !== typeof this.$element.attr('name') && this.$element.attr('name').length)
- multiple = name = this.$element.attr('name');
- else if ('undefined' !== typeof this.$element.attr('id') && this.$element.attr('id').length)
- multiple = this.$element.attr('id');
- // Special select multiple input
- if (this.$element.is('select') && 'undefined' !== typeof this.$element.attr('multiple')) {
- return this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple || this.__id__);
- // Else for radio / checkboxes, we need a `name` or `data-parsley-multiple` to properly bind it
- } else if ('undefined' === typeof multiple) {
- if (window.console && window.console.warn)
- window.console.warn('To be binded by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.', this.$element);
- return this;
- }
- // Remove special chars
- multiple = multiple.replace(/(:|\.|\[|\]|\$)/g, '');
- // Add proper `data-parsley-multiple` to siblings if we have a valid multiple name
- if ('undefined' !== typeof name) {
- $('input[name="' + name + '"]').each(function () {
- if ($(this).is('input[type=radio], input[type=checkbox]'))
- $(this).attr(that.options.namespace + 'multiple', multiple);
- });
- }
- // Check here if we don't already have a related multiple instance saved
- if ($('[' + this.options.namespace + 'multiple=' + multiple +']').length) {
- for (var i = 0; i < $('[' + this.options.namespace + 'multiple=' + multiple +']').length; i++) {
- if ('undefined' !== typeof $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley')) {
- parsleyMultipleInstance = $($('[' + this.options.namespace + 'multiple=' + multiple +']').get(i)).data('Parsley');
- if (!this.$element.data('ParsleyFieldMultiple')) {
- parsleyMultipleInstance.addElement(this.$element);
- this.$element.attr(this.options.namespace + 'id', parsleyMultipleInstance.__id__);
- }
- break;
- }
- }
- }
- // Create a secret ParsleyField instance for every multiple field. It would be stored in `data('ParsleyFieldMultiple')`
- // And would be useful later to access classic `ParsleyField` stuff while being in a `ParsleyFieldMultiple` instance
- this.bind('parsleyField', parsleyFormInstance, multiple, true);
- return parsleyMultipleInstance || this.bind('parsleyFieldMultiple', parsleyFormInstance, multiple);
- },
- // Retrieve namespace used for DOM-API
- getNamespace: function (options) {
- // `data-parsley-namespace=<namespace>`
- if ('undefined' !== typeof this.$element.data('parsleyNamespace'))
- return this.$element.data('parsleyNamespace');
- if ('undefined' !== typeof ParsleyUtils.get(options, 'namespace'))
- return options.namespace;
- if ('undefined' !== typeof ParsleyUtils.get(window, 'ParsleyConfig.namespace'))
- return window.ParsleyConfig.namespace;
- return ParsleyDefaults.namespace;
- },
- // Return proper `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
- bind: function (type, parentParsleyFormInstance, multiple, doNotStore) {
- var parsleyInstance;
- switch (type) {
- case 'parsleyForm':
- parsleyInstance = $.extend(
- new ParsleyForm(this.$element, this.OptionsFactory),
- new ParsleyAbstract(),
- window.ParsleyExtend
- )._bindFields();
- break;
- case 'parsleyField':
- parsleyInstance = $.extend(
- new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
- new ParsleyAbstract(),
- window.ParsleyExtend
- );
- break;
- case 'parsleyFieldMultiple':
- parsleyInstance = $.extend(
- new ParsleyField(this.$element, this.OptionsFactory, parentParsleyFormInstance),
- new ParsleyAbstract(),
- new ParsleyMultiple(),
- window.ParsleyExtend
- )._init(multiple);
- break;
- default:
- throw new Error(type + 'is not a supported Parsley type');
- }
- if ('undefined' !== typeof multiple)
- ParsleyUtils.setAttr(this.$element, this.options.namespace, 'multiple', multiple);
- if ('undefined' !== typeof doNotStore) {
- this.$element.data('ParsleyFieldMultiple', parsleyInstance);
- return parsleyInstance;
- }
- // Store instance if `ParsleyForm`, `ParsleyField` or `ParsleyFieldMultiple`
- if (new RegExp('ParsleyF', 'i').test(parsleyInstance.__class__)) {
- // Store for later access the freshly binded instance in DOM element itself using jQuery `data()`
- this.$element.data('Parsley', parsleyInstance);
- // Tell the world we got a new ParsleyForm or ParsleyField instance!
- $.emit('parsley:' + ('parsleyForm' === type ? 'form' : 'field') + ':init', parsleyInstance);
- }
- return parsleyInstance;
- }
- };
- // ### jQuery API
- // `$('.elem').parsley(options)` or `$('.elem').psly(options)`
- $.fn.parsley = $.fn.psly = function (options) {
- if (this.length > 1) {
- var instances = [];
- this.each(function () {
- instances.push($(this).parsley(options));
- });
- return instances;
- }
- // Return undefined if applied to non existing DOM element
- if (!$(this).length) {
- if (window.console && window.console.warn)
- window.console.warn('You must bind Parsley on an existing element.');
- return;
- }
- return new Parsley(this, options);
- };
- // ### ParsleyUI
- // UI is a class apart that only listen to some events and them modify DOM accordingly
- // Could be overriden by defining a `window.ParsleyConfig.ParsleyUI` appropriate class (with `listen()` method basically)
- window.ParsleyUI = 'function' === typeof ParsleyUtils.get(window, 'ParsleyConfig.ParsleyUI') ?
- new window.ParsleyConfig.ParsleyUI().listen() : new ParsleyUI().listen();
- // ### ParsleyField and ParsleyForm extension
- // Ensure that defined if not already the case
- if ('undefined' === typeof window.ParsleyExtend)
- window.ParsleyExtend = {};
- // ### ParsleyConfig
- // Ensure that defined if not already the case
- if ('undefined' === typeof window.ParsleyConfig)
- window.ParsleyConfig = {};
- // ### Globals
- window.Parsley = window.psly = Parsley;
- window.ParsleyUtils = ParsleyUtils;
- window.ParsleyValidator = new ParsleyValidator(window.ParsleyConfig.validators, window.ParsleyConfig.i18n);
- // ### PARSLEY auto-binding
- // Prevent it by setting `ParsleyConfig.autoBind` to `false`
- if (false !== ParsleyUtils.get(window, 'ParsleyConfig.autoBind'))
- $(document).ready(function () {
- // Works only on `data-parsley-validate`.
- if ($('[data-parsley-validate]').length)
- $('[data-parsley-validate]').parsley();
- });
- }));
|