jquery-form-validator-rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * jQuery Form Validator Module: html5
3
+ * ------------------------------------------
4
+ * Created by Victor Jonsson <http://www.victorjonsson.se>
5
+ *
6
+ * The following module will make this jQuery plugin serve as a
7
+ * html5 fallback. It makes older browsers support the following
8
+ * - validation when type="email"
9
+ * - validation when type="url"
10
+ * - validation when type="time"
11
+ * - validation when type="date"
12
+ * - validation when type="number" and max="" min=""
13
+ * - validation when pattern="REGEXP"
14
+ * - validation when using maxlength
15
+ * - Using datalist element for creating suggestions
16
+ * - placeholders
17
+ *
18
+ * @website http://formvalidator.net/
19
+ * @license Dual licensed under the MIT or GPL Version 2 licenses
20
+ * @version 2.2.beta.50
21
+ */
22
+ (function($, window) {
23
+
24
+ "use strict";
25
+
26
+ var SUPPORTS_PLACEHOLDER = 'placeholder' in document.createElement('INPUT'),
27
+ SUPPORTS_DATALIST = 'options' in document.createElement('DATALIST');
28
+
29
+ $(window).bind('validatorsLoaded formValidationSetup', function(evt, $form) {
30
+
31
+ if( !$form ) {
32
+ $form = $('form');
33
+ }
34
+
35
+ var hasLoadedDateModule = false;
36
+
37
+ $form.each(function() {
38
+ var $f = $(this),
39
+ $formInputs = $f.find('input,textarea,select'),
40
+ foundHtml5Rule = false;
41
+
42
+ $formInputs.each(function() {
43
+ var validation = [],
44
+ $input = $(this),
45
+ isRequired = $input.attr('required'),
46
+ attrs = {};
47
+
48
+ switch ( ($input.attr('type') || '').toLowerCase() ) {
49
+ case 'time':
50
+ validation.push('time');
51
+ if( !$.formUtils.validators.validate_date && !hasLoadedDateModule ) {
52
+ hasLoadedDateModule = true;
53
+ $.formUtils.loadModules('date');
54
+ }
55
+ break;
56
+ case 'url':
57
+ validation.push('url');
58
+ break;
59
+ case 'email':
60
+ validation.push('email');
61
+ break;
62
+ case 'date':
63
+ validation.push('date');
64
+ break;
65
+ case 'number':
66
+ validation.push('number');
67
+ var max = $input.attr('max'),
68
+ min = $input.attr('min');
69
+ if( min || max ) {
70
+ if( !min )
71
+ min = 0;
72
+ if( !max )
73
+ max = 9007199254740992; // js max int
74
+
75
+ attrs['data-validation-allowing'] = 'range['+min+';'+max+']';
76
+ if( min.indexOf('-') === 0 || max.indexOf('-') === 0 ) {
77
+ attrs['data-validation-allowing'] += ',negative';
78
+ }
79
+ if( min.indexOf('.') > -1 || max.indexOf('.') > -1 ) {
80
+ attrs['data-validation-allowing'] += ',float';
81
+ }
82
+ }
83
+ break;
84
+ }
85
+
86
+ if( $input.attr('pattern') ) {
87
+ validation.push('custom');
88
+ attrs['data-validation-regexp'] = $input.attr('pattern');
89
+ }
90
+ if( $input.attr('maxlength') ) {
91
+ validation.push('length');
92
+ attrs['data-validation-length'] = 'max'+$input.attr('maxlength');
93
+ }
94
+
95
+ if( !SUPPORTS_DATALIST && $input.attr('list') ) {
96
+ var suggestions = [];
97
+ $('#'+$input.attr('list')+' option').each(function() {
98
+ var $opt = $(this);
99
+ suggestions.push($opt.attr('value') || $opt.text());
100
+ });
101
+ $.formUtils.suggest( $input, suggestions );
102
+ }
103
+
104
+ if( validation.length ) {
105
+ if( !isRequired ) {
106
+ attrs['data-validation-optional'] = 'true';
107
+ }
108
+
109
+ foundHtml5Rule = true;
110
+ $input.attr('data-validation', validation.join(' '));
111
+
112
+ $.each(attrs, function(attrName, attrVal) {
113
+ $input.attr(attrName, attrVal);
114
+ });
115
+ }
116
+ });
117
+
118
+ if( foundHtml5Rule ) {
119
+ $f.trigger('html5ValidationAttrsFound');
120
+ }
121
+
122
+ if( !SUPPORTS_PLACEHOLDER ) {
123
+ $formInputs.filter('input[placeholder]').each(function() {
124
+ this.defaultValue = this.getAttribute('placeholder');
125
+ $(this)
126
+ .bind('focus', function() {
127
+ if(this.value == this.defaultValue) {
128
+ this.value = '';
129
+ $(this).removeClass('showing-placeholder');
130
+ }
131
+ })
132
+ .bind('blur', function() {
133
+ if($.trim(this.value) == '') {
134
+ this.value = this.defaultValue;
135
+ $(this).addClass('showing-placeholder');
136
+ }
137
+ });
138
+ });
139
+ }
140
+
141
+ });
142
+ });
143
+
144
+ })(jQuery, window);
@@ -1 +1 @@
1
- (function($,window){"use strict";var SUPPORTS_PLACEHOLDER="placeholder"in document.createElement("INPUT"),SUPPORTS_DATALIST="options"in document.createElement("DATALIST");$(window).bind("validatorsLoaded formValidationSetup",function(evt,$form){if(!$form){$form=$("form")}var hasLoadedDateModule=false;$form.each(function(){var $f=$(this),$formInputs=$f.find("input,textarea,select"),foundHtml5Rule=false;$formInputs.each(function(){var validation=[],$input=$(this),isRequired=$input.attr("required"),attrs={};switch(($input.attr("type")||"").toLowerCase()){case"time":validation.push("time");if(!$.formUtils.validators.validate_date&&!hasLoadedDateModule){hasLoadedDateModule=true;$.formUtils.loadModules("date")}break;case"url":validation.push("url");break;case"email":validation.push("email");break;case"date":validation.push("date");break;case"number":validation.push("number");var max=$input.attr("max"),min=$input.attr("min");if(min||max){if(!min)min=0;if(!max)max=9007199254740992;attrs["data-validation-allowing"]="range["+min+";"+max+"]";if(min.indexOf("-")===0||max.indexOf("-")===0){attrs["data-validation-allowing"]+=",negative"}if(min.indexOf(".")>-1||max.indexOf(".")>-1){attrs["data-validation-allowing"]+=",float"}}break}if($input.attr("pattern")){validation.push("custom");attrs["data-validation-regexp"]=$input.attr("pattern")}if($input.attr("maxlength")){validation.push("length");attrs["data-validation-length"]="max"+$input.attr("maxlength")}console.log($input.html());if(!SUPPORTS_DATALIST&&$input.attr("list")){console.log($input.attr("list"));var suggestions=[];$("#"+$input.attr("list")+" option").each(function(){var $opt=$(this);suggestions.push($opt.attr("value")||$opt.text())});$.formUtils.suggest($input,suggestions)}if(validation.length){if(!isRequired){attrs["data-validation-optional"]="true"}foundHtml5Rule=true;$input.attr("data-validation",validation.join(" "));$.each(attrs,function(attrName,attrVal){$input.attr(attrName,attrVal)})}});if(foundHtml5Rule){$f.trigger("html5ValidationAttrsFound")}if(!SUPPORTS_PLACEHOLDER){$formInputs.filter("input[placeholder]").each(function(){this.defaultValue=this.getAttribute("placeholder");$(this).bind("focus",function(){if(this.value==this.defaultValue){this.value="";$(this).removeClass("showing-placeholder")}}).bind("blur",function(){if($.trim(this.value)==""){this.value=this.defaultValue;$(this).addClass("showing-placeholder")}})})}})})})(jQuery,window);
1
+ (function($,window){"use strict";var SUPPORTS_PLACEHOLDER="placeholder"in document.createElement("INPUT"),SUPPORTS_DATALIST="options"in document.createElement("DATALIST");$(window).bind("validatorsLoaded formValidationSetup",function(evt,$form){if(!$form){$form=$("form")}var hasLoadedDateModule=false;$form.each(function(){var $f=$(this),$formInputs=$f.find("input,textarea,select"),foundHtml5Rule=false;$formInputs.each(function(){var validation=[],$input=$(this),isRequired=$input.attr("required"),attrs={};switch(($input.attr("type")||"").toLowerCase()){case"time":validation.push("time");if(!$.formUtils.validators.validate_date&&!hasLoadedDateModule){hasLoadedDateModule=true;$.formUtils.loadModules("date")}break;case"url":validation.push("url");break;case"email":validation.push("email");break;case"date":validation.push("date");break;case"number":validation.push("number");var max=$input.attr("max"),min=$input.attr("min");if(min||max){if(!min)min=0;if(!max)max=9007199254740992;attrs["data-validation-allowing"]="range["+min+";"+max+"]";if(min.indexOf("-")===0||max.indexOf("-")===0){attrs["data-validation-allowing"]+=",negative"}if(min.indexOf(".")>-1||max.indexOf(".")>-1){attrs["data-validation-allowing"]+=",float"}}break}if($input.attr("pattern")){validation.push("custom");attrs["data-validation-regexp"]=$input.attr("pattern")}if($input.attr("maxlength")){validation.push("length");attrs["data-validation-length"]="max"+$input.attr("maxlength")}if(!SUPPORTS_DATALIST&&$input.attr("list")){var suggestions=[];$("#"+$input.attr("list")+" option").each(function(){var $opt=$(this);suggestions.push($opt.attr("value")||$opt.text())});$.formUtils.suggest($input,suggestions)}if(validation.length){if(!isRequired){attrs["data-validation-optional"]="true"}foundHtml5Rule=true;$input.attr("data-validation",validation.join(" "));$.each(attrs,function(attrName,attrVal){$input.attr(attrName,attrVal)})}});if(foundHtml5Rule){$f.trigger("html5ValidationAttrsFound")}if(!SUPPORTS_PLACEHOLDER){$formInputs.filter("input[placeholder]").each(function(){this.defaultValue=this.getAttribute("placeholder");$(this).bind("focus",function(){if(this.value==this.defaultValue){this.value="";$(this).removeClass("showing-placeholder")}}).bind("blur",function(){if($.trim(this.value)==""){this.value=this.defaultValue;$(this).addClass("showing-placeholder")}})})}})})})(jQuery,window);
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @website http://formvalidator.net/
7
7
  * @license Dual licensed under the MIT or GPL Version 2 licenses
8
- * @version 2.1.66
8
+ * @version 2.2.beta.50
9
9
  */
10
10
  (function($) {
11
11
 
@@ -15,10 +15,15 @@
15
15
  _applyErrorStyle = function($elem, conf) {
16
16
  $elem
17
17
  .addClass(conf.errorElementClass)
18
- .removeClass('valid')
19
- .parent()
20
- .addClass('has-error')
21
- .removeClass('has-success'); // twitter bs
18
+ .removeClass('valid');
19
+
20
+ var $parent = $elem.parent();
21
+ if($parent.hasClass("input-group"))
22
+ $parent = $parent.parent();
23
+
24
+ $parent
25
+ .addClass(conf.inputParentClassOnError)
26
+ .removeClass(conf.inputParentClassOnSuccess);
22
27
 
23
28
  if(conf.borderColorOnError !== '') {
24
29
  $elem.css('border-color', conf.borderColorOnError);
@@ -26,20 +31,29 @@
26
31
  },
27
32
  _removeErrorStyle = function($elem, conf) {
28
33
  $elem.each(function() {
29
- _setInlineErrorMessage($(this), '', conf, conf.errorMessagePosition);
30
- $(this)
34
+ var $this = $(this),
35
+ $parent = $this.parent();
36
+
37
+ if($parent.hasClass("input-group"))
38
+ $parent = $parent.parent();
39
+
40
+ _setInlineErrorMessage($this, '', conf, conf.errorMessagePosition);
41
+
42
+ $this
31
43
  .removeClass('valid')
32
44
  .removeClass(conf.errorElementClass)
33
- .css('border-color', '')
34
- .parent()
35
- .removeClass('has-error')
36
- .removeClass('has-success')
37
- .find('.'+conf.errorMessageClass) // remove inline error message
38
- .remove();
45
+ .css('border-color', '');
46
+
47
+ $parent
48
+ .removeClass(conf.inputParentClassOnError)
49
+ .removeClass(conf.inputParentClassOnSuccess)
50
+ .find('.'+conf.errorMessageClass) // remove inline span holding error message
51
+ .remove();
39
52
  });
40
53
  },
41
54
  _setInlineErrorMessage = function($input, mess, conf, $messageContainer) {
42
55
  var custom = _getInlineErrorElement($input);
56
+
43
57
  if( custom ) {
44
58
  custom.innerHTML = mess;
45
59
  }
@@ -64,10 +78,12 @@
64
78
  }
65
79
  }
66
80
  else {
67
- var $mess = $input.parent().find('.'+conf.errorMessageClass+'.help-block');
81
+ var $parent = $input.parent();
82
+ if($parent.hasClass("input-group")) $parent = $parent.parent();
83
+ var $mess = $parent.find('.'+conf.errorMessageClass+'.help-block');
68
84
  if( $mess.length == 0 ) {
69
85
  $mess = $('<span></span>').addClass('help-block').addClass(conf.errorMessageClass);
70
- $mess.appendTo($input.parent());
86
+ $mess.appendTo($parent);
71
87
  }
72
88
  $mess.html(mess);
73
89
  }
@@ -97,8 +113,15 @@
97
113
  $.fn.validateOnBlur = function(language, settings) {
98
114
  this.find('input[data-validation],textarea[data-validation],select[data-validation]')
99
115
  .bind('blur.validation', function() {
100
- $(this).validateInputOnBlur(language, settings);
116
+ $(this).validateInputOnBlur(language, settings, true, 'blur');
117
+ });
118
+ if(settings.validateCheckboxRadioOnClick) {
119
+ // bind click event to validate on click for radio & checkboxes for nice UX
120
+ this.find('input[type=checkbox][data-validation],input[type=radio][data-validation]')
121
+ .bind('click.validation', function() {
122
+ $(this).validateInputOnBlur(language, settings, true, 'click');
101
123
  });
124
+ }
102
125
 
103
126
  return this;
104
127
  };
@@ -113,10 +136,10 @@
113
136
  this.find('input[data-validation][data-validation-event],textarea[data-validation][data-validation-event],select[data-validation][data-validation-event]')
114
137
  .each(function(){
115
138
  var $el = $(this),
116
- etype = $el.attr("data-validation-event");
139
+ etype = $el.valAttr("event");
117
140
  if (etype){
118
141
  $el.bind(etype + ".validation", function(){
119
- $(this).validateInputOnBlur(language, settings, false, etype);
142
+ $(this).validateInputOnBlur(language, settings, true, etype);
120
143
  });
121
144
  }
122
145
  });
@@ -139,8 +162,6 @@
139
162
  // Remove previously added event listeners
140
163
  this.find('.has-help-txt')
141
164
  .valAttr('has-keyup-event', false)
142
- .valAttr('backend-valid', false)
143
- .valAttr('backend-invalid', false)
144
165
  .removeClass('has-help-txt');
145
166
 
146
167
  // Add help text listeners
@@ -188,23 +209,21 @@
188
209
  *
189
210
  * @param {Object} [language] Optional, will override $.formUtils.LANG
190
211
  * @param {Object} [conf] Optional, will override the default settings
191
- * @param {Boolean} [attachKeyupEvent] Optional
192
- * @param {String} [eventContext]
212
+ * @param {Boolean} attachKeyupEvent Optional
213
+ * @param {String} eventType
193
214
  * @return {jQuery}
194
215
  */
195
- $.fn.validateInputOnBlur = function(language, conf, attachKeyupEvent, eventContext) {
196
- if(attachKeyupEvent === undefined)
197
- attachKeyupEvent = true;
198
- if(!eventContext)
199
- eventContext = 'blur';
216
+ $.fn.validateInputOnBlur = function(language, conf, attachKeyupEvent, eventType) {
217
+
218
+ $.formUtils.eventType = eventType;
200
219
 
201
220
  if( (this.valAttr('suggestion-nr') || this.valAttr('postpone') || this.hasClass('hasDatepicker')) && !window.postponedValidation ) {
202
- // This validation has to be postponed
221
+ // This validation has to be postponed
203
222
  var _self = this,
204
223
  postponeTime = this.valAttr('postpone') || 200;
205
224
 
206
225
  window.postponedValidation = function() {
207
- _self.validateInputOnBlur(language, conf, attachKeyupEvent);
226
+ _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventType);
208
227
  window.postponedValidation = false;
209
228
  };
210
229
  setTimeout(function() {
@@ -218,7 +237,6 @@
218
237
 
219
238
  language = $.extend({}, $.formUtils.LANG, language || {});
220
239
  _removeErrorStyle(this, conf);
221
-
222
240
  var $elem = this,
223
241
  $form = $elem.closest("form"),
224
242
  validationRule = $elem.attr(conf.validationRuleAttribute),
@@ -227,25 +245,26 @@
227
245
  language,
228
246
  $.extend({}, conf, {errorMessagePosition:'element'}),
229
247
  $form,
230
- eventContext
248
+ eventType
231
249
  );
232
-
233
- $elem.trigger('validation', [validation===null ? null : validation===true]);
234
-
250
+
235
251
  if(validation === true) {
236
252
  $elem
237
253
  .addClass('valid')
238
254
  .parent()
239
- .addClass('has-success'); // twitter bs
255
+ .addClass(conf.inputParentClassOnSuccess);
256
+
240
257
  } else if(validation !== null) {
241
258
 
242
259
  _applyErrorStyle($elem, conf);
243
260
  _setInlineErrorMessage($elem, validation, conf, conf.errorMessagePosition);
244
261
 
245
262
  if(attachKeyupEvent) {
246
- $elem.bind('keyup', function() {
247
- $(this).validateInputOnBlur(language, conf, false, 'keyup');
248
- });
263
+ $elem
264
+ .unbind('keyup.validation')
265
+ .bind('keyup.validation', function() {
266
+ $(this).validateInputOnBlur(language, conf, false, 'keyup');
267
+ });
249
268
  }
250
269
  }
251
270
 
@@ -273,7 +292,7 @@
273
292
  };
274
293
 
275
294
  /**
276
- * Function that validate all inputs in given element
295
+ * Function that validates all inputs in active form
277
296
  *
278
297
  * @param {Object} [language]
279
298
  * @param {Object} [conf]
@@ -293,6 +312,14 @@
293
312
  language = $.extend({}, $.formUtils.LANG, language || {});
294
313
  displayError = displayError !== false;
295
314
 
315
+ if($.formUtils.errorDisplayPreventedWhenHalted) {
316
+ // isValid() was called programmatically with argument displayError set
317
+ // to false when the validation was halted by any of the validators
318
+ delete $.formUtils.errorDisplayPreventedWhenHalted
319
+ displayError = false;
320
+ }
321
+
322
+
296
323
  $.formUtils.isValidatingEntireForm = true;
297
324
  $.formUtils.haltValidation = false;
298
325
 
@@ -303,18 +330,18 @@
303
330
  * @para {jQuery} $elem
304
331
  */
305
332
  var addErrorMessage = function(mess, $elem) {
306
- // validate server side will return null as error message before the server is requested
307
- if(mess !== null) {
308
- if ($.inArray(mess, errorMessages) < 0) {
309
- errorMessages.push(mess);
310
- }
311
- errorInputs.push($elem);
312
- $elem.attr('current-error', mess);
313
- if( displayError )
314
- _applyErrorStyle($elem, conf);
333
+ if ($.inArray(mess, errorMessages) < 0) {
334
+ errorMessages.push(mess);
315
335
  }
336
+ errorInputs.push($elem);
337
+ $elem.attr('current-error', mess);
338
+ if( displayError )
339
+ _applyErrorStyle($elem, conf);
316
340
  },
317
341
 
342
+ /** Holds inputs (of type checkox or radio) already validated, to prevent recheck of mulitple checkboxes & radios */
343
+ checkedInputs = [],
344
+
318
345
  /** Error messages for this validation */
319
346
  errorMessages = [],
320
347
 
@@ -346,9 +373,15 @@
346
373
 
347
374
  // Validate element values
348
375
  $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function() {
349
- var $elem = $(this);
350
- var elementType = $elem.attr('type');
351
- if (!ignoreInput($elem.attr('name'), elementType)) {
376
+ var $elem = $(this),
377
+ elementType = $elem.attr('type'),
378
+ isCheckboxOrRadioBtn = elementType == 'radio' || elementType == 'checkbox',
379
+ elementName = $elem.attr('name');
380
+
381
+ if (!ignoreInput(elementName, elementType) && (!isCheckboxOrRadioBtn || $.inArray(elementName, checkedInputs) < 0) ) {
382
+
383
+ if( isCheckboxOrRadioBtn )
384
+ checkedInputs.push(elementName);
352
385
 
353
386
  var validation = $.formUtils.validateInput(
354
387
  $elem,
@@ -358,24 +391,18 @@
358
391
  'submit'
359
392
  );
360
393
 
361
- $elem.trigger('validation', [validation===true]);
362
-
363
- // Run element validation callback
364
- if( typeof conf.onElementValidate == 'function' ) {
365
- conf.onElementValidate((validation === true), $elem, $form, validation);
366
- }
367
-
368
- if(validation !== true) {
369
- addErrorMessage(validation, $elem);
370
- } else {
371
- $elem
372
- .valAttr('current-error', false)
373
- .addClass('valid')
374
- .parent()
394
+ if(validation != null) {
395
+ if(validation !== true) {
396
+ addErrorMessage(validation, $elem);
397
+ } else {
398
+ $elem
399
+ .valAttr('current-error', false)
400
+ .addClass('valid')
401
+ .parent()
375
402
  .addClass('has-success');
403
+ }
376
404
  }
377
405
  }
378
-
379
406
  });
380
407
 
381
408
  // Run validation callback
@@ -423,6 +450,10 @@
423
450
  return false;
424
451
  }
425
452
 
453
+ if( !displayError && $.formUtils.haltValidation ) {
454
+ $.formUtils.errorDisplayPreventedWhenHalted = true;
455
+ }
456
+
426
457
  return !$.formUtils.haltValidation;
427
458
  };
428
459
 
@@ -469,32 +500,34 @@
469
500
 
470
501
  /**
471
502
  * A bit smarter split function
503
+ * delimiter can be space, comma, dash or pipe
472
504
  * @param {String} val
473
505
  * @param {Function|String} [func]
474
- * @param {String} [delim]
475
506
  * @returns {Array|void}
476
507
  */
477
- $.split = function(val, func, delim) {
508
+ $.split = function(val, func) {
478
509
  if( typeof func != 'function' ) {
479
- // return string
510
+ // return array
480
511
  if( !val )
481
512
  return [];
482
513
  var values = [];
483
- $.each(val.split(func ? func:','), function(i,str) {
484
- str = $.trim(str);
485
- if( str.length )
486
- values.push(str);
487
- });
514
+ $.each(val.split(func ? func: /[,|-\s]\s*/g ),
515
+ function(i,str) {
516
+ str = $.trim(str);
517
+ if( str.length )
518
+ values.push(str);
519
+ }
520
+ );
488
521
  return values;
489
522
  } else if( val ) {
490
- // use callback on each
491
- if( !delim )
492
- delim = ',';
493
- $.each(val.split(delim), function(i, str) {
494
- str = $.trim(str);
495
- if( str.length )
496
- return func(str, i);
497
- });
523
+ // exec callback func on each
524
+ $.each(val.split(/[,|-\s]\s*/g),
525
+ function(i, str) {
526
+ str = $.trim(str);
527
+ if( str.length )
528
+ return func(str, i);
529
+ }
530
+ );
498
531
  }
499
532
  };
500
533
 
@@ -511,6 +544,7 @@
511
544
  */
512
545
  validateOnEvent : true,
513
546
  validateOnBlur : true,
547
+ validateCheckboxRadioOnClick : true,
514
548
  showHelpOnFocus : true,
515
549
  addSuggestions : true,
516
550
  modules : '',
@@ -518,15 +552,15 @@
518
552
  language : false,
519
553
  onSuccess : false,
520
554
  onError : false,
521
- onElementValidate : false
555
+ onElementValidate : false,
522
556
  });
523
557
 
524
558
  conf = $.extend(defaultConf, conf || {});
525
559
 
526
560
  // Add validation to forms
527
- $.split(conf.form, function(formQuery) {
561
+ $(conf.form).each(function(i, form) {
528
562
 
529
- var $form = $(formQuery);
563
+ var $form = $(form);
530
564
  $window.trigger('formValidationSetup', [$form]);
531
565
 
532
566
  // Remove all event listeners previously added
@@ -544,22 +578,34 @@
544
578
  $form.bind('submit.validation', function() {
545
579
  var $form = $(this);
546
580
 
581
+ if( $.formUtils.haltValidation ) {
582
+ // pressing several times on submit button while validation is halted
583
+ return false;
584
+ }
585
+
547
586
  if($.formUtils.isLoadingModules) {
548
587
  setTimeout(function() {
549
588
  $form.trigger('submit.validation');
550
589
  }, 200);
551
590
  return false;
552
591
  }
592
+
553
593
  var valid = $form.isValid(conf.language, conf);
554
- if( valid && typeof conf.onSuccess == 'function') {
555
- var callbackResponse = conf.onSuccess($form);
556
- if( callbackResponse === false )
557
- return false;
558
- } else if ( !valid && typeof conf.onError == 'function' ) {
559
- conf.onError($form);
594
+
595
+ if( $.formUtils.haltValidation ) {
596
+ // Validation got halted by one of the validators
560
597
  return false;
561
598
  } else {
562
- return valid;
599
+ if( valid && typeof conf.onSuccess == 'function') {
600
+ var callbackResponse = conf.onSuccess($form);
601
+ if( callbackResponse === false )
602
+ return false;
603
+ } else if ( !valid && typeof conf.onError == 'function' ) {
604
+ conf.onError($form);
605
+ return false;
606
+ } else {
607
+ return valid;
608
+ }
563
609
  }
564
610
  })
565
611
  .bind('reset.validation', function() {
@@ -621,7 +667,9 @@
621
667
  scrollToTopOnError : true,
622
668
  dateFormat : 'yyyy-mm-dd',
623
669
  addValidClassOnAll : false, // whether or not to apply class="valid" even if the input wasn't validated
624
- decimalSeparator : '.'
670
+ decimalSeparator : '.',
671
+ inputParentClassOnError : 'has-error', // twitter-bootstrap default class name
672
+ inputParentClassOnSuccess : 'has-success' // twitter-bootstrap default class name
625
673
  }
626
674
  },
627
675
 
@@ -763,16 +811,11 @@
763
811
  } else {
764
812
  var findScriptPathAndLoadModules = function() {
765
813
  var foundPath = false;
766
- $('script').each(function() {
767
- if( this.src ) {
768
- var scriptName = this.src.substr(this.src.lastIndexOf('/')+1, this.src.length);
769
- if(scriptName.indexOf('jquery.form-validator.js') > -1 || scriptName.indexOf('jquery.form-validator.min.js') > -1) {
770
- foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
771
- if( foundPath == '/' )
772
- foundPath = '';
773
- return false;
774
- }
775
- }
814
+ $('script[src*="form-validator"]').each(function() {
815
+ foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/';
816
+ if( foundPath == '/' )
817
+ foundPath = '';
818
+ return false;
776
819
  });
777
820
 
778
821
  if( foundPath !== false) {
@@ -790,8 +833,8 @@
790
833
 
791
834
  /**
792
835
  * Validate the value of given element according to the validation rules
793
- * found in the attribute data-validation. Will return true if valid,
794
- * error message otherwise
836
+ * found in the attribute data-validation. Will return null if no validation
837
+ * should take place, returns true if valid or error message if not valid
795
838
  *
796
839
  * @param {jQuery} $elem
797
840
  * @param {Object} language ($.formUtils.LANG)
@@ -807,7 +850,7 @@
807
850
 
808
851
  $elem.trigger('beforeValidation');
809
852
 
810
- var value = $.trim( $elem.val() || ''),
853
+ var value = $elem.val() || '',
811
854
  optional = $elem.valAttr('optional'),
812
855
 
813
856
  // test if a checkbox forces this element to be validated
@@ -859,41 +902,58 @@
859
902
  var validator = $.formUtils.validators[rule];
860
903
 
861
904
  if( validator && typeof validator['validatorFunction'] == 'function' ) {
905
+
862
906
  // special change of element for checkbox_group rule
863
907
  if ( rule == 'validate_checkbox_group' ) {
864
- // set element to first in group, so error msg is set only once
908
+ // set element to first in group, so error msg attr doesn't need to be set on all elements in group
865
909
  $elem = $("[name='"+$elem.attr('name')+"']:eq(0)");
866
910
  }
867
-
868
- var isValid = true;
911
+
912
+ var isValid = null;
869
913
  if( eventContext != 'keyup' || validator.validateOnKeyUp ) {
870
914
  isValid = validator.validatorFunction(value, $elem, conf, language, $form);
871
915
  }
872
916
 
873
917
  if(!isValid) {
874
- validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute+'-'+rule.replace('validate_', ''));
875
- if( !validationErrorMsg ) {
876
- validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
918
+ validationErrorMsg = null;
919
+ if( isValid !== null ) {
920
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute+'-'+rule.replace('validate_', ''));
877
921
  if( !validationErrorMsg ) {
878
- validationErrorMsg = language[validator.errorMessageKey];
879
- if( !validationErrorMsg )
880
- validationErrorMsg = validator.errorMessage;
922
+ validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute);
923
+ if( !validationErrorMsg ) {
924
+ validationErrorMsg = language[validator.errorMessageKey];
925
+ if( !validationErrorMsg )
926
+ validationErrorMsg = validator.errorMessage;
927
+ }
881
928
  }
882
929
  }
883
930
  return false; // breaks the iteration
884
931
  }
885
932
 
886
933
  } else {
887
- console.warn('Using undefined validator "'+rule+'"');
934
+ throw new Error('Using undefined validator "'+rule+'"');
888
935
  }
889
936
 
890
937
  }, ' ');
891
938
 
939
+ var result;
940
+
892
941
  if( typeof validationErrorMsg == 'string' ) {
893
- return validationErrorMsg;
942
+ $elem.trigger('validation', false);
943
+ result = validationErrorMsg;
944
+ } else if( validationErrorMsg === null && !conf.addValidClassOnAll ) {
945
+ result = null;
894
946
  } else {
895
- return true;
947
+ $elem.trigger('validation', true);
948
+ result = true;
949
+ }
950
+
951
+ // Run element validation callback
952
+ if( typeof conf.onElementValidate == 'function' && result !== null ) {
953
+ conf.onElementValidate((result === true), $elem, $form, validationErrorMsg);
896
954
  }
955
+
956
+ return result;
897
957
  },
898
958
 
899
959
  /**
@@ -907,7 +967,7 @@
907
967
  parseDate : function(val, dateFormat) {
908
968
  var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0,1),
909
969
  regexp = '^',
910
- formatParts = dateFormat.split(divider),
970
+ formatParts = dateFormat.split(divider || null),
911
971
  matches, day, month, year;
912
972
 
913
973
  $.each(formatParts, function(i, part) {
@@ -1018,7 +1078,7 @@
1018
1078
  numericRangeCheck : function(value, rangeAllowed)
1019
1079
  {
1020
1080
  // split by dash
1021
- var range = $.split(rangeAllowed, '-');
1081
+ var range = $.split(rangeAllowed);
1022
1082
  // min or max
1023
1083
  var minmax = parseInt(rangeAllowed.substr(3),10)
1024
1084
  // range ?
@@ -1028,7 +1088,8 @@
1028
1088
  { return ["min", minmax]; } // value is below min
1029
1089
  else if (rangeAllowed.indexOf('max') === 0 && (value > minmax ) ) // max
1030
1090
  { return ["max", minmax]; } // value is above max
1031
- else { return [ "ok" ] ; } // value is in allowed range
1091
+ // since no other returns executed, value is in allowed range
1092
+ return [ "ok" ] ;
1032
1093
  },
1033
1094
 
1034
1095
 
@@ -1269,24 +1330,24 @@
1269
1330
  badTelephone : 'You have not given a correct phone number',
1270
1331
  badSecurityAnswer : 'You have not given a correct answer to the security question',
1271
1332
  badDate : 'You have not given a correct date',
1272
- lengthBadStart : 'You must give an answer between ',
1333
+ lengthBadStart : 'The input value must be between ',
1273
1334
  lengthBadEnd : ' characters',
1274
- lengthTooLongStart : 'You have given an answer longer than ',
1275
- lengthTooShortStart : 'You have given an answer shorter than ',
1276
- notConfirmed : 'Values could not be confirmed',
1335
+ lengthTooLongStart : 'The input value is longer than ',
1336
+ lengthTooShortStart : 'The input value is shorter than ',
1337
+ notConfirmed : 'Input values could not be confirmed',
1277
1338
  badDomain : 'Incorrect domain value',
1278
- badUrl : 'The answer you gave was not a correct URL',
1279
- badCustomVal : 'You gave an incorrect answer',
1280
- badInt : 'The answer you gave was not a correct number',
1281
- badSecurityNumber : 'Your isVsocial security number was incorrect',
1339
+ badUrl : 'The input value is not a correct URL',
1340
+ badCustomVal : 'The input value is incorrect',
1341
+ badInt : 'The input value was not a correct number',
1342
+ badSecurityNumber : 'Your social security number was incorrect',
1282
1343
  badUKVatAnswer : 'Incorrect UK VAT Number',
1283
1344
  badStrength : 'The password isn\'t strong enough',
1284
1345
  badNumberOfSelectedOptionsStart : 'You have to choose at least ',
1285
1346
  badNumberOfSelectedOptionsEnd : ' answers',
1286
- badAlphaNumeric : 'The answer you gave must contain only alphanumeric characters ',
1347
+ badAlphaNumeric : 'The input value can only contain alphanumeric characters ',
1287
1348
  badAlphaNumericExtra: ' and ',
1288
- wrongFileSize : 'The file you are trying to upload is too large',
1289
- wrongFileType : 'The file you are trying to upload is of wrong type',
1349
+ wrongFileSize : 'The file you are trying to upload is too large (max %s)',
1350
+ wrongFileType : 'Only files of type %s is allowed',
1290
1351
  groupCheckedRangeStart : 'Please choose between ',
1291
1352
  groupCheckedTooFewStart : 'Please choose at least ',
1292
1353
  groupCheckedTooManyStart : 'Please choose a maximum of ',
@@ -1312,7 +1373,7 @@
1312
1373
  var emailParts = email.toLowerCase().split('@');
1313
1374
  if( emailParts.length == 2 ) {
1314
1375
  return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
1315
- !(/[^\w\+\.\-]/.test(emailParts[0]));
1376
+ !(/[^\w\+\.\-]/.test(emailParts[0])) && emailParts[0].length > 0;
1316
1377
  }
1317
1378
 
1318
1379
  return false;
@@ -1326,98 +1387,14 @@
1326
1387
  */
1327
1388
  $.formUtils.addValidator({
1328
1389
  name : 'domain',
1329
- validatorFunction : function(val, $input) {
1330
-
1331
- var topDomains = ['.ac', '.ad', '.ae', '.aero', '.af', '.ag', '.ai', '.al', '.am', '.an', '.ao',
1332
- '.aq', '.ar', '.arpa', '.as', '.asia', '.at', '.au', '.aw', '.ax', '.az', '.ba', '.bb',
1333
- '.bd', '.be', '.bf', '.bg', '.bh', '.bi', '.bike', '.biz', '.bj', '.bm', '.bn', '.bo',
1334
- '.br', '.bs', '.bt', '.bv', '.bw', '.by', '.bz', '.ca', '.camera', '.cat', '.cc', '.cd',
1335
- '.cf', '.cg', '.ch', '.ci', '.ck', '.cl', '.clothing', '.cm', '.cn', '.co', '.com',
1336
- '.construction', '.contractors', '.coop', '.cr', '.cu', '.cv', '.cw', '.cx', '.cy', '.cz',
1337
- '.de', '.diamonds', '.directory', '.dj', '.dk', '.dm', '.do', '.dz', '.ec', '.edu', '.ee',
1338
- '.eg', '.enterprises', '.equipment', '.er', '.es', '.estate', '.et', '.eu', '.fi', '.fj',
1339
- '.fk', '.fm', '.fo', '.fr', '.ga', '.gallery', '.gb', '.gd', '.ge', '.gf', '.gg', '.gh',
1340
- '.gi', '.gl', '.gm', '.gn', '.gov', '.gp', '.gq', '.gr', '.graphics', '.gs', '.gt', '.gu',
1341
- '.guru', '.gw', '.gy', '.hk', '.hm', '.hn', '.holdings', '.hr', '.ht', '.hu', '.id', '.ie',
1342
- '.il', '.im', '.in', '.info', '.int', '.io', '.iq', '.ir', '.is', '.it', '.je', '.jm', '.jo',
1343
- '.jobs', '.jp', '.ke', '.kg', '.kh', '.ki', '.kitchen', '.km', '.kn', '.kp', '.kr', '.kw',
1344
- '.ky', '.kz', '.la', '.land', '.lb', '.lc', '.li', '.lighting', '.lk', '.lr', '.ls', '.lt',
1345
- '.lu', '.lv', '.ly', '.ma', '.mc', '.md', '.me', '.menu', '.mg', '.mh', '.mil', '.mk', '.ml',
1346
- '.mm', '.mn', '.mo', '.mobi', '.mp', '.mq', '.mr', '.ms', '.mt', '.mu', '.museum', '.mv',
1347
- '.mw', '.mx', '.my', '.mz', '.na', '.name', '.nc', '.ne', '.net', '.nf', '.ng', '.ni',
1348
- '.nl', '.no', '.np', '.nr', '.nu', '.nz', '.om', '.org', '.pa', '.pe', '.pf', '.pg', '.ph',
1349
- '.photography', '.pk', '.pl', '.plumbing', '.pm', '.pn', '.post', '.pr', '.pro', '.ps', '.pt',
1350
- '.pw', '.py', '.qa', '.re', '.ro', '.rs', '.ru', '.rw', '.sa', '.sb', '.sc', '.sd', '.se',
1351
- '.sexy', '.sg', '.sh', '.si', '.singles', '.sj', '.sk', '.sl', '.sm', '.sn', '.so', '.sr',
1352
- '.st', '.su', '.sv', '.sx', '.sy', '.sz', '.tattoo', '.tc', '.td', '.technology', '.tel', '.tf',
1353
- '.tg', '.th', '.tips', '.tj', '.tk', '.tl', '.tm', '.tn', '.to', '.today', '.tp', '.tr', '.travel',
1354
- '.tt', '.tv', '.tw', '.tz', '.ua', '.ug', '.uk', '.uno', '.us', '.uy', '.uz', '.va', '.vc', '.ve',
1355
- '.ventures', '.vg', '.vi', '.vn', '.voyage', '.vu', '.wf', '.ws', '.xn--3e0b707e', '.xn--45brj9c',
1356
- '.xn--80ao21a', '.xn--80asehdb', '.xn--80aswg', '.xn--90a3ac', '.xn--clchc0ea0b2g2a9gcd', '.xn--fiqs8s',
1357
- '.xn--fiqz9s', '.xn--fpcrj9c3d', '.xn--fzc2c9e2c', '.xn--gecrj9c', '.xn--h2brj9c', '.xn--j1amh',
1358
- '.xn--j6w193g', '.xn--kprw13d', '.xn--kpry57d', '.xn--l1acc', '.xn--lgbbat1ad8j', '.xn--mgb9awbf',
1359
- '.xn--mgba3a4f16a', '.xn--mgbaam7a8h', '.xn--mgbayh7gpa', '.xn--mgbbh1a71e', '.xn--mgbc0a9azcg',
1360
- '.xn--mgberp4a5d4ar', '.xn--mgbx4cd0ab', '.xn--ngbc5azd', '.xn--o3cw4h', '.xn--ogbpf8fl', '.xn--p1ai',
1361
- '.xn--pgbs0dh', '.xn--q9jyb4c', '.xn--s9brj9c', '.xn--unup4y', '.xn--wgbh1c', '.xn--wgbl6a',
1362
- '.xn--xkc2al3hye2a', '.xn--xkc2dl3a5ee0h', '.xn--yfro4i67o', '.xn--ygbi2ammx', '.xxx', '.ye',
1363
- '.yt', '.za', '.zm', '.zw'],
1364
-
1365
- ukTopDomains = ['co', 'me', 'ac', 'gov', 'judiciary','ltd', 'mod', 'net', 'nhs', 'nic',
1366
- 'org', 'parliament', 'plc', 'police', 'sch', 'bl', 'british-library', 'jet','nls'],
1367
-
1368
- dot = val.lastIndexOf('.'),
1369
- domain = val.substring(0, dot),
1370
- ext = val.substring(dot, val.length),
1371
- hasTopDomain = false;
1372
-
1373
- for (var i = 0; i < topDomains.length; i++) {
1374
- if (topDomains[i] === ext) {
1375
- if(ext==='.uk') {
1376
- //Run Extra Checks for UK Domain Names
1377
- var domainParts = val.split('.');
1378
- var tld2 = domainParts[domainParts.length-2];
1379
- for(var j = 0; j < ukTopDomains.length; j++) {
1380
- if(ukTopDomains[j] === tld2) {
1381
- hasTopDomain = true;
1382
- break;
1383
- }
1384
- }
1385
-
1386
- if(hasTopDomain)
1387
- break;
1388
-
1389
- } else {
1390
- hasTopDomain = true;
1391
- break;
1392
- }
1393
- }
1394
- }
1395
-
1396
- if (!hasTopDomain) {
1397
- return false;
1398
- } else if (dot < 2 || dot > 57) {
1399
- return false;
1400
- } else {
1401
- var firstChar = domain.substring(0, 1),
1402
- lastChar = domain.substring(domain.length - 1, domain.length);
1403
-
1404
- if (firstChar === '-' || firstChar === '.' || lastChar === '-' || lastChar === '.') {
1405
- return false;
1406
- }
1407
- if (domain.split('.').length > 3 || domain.split('..').length > 1) {
1408
- return false;
1409
- }
1410
- if (domain.replace(/[-\da-z\.]/g, '') !== '') {
1411
- return false;
1412
- }
1413
- }
1414
-
1415
- // It's valid, lets update input with trimmed value perhaps??
1416
- if(typeof $input !== 'undefined') {
1417
- $input.val(val);
1418
- }
1419
-
1420
- return true;
1390
+ validatorFunction : function(val) {
1391
+ return val.length > 0 &&
1392
+ val.length <= 253 && // Including sub domains
1393
+ !(/[^a-zA-Z0-9]/.test(val.substr(-2))) &&
1394
+ !(/[^a-zA-Z]/.test(val.substr(0,1))) &&
1395
+ !(/[^a-zA-Z0-9\.\-]/.test(val)) &&
1396
+ val.split('..').length == 1 &&
1397
+ val.split('.').length > 1;
1421
1398
  },
1422
1399
  errorMessage : '',
1423
1400
  errorMessageKey: 'badDomain'
@@ -1452,8 +1429,7 @@
1452
1429
  type = $el.attr('type');
1453
1430
 
1454
1431
  if(lengthAllowed == undefined) {
1455
- var elementType = $el.get(0).nodeName;
1456
- alert('Please add attribute "data-validation-length" to '+elementType+' named '+$el.attr('name'));
1432
+ alert('Please add attribute "data-validation-length" to '+$el[0].nodeName+' named '+$el.attr('name'));
1457
1433
  return true;
1458
1434
  }
1459
1435
 
@@ -1500,8 +1476,9 @@
1500
1476
  // - General improvements made by Stéphane Moureau <https://github.com/TraderStf>
1501
1477
  var urlFilter = /^(https?|ftp):\/\/((((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\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])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|\[|\]|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
1502
1478
  if( urlFilter.test(url) ) {
1503
- var domain = url.split('://')[1];
1504
- var domainSlashPos = domain.indexOf('/');
1479
+ var domain = url.split('://')[1],
1480
+ domainSlashPos = domain.indexOf('/');
1481
+
1505
1482
  if(domainSlashPos > -1)
1506
1483
  domain = domain.substr(0, domainSlashPos);
1507
1484
 
@@ -1523,7 +1500,9 @@
1523
1500
  var allowing = $el.valAttr('allowing') || '',
1524
1501
  decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator,
1525
1502
  allowsRange = false,
1526
- begin, end;
1503
+ begin, end,
1504
+ steps = $el.valAttr('step') || '',
1505
+ allowsSteps = false;
1527
1506
 
1528
1507
  if(allowing.indexOf('number') == -1)
1529
1508
  allowing += ',number';
@@ -1538,6 +1517,9 @@
1538
1517
  end = parseFloat(allowing.substring(allowing.indexOf(";")+1,allowing.indexOf("]")));
1539
1518
  allowsRange = true;
1540
1519
  }
1520
+
1521
+ if(steps != "")
1522
+ allowsSteps = true;
1541
1523
 
1542
1524
  if( decimalSeparator == ',' ) {
1543
1525
  if( val.indexOf('.') > -1 ) {
@@ -1547,10 +1529,10 @@
1547
1529
  val = val.replace(',', '.');
1548
1530
  }
1549
1531
 
1550
- if(allowing.indexOf('number') > -1 && val.replace(/[0-9]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) ) {
1532
+ if(allowing.indexOf('number') > -1 && val.replace(/[0-9]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val%steps == 0)) ) {
1551
1533
  return true;
1552
1534
  }
1553
- if(allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) ) {
1535
+ if(allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val%steps == 0)) ) {
1554
1536
  return true;
1555
1537
  }
1556
1538
  }
@@ -1568,7 +1550,7 @@
1568
1550
  validatorFunction : function(val, $el, conf, language) {
1569
1551
  var patternStart = '^([a-zA-Z0-9',
1570
1552
  patternEnd = ']+)$',
1571
- additionalChars = $el.attr('data-validation-allowing'),
1553
+ additionalChars = $el.valAttr('allowing'),
1572
1554
  pattern = '';
1573
1555
 
1574
1556
  if( additionalChars ) {
@@ -1609,14 +1591,7 @@
1609
1591
  $.formUtils.addValidator({
1610
1592
  name : 'date',
1611
1593
  validatorFunction : function(date, $el, conf) {
1612
- var dateFormat = 'yyyy-mm-dd';
1613
- if($el.valAttr('format')) {
1614
- dateFormat = $el.valAttr('format');
1615
- }
1616
- else if( conf.dateFormat ) {
1617
- dateFormat = conf.dateFormat;
1618
- }
1619
-
1594
+ var dateFormat = $el.valAttr('format') || conf.dateFormat || 'yyyy-mm-dd';
1620
1595
  return $.formUtils.parseDate(date, dateFormat) !== false;
1621
1596
  },
1622
1597
  errorMessage : '',
@@ -1635,20 +1610,24 @@
1635
1610
  $.formUtils.addValidator({
1636
1611
  name : 'checkbox_group',
1637
1612
  validatorFunction : function(val, $el, conf, lang, $form)
1638
- { // preset return var
1639
- var checkResult = true;
1640
- // get name of element. since it is a checkbox group, all checkboxes will have same name
1641
- var elname = $el.attr('name');
1642
- // get count of checked checkboxes with this name
1643
- var checkedCount = $("input[type=checkbox][name^='"+elname+"']:checked", $form).length;
1644
- // get el attr that specs qty required / allowed
1645
- var qtyAllowed = $el.valAttr('qty');
1613
+ {
1614
+ // preset return var
1615
+ var checkResult = true,
1616
+ // get name of element. since it is a checkbox group, all checkboxes will have same name
1617
+ elname = $el.attr('name'),
1618
+ // get count of checked checkboxes with this name
1619
+ checkedCount = $("input[type=checkbox][name^='"+elname+"']:checked", $form).length,
1620
+ // get el attr that specs qty required / allowed
1621
+ qtyAllowed = $el.valAttr('qty');
1622
+
1646
1623
  if (qtyAllowed == undefined) {
1647
1624
  var elementType = $el.get(0).nodeName;
1648
1625
  alert('Attribute "data-validation-qty" is missing from '+elementType+' named '+$el.attr('name'));
1649
1626
  }
1627
+
1650
1628
  // call Utility function to check if count is above min, below max, within range etc.
1651
1629
  var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed) ;
1630
+
1652
1631
  // results will be array, [0]=result str, [1]=qty int
1653
1632
  switch(qtyCheckResults[0] ) {
1654
1633
  // outside allowed range
@@ -1671,8 +1650,7 @@
1671
1650
  checkResult = true;
1672
1651
  }
1673
1652
 
1674
- return checkResult;
1675
-
1653
+ return checkResult;
1676
1654
  }
1677
1655
  // errorMessage : '', // set above in switch statement
1678
1656
  // errorMessageKey: '' // not used