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.