PageSourceSearch

https://www.equestrian.org.au/sites/all/modules/clientside_validation/clientside_validation.js?tjdipd

js equestrian.org.au collected 2026-10-01 10:40:00 UTC 56,685 bytes, 1,495 lines download raw bytes

1/*jshint strict:true, browser:true, curly:true, eqeqeq:true, expr:true, forin:true, latedef:true, newcap:true, noarg:true, trailing: true, undef:true, unused:true */
2/*global Drupal: true, jQuery: true, XRegExp:true*/
3/**
4 * File:        clientside_validation.js
5 * Version:     7.x-1.x
6 * Description: Add clientside validation rules
7 * Author:      Attiks
8 * Language:    Javascript
9 * Project:     clientside_validation
10 * @module clientside_validation
11 */
12
13
14(/** @lends Drupal */function ($) {
15  /**
16   * Drupal.behaviors.clientsideValidation.
17   *
18   * Attach clientside validation to the page or rebind the rules in case of AJAX calls.
19   * @extends Drupal.behaviors
20   * @fires clientsideValidationInitialized
21   */
22  "use strict";
23  Drupal.behaviors.clientsideValidation = {
24    attach: function (context) {
25      if (!Drupal.myClientsideValidation) {
26        if (Drupal.settings.clientsideValidation) {
27          Drupal.myClientsideValidation = new Drupal.clientsideValidation();
28        }
29      }
30      else {
31        if (typeof(Drupal.settings.clientsideValidation.forms) === 'undefined') {
32          return;
33        }
34        var update = false;
35        jQuery.each(Drupal.settings.clientsideValidation.forms, function (f) {
36          if ($(context).find('#' + f).length || $(context).is('#' + f)) {
37            update = true;
38          }
39        });
40        //update settings
41        if (update) {
42          Drupal.myClientsideValidation.data = Drupal.settings.clientsideValidation;
43          Drupal.myClientsideValidation.forms = Drupal.myClientsideValidation.data.forms;
44          Drupal.myClientsideValidation.groups = Drupal.myClientsideValidation.data.groups;
45          Drupal.myClientsideValidation.bindForms();
46        }
47      }
48
49      /**
50       * Let other modules know we are ready.
51       * @event clientsideValidationInitialized
52       * @name clientsideValidationInitialized
53       * @memberof Drupal.clientsideValidation
54       */
55      jQuery.event.trigger('clientsideValidationInitialized');
56    }
57  };
58
59  /**
60   * Drupal.clientsideValidation.
61   * This module adds clientside validation for all forms and webforms using jquery.validate
62   * Don't forget to read the README
63   *
64   * @class Drupal.clientsideValidation
65   * @see https://github.com/jzaefferer/jquery-validation
66   * @fires clientsideValidationAddCustomRules
67   */
68  Drupal.clientsideValidation = function() {
69    var self = this;
70    if (typeof window.time !== 'undefined') {
71      // activate by setting clientside_validation_add_js_timing
72      self.time = window.time;
73    }
74    else {
75      self.time = {
76        start: function() {},
77        stop: function() {},
78        report: function() {}
79      };
80    }
81    self.time.start('1. clientsideValidation');
82
83    /**
84     * prefix to use
85     * @memberof Drupal.clientsideValidation
86     * @type string
87     * @readonly
88     * @private
89     */
90    this.prefix = 'clientsidevalidation-';
91
92    /**
93     * local copy of settings
94     * @memberof Drupal.clientsideValidation
95     * @type array
96     * @readonly
97     * @private
98     */
99    this.data = $.extend(true, {}, Drupal.settings.clientsideValidation);
100
101    /**
102     * local reference of all defined forms
103     * @memberof Drupal.clientsideValidation
104     * @type array
105     * @readonly
106     */
107    this.forms = this.data.forms;
108
109    /**
110     * list of all defined validators
111     * @memberof Drupal.clientsideValidation
112     * @type array
113     * @readonly
114     */
115    this.validators = {};
116
117    /**
118     * groups used for radios/checkboxes
119     * @memberof Drupal.clientsideValidation
120     * @type array
121     * @readonly
122     * @private
123     */
124    this.groups = this.data.groups;
125
126    // disable class and attribute rules defined by jquery.validate
127    $.validator.classRules = function() {
128      return {};
129    };
130    $.validator.attributeRules = function() {
131      return {};
132    };
133
134    /**
135     * add extra rules not defined in jquery.validate
136     * @see jquery.validate
137     */
138    this.addExtraRules();
139
140    /**
141     * bind all rules to all forms
142     * @see Drupal.clientsideValidation.prototype.bindForms
143     */
144    this.bindForms();
145    self.time.stop('1. clientsideValidation');
146    self.time.report();
147  };
148
149  /**
150   * findVerticalTab helper.
151   * @memberof Drupal.clientsideValidation
152   * @private
153   */
154  Drupal.clientsideValidation.prototype.findVerticalTab = function(element) {
155    element = $(element);
156
157    // Check for the vertical tabs fieldset and the verticalTab data
158    var fieldset = element.parents('fieldset.vertical-tabs-pane');
159    if ((fieldset.size() > 0) && (typeof(fieldset.data('verticalTab')) !== 'undefined')) {
160      var tab = $(fieldset.data('verticalTab').item[0]).find('a');
161      if (tab.size()) {
162        return tab;
163      }
164    }
165
166    // Return null by default
167    return null;
168  };
169
170  /**
171   * findHorizontalTab helper.
172   * @memberof Drupal.clientsideValidation
173   * @private
174   */
175  Drupal.clientsideValidation.prototype.findHorizontalTab = function(element) {
176    element = $(element);
177
178    // Check for the vertical tabs fieldset and the verticalTab data
179    var fieldset = element.parents('fieldset.horizontal-tabs-pane');
180    if ((fieldset.size() > 0) && (typeof(fieldset.data('horizontalTab')) !== 'undefined')) {
181      var tab = $(fieldset.data('horizontalTab').item[0]).find('a');
182      if (tab.size()) {
183        return tab;
184      }
185    }
186
187    // Return null by default
188    return null;
189  };
190
191  /**
192   * Bind all forms.
193   * @memberof Drupal.clientsideValidation
194   * @public
195   */
196  Drupal.clientsideValidation.prototype.bindForms = function(){
197    var self = this;
198    var groupkey;
199    if (typeof(self.forms) === 'undefined') {
200      return;
201    }
202    self.time.start('2. bindForms');
203    // unset invalid forms
204    jQuery.each (self.forms, function (f) {
205      if ($('#' + f).length < 1) {
206        delete self.forms[f];
207      }
208    });
209    jQuery.each (self.forms, function(f) {
210      var errorel = self.prefix + f + '-errors';
211      // Remove any existing validation stuff
212      if (self.validators[f]) {
213        // Doesn't work :: $('#' + f).rules('remove');
214        var form = $('#' + f).get(0);
215        if (typeof(form) !== 'undefined') {
216          jQuery.removeData(form, 'validator');
217        }
218      }
219
220      if('checkboxrules' in self.forms[f]){
221        self.time.start('checkboxrules_groups');
222        groupkey = "";
223        jQuery.each (self.forms[f].checkboxrules, function(r) {
224          groupkey = r + '_group';
225          self.groups[f][groupkey] = [];
226          jQuery.each(this, function(){
227            $(this[2]).find('input[type=checkbox]').each(function(){
228              self.groups[f][groupkey].push($(this).attr('name'));
229            });
230          });
231        });
232        self.time.stop('checkboxrules_groups');
233      }
234
235      if('daterangerules' in self.forms[f]){
236        self.time.start('daterangerules');
237        groupkey = "";
238        jQuery.each (self.forms[f].daterangerules, function(r) {
239          groupkey = r + '_group';
240          self.groups[f][groupkey] = [];
241          jQuery.each(this, function(){
242            $('#' + f + ' #' + r + ' :input').not('input[type=image]').each(function(){
243              self.groups[f][groupkey].push($(this).attr('name'));
244            });
245          });
246        });
247        self.time.stop('daterangerules');
248      }
249
250      if('dateminrules' in self.forms[f]){
251        self.time.start('dateminrules');
252        groupkey = "";
253        jQuery.each (self.forms[f].dateminrules, function(r) {
254          groupkey = r + '_group';
255          self.groups[f][groupkey] = [];
256          jQuery.each(this, function(){
257            $('#' + f + ' #' + r + ' :input').not('input[type=image]').each(function(){
258              self.groups[f][groupkey].push($(this).attr('name'));
259            });
260          });
261        });
262        self.time.stop('dateminrules');
263      }
264
265      if('datemaxrules' in self.forms[f]){
266        self.time.start('datemaxrules');
267        groupkey = "";
268        jQuery.each (self.forms[f].datemaxrules, function(r) {
269          groupkey = r + '_group';
270          self.groups[f][groupkey] = [];
271          jQuery.each(this, function(){
272            $('#' + f + ' #' + r + ' :input').not('input[type=image]').each(function(){
273              self.groups[f][groupkey].push($(this).attr('name'));
274            });
275          });
276        });
277        self.time.stop('datemaxrules');
278      }
279
280
281      // Add basic settings
282      // todo: find cleaner fix
283      // ugly fix for nodes in colorbox
284      if(typeof $('#' + f).validate === 'function') {
285        var validate_options = {
286          errorClass: 'error',
287          groups: self.groups[f],
288          errorElement: self.forms[f].general.errorElement,
289          unhighlight: function(element, errorClass, validClass) {
290            var tab;
291            // Default behavior
292            $(element).removeClass(errorClass).addClass(validClass);
293
294            // Sort the classes out for the tabs - we only want to remove the
295            // highlight if there are no inputs with errors...
296            var fieldset = $(element).parents('fieldset.vertical-tabs-pane');
297            if (fieldset.size() && fieldset.find('.' + errorClass).not('label').size() === 0) {
298              tab = self.findVerticalTab(element);
299              if (tab) {
300                tab.removeClass(errorClass).addClass(validClass);
301              }
302            }
303
304            // Same for horizontal tabs
305            fieldset = $(element).parents('fieldset.horizontal-tabs-pane');
306            if (fieldset.size() && fieldset.find('.' + errorClass).not('label').size() === 0) {
307              tab = self.findHorizontalTab(element);
308              if (tab) {
309                tab.removeClass(errorClass).addClass(validClass);
310              }
311            }
312          },
313          highlight: function(element, errorClass, validClass) {
314            // Default behavior
315            $(element).addClass(errorClass).removeClass(validClass);
316
317            // Sort the classes out for the tabs
318            var tab = self.findVerticalTab(element);
319            if (tab) {
320              tab.addClass(errorClass).removeClass(validClass);
321            }
322            tab = self.findHorizontalTab(element);
323            if (tab) {
324              tab.addClass(errorClass).removeClass(validClass);
325            }
326          },
327          invalidHandler: function(form, validator) {
328            var tab;
329            if (validator.errorList.length > 0) {
330              // Check if any of the errors are in the selected tab
331              var errors_in_selected = false;
332              for (var i = 0; i < validator.errorList.length; i++) {
333                tab = self.findVerticalTab(validator.errorList[i].element);
334                if (tab && tab.parent().hasClass('selected')) {
335                  errors_in_selected = true;
336                  break;
337                }
338              }
339
340              // Only focus the first tab with errors if the selected tab doesn't have
341              // errors itself. We shouldn't hide a tab that contains errors!
342              if (!errors_in_selected) {
343                tab = self.findVerticalTab(validator.errorList[0].element);
344                if (tab) {
345                  tab.click();
346                }
347              }
348
349              // Same for vertical tabs
350              // Check if any of the errors are in the selected tab
351              errors_in_selected = false;
352              for (i = 0; i < validator.errorList.length; i++) {
353                tab = self.findHorizontalTab(validator.errorList[i].element);
354                if (tab && tab.parent().hasClass('selected')) {
355                  errors_in_selected = true;
356                  break;
357                }
358              }
359
360              // Only focus the first tab with errors if the selected tab doesn't have
361              // errors itself. We shouldn't hide a tab that contains errors!
362              if (!errors_in_selected) {
363                tab = self.findHorizontalTab(validator.errorList[0].element);
364                if (tab) {
365                  tab.click();
366                }
367              }
368              if (self.forms[f].general.scrollTo) {
369                if (!$('html, body').hasClass('cv-scrolling')) {
370                  var x;
371                  if ($("#" + errorel).length) {
372                    $("#" + errorel).show();
373                    x = $("#" + errorel).offset().top - $("#" + errorel).height() - 100; // provides buffer in viewport
374                  }
375                  else {
376                    x = $(validator.errorList[0].element).offset().top - $(validator.errorList[0].element).height() - 100;
377                  }
378                  $('html, body').addClass('cv-scrolling').animate(
379                    {scrollTop: x},
380                    {
381                      duration: self.forms[f].general.scrollSpeed,
382                      complete: function () {
383                        $('html, body').removeClass('cv-scrolling')
384                      }
385                    }
386                  );
387                  $('.wysiwyg-toggle-wrapper a').each(function() {
388                    $(this).click();
389                    $(this).click();
390                  });
391                }
392              }
393
394              /**
395               * Notify that the form contains errors.
396               * @event clientsideValidationFormHasErrors
397               * @name clientsideValidationFormHasErrors
398               * @memberof Drupal.clientsideValidation
399               */
400              jQuery.event.trigger('clientsideValidationFormHasErrors', [form.target]);
401            }
402          }
403        };
404
405        switch (parseInt(self.forms[f].errorPlacement, 10)) {
406          case 0: // CLIENTSIDE_VALIDATION_JQUERY_SELECTOR
407            if ($(self.forms[f].errorJquerySelector).length) {
408              if (!$(self.forms[f].errorJquerySelector + ' #' + errorel).length) {
409                $('<div id="' + errorel + '" class="messages error clientside-error"><ul></ul></div>').prependTo(self.forms[f].errorJquerySelector).hide();
410              }
411            }
412            else if (!$('#' + errorel).length) {
413              $('<div id="' + errorel + '" class="messages error clientside-error"><ul></ul></div>').insertBefore('#' + f).hide();
414            }
415            validate_options.errorContainer = '#' + errorel;
416            validate_options.errorLabelContainer = '#' + errorel + ' ul';
417            validate_options.wrapper = 'li';
418            break;
419          case 1: // CLIENTSIDE_VALIDATION_TOP_OF_FORM
420            if (!$('#' + errorel).length) {
421              $('<div id="' + errorel + '" class="messages error clientside-error"><ul></ul></div>').insertBefore('#' + f).hide();
422            }
423            validate_options.errorContainer = '#' + errorel;
424            validate_options.errorLabelContainer = '#' + errorel + ' ul';
425            validate_options.wrapper = 'li';
426            break;
427          case 2: // CLIENTSIDE_VALIDATION_BEFORE_LABEL
428            validate_options.errorPlacement = function(error, element) {
429              var parents;
430              if (element.is(":radio")) {
431                parents = element.parents(".form-type-checkbox-tree");
432                if(parents.length) {
433                  error.insertBefore(parents.find("label").first());
434                }
435                else {
436                  parents = element.parents('.form-radios').prev('label');
437                  if (!parents.length) {
438                    parents = 'label[for="'+ element.attr('id') +'"]';
439                  }
440                  error.insertBefore(parents);
441                }
442              }
443              else if (element.is(":checkbox")) {
444                parents = element.parents(".form-type-checkbox-tree");
445                if(parents.length) {
446                  error.insertBefore(parents.find("label").first());
447                }
448                else {
449                  parents = element.parents('.form-radios').prev('label');
450                  if (!parents.length) {
451                    parents = 'label[for="'+ element.attr('id') +'"]';
452                  }
453                  error.insertBefore(parents);
454                }
455              }
456              else {
457                error.insertBefore('label[for="'+ element.attr('id') +'"]');
458              }
459            };
460            break;
461          case 3: // CLIENTSIDE_VALIDATION_AFTER_LABEL
462            validate_options.errorPlacement = function(error, element) {
463              var parents;
464              if (element.is(":radio")) {
465                parents = element.parents(".form-type-checkbox-tree");
466                if(parents.length) {
467                  error.insertAfter(parents.find("label").first());
468                }
469                else {
470                  parents = element.parents('.form-radios').prev('label');
471                  if (!parents.length) {
472                    parents = 'label[for="'+ element.attr('id') +'"]';
473                  }
474                  error.insertAfter(parents);
475                }
476              }
477              else if (element.is(":checkbox")) {
478                parents = element.parents(".form-type-checkbox-tree");
479                if(parents.length) {
480                  error.insertAfter(parents.find("label").first());
481                }
482                else {
483                  parents = element.parents('.form-checkboxes').prev('label');
484                  if (!parents.length) {
485                    parents = 'label[for="'+ element.attr('id') +'"]';
486                  }
487                  error.insertAfter(parents);
488                }
489              }
490              else {
491                error.insertAfter('label[for="'+ element.attr('id') +'"]');
492              }
493            };
494            break;
495          case 4: // CLIENTSIDE_VALIDATION_BEFORE_INPUT
496            validate_options.errorPlacement = function(error, element) {
497              error.insertBefore(element);
498            };
499            break;
500          case 5: // CLIENTSIDE_VALIDATION_AFTER_INPUT
501            validate_options.errorPlacement = function(error, element) {
502              var parents;
503              if (element.is(":radio")) {
504                parents = element.parents(".form-type-checkbox-tree");
505                if(parents.length) {
506                  error.insertAfter(parents);
507                }
508                else {
509                  parents = element.parents('.form-radios');
510                  if (!parents.length) {
511                    parents = element;
512                  }
513                  error.insertAfter(parents);
514                }
515              }
516              else if (element.is(":checkbox")) {
517                parents = element.parents(".form-type-checkbox-tree");
518                if(parents.length) {
519                  error.insertAfter(parents);
520                }
521                else {
522                  parents = element.parents('.form-checkboxes');
523                  if (!parents.length) {
524                    parents = element;
525                  }
526                  error.insertAfter(parents);
527                }
528              }
529              else if (element.next('div.grippie').length) {
530                error.insertAfter(element.next('div.grippie'));
531              } else {
532                error.insertAfter(element);
533              }
534            };
535            break;
536          case 6: // CLIENTSIDE_VALIDATION_TOP_OF_FIRST_FORM
537            if ($('div.messages.error').length) {
538              if ($('div.messages.error').attr('id').length) {
539                errorel = $('div.messages.error').attr('id');
540              }
541              else {
542                $('div.messages.error').attr('id', errorel);
543              }
544            }
545            else if (!$('#' + errorel).length) {
546              $('<div id="' + errorel + '" class="messages error clientside-error"><ul></ul></div>').insertBefore('#' + f).hide();
547            }
548            validate_options.errorContainer = '#' + errorel;
549            validate_options.errorLabelContainer = '#' + errorel + ' ul';
550            validate_options.wrapper = 'li';
551            break;
552          case 7: // CLIENTSIDE_VALIDATION_CUSTOM_ERROR_FUNCTION
553            validate_options.errorPlacement = function (error, element) {
554              var func = self.forms[f].customErrorFunction;
555              Drupal.myClientsideValidation[func](error, element);
556            };
557            break;
558        }
559
560        if (!self.forms[f].includeHidden) {
561          validate_options.ignore = ':input:hidden';
562        }
563        else {
564          validate_options.ignore = '';
565        }
566        if(self.forms[f].general.validateTabs) {
567          if($('.vertical-tabs-pane input').length) {
568            validate_options.ignore += ' :not(.vertical-tabs-pane :input, .horizontal-tabs-pane :input)';
569          }
570        }
571        else {
572          validate_options.ignore += ', .horizontal-tab-hidden :input';
573        }
574        //Since we can only give boolean false to onsubmit, onfocusout and onkeyup, we need
575        //a lot of if's (boolean true can not be passed to these properties).
576        if (!Boolean(parseInt(self.forms[f].general.validateOnSubmit, 10))) {
577          validate_options.onsubmit = false;
578        }
579        if (!Boolean(parseInt(self.forms[f].general.validateOnBlur, 10))) {
580          validate_options.onfocusout = false;
581        }
582        if (Boolean(parseInt(self.forms[f].general.validateOnBlurAlways, 10))) {
583          validate_options.onfocusout = function(element) {
584            if ( !this.checkable(element) ) {
585              this.element(element);
586            }
587          };
588        }
589        if (!Boolean(parseInt(self.forms[f].general.validateOnKeyUp, 10))) {
590          validate_options.onkeyup = false;
591        }
592        // Only apply this setting if errorplacement is set to the top of the form
593        if (parseInt(self.forms[f].general.showMessages, 10) > 0 && parseInt(self.forms[f].errorPlacement, 10) === 1) {
594          var showMessages = parseInt(self.forms[f].general.showMessages, 10);
595          // Show only last message
596          if (showMessages === 2) {
597            validate_options.showErrors = function() {
598              var allErrors = this.errors();
599              var i;
600              this.toHide = allErrors;
601              $(':input.' + this.settings.errorClass).removeClass(this.settings.errorClass);
602              for ( i = this.errorList.length -1; this.errorList[i]; i++ ) {
603                var error = this.errorList[i];
604                this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
605                this.showLabel( error.element, error.message );
606              }
607              if( this.errorList.length ) {
608                this.toShow = this.toShow.add( this.containers );
609              }
610              if (this.settings.success) {
611                for ( i = 0; this.successList[i]; i++ ) {
612                  this.showLabel( this.successList[i] );
613                }
614              }
615              if (this.settings.unhighlight) {
616                var elements;
617                for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
618                  this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
619                }
620              }
621              this.toHide = this.toHide.not( this.toShow );
622              this.hideErrors();
623              this.addWrapper( this.toShow ).show();
624            };
625          }
626          // Show only first message
627          else if(showMessages === 1) {
628            validate_options.showErrors = function() {
629              var allErrors = this.errors();
630              var i;
631              var elements;
632              if (this.settings.unhighlight) {
633                var firstErrorElement = this.clean($(allErrors[0]).attr('for'));
634                //for attr points to name or id
635                if (typeof firstErrorElement === 'undefined') {
636                  firstErrorElement = this.clean('#' + $(allErrors[0]).attr('for'));
637                }
638                for (i = 0, elements = this.elements().not($(firstErrorElement)); elements[i]; i++) {
639                  this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
640                }
641              }
642
643              for ( i = 0; this.errorList[i] && i<1; i++ ) {
644                var error = this.errorList[i];
645                this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
646                this.showLabel( error.element, error.message );
647              }
648              if( this.errorList.length ) {
649                this.toShow = this.toShow.add( this.containers );
650              }
651              if (this.settings.success) {
652                for ( i = 0; this.successList[i]; i++ ) {
653                  this.showLabel( this.successList[i] );
654                }
655              }
656              if (this.settings.unhighlight) {
657                for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
658                  this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
659                }
660              }
661
662              this.toHide = this.toHide.not( this.toShow );
663              this.hideErrors();
664              this.addWrapper( this.toShow ).show();
665              allErrors = this.errors();
666              allErrors.splice(0,1);
667              this.toHide = allErrors;
668              this.hideErrors();
669            };
670          }
671        }
672        self.validators[f] = $('#' + f).validate(validate_options);
673
674        // Disable HTML5 validation
675        if (!Boolean(parseInt(self.forms[f].general.disableHtml5Validation, 10))) {
676          $('#' + f).removeAttr('novalidate');
677        }
678        else {
679          $('#' + f).attr('novalidate', 'novalidate');
680        }
681        // Bind all rules
682        self.bindRules(f);
683
684      }
685    });
686  self.time.stop('2. bindForms');
687  };
688
689  /**
690   * Bind all rules.
691   * @memberof Drupal.clientsideValidation
692   */
693  Drupal.clientsideValidation.prototype.bindRules = function(formid){
694    var self = this;
695    self.time.start('3. bindRules');
696    var $form = $('#' + formid);
697    var hideErrordiv = function(){
698      //wait just one milisecond until the error div is updated
699      window.setTimeout(function(){
700        var visibles = 0;
701        // @TODO: check settings
702        $(".clientside-error ul li").each(function(){
703          if($(this).is(':visible')){
704            visibles++;
705          }
706          else {
707            $(this).remove();
708          }
709        });
710        if(visibles < 1){
711          $(".clientside-error").hide();
712        }
713      }, 1);
714    };
715    if('checkboxrules' in self.forms[formid]){
716      self.time.start('checkboxrules');
717      jQuery.each (self.forms[formid].checkboxrules, function(r) {
718        var $checkboxes = $form.find(this.checkboxgroupminmax[2]).find('input[type="checkbox"]');
719        if ($checkboxes.length) {
720          var identifier = 'require-one-' + this.checkboxgroupminmax[2].substring(1);
721          var min = this.checkboxgroupminmax[0];
722          var message = this.messages.checkboxgroupminmax;
723          $checkboxes.addClass(identifier);
724          $checkboxes.each(function(){
725            var $checkbox = $(this);
726            var newrule = {
727              require_from_group: [min, '.' + identifier]
728            };
729            $checkbox.rules("add", newrule);
730            $checkbox.change(hideErrordiv);
731
732            if (typeof self.validators[formid].settings.messages[$checkbox.attr('name')] === 'undefined') {
733              self.validators[formid].settings.messages[$checkbox.attr('name')] = {};
734            }
735            $.extend(self.validators[formid].settings.messages[$checkbox.attr('name')], {
736              require_from_group: message
737            });
738          });
739
740          if (typeof self.validators[formid].settings.messages['.' + identifier] === 'undefined') {
741            self.validators[formid].settings.messages['.' + identifier] = {};
742          }
743          $.extend(self.validators[formid].settings.messages['.' + identifier], {
744            require_from_group: message
745          });
746        }
747      });
748      self.time.stop('checkboxrules');
749    }
750    if('daterangerules' in self.forms[formid]){
751      self.time.start('daterangerules');
752      jQuery.each (self.forms[formid].daterangerules, function(r) {
753        $form.find('#' + r).find('input, select').not('input[type=image]').each(function(){
754          // Make sure we are working with the copy of rules object.
755          var rule = jQuery.extend(true, {}, self.forms[formid].daterangerules[r]);
756          if (typeof self.validators[formid].settings.messages[r] === 'undefined') {
757            self.validators[formid].settings.messages[r] = {};
758          }
759          $.extend(self.validators[formid].settings.messages[r], rule.messages);
760          delete rule.messages;
761          $(this).rules("add", rule);
762          $(this).blur(hideErrordiv);
763        });
764      });
765      self.time.stop('daterangerules');
766    }
767
768    if('dateminrules' in self.forms[formid]){
769      self.time.start('dateminrules');
770      jQuery.each (self.forms[formid].dateminrules, function(r) {
771        $form.find('#' + r).find('input, select').not('input[type=image]').each(function(){
772          // Make sure we are working with the copy of rules object.
773          var rule = jQuery.extend(true, {}, self.forms[formid].dateminrules[r]);
774          if (typeof self.validators[formid].settings.messages[r] === 'undefined') {
775            self.validators[formid].settings.messages[r] = {};
776          }
777          $.extend(self.validators[formid].settings.messages[r], rule.messages);
778          delete rule.messages;
779          $(this).rules("add", rule);
780          $(this).blur(hideErrordiv);
781        });
782      });
783      self.time.stop('dateminrules');
784    }
785
786    if('datemaxrules' in self.forms[formid]){
787      self.time.start('datemaxrules');
788      jQuery.each (self.forms[formid].datemaxrules, function(r) {
789        $form.find('#' + r).find('input, select').not('input[type=image]').each(function(){
790          // Make sure we are working with the copy of rules object.
791          var rule = jQuery.extend(true, {}, self.forms[formid].datemaxrules[r]);
792          if (typeof self.validators[formid].settings.messages[r] === 'undefined') {
793            self.validators[formid].settings.messages[r] = {};
794          }
795          $.extend(self.validators[formid].settings.messages[r], rule.messages);
796          delete rule.messages;
797          $(this).rules("add", rule);
798          $(this).blur(hideErrordiv);
799        });
800      });
801      self.time.stop('datemaxrules');
802    }
803
804    if ('rules' in self.forms[formid]) {
805      self.time.start('rules');
806      // Make sure we are working with the copy of rules object.
807      var rules = jQuery.extend(true, {}, self.forms[formid].rules);
808      // :input can be slow, see http://jsperf.com/input-vs-input/2
809      $form.find('input, textarea, select').each(function(idx, elem) {
810        var rule = rules[elem.name];
811        if (rule) {
812          var $elem = $(elem);
813          if (typeof self.validators[formid].settings.messages[elem.name] === 'undefined') {
814            self.validators[formid].settings.messages[elem.name] = {};
815          }
816          $.extend(self.validators[formid].settings.messages[elem.name], rule.messages);
817          delete rule.messages;
818          $elem.rules("add",rule);
819          $elem.change(hideErrordiv);
820        }
821      });
822      self.time.stop('rules');
823    }
824    self.time.stop('3. bindRules');
825  };
826
827  /**
828   * Add extra rules.
829   * @memberof Drupal.clientsideValidation
830  */
831  Drupal.clientsideValidation.prototype.addExtraRules = function(){
832    var self = this;
833
834    jQuery.validator.addMethod("numberDE", function(value, element) {
835      return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);
836    });
837
838    jQuery.validator.addMethod("min_comma", function(value, element, param) {
839      var real_val = Number(value.replace(',', '.'));
840      return this.optional(element) || real_val >= param;
841    });
842
843    jQuery.validator.addMethod("max_comma", function(value, element, param) {
844      var real_val = Number(value.replace(',', '.'));
845      return this.optional(element) || real_val <= param;
846    });
847
848    jQuery.validator.addMethod("range_comma", function(value, element, param) {
849      var real_val = Number(value.replace(',', '.'));
850      return this.optional(element) || (real_val >= param[0] && real_val <= param[1]);
851    });
852
853    // Min a and maximum b checkboxes from a group
854    jQuery.validator.addMethod("checkboxgroupminmax", function(value, element, param) {
855      var amountChecked = $(param[2]).find('input:checked').length;
856      return (amountChecked >= param[0] && amountChecked <= param[1]);
857    }, jQuery.format('Minimum {0}, maximum {1}'));
858
859    // Allow integers, same as digits but including a leading '-'
860    jQuery.validator.addMethod("digits_negative", function(value, element) {
861      return this.optional(element) || /^-?\d+$/.test(value);
862    }, jQuery.format('Please enter only digits.'));
863
864    // One of the values
865    jQuery.validator.addMethod("oneOf", function(value, element, param) {
866      for (var p in param.values) {
867        if (param.values[p] === value && param.caseSensitive) {
868          return !param.negate;
869        }
870        else if (param.values[p].toLowerCase() === value.toLowerCase() && !param.caseSensitive) {
871          return !param.negate;
872        }
873      }
874      return param.negate;
875    }, jQuery.format(''));
876
877    jQuery.validator.addMethod("specificVals", function(value, element, param){
878      for (var i in value) {
879        if(param.indexOf(value[i]) === -1) {
880            return false;
881        }
882      }
883      return true;
884    });
885
886    jQuery.validator.addMethod("blacklist", function(value, element, param) {
887      if (typeof(value) !== 'object') {
888        value = value.split(' ');
889      }
890      for (var i in value) {
891        if(param.values.indexOf(value[i]) !== -1) {
892            return param.negate;
893        }
894      }
895      return !param.negate;
896    });
897
898    // Default regular expression support
899    var ajaxPCREfn = function(value, element, param) {
900      var result = false;
901      jQuery.ajax({
902        'url': Drupal.settings.basePath + 'clientside_validation/ajax',
903        'type': "POST",
904        'data': {
905          'value': value,
906          'param': param
907        },
908        'dataType': 'json',
909        'async': false,
910        'success': function(res){
911          result = res;
912        }
913      });
914      if (result.result === false) {
915        if (result.message.length) {
916          jQuery.extend(jQuery.validator.messages, {
917            "regexMatchPCRE": result.message
918          });
919        }
920      }
921      return result.result;
922    };
923
924    // Regular expression support using XRegExp
925    var xregexPCREfn = function(value, element, param) {
926      if (window.XRegExp && XRegExp.version ) {
927        try {
928          var result = true;
929          for (var i = 0; i < param.expressions.length; i++) {
930            var reg = param.expressions[i];
931            var delim = reg.lastIndexOf(reg.charAt(0));
932            // Only allow supported modifiers
933            var modraw = reg.substr(delim + 1) || '';
934            var mod = '';
935            if (mod !== '') {
936              for (var l = 0; l < 6; l++) {
937                if (modraw.indexOf('gimnsx'[l]) !== -1) {
938                  mod += 'gimnsx'[l];
939                }
940              }
941            }
942            reg = reg.substring(1, delim);
943            if (!(new XRegExp(reg, mod).test(value))) {
944              result = false;
945              if (param.messages[i].length) {
946                jQuery.extend(jQuery.validator.messages, {
947                  "regexMatchPCRE": param.messages[i]
948                });
949              }
950            }
951          }
952          return result;
953        }
954        catch (e) {
955          return ajaxPCREfn(value, element, param);
956        }
957      }
958      else {
959        return ajaxPCREfn(value, element, param);
960      }
961    };
962
963    // Decide which one to use
964    if (self.data.general.usexregxp) {
965      jQuery.validator.addMethod("regexMatchPCRE", xregexPCREfn, jQuery.format('The value does not match the expected format.'));
966    }
967    else {
968      jQuery.validator.addMethod("regexMatchPCRE", ajaxPCREfn, jQuery.format('The value does not match the expected format.'));
969    }
970
971    // Unique values
972    jQuery.validator.addMethod("notEqualTo", function(value, element, param) {
973      var ret = true;
974      jQuery.each(param, function (index, selector){
975        var $target = $(selector);
976        $target.unbind(".validate-notEqualTo").bind("blur.validate-notEqualTo", function() {
977          $(element).valid();
978        });
979        ret = ret && ($target.val() !== value);
980      });
981      return ret;
982    }, jQuery.format('Please don\'t enter the same value again.'));
983
984    jQuery.validator.addMethod("regexMatch", function(value, element, param) {
985      if (this.optional(element) && value === '') {
986        return this.optional(element);
987      }
988      else {
989        var modifier = param.regex[1];
990        var valid_modifiers = ['i', 'g', 'm'];
991        if (jQuery.inArray(modifier, valid_modifiers) === -1) {
992          modifier = '';
993        }
994        var regexp = new RegExp(param.regex[0], modifier);
995        if(regexp.test(value)){
996          return !param.negate;
997        }
998        return param.negate;
999      }
1000
1001    }, jQuery.format('The value does not match the expected format.'));
1002
1003    jQuery.validator.addMethod("captcha", function (value, element, param) {
1004      var result = false;
1005      var sid = $(element).closest('.captcha').find('input[name=captcha_sid]').val();
1006      jQuery.ajax({
1007        'url': Drupal.settings.basePath + 'clientside_validation/captcha',
1008        'type': "POST",
1009        'data': {
1010          'value': value,
1011          'param': [sid, param]
1012        },
1013        'dataType': 'json',
1014        'async': false,
1015        'success': function(res){
1016          result = res;
1017        }
1018      });
1019      if (result.result === false) {
1020        if (typeof result.message !== 'undefined' && result.message.length) {
1021          jQuery.extend(jQuery.validator.messages, {
1022            "captcha": result.message
1023          });
1024        }
1025      }
1026      return result.result;
1027    }, jQuery.format('Wrong answer.'));
1028
1029    jQuery.validator.addMethod("rangewords", function(value, element, param) {
1030      return this.optional(element) || (param[0] <= jQuery.trim(value).split(/\s+/).length && value.split(/\s+/).length <= param[1]);
1031    }, jQuery.format('The value must be between {0} and {1} words long'));
1032
1033    jQuery.validator.addMethod("minwords", function(value, element, param) {
1034      return this.optional(element) || param <= jQuery.trim(value).split(/\s+/).length;
1035    }, jQuery.format('The value must be more than {0} words long'));
1036
1037    jQuery.validator.addMethod("maxwords", function(value, element, param) {
1038      return this.optional(element) || jQuery.trim(value).split(/\s+/).length <= param;
1039    }, jQuery.format('The value must be fewer than {0} words long'));
1040
1041    jQuery.validator.addMethod("plaintext", function(value, element, param){
1042      var result = param.negate ? (value !== strip_tags(value, param.tags)) : (value === strip_tags(value, param.tags));
1043      return this.optional(element) || result;
1044    }, jQuery.format('The value must be plaintext'));
1045
1046    jQuery.validator.addMethod("selectMinlength", function(value, element, param) {
1047      var result = $(element).find('option:selected').length >= param.min;
1048      if (param.negate) {
1049        result = !result;
1050      }
1051      return this.optional(element) || result;
1052    }, jQuery.format('You must select at least {0} values'));
1053
1054    jQuery.validator.addMethod("selectMaxlength", function(value, element, param) {
1055      var result = $(element).find('option:selected').length <= param.max;
1056      if (param.negate) {
1057        result = !result;
1058      }
1059      return this.optional(element) || result;
1060    }, jQuery.format('You must select a maximum of {0} values'));
1061
1062    jQuery.validator.addMethod("selectRangelength", function(value, element, param) {
1063      var result = ($(element).find('option:selected').length >= param.range[0] && $(element).find('option:selected').length <= param.range[1]);
1064      if (param.negate) {
1065        result = !result;
1066      }
1067      return this.optional(element) || result;
1068    }, jQuery.format('You must select at between {0} and {1} values'));
1069
1070    jQuery.validator.addMethod("datemin", function(value, element, param) {
1071      //Assume [month], [day], and [year] ??
1072      var dayelem, monthelem, yearelem, name, $form, element_name;
1073      $form = $(element).closest('form');
1074      element_name = $(element).attr('name');
1075      if (element_name.indexOf('[day]') > 0) {
1076        dayelem = $(element);
1077        name = dayelem.attr('name').replace('[day]', '');
1078        monthelem = $form.find("[name='" + name + "[month]']");
1079        yearelem = $form.find("[name='" + name + "[year]']");
1080      }
1081      else if (element_name.indexOf('[month]') > 0) {
1082        monthelem = $(element);
1083        name = monthelem.attr('name').replace('[month]', '');
1084        dayelem = $form.find("[name='" + name + "[day]']");
1085        yearelem = $form.find("[name='" + name + "[year]']");
1086      }
1087      else if ($(element).attr('name').indexOf('[year]') > 0) {
1088        yearelem = $(element);
1089        name = yearelem.attr('name').replace('[year]', '');
1090        dayelem = $form.find("[name='" + name + "[day]']");
1091        monthelem = $form.find("[name='" + name + "[month]']");
1092      }
1093
1094      if (parseInt(yearelem.val(), 10) < parseInt(param[0], 10)) {
1095        return false;
1096      }
1097      else if (parseInt(yearelem.val(), 10) === parseInt(param[0], 10)){
1098        if (parseInt(monthelem.val(), 10) < parseInt(param[1], 10)){
1099          return false;
1100        }
1101        else if (parseInt(monthelem.val(), 10) === parseInt(param[1], 10)){
1102          if(parseInt(dayelem.val(), 10) < parseInt(param[2], 10)) {
1103            return false;
1104          }
1105        }
1106      }
1107      yearelem.once('daterange', function() {
1108        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1109      }).removeClass('error');
1110      monthelem.once('daterange', function() {
1111        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1112      }).removeClass('error');
1113      dayelem.once('daterange', function() {
1114        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1115      }).removeClass('error');
1116      return true;
1117    });
1118
1119    jQuery.validator.addMethod("datemax", function(value, element, param) {
1120      //Assume [month], [day], and [year] ??
1121      var dayelem, monthelem, yearelem, name, $form, element_name;
1122      $form = $(element).closest('form');
1123      element_name = $(element).attr('name');
1124      if (element_name.indexOf('[day]') > 0) {
1125        dayelem = $(element);
1126        name = dayelem.attr('name').replace('[day]', '');
1127        monthelem = $form.find("[name='" + name + "[month]']");
1128        yearelem = $form.find("[name='" + name + "[year]']");
1129      }
1130      else if (element_name.indexOf('[month]') > 0) {
1131        monthelem = $(element);
1132        name = monthelem.attr('name').replace('[month]', '');
1133        dayelem = $form.find("[name='" + name + "[day]']");
1134        yearelem = $form.find("[name='" + name + "[year]']");
1135      }
1136      else if (element_name.indexOf('[year]') > 0) {
1137        yearelem = $(element);
1138        name = yearelem.attr('name').replace('[year]', '');
1139        dayelem = $form.find("[name='" + name + "[day]']");
1140        monthelem = $form.find("[name='" + name + "[month]']");
1141
1142      }
1143
1144      if (parseInt(yearelem.val(), 10) > parseInt(param[0], 10)) {
1145        return false;
1146      }
1147      else if (parseInt(yearelem.val(), 10) === parseInt(param[0], 10)){
1148        if (parseInt(monthelem.val(), 10) > parseInt(param[1], 10)){
1149          return false;
1150        }
1151        else if (parseInt(monthelem.val(), 10) === parseInt(param[1], 10)){
1152          if(parseInt(dayelem.val(), 10) > parseInt(param[2], 10)) {
1153            return false;
1154          }
1155        }
1156      }
1157      yearelem.once('daterange', function() {
1158        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1159      }).removeClass('error');
1160      monthelem.once('daterange', function() {
1161        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1162      }).removeClass('error');
1163      dayelem.once('daterange', function() {
1164        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1165      }).removeClass('error');
1166      return true;
1167    });
1168
1169    jQuery.validator.addMethod("daterange", function(value, element, param) {
1170      //Assume [month], [day], and [year] ??
1171      var dayelem, monthelem, yearelem, name, $form, element_name;
1172      $form = $(element).closest('form');
1173      element_name = $(element).attr('name');
1174      if (element_name.indexOf('[day]') > 0) {
1175        dayelem = $(element);
1176        name = dayelem.attr('name').replace('[day]', '');
1177        monthelem = $form.find("[name='" + name + "[month]']");
1178        yearelem = $form.find("[name='" + name + "[year]']");
1179      }
1180      else if (element_name.indexOf('[month]') > 0) {
1181        monthelem = $(element);
1182        name = monthelem.attr('name').replace('[month]', '');
1183        dayelem = $form.find("[name='" + name + "[day]']");
1184        yearelem = $form.find("[name='" + name + "[year]']");
1185      }
1186      else if (element_name.indexOf('[year]') > 0) {
1187        yearelem = $(element);
1188        name = yearelem.attr('name').replace('[year]', '');
1189        dayelem = $form.find("[name='" + name + "[day]']");
1190        monthelem = $form.find("[name='" + name + "[month]']");
1191      }
1192
1193      if (parseInt(yearelem.val(), 10) < parseInt(param[0][0], 10)) {
1194        return false;
1195      }
1196      else if (parseInt(yearelem.val(), 10) === parseInt(param[0][0], 10)){
1197        if (parseInt(monthelem.val(), 10) < parseInt(param[0][1], 10)){
1198          return false;
1199        }
1200        else if (parseInt(monthelem.val(), 10) === parseInt(param[0][1], 10)){
1201          if(parseInt(dayelem.val(), 10) < parseInt(param[0][2], 10)) {
1202            return false;
1203          }
1204        }
1205      }
1206
1207      if (parseInt(yearelem.val(), 10) > parseInt(param[1][0], 10)) {
1208        return false;
1209      }
1210      else if (parseInt(yearelem.val(), 10) === parseInt(param[1][0], 10)){
1211        if (parseInt(monthelem.val(), 10) > parseInt(param[1][1], 10)){
1212          return false;
1213        }
1214        else if (parseInt(monthelem.val(), 10) === parseInt(param[1][1], 10)){
1215          if(parseInt(dayelem.val(), 10) > parseInt(param[1][2], 10)) {
1216            return false;
1217          }
1218        }
1219      }
1220      yearelem.once('daterange', function() {
1221        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1222      }).removeClass('error');
1223      monthelem.once('daterange', function() {
1224        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1225      }).removeClass('error');
1226      dayelem.once('daterange', function() {
1227        $(this).change(function(){$(this).trigger('focusout').trigger('blur');});
1228      }).removeClass('error');
1229      return true;
1230    });
1231
1232    jQuery.validator.addMethod("dateFormat", function(value, element, param) {
1233      try{
1234        var parts = value.split(param.splitter);
1235        var expectedpartscount = 0;
1236        var day = parseInt(parts[param.daypos], 10);
1237
1238        var month = parseInt(parts[param.monthpos], 10);
1239        if (isNaN(month)) {
1240          var date_parts = param.format.split(param.splitter);
1241          var full_idx = date_parts.indexOf("F");
1242          var abbr_idx = date_parts.indexOf("M");
1243          var mopos = Math.max(full_idx, abbr_idx);
1244          if (parseInt(mopos) > -1) {
1245            param.monthpos = mopos;
1246            date = new Date(parts[param.monthpos] + " 1, 2000");
1247            month = date.getMonth();
1248          }
1249          else {
1250            if (typeof Drupal.settings.clientsideValidation.general.months[parts[param.monthpos]] !== 'undefined') {
1251              month = Drupal.settings.clientsideValidation.general.months[parts[param.monthpos]];
1252            }
1253            else {
1254              month = new Date(parts[param.monthpos] + " 1, 2000");
1255              month = month.getMonth();
1256            }
1257          }
1258        }
1259        else {
1260          month--;
1261        }
1262
1263        var year = parseInt(parts[param.yearpos], 10);
1264        var date = new Date();
1265        var result = true;
1266        if (param.daypos !== false && parts[param.daypos].toString().length !== parts[param.daypos].length){
1267          result = false;
1268        }
1269        if (param.monthpos !== false && parts[param.monthpos].toString().length !== parts[param.monthpos].length){
1270          result = false;
1271        }
1272        if (param.yearpos !== false && parts[param.yearpos].toString().length !== parts[param.yearpos].length){
1273          result = false;
1274        }
1275        if (param.yearpos !== false){
1276          expectedpartscount++;
1277          date.setFullYear(year);
1278          if (year !== date.getFullYear()) {
1279            result = false;
1280          }
1281        }
1282        if (param.monthpos !== false) {
1283          expectedpartscount++;
1284          date.setMonth(month, 1);
1285          if (month !== date.getMonth()) {
1286            result = false;
1287          }
1288        }
1289        if (param.daypos !== false) {
1290          expectedpartscount++;
1291          date.setDate(day);
1292          if (day !== date.getDate()) {
1293            result = false;
1294          }
1295        }
1296        if (expectedpartscount !== parts.length) {
1297          result = false;
1298        }
1299        return this.optional(element) || result;
1300      } catch(e) {
1301        return this.optional(element) || false;
1302      }
1303    }, jQuery.format('The date is not in a valid format'));
1304
1305    // Require one of several
1306    jQuery.validator.addMethod("requireOneOf", function(value, element, param) {
1307      var ret = false;
1308      if (value === "") {
1309        jQuery.each(param, function(index, name) {
1310          // @TODO: limit to current form
1311          if (!ret && $("[name='" + name + "']").val().length) {
1312            ret = true;
1313          }
1314        });
1315      }
1316      else {
1317        $(element).removeClass("error");
1318        ret = true;
1319      }
1320      $(element).blur(function () {
1321        jQuery.each(param, function(index, name) {
1322          // @TODO: limit to current form
1323          $("[name='" + name + "']").valid();
1324        });
1325      });
1326      return ret;
1327    }, jQuery.format('Please fill in at least one of the fields'));
1328
1329    // Support for Drupal urls.
1330    jQuery.validator.addMethod("drupalURL", function(value, element) {
1331      var result = false;
1332      if (this.settings['name_event'] == 'onkeyup') {
1333        return true;
1334      }
1335      if (jQuery.validator.methods.url.call(this, value, element)) {
1336        return true;
1337      }
1338      jQuery.ajax({
1339        'url': Drupal.settings.basePath + 'clientside_validation/drupalURL',
1340        'type': "POST",
1341        'data': {
1342          'value': value
1343        },
1344        'dataType': 'json',
1345        'async': false,
1346        'success': function(res){
1347          result = res;
1348        }
1349      });
1350      return result.result;
1351    }, jQuery.format('Please fill in a valid url'));
1352
1353    // Support for phone
1354    jQuery.validator.addMethod("phone", function(value, element, param) {
1355      var country_code = param;
1356      var result = false;
1357      jQuery.ajax({
1358        'url': Drupal.settings.basePath + 'clientside_validation/phone',
1359        'type': "POST",
1360        'data': {
1361          'value': value,
1362          'country_code': country_code
1363        },
1364        'dataType': 'json',
1365        'async': false,
1366        'success': function(res){
1367          result = res;
1368        }
1369      });
1370      return this.optional(element) || result.result;
1371
1372    }, jQuery.format('Please fill in a valid phone number'));
1373
1374    // EAN code
1375    jQuery.validator.addMethod("validEAN", function(value, element) {
1376      if (this.optional(element) && value === '') {
1377        return this.optional(element);
1378      }
1379      else {
1380        if (value.length > 13) {
1381          return false;
1382        }
1383        else if (value.length !== 13) {
1384          value = '0000000000000'.substr(0, 13 - value.length).concat(value);
1385        }
1386        if (value === '0000000000000') {
1387          return false;
1388        }
1389        if (isNaN(parseInt(value, 10)) || parseInt(value, 10) === 0) {
1390          return false;
1391        }
1392        var runningTotal = 0;
1393        for (var c = 0; c < 12; c++) {
1394          if (c % 2 === 0) {
1395            runningTotal += 3 * parseInt(value.substr(c, 1), 10);
1396          }
1397          else {
1398            runningTotal += parseInt(value.substr(c, 1), 10);
1399          }
1400        }
1401        var rem = runningTotal % 10;
1402        if (rem !== 0) {
1403          rem = 10 - rem;
1404        }
1405
1406        return rem === parseInt(value.substr(12, 1), 10);
1407
1408      }
1409    }, jQuery.format('Not a valid EAN number.'));
1410
1411    jQuery.validator.addMethod("require_from_group", function(value, element, options) {
1412      var $fields = $(options[1], element.form),
1413        $fieldsFirst = $fields.eq(0),
1414        validator = $fieldsFirst.data("valid_req_grp") ? $fieldsFirst.data("valid_req_grp") : $.extend({}, this),
1415        isValid = $fields.filter(function() {
1416          return validator.elementValue(this);
1417        }).length >= options[0];
1418
1419      // Store the cloned validator for future validation
1420      $fieldsFirst.data("valid_req_grp", validator);
1421
1422      // If element isn't being validated, run each require_from_group field's validation rules
1423      if (!$(element).data("being_validated")) {
1424        $fields.data("being_validated", true);
1425        $fields.each(function() {
1426          validator.element(this);
1427        });
1428        $fields.data("being_validated", false);
1429      }
1430      return isValid;
1431    }, jQuery.validator.format("Please fill at least {0} of these fields."));
1432
1433    /**
1434     * Allow other modules to add more rules.
1435     * @event clientsideValidationAddCustomRules
1436     * @name clientsideValidationAddCustomRules
1437     * @memberof Drupal.clientsideValidation
1438     */
1439    jQuery.event.trigger('clientsideValidationAddCustomRules');
1440
1441
1442    /**
1443     * strip illegal tags
1444     * @memberof Drupal.clientsideValidation
1445     * @private
1446     */
1447    function strip_tags (input, allowed) {
1448      allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
1449      var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
1450          commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
1451      return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
1452        return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
1453      });
1454    }
1455  };
1456
1457  Drupal.behaviors.ZZZClientsideValidation = {
1458    attach: function () {
1459      function changeAjax(ajax_el) {
1460        var origBeforeSubmit = Drupal.ajax[ajax_el].options.beforeSubmit;
1461        Drupal.ajax[ajax_el].options.beforeSubmit = function (form_values, element, options) {
1462          var ret = origBeforeSubmit(form_values, element, options);
1463          // If this function didn't return anything, just set the return value to true.
1464          // If it did return something, allow it to prevent submit if necessary.
1465          if (typeof ret === 'undefined') {
1466            ret = true;
1467          }
1468          var id = element.is('form') ? element.attr('id') : element.closest('form').attr('id');
1469          if (id && Drupal.myClientsideValidation.validators[id]) {
1470            Drupal.myClientsideValidation.validators[id].onsubmit = false;
1471            ret = ret && Drupal.myClientsideValidation.validators[id].form();
1472            if (!ret) {
1473              Drupal.ajax[ajax_el].ajaxing = false;
1474            }
1475          }
1476          return ret;
1477        };
1478      }
1479      // Set validation for ctools modal forms
1480      for (var ajax_el in Drupal.ajax) {
1481        if (Drupal.ajax.hasOwnProperty(ajax_el) && typeof Drupal.ajax[ajax_el] !== 'undefined') {
1482          var $ajax_el = jQuery(Drupal.ajax[ajax_el].element);
1483          var ajax_form = $ajax_el.is('form') ? $ajax_el.attr('id') : $ajax_el.closest('form').attr('id');
1484          var change_ajax = true;
1485          if (typeof Drupal.myClientsideValidation.forms[ajax_form] !== 'undefined') {
1486            change_ajax = Boolean(parseInt(Drupal.myClientsideValidation.forms[ajax_form].general.validateBeforeAjax, 10));
1487          }
1488          if (!$ajax_el.hasClass('cancel') && change_ajax) {
1489            changeAjax(ajax_el);
1490          }
1491        }
1492      }
1493    }
1494  };
1495})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.