1(function (root, factory) { 2 if (typeof define === 'function' && define.amd) { 3 // AMD. Register as an anonymous module unless amdModuleId is set 4 define(["jquery"], function (a0) { 5 return (factory(a0)); 6 }); 7 } else if (typeof module === 'object' && module.exports) { 8 // Node. Does not work with strict CommonJS, but 9 // only CommonJS-like environments that support module.exports, 10 // like Node. 11 module.exports = factory(require("jquery")); 12 } else { 13 factory(root["jQuery"]); 14 } 15}(this, function (jQuery) { 16 17/** File generated by Grunt -- do not modify 18 * JQUERY-FORM-VALIDATOR 19 * 20 * @version 2.3.77 21 * @website http://formvalidator.net/ 22 * @author Victor Jonsson, http://victorjonsson.se 23 * @license MIT 24 */ 25/** 26 */ 27(function ($, window, undefined) { 28 29 var disableFormSubmit = function () { 30 return false; 31 }, 32 lastFormEvent = null, 33 HaltManager = { 34 numHalted: 0, 35 haltValidation: function($form) { 36 this.numHalted++; 37 $.formUtils.haltValidation = true; 38 $form 39 .unbind('submit', disableFormSubmit) 40 .bind('submit', disableFormSubmit) 41 .find('*[type="submit"]') 42 .addClass('disabled') 43 .attr('disabled', 'disabled'); 44 }, 45 unHaltValidation: function($form) { 46 this.numHalted--; 47 if (this.numHalted === 0) { 48 $.formUtils.haltValidation = false; 49 $form 50 .unbind('submit', disableFormSubmit) 51 .find('*[type="submit"]') 52 .removeClass('disabled') 53 .removeAttr('disabled', 'disabled'); 54 } 55 } 56 }; 57 58 function AsyncValidation($form, $input) { 59 this.$form = $form; 60 this.$input = $input; 61 this.reset(); 62 $input.on('change paste', this.reset.bind(this)); 63 } 64 65 AsyncValidation.prototype.reset = function() { 66 this.haltedFormValidation = false; 67 this.hasRun = false; 68 this.isRunning = false; 69 this.result = undefined; 70 }; 71 72 AsyncValidation.prototype.run = function(eventContext, callback) { 73 if (eventContext === 'keyup') { 74 return null; 75 } else if (this.isRunning) { 76 lastFormEvent = eventContext; 77 if (!this.haltedFormValidation) { 78 HaltManager.haltValidation(); 79 this.haltedFormValidation = true; 80 } 81 return null; // Waiting for result 82 } else if(this.hasRun) { 83 //this.$input.one('keyup change paste', this.reset.bind(this)); 84 return this.result; 85 } else { 86 lastFormEvent = eventContext; 87 HaltManager.haltValidation(this.$form); 88 this.haltedFormValidation = true; 89 this.isRunning = true; 90 this.$input 91 .attr('disabled', 'disabled') 92 .addClass('async-validation'); 93 this.$form.addClass('async-validation'); 94 95 callback(function(result) { 96 this.done(result); 97 }.bind(this)); 98 99 return null; 100 } 101 }; 102 103 AsyncValidation.prototype.done = function(result) { 104 this.result = result; 105 this.hasRun = true; 106 this.isRunning = false; 107 this.$input 108 .removeAttr('disabled') 109 .removeClass('async-validation'); 110 this.$form.removeClass('async-validation'); 111 if (this.haltedFormValidation) { 112 HaltManager.unHaltValidation(this.$form); 113 if (lastFormEvent === 'submit') { 114 this.$form.trigger('submit'); 115 } else { 116 this.$input.trigger('validation.revalidate'); 117 } 118 } 119 }; 120 121 AsyncValidation.loadInstance = function(validatorName, $input, $form) { 122 // Return async validator attached to this input element 123 // or create a new async validator and attach it to the input 124 var asyncValidation, 125 input = $input.get(0); 126 127 if (!input.asyncValidators) { 128 input.asyncValidators = {}; 129 } 130 131 if (input.asyncValidators[validatorName]) { 132 asyncValidation = input.asyncValidators[validatorName]; 133 } else { 134 asyncValidation = new AsyncValidation($form, $input); 135 input.asyncValidators[validatorName] = asyncValidation; 136 } 137 138 return asyncValidation; 139 }; 140 141 $.formUtils = $.extend($.formUtils || {}, { 142 143 /** 144 * @deprecated 145 * @param validatorName 146 * @param $input 147 * @param $form 148 */
149 asyncValidation: function(validatorName, $input, $form) { 150 // @todo: Remove when moving up to version 3.0 151 this.warn('Use of deprecated function $.formUtils.asyncValidation, use $.formUtils.addAsyncValidator() instead'); 152 return AsyncValidation.loadInstance(validatorName, $input, $form); 153 }, 154 155 /** 156 * @param {Object} asyncValidator 157 */ 158 addAsyncValidator: function (asyncValidator) { 159 var validator = $.extend({}, asyncValidator), 160 originalValidatorFunc = validator.validatorFunction; 161 validator.async = true; 162 validator.validatorFunction = function (value, $el, config, language, $form, eventContext) { 163 var asyncValidation = AsyncValidation.loadInstance(this.name, $el, $form); 164 return asyncValidation.run(eventContext, function(done) { 165 originalValidatorFunc.apply(validator, [ 166 done, value, $el, config, language, $form, eventContext 167 ]); 168 }); 169 }; 170 this.addValidator(validator); 171 } 172 }); 173 174 // Tag elements having async validators 175 $(window).bind('validatorsLoaded formValidationSetup', function (evt, $form) { 176 if (!$form) { 177 $form = $('form'); 178 } 179 $form.find('[data-validation]').each(function () { 180 var $input = $(this); 181 $input.valAttr('async', false); 182 $.each($.split($input.attr('data-validation')), function (i, validatorName) { 183 var validator = $.formUtils.validators['validate_'+validatorName]; 184 if (validator && validator.async) { 185 $input.valAttr('async', 'yes'); 186 } 187 }); 188 }); 189 }); 190 191})(jQuery, window); 192 193/** 194 * Deprecated functions and attributes 195 * @todo: Remove in release of 3.0 196 */ 197(function ($, undefined) { 198 199 'use strict'; 200 201 /** 202 * @deprecated 203 * @param language 204 * @param conf 205 */ 206 $.fn.validateForm = function (language, conf) { 207 $.formUtils.warn('Use of deprecated function $.validateForm, use $.isValid instead'); 208 return this.isValid(language, conf, true); 209 }; 210 211 $(window) 212 .on('formValidationPluginInit', function(evt, config) { 213 convertDeprecatedLangCodeToISO6391(config); 214 addSupportForCustomErrorMessageCallback(config); 215 addSupportForElementReferenceInPositionParam(config); 216 }) 217 .on('validatorsLoaded formValidationSetup', function(evt, $form) { 218 if( !$form ) { 219 $form = $('form'); 220 } 221 addSupportForValidationDependingOnCheckedInput($form); 222 }); 223 224 225 function addSupportForCustomErrorMessageCallback(config) { 226 if (config && 227 config.errorMessagePosition === 'custom' && 228 typeof config.errorMessageCustom === 'function') { 229 230 $.formUtils.warn('Use of deprecated function errorMessageCustom, use config.submitErrorMessageCallback instead'); 231 232 config.submitErrorMessageCallback = function($form, errorMessages) { 233 config.errorMessageCustom( 234 $form, 235 config.language.errorTitle, 236 errorMessages, 237 config 238 ); 239 }; 240 } 241 } 242 243 function addSupportForElementReferenceInPositionParam(config) { 244 if (config.errorMessagePosition && typeof config.errorMessagePosition === 'object') { 245 $.formUtils.warn('Deprecated use of config parameter errorMessagePosition, use config.submitErrorMessageCallback instead'); 246 var $errorMessageContainer = config.errorMessagePosition; 247 config.errorMessagePosition = 'top'; 248 config.submitErrorMessageCallback = function() { 249 return $errorMessageContainer; 250 }; 251 } 252 } 253 254 function addSupportForValidationDependingOnCheckedInput($form) { 255 var $inputsDependingOnCheckedInputs = $form.find('[data-validation-if-checked]'); 256 if ($inputsDependingOnCheckedInputs.length) { 257 $.formUtils.warn( 258 'Detected use of attribute "data-validation-if-checked" which is '+ 259 'deprecated. Use "data-validation-depends-on" provided by module "logic"' 260 ); 261 } 262 263 $inputsDependingOnCheckedInputs 264 .on('beforeValidation', function() { 265 266 var $elem = $(this), 267 nameOfDependingInput = $elem.valAttr('if-checked'); 268 269 // Set the boolean telling us that the validation depends 270 // on another input being checked
271 var $dependingInput = $('input[name="' + nameOfDependingInput + '"]', $form), 272 dependingInputIsChecked = $dependingInput.is(':checked'), 273 valueOfDependingInput = ($.formUtils.getValue($dependingInput) || '').toString(), 274 requiredValueOfDependingInput = $elem.valAttr('if-checked-value'); 275 276 if (!dependingInputIsChecked || !( 277 !requiredValueOfDependingInput || 278 requiredValueOfDependingInput === valueOfDependingInput 279 )) { 280 $elem.valAttr('skipped', true); 281 } 282 283 }); 284 } 285 286 function convertDeprecatedLangCodeToISO6391(config) { 287 var deprecatedLangCodes = { 288 se: 'sv', 289 cz: 'cs', 290 dk: 'da' 291 }; 292 293 if (config.lang in deprecatedLangCodes) { 294 var newLangCode = deprecatedLangCodes[config.lang]; 295 $.formUtils.warn( 296 'Deprecated use of lang code "'+config.lang+'" use "'+newLangCode+'" instead' 297 ); 298 config.lang = newLangCode; 299 } 300 } 301 302})(jQuery); 303 304/** 305 * Utility methods used for displaying error messages (attached to $.formUtils) 306 */ 307(function ($) { 308 309 'use strict'; 310 311 var dialogs = { 312 313 resolveErrorMessage: function($elem, validator, validatorName, conf, language) { 314 var errorMsgAttr = conf.validationErrorMsgAttribute + '-' + validatorName.replace('validate_', ''), 315 validationErrorMsg = $elem.attr(errorMsgAttr); 316 317 if (!validationErrorMsg) { 318 validationErrorMsg = $elem.attr(conf.validationErrorMsgAttribute); 319 if (!validationErrorMsg) { 320 if (typeof validator.errorMessageKey !== 'function') { 321 validationErrorMsg = language[validator.errorMessageKey]; 322 } 323 else { 324 validationErrorMsg = language[validator.errorMessageKey(conf)]; 325 } 326 if (!validationErrorMsg) { 327 validationErrorMsg = validator.errorMessage; 328 } 329 } 330 } 331 return validationErrorMsg; 332 }, 333 getParentContainer: function ($elem) { 334 if ($elem.valAttr('error-msg-container')) { 335 return $($elem.valAttr('error-msg-container')); 336 } else { 337 var $parent = $elem.parent(); 338 if($elem.attr('type') === 'checkbox' && $elem.closest('.checkbox').length) { 339 $parent = $elem.closest('.checkbox').parent(); 340 } else if($elem.attr('type') === 'radio' && $elem.closest('.radio').length) { 341 $parent = $elem.closest('.radio').parent(); 342 } 343 if($parent.closest('.input-group').length) { 344 $parent = $parent.closest('.input-group').parent(); 345 } 346 return $parent; 347 } 348 }, 349 applyInputErrorStyling: function ($input, conf) { 350 $input 351 .addClass(conf.errorElementClass) 352 .removeClass(conf.successElementClass); 353 354 this.getParentContainer($input) 355 .addClass(conf.inputParentClassOnError) 356 .removeClass(conf.inputParentClassOnSuccess); 357 358 if (conf.borderColorOnError !== '') { 359 $input.css('border-color', conf.borderColorOnError); 360 } 361 }, 362 applyInputSuccessStyling: function($input, conf) { 363 $input.addClass(conf.successElementClass); 364 this.getParentContainer($input) 365 .addClass(conf.inputParentClassOnSuccess); 366 }, 367 removeInputStylingAndMessage: function($input, conf) { 368 369 // Reset input css 370 $input 371 .removeClass(conf.successElementClass) 372 .removeClass(conf.errorElementClass) 373 .css('border-color', ''); 374 375 var $parentContainer = dialogs.getParentContainer($input); 376 377 // Reset parent css 378 $parentContainer 379 .removeClass(conf.inputParentClassOnError) 380 .removeClass(conf.inputParentClassOnSuccess); 381 382 // Remove possible error message 383 if (typeof conf.inlineErrorMessageCallback === 'function') { 384 var $errorMessage = conf.inlineErrorMessageCallback($input, false, conf); 385 if ($errorMessage) { 386 $errorMessage.html(''); 387 } 388 } else { 389 $parentContainer 390 .find('.' + conf.errorMessageClass) 391 .remove(); 392 } 393 394 }, 395 removeAllMessagesAndStyling: function($form, conf) { 396
397 // Remove error messages in top of form 398 if (typeof conf.submitErrorMessageCallback === 'function') { 399 var $errorMessagesInTopOfForm = conf.submitErrorMessageCallback($form, false, conf); 400 if ($errorMessagesInTopOfForm) { 401 $errorMessagesInTopOfForm.html(''); 402 } 403 } else { 404 $form.find('.' + conf.errorMessageClass + '.alert').remove(); 405 } 406 407 // Remove input css/messages 408 $form.find('.' + conf.errorElementClass + ',.' + conf.successElementClass).each(function() { 409 dialogs.removeInputStylingAndMessage($(this), conf); 410 }); 411 }, 412 setInlineMessage: function ($input, errorMsg, conf) { 413 414 this.applyInputErrorStyling($input, conf); 415 416 var custom = document.getElementById($input.attr('name') + '_err_msg'), 417 $messageContainer = false, 418 setErrorMessage = function ($elem) { 419 $.formUtils.$win.trigger('validationErrorDisplay', [$input, $elem]); 420 $elem.html(errorMsg); 421 }, 422 addErrorToMessageContainer = function() { 423 var $found = false; 424 $messageContainer.find('.' + conf.errorMessageClass).each(function () { 425 if (this.inputReferer === $input[0]) { 426 $found = $(this); 427 return false; 428 } 429 }); 430 if ($found) { 431 if (!errorMsg) { 432 $found.remove(); 433 } else { 434 setErrorMessage($found); 435 } 436 } else if(errorMsg !== '') { 437 $message = $('<div class="' + conf.errorMessageClass + ' alert"></div>'); 438 setErrorMessage($message); 439 $message[0].inputReferer = $input[0]; 440 $messageContainer.prepend($message); 441 } 442 }, 443 $message; 444 445 if (custom) { 446 // Todo: remove in 3.0 447 $.formUtils.warn('Using deprecated element reference ' + custom.id); 448 $messageContainer = $(custom); 449 addErrorToMessageContainer(); 450 } else if (typeof conf.inlineErrorMessageCallback === 'function') { 451 $messageContainer = conf.inlineErrorMessageCallback($input, errorMsg, conf); 452 if (!$messageContainer) { 453 // Error display taken care of by inlineErrorMessageCallback 454 return; 455 } 456 addErrorToMessageContainer(); 457 } else { 458 var $parent = this.getParentContainer($input); 459 $message = $parent.find('.' + conf.errorMessageClass + '.help-block'); 460 if ($message.length === 0) { 461 $message = $('<span></span>').addClass('help-block').addClass(conf.errorMessageClass); 462 $message.appendTo($parent); 463 } 464 setErrorMessage($message); 465 } 466 }, 467 setMessageInTopOfForm: function ($form, errorMessages, conf, lang) { 468 var view = '<div class="{errorMessageClass} alert alert-danger">'+ 469 '<strong>{errorTitle}</strong>'+ 470 '<ul>{fields}</ul>'+ 471 '</div>', 472 $container = false; 473 474 if (typeof conf.submitErrorMessageCallback === 'function') { 475 $container = conf.submitErrorMessageCallback($form, errorMessages, conf); 476 if (!$container) { 477 // message display taken care of by callback 478 return; 479 } 480 } 481 482 var viewParams = { 483 errorTitle: lang.errorTitle, 484 fields: '', 485 errorMessageClass: conf.errorMessageClass 486 }; 487 488 $.each(errorMessages, function (i, msg) { 489 viewParams.fields += '<li>'+msg+'</li>'; 490 }); 491 492 $.each(viewParams, function(param, value) { 493 view = view.replace('{'+param+'}', value); 494 }); 495 496 if ($container) { 497 $container.html(view); 498 } else { 499 $form.children().eq(0).before($(view)); 500 } 501 } 502 }; 503 504 $.formUtils = $.extend($.formUtils || {}, { 505 dialogs: dialogs 506 }); 507 508})(jQuery); 509 510/** 511 * File declaring all methods if this plugin which is applied to $.fn. 512 */ 513(function($, window, undefined) { 514 515 'use strict'; 516 517 var _helpers = 0; 518 519 520 /** 521 * Assigns validateInputOnBlur function to elements blur event 522 * 523 * @param {Object} language Optional, will override $.formUtils.LANG 524 * @param {Object} conf Optional, will override the default settings 525 * @return {jQuery} 526 */ 527 $.fn.validateOnBlur = function (language, conf) { 528 var $form = this, 529 $elems = this.find('*[data-validation]'); 530 531 $elems.each(function(){ 532 var $this = $(this); 533 if ($this.is('[type=radio]')){ 534 var $additionals = $form.find('[type=radio][name="' + $this.attr('name') + '"]'); 535 $additionals.bind('blur.validation', function(){ 536 $this.validateInputOnBlur(language, conf, true, 'blur'); 537 }); 538 if (conf.validateCheckboxRadioOnClick) { 539 $additionals.bind('click.validation', function () { 540 $this.validateInputOnBlur(language, conf, true, 'click'); 541 }); 542 } 543 } 544 }); 545 546 $elems.bind('blur.validation', function () {
547 $(this).validateInputOnBlur(language, conf, true, 'blur'); 548 }); 549 550 if (conf.validateCheckboxRadioOnClick) { 551 // bind click event to validate on click for radio & checkboxes for nice UX 552 this.find('input[type=checkbox][data-validation],input[type=radio][data-validation]') 553 .bind('click.validation', function () { 554 $(this).validateInputOnBlur(language, conf, true, 'click'); 555 }); 556 } 557 558 return this; 559 }; 560 561 /* 562 * Assigns validateInputOnBlur function to elements custom event 563 * @param {Object} language Optional, will override $.formUtils.LANG 564 * @param {Object} settings Optional, will override the default settings 565 * * @return {jQuery} 566 */ 567 $.fn.validateOnEvent = function (language, config) { 568 var $elements = this[0].nodeName === 'FORM' ? this.find('*[data-validation-event]') : this; 569 $elements 570 .each(function () { 571 var $el = $(this), 572 etype = $el.valAttr('event'); 573 if (etype) { 574 $el 575 .unbind(etype + '.validation') 576 .bind(etype + '.validation', function (evt) { 577 if( (evt || {}).keyCode !== 9 ) { 578 $(this).validateInputOnBlur(language, config, true, etype); 579 } 580 }); 581 } 582 }); 583 return this; 584 }; 585 586 /** 587 * fade in help message when input gains focus 588 * fade out when input loses focus 589 * <input data-help="The info that I want to display for the user when input is focused" ... /> 590 * 591 * @param {String} attrName - Optional, default is data-help 592 * @return {jQuery} 593 */ 594 $.fn.showHelpOnFocus = function (attrName) { 595 if (!attrName) { 596 attrName = 'data-validation-help'; 597 } 598 599 // Add help text listeners 600 this.find('textarea,input').each(function () { 601 var $elem = $(this), 602 className = 'jquery_form_help_' + (++_helpers), 603 help = $elem.attr(attrName); 604 605 // Reset 606 $elem 607 .removeClass('has-help-text') 608 .unbind('focus.help') 609 .unbind('blur.help'); 610 611 if (help) { 612 $elem 613 .addClass('has-help-txt') 614 .bind('focus.help', function () { 615 var $help = $elem.parent().find('.' + className); 616 if ($help.length === 0) { 617 $help = $('<span />') 618 .addClass(className) 619 .addClass('help') 620 .addClass('help-block') // twitter bs 621 .text(help) 622 .hide(); 623 624 $elem.after($help); 625 } 626 $help.fadeIn(); 627 }) 628 .bind('blur.help', function () { 629 $(this) 630 .parent() 631 .find('.' + className) 632 .fadeOut('slow'); 633 }); 634 } 635 }); 636 637 return this; 638 }; 639 640 /** 641 * @param {Function} cb 642 * @param {Object} [conf] 643 * @param {Object} [lang] 644 */ 645 $.fn.validate = function(cb, conf, lang) { 646 var language = $.extend({}, $.formUtils.LANG, lang || {}); 647 this.each(function() { 648 var $elem = $(this), 649 closestFormElem = $elem.closest('form').get(0) || {}, 650 formDefaultConfig = closestFormElem.validationConfig || $.formUtils.defaultConfig(); 651 652 $elem.one('validation', function(evt, isValid) { 653 if ( typeof cb === 'function' ) { 654 cb(isValid, this, evt); 655 } 656 }); 657 658 $elem.validateInputOnBlur( 659 language, 660 $.extend({}, formDefaultConfig, conf || {}), 661 true 662 ); 663 }); 664 }; 665 666 /** 667 * Tells whether or not validation of this input will have to postpone the form submit () 668 * @returns {Boolean} 669 */ 670 $.fn.willPostponeValidation = function() { 671 return (this.valAttr('suggestion-nr') || 672 this.valAttr('postpone') || 673 this.hasClass('hasDatepicker')) && 674 !window.postponedValidation; 675 }; 676 677 /** 678 * Validate single input when it loses focus 679 * shows error message in a span element 680 * that is appended to the parent element 681 * 682 * @param {Object} [language] Optional, will override $.formUtils.LANG 683 * @param {Object} [conf] Optional, will override the default settings 684 * @param {Boolean} attachKeyupEvent Optional 685 * @param {String} eventContext 686 * @return {jQuery} 687 */ 688 $.fn.validateInputOnBlur = function (language, conf, attachKeyupEvent, eventContext) { 689 690 $.formUtils.eventType = eventContext; 691 692 if ( this.willPostponeValidation() ) { 693 // This validation has to be postponed 694 var _self = this, 695 postponeTime = this.valAttr('postpone') || 200; 696 697 window.postponedValidation = function () { 698 _self.validateInputOnBlur(language, conf, attachKeyupEvent, eventContext); 699 window.postponedValidation = false;
700 }; 701 702 setTimeout(function () { 703 if (window.postponedValidation) { 704 window.postponedValidation(); 705 } 706 }, postponeTime); 707 708 return this; 709 } 710 711 language = $.extend({}, $.formUtils.LANG, language || {}); 712 $.formUtils.dialogs.removeInputStylingAndMessage(this, conf); 713 714 var $elem = this, 715 $form = $elem.closest('form'), 716 result = $.formUtils.validateInput( 717 $elem, 718 language, 719 conf, 720 $form, 721 eventContext 722 ); 723 724 var reValidate = function() { 725 $elem.validateInputOnBlur(language, conf, false, 'blur.revalidated'); 726 }; 727 728 if (eventContext === 'blur') { 729 $elem 730 .unbind('validation.revalidate', reValidate) 731 .one('validation.revalidate', reValidate); 732 } 733 734 if (attachKeyupEvent) { 735 $elem.removeKeyUpValidation(); 736 } 737 738 if (result.shouldChangeDisplay) { 739 if (result.isValid) { 740 $.formUtils.dialogs.applyInputSuccessStyling($elem, conf); 741 } else { 742 $.formUtils.dialogs.setInlineMessage($elem, result.errorMsg, conf); 743 } 744 } 745 746 if (!result.isValid && attachKeyupEvent) { 747 $elem.validateOnKeyUp(language, conf); 748 } 749 750 return this; 751 }; 752 753 /** 754 * Validate element on keyup-event 755 */ 756 $.fn.validateOnKeyUp = function(language, conf) { 757 this.each(function() { 758 var $input = $(this); 759 if (!$input.valAttr('has-keyup-event')) { 760 $input 761 .valAttr('has-keyup-event', 'true') 762 .bind('keyup.validation', function (evt) { 763 if( evt.keyCode !== 9 ) { 764 $input.validateInputOnBlur(language, conf, false, 'keyup'); 765 } 766 }); 767 } 768 }); 769 return this; 770 }; 771 772 /** 773 * Remove validation on keyup 774 */ 775 $.fn.removeKeyUpValidation = function() { 776 this.each(function() { 777 $(this) 778 .valAttr('has-keyup-event', false) 779 .unbind('keyup.validation'); 780 }); 781 return this; 782 }; 783 784 /** 785 * Short hand for fetching/adding/removing element attributes 786 * prefixed with 'data-validation-' 787 * 788 * @param {String} name 789 * @param {String|Boolean} [val] 790 * @return {String|undefined|jQuery} 791 * @protected 792 */ 793 $.fn.valAttr = function (name, val) { 794 if (val === undefined) { 795 return this.attr('data-validation-' + name); 796 } else if (val === false || val === null) { 797 return this.removeAttr('data-validation-' + name); 798 } else { 799 name = ((name.length > 0) ? '-' + name : ''); 800 return this.attr('data-validation' + name, val); 801 } 802 }; 803 804 /** 805 * Function that validates all inputs in active form 806 * 807 * @param {Object} [language] 808 * @param {Object} [conf] 809 * @param {Boolean} [displayError] Defaults to true 810 */ 811 $.fn.isValid = function (language, conf, displayError) { 812 813 if ($.formUtils.isLoadingModules) { 814 var $self = this; 815 setTimeout(function () { 816 $self.isValid(language, conf, displayError); 817 }, 200); 818 return null; 819 } 820 821 conf = $.extend({}, $.formUtils.defaultConfig(), conf || {}); 822 language = $.extend({}, $.formUtils.LANG, language || {}); 823 displayError = displayError !== false; 824 825 if ($.formUtils.errorDisplayPreventedWhenHalted) { 826 // isValid() was called programmatically with argument displayError set 827 // to false when the validation was halted by any of the validators 828 delete $.formUtils.errorDisplayPreventedWhenHalted; 829 displayError = false; 830 } 831 832 /** 833 * Adds message to error message stack if not already in the message stack 834 * 835 * @param {String} mess 836 * @para {jQuery} $elem 837 */ 838 var addErrorMessage = function (mess, $elem) { 839 if ($.inArray(mess, errorMessages) < 0) { 840 errorMessages.push(mess); 841 } 842 errorInputs.push($elem); 843 $elem.valAttr('current-error', mess); 844 if (displayError) { 845 $.formUtils.dialogs.applyInputErrorStyling($elem, conf); 846 } 847 }, 848 849 /** Holds inputs (of type checkox or radio) already validated, to prevent recheck of mulitple checkboxes & radios */ 850 checkedInputs = [], 851 852 /** Error messages for this validation */ 853 errorMessages = [], 854
855 /** Input elements which value was not valid */ 856 errorInputs = [], 857 858 /** Form instance */ 859 $form = this, 860 861 /** 862 * Tells whether or not to validate element with this name and of this type 863 * 864 * @param {String} name 865 * @param {String} type 866 * @return {Boolean} 867 */ 868 ignoreInput = function (name, type) { 869 if (type === 'submit' || type === 'button' || type === 'reset') { 870 return true; 871 } 872 return $.inArray(name, conf.ignore || []) > -1; 873 }; 874 875 // Reset style and remove error class 876 if (displayError) { 877 $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf); 878 } 879 880 // Validate element values 881 $form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function () { 882 var $elem = $(this), 883 elementType = $elem.attr('type'), 884 isCheckboxOrRadioBtn = elementType === 'radio' || elementType === 'checkbox', 885 elementName = $elem.attr('name'); 886 887 if (!ignoreInput(elementName, elementType) && (!isCheckboxOrRadioBtn || $.inArray(elementName, checkedInputs) < 0)) { 888 889 if (isCheckboxOrRadioBtn) { 890 checkedInputs.push(elementName); 891 } 892 893 var result = $.formUtils.validateInput( 894 $elem, 895 language, 896 conf, 897 $form, 898 'submit' 899 ); 900 901 if (!result.isValid) { 902 addErrorMessage(result.errorMsg, $elem); 903 } else if (result.isValid && result.shouldChangeDisplay) { 904 $elem.valAttr('current-error', false); 905 $.formUtils.dialogs.applyInputSuccessStyling($elem, conf); 906 } 907 } 908 909 }); 910 911 // Run validation callback 912 if (typeof conf.onValidate === 'function') { 913 var errors = conf.onValidate($form); 914 if ($.isArray(errors)) { 915 $.each(errors, function (i, err) { 916 addErrorMessage(err.message, err.element); 917 }); 918 } 919 else if (errors && errors.element && errors.message) { 920 addErrorMessage(errors.message, errors.element); 921 } 922 } 923 924 // Reset form validation flag 925 $.formUtils.isValidatingEntireForm = false; 926 927 // Validation failed 928 if (errorInputs.length > 0) { 929 if (displayError) { 930 if (conf.errorMessagePosition === 'top') { 931 $.formUtils.dialogs.setMessageInTopOfForm($form, errorMessages, conf, language); 932 } else { 933 $.each(errorInputs, function (i, $input) { 934 $.formUtils.dialogs.setInlineMessage($input, $input.valAttr('current-error'), conf); 935 }); 936 } 937 if (conf.scrollToTopOnError) { 938 $.formUtils.$win.scrollTop($form.offset().top - 20); 939 } 940 } 941 } 942 943 if (!displayError && $.formUtils.haltValidation) { 944 $.formUtils.errorDisplayPreventedWhenHalted = true; 945 } 946 947 return errorInputs.length === 0 && !$.formUtils.haltValidation; 948 }; 949 950 /** 951 * Plugin for displaying input length restriction 952 */ 953 $.fn.restrictLength = function (maxLengthElement) { 954 new $.formUtils.lengthRestriction(this, maxLengthElement); 955 return this; 956 }; 957 958 /** 959 * Add suggestion dropdown to inputs having data-suggestions with a comma 960 * separated string with suggestions 961 * @param {Array} [settings] 962 * @returns {jQuery} 963 */ 964 $.fn.addSuggestions = function (settings) { 965 var sugs = false; 966 this.find('input').each(function () { 967 var $field = $(this); 968 969 sugs = $.split($field.attr('data-suggestions')); 970 971 if (sugs.length > 0 && !$field.hasClass('has-suggestions')) { 972 $.formUtils.suggest($field, sugs, settings); 973 $field.addClass('has-suggestions'); 974 } 975 }); 976 return this; 977 }; 978 979 980})(jQuery, window); 981 982/** 983 * Utility methods used for handling loading of modules (attached to $.formUtils) 984 */ 985(function($) { 986 987 'use strict'; 988 989 $.formUtils = $.extend($.formUtils || {}, { 990 991 /** 992 * @var {Boolean} 993 */ 994 isLoadingModules: false, 995 996 /** 997 * @var {Object} 998 */ 999 loadedModules: {}, 1000 1001 /** 1002 * @param {String} name 1003 */ 1004 registerLoadedModule: function (name) { 1005 this.loadedModules[$.trim(name).toLowerCase()] = true; 1006 }, 1007 1008 /** 1009 * @param {String} name 1010 * @return {Boolean} 1011 */ 1012 hasLoadedModule: function (name) { 1013 return $.trim(name).toLowerCase() in this.loadedModules; 1014 }, 1015 1016 /** 1017 * @example
1018 * $.formUtils.loadModules('date, security.dev'); 1019 * 1020 * Will load the scripts date.js and security.dev.js from the 1021 * directory where this script resides. If you want to load 1022 * the modules from another directory you can use the 1023 * path argument. 1024 * 1025 * The script will be cached by the browser unless the module 1026 * name ends with .dev 1027 * 1028 * @param {String} modules - Comma separated string with module file names (no directory nor file extension) 1029 * @param {String} [path] - Path where the module files are located if their not in the same directory as the core modules 1030 * @param {function} [callback] - Callback invoked when all modules are loaded 1031 */ 1032 loadModules: function (modules, path, callback) { 1033 1034 if ($.formUtils.isLoadingModules) { 1035 setTimeout(function () { 1036 $.formUtils.loadModules(modules, path, callback); 1037 }, 100); 1038 return; 1039 } 1040 1041 var loadModuleScripts = function (modules, path) { 1042 1043 var moduleList = $.split(modules), 1044 numModules = moduleList.length, 1045 moduleLoadedCallback = function () { 1046 numModules--; 1047 if (numModules === 0) { 1048 $.formUtils.isLoadingModules = false; 1049 if (typeof callback === 'function') { 1050 callback(); 1051 } 1052 } 1053 }; 1054 1055 if (numModules > 0) { 1056 $.formUtils.isLoadingModules = true; 1057 } 1058 1059 var cacheSuffix = '?_=' + ( new Date().getTime() ), 1060 appendToElement = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]; 1061 1062 $.each(moduleList, function (i, modName) { 1063 modName = $.trim(modName); 1064 if (modName.length === 0 || $.formUtils.hasLoadedModule(modName)) { 1065 moduleLoadedCallback(); 1066 } else { 1067 var scriptUrl = path + modName + (modName.slice(-3) === '.js' ? '' : '.js'), 1068 script = document.createElement('SCRIPT'); 1069 1070 if (typeof define === 'function' && define.amd) { 1071 require([scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' )], moduleLoadedCallback); 1072 } else { 1073 // Load the script 1074 script.type = 'text/javascript'; 1075 script.onload = moduleLoadedCallback; 1076 script.src = scriptUrl + ( scriptUrl.slice(-7) === '.dev.js' ? cacheSuffix : '' ); 1077 script.onerror = function() { 1078 $.formUtils.warn('Unable to load form validation module '+scriptUrl, true); 1079 moduleLoadedCallback(); 1080 }; 1081 script.onreadystatechange = function () { 1082 // IE 7 fix 1083 if (this.readyState === 'complete' || this.readyState === 'loaded') { 1084 moduleLoadedCallback(); 1085 // Handle memory leak in IE 1086 this.onload = null; 1087 this.onreadystatechange = null; 1088 } 1089 }; 1090 appendToElement.appendChild(script); 1091 } 1092 } 1093 }); 1094 }; 1095 1096 if (path) { 1097 loadModuleScripts(modules, path); 1098 } else { 1099 var findScriptPathAndLoadModules = function () { 1100 var foundPath = false; 1101 $('script[src*="form-validator"]').each(function () { 1102 var isScriptFromPluginNodeModulesDirectory = this.src.split('form-validator')[1].split('node_modules').length > 1; 1103 if (!isScriptFromPluginNodeModulesDirectory) { 1104 foundPath = this.src.substr(0, this.src.lastIndexOf('/')) + '/'; 1105 if (foundPath === '/') { 1106 foundPath = ''; 1107 } 1108 return false; 1109 } 1110 }); 1111 1112 if (foundPath !== false) { 1113 loadModuleScripts(modules, foundPath); 1114 return true; 1115 } 1116 return false; 1117 }; 1118 1119 if (!findScriptPathAndLoadModules()) { 1120 $(function () { 1121 var hasLoadedModuleScripts = findScriptPathAndLoadModules(); 1122 if (!hasLoadedModuleScripts) { 1123 // The modules may have been inserted via a minified script 1124 if (typeof callback === 'function') { 1125 callback(); 1126 } 1127 } 1128 }); 1129 } 1130 } 1131 } 1132 1133 }); 1134 1135})(jQuery); 1136 1137/** 1138 * Setup function for the plugin 1139 */ 1140(function ($) { 1141 1142 'use strict'; 1143 1144 1145 /** 1146 * A bit smarter split function 1147 * delimiter can be space, comma, dash or pipe 1148 * @param {String} val 1149 * @param {Function|String} [callback] 1150 * @param {Boolean}
1150 [allowSpaceAsDelimiter] 1151 * @returns {Array|void} 1152 */ 1153 $.split = function (val, callback, allowSpaceAsDelimiter) { 1154 // default to true 1155 allowSpaceAsDelimiter = allowSpaceAsDelimiter === undefined || allowSpaceAsDelimiter === true; 1156 var pattern = '[,|'+(allowSpaceAsDelimiter ? '\\s':'')+'-]\\s*', 1157 regex = new RegExp(pattern, 'g'); 1158 if (typeof callback !== 'function') { 1159 // return array 1160 if (!val) { 1161 return []; 1162 } 1163 var values = []; 1164 $.each(val.split(callback ? callback : regex), 1165 function (i, str) { 1166 str = $.trim(str); 1167 if (str.length) { 1168 values.push(str); 1169 } 1170 } 1171 ); 1172 return values; 1173 } else if (val) { 1174 // exec callback func on each 1175 $.each(val.split(regex), 1176 function (i, str) { 1177 str = $.trim(str); 1178 if (str.length) { 1179 return callback(str, i); 1180 } 1181 } 1182 ); 1183 } 1184 }; 1185 1186 /** 1187 * Short hand function that makes the validation setup require less code 1188 * @param conf 1189 */ 1190 $.validate = function (conf) { 1191 1192 var defaultConf = $.extend($.formUtils.defaultConfig(), { 1193 form: 'form', 1194 validateOnEvent: false, 1195 validateOnBlur: true, 1196 validateCheckboxRadioOnClick: true, 1197 showHelpOnFocus: true, 1198 addSuggestions: true, 1199 modules: '', 1200 onModulesLoaded: null, 1201 language: false, 1202 onSuccess: false, 1203 onError: false, 1204 onElementValidate: false 1205 }); 1206 1207 conf = $.extend(defaultConf, conf || {}); 1208 1209 $(window).trigger('formValidationPluginInit', [conf]); 1210 1211 if( conf.lang && conf.lang !== 'en' ) { 1212 var langModule = 'lang/'+conf.lang+'.js'; 1213 conf.modules += conf.modules.length ? ','+langModule : langModule; 1214 } 1215 1216 // Add validation to forms 1217 $(conf.form).each(function (i, form) { 1218 1219 // Make a reference to the config for this form 1220 form.validationConfig = conf; 1221 1222 // Trigger jQuery event that we're about to setup validation 1223 var $form = $(form); 1224 $form.trigger('formValidationSetup', [$form, conf]); 1225 1226 // Remove classes and event handlers that might have been 1227 // added by a previous call to $.validate 1228 $form.find('.has-help-txt') 1229 .unbind('focus.validation') 1230 .unbind('blur.validation'); 1231 1232 $form 1233 .removeClass('has-validation-callback') 1234 .unbind('submit.validation') 1235 .unbind('reset.validation') 1236 .find('input[data-validation],textarea[data-validation]') 1237 .unbind('blur.validation'); 1238 1239 // Validate when submitted 1240 $form.bind('submit.validation', function (evt) { 1241 1242 var $form = $(this), 1243 stop = function() { 1244 evt.stopImmediatePropagation(); 1245 return false; 1246 }; 1247 1248 if ($.formUtils.haltValidation) { 1249 // pressing several times on submit button while validation is halted 1250 return stop(); 1251 } 1252 1253 if ($.formUtils.isLoadingModules) { 1254 setTimeout(function () { 1255 $form.trigger('submit.validation'); 1256 }, 200); 1257 return stop(); 1258 } 1259 1260 var valid = $form.isValid(conf.language, conf); 1261 if ($.formUtils.haltValidation) { 1262 // Validation got halted by one of the validators 1263 return stop(); 1264 } else { 1265 if (valid && typeof conf.onSuccess === 'function') { 1266 var callbackResponse = conf.onSuccess($form); 1267 if (callbackResponse === false) { 1268 return stop(); 1269 } 1270 } else if (!valid && typeof conf.onError === 'function') { 1271 conf.onError($form); 1272 return stop(); 1273 } else { 1274 return valid ? true : stop(); 1275 } 1276 } 1277 }) 1278 .bind('reset.validation', function () { 1279 $.formUtils.dialogs.removeAllMessagesAndStyling($form, conf); 1280 }) 1281 .addClass('has-validation-callback'); 1282 1283 if (conf.showHelpOnFocus) { 1284 $form.showHelpOnFocus(); 1285 } 1286 if (conf.addSuggestions) { 1287 $form.addSuggestions(); 1288 } 1289 if (conf.validateOnBlur) { 1290 $form.validateOnBlur(conf.language, conf); 1291 $form.bind('html5ValidationAttrsFound', function () { 1292 $form.validateOnBlur(conf.language, conf); 1293 }); 1294 } 1295 if (conf.validateOnEvent) { 1296 $form.validateOnEvent(conf.language, conf); 1297 } 1298 }); 1299 1300 if (conf.modules !== '') {
1301 $.formUtils.loadModules(conf.modules, null, function() { 1302 if (typeof conf.onModulesLoaded === 'function') { 1303 conf.onModulesLoaded(); 1304 } 1305 var $form = typeof conf.form === 'string' ? $(conf.form) : conf.form; 1306 $.formUtils.$win.trigger('validatorsLoaded', [$form, conf]); 1307 }); 1308 } 1309 }; 1310 1311})(jQuery); 1312 1313/** 1314 * Utility methods and properties attached to $.formUtils 1315 */ 1316(function($, window) { 1317 1318 'use strict'; 1319 1320 var $win = $(window); 1321 1322 $.formUtils = $.extend($.formUtils || {}, { 1323 1324 $win: $win, 1325 1326 /** 1327 * Default config for $(...).isValid(); 1328 */ 1329 defaultConfig: function () { 1330 return { 1331 ignore: [], // Names of inputs not to be validated even though `validationRuleAttribute` containing the validation rules tells us to 1332 errorElementClass: 'error', // Class that will be put on elements which value is invalid 1333 successElementClass: 'valid', // Class that will be put on elements that has been validated with success 1334 borderColorOnError: '#b94a48', // Border color of elements which value is invalid, empty string to not change border color 1335 errorMessageClass: 'form-error', // class name of div containing error messages when validation fails 1336 validationRuleAttribute: 'data-validation', // name of the attribute holding the validation rules 1337 validationErrorMsgAttribute: 'data-validation-error-msg', // define custom err msg inline with element 1338 errorMessagePosition: 'inline', // Can be either "top" or "inline" 1339 errorMessageTemplate: { 1340 container: '<div class="{errorMessageClass} alert alert-danger">{messages}</div>', 1341 messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>', 1342 field: '<li>{msg}</li>' 1343 }, 1344 scrollToTopOnError: true, 1345 dateFormat: 'yyyy-mm-dd', 1346 addValidClassOnAll: false, // whether or not to apply class="valid" even if the input wasn't validated 1347 decimalSeparator: '.', 1348 inputParentClassOnError: 'has-error', // twitter-bootstrap default class name 1349 inputParentClassOnSuccess: 'has-success', // twitter-bootstrap default class name 1350 validateHiddenInputs: false, // whether or not hidden inputs should be validated 1351 inlineErrorMessageCallback: false, 1352 submitErrorMessageCallback: false 1353 }; 1354 }, 1355 1356 /** 1357 * Available validators 1358 */ 1359 validators: {}, 1360 1361 /** 1362 * Events triggered by form validator 1363 */ 1364 _events: {load: [], valid: [], invalid: []}, 1365 1366 /** 1367 * Setting this property to true during validation will 1368 * stop further validation from taking place and form will 1369 * not be sent 1370 */ 1371 haltValidation: false, 1372 1373 /** 1374 * Function for adding a validator 1375 * @see $.formUtils.addAsyncValidator (async.js) 1376 * @param {Object} validator 1377 */ 1378 addValidator: function (validator) { 1379 // prefix with "validate_" for backward compatibility reasons 1380 var name = validator.name.indexOf('validate_') === 0 ? validator.name : 'validate_' + validator.name; 1381 if (validator.validateOnKeyUp === undefined) { 1382 validator.validateOnKeyUp = true; 1383 } 1384 this.validators[name] = validator; 1385 }, 1386 1387 /** 1388 * Warn user via the console if available 1389 */ 1390 warn: function(msg, fallbackOnAlert) { 1391 if( 'console' in window ) { 1392 if( typeof window.console.warn === 'function' ) { 1393 window.console.warn(msg); 1394 } else if( typeof window.console.log === 'function' ) { 1395 window.console.log(msg); 1396 } 1397 } else if (fallbackOnAlert) { 1398 // This is for some old IE version... 1399 alert(msg); 1400 } 1401 }, 1402 1403 /** 1404 * Same as input $.fn.val() but also supporting input of typ radio or checkbox 1405 * @example 1406 * 1407 * $.formUtils.getValue('.myRadioButtons', $('#some-form')); 1408 * $.formUtils.getValue($('#some-form').find('.check-boxes')); 1409 * 1410 * @param query 1411 * @param $parent 1412 * @returns {String|Boolean} 1413 */ 1414 getValue: function(query, $parent) { 1415 var $inputs = $parent ? $parent.find(query) : query; 1416 if ($inputs.length > 0 ) { 1417 var type = $inputs.eq(0).attr('type'); 1418 if (type === 'radio' || type === 'checkbox') { 1419 return $inputs.filter(':checked').val() || ''; 1420 } else { 1421 return $inputs.val() || ''; 1422 } 1423 } 1424 return false;
1425 }, 1426 1427 /** 1428 * Validate the value of given element according to the validation rules 1429 * found in the attribute data-validation. Will return an object representing 1430 * a validation result, having the props shouldChangeDisplay, isValid and errorMsg 1431 * @param {jQuery} $elem 1432 * @param {Object} language ($.formUtils.LANG) 1433 * @param {Object} conf 1434 * @param {jQuery} $form 1435 * @param {String} [eventContext] 1436 * @return {Object} 1437 */ 1438 validateInput: function ($elem, language, conf, $form, eventContext) { 1439 1440 conf = conf || $.formUtils.defaultConfig(); 1441 language = language || $.formUtils.LANG; 1442 1443 if (!$form.length) { 1444 $form = $elem.parent(); 1445 } 1446 1447 var value = this.getValue($elem); 1448 1449 $elem 1450 .valAttr('skipped', false) 1451 .one('beforeValidation', function() { 1452 // Skip input because its hidden or disabled 1453 // Doing this in a callback makes it possible for others to prevent the default 1454 // behaviour by binding to the same event and call evt.stopImmediatePropagation() 1455 if ($elem.attr('disabled') || (!$elem.is(':visible') && !conf.validateHiddenInputs)) { 1456 $elem.valAttr('skipped', 1); 1457 } 1458 }) 1459 .trigger('beforeValidation', [value, language, conf]); 1460 1461 var inputIsOptional = $elem.valAttr('optional') === 'true', 1462 skipBecauseItsEmpty = !value && inputIsOptional, 1463 validationRules = $elem.attr(conf.validationRuleAttribute), 1464 isValid = true, 1465 errorMsg = '', 1466 result = {isValid: true, shouldChangeDisplay:true, errorMsg:''}; 1467 1468 // For input type="number", browsers attempt to parse the entered value into a number. 1469 // If the input is not numeric, browsers handle the situation differently: 1470 // Chrome 48 simply disallows non-numeric input; FF 44 clears out the input box on blur; 1471 // Safari 5 parses the entered string to find a leading number. 1472 // If the input fails browser validation, the browser sets the input value equal to an empty string. 1473 // Therefore, we cannot distinguish (apart from hacks) between an empty input type="text" and one with a 1474 // value that can't be parsed by the browser. 1475 1476 if (!validationRules || skipBecauseItsEmpty || $elem.valAttr('skipped')) { 1477 result.shouldChangeDisplay = conf.addValidClassOnAll; 1478 return result; 1479 } 1480 1481 // Filter out specified characters 1482 var ignore = $elem.valAttr('ignore'); 1483 if (ignore) { 1484 $.each(ignore.split(''), function(i, character) { 1485 value = value.replace(new RegExp('\\'+character, 'g'), ''); 1486 }); 1487 } 1488 1489 $.split(validationRules, function (rule) { 1490 1491 if (rule.indexOf('validate_') !== 0) { 1492 rule = 'validate_' + rule; 1493 } 1494 1495 var validator = $.formUtils.validators[rule]; 1496 1497 if (validator) { 1498 1499 // special change of element for checkbox_group rule 1500 if (rule === 'validate_checkbox_group') { 1501 // set element to first in group, so error msg attr doesn't need to be set on all elements in group 1502 $elem = $form.find('[name="' + $elem.attr('name') + '"]:eq(0)'); 1503 } 1504 1505 if (eventContext !== 'keyup' || validator.validateOnKeyUp) { 1506 // A validator can prevent itself from getting triggered on keyup 1507 isValid = validator.validatorFunction(value, $elem, conf, language, $form, eventContext); 1508 } 1509 1510 if (!isValid) { 1511 if (conf.validateOnBlur) { 1512 $elem.validateOnKeyUp(language, conf); 1513 } 1514 errorMsg = $.formUtils.dialogs.resolveErrorMessage($elem, validator, rule, conf, language); 1515 return false; // break iteration 1516 } 1517 1518 } else { 1519 1520 // todo: Add some validator lookup function and tell immediately which module is missing 1521 throw new Error('Using undefined validator "' + rule + 1522 '". Maybe you have forgotten to load the module that "' + rule +'" belongs to?'); 1523 1524 } 1525 1526 }); 1527 1528 1529 if (isValid === false) { 1530 $elem.trigger('validation', false); 1531 result.errorMsg = errorMsg; 1532 result.isValid = false;
1533 result.shouldChangeDisplay = true; 1534 } else if (isValid === null) { 1535 // A validatorFunction returning null means that it's not able to validate 1536 // the input at this time. Most probably some async stuff need to gets finished 1537 // first and then the validator will re-trigger the validation. 1538 result.shouldChangeDisplay = false; 1539 } else { 1540 $elem.trigger('validation', true); 1541 result.shouldChangeDisplay = true; 1542 } 1543 1544 // Run element validation callback 1545 if (typeof conf.onElementValidate === 'function' && errorMsg !== null) { 1546 conf.onElementValidate(result.isValid, $elem, $form, errorMsg); 1547 } 1548 1549 $elem.trigger('afterValidation', [result, eventContext]); 1550 1551 return result; 1552 }, 1553 1554 /** 1555 * Is it a correct date according to given dateFormat. Will return false if not, otherwise 1556 * an array 0=>year 1=>month 2=>day 1557 * 1558 * @param {String} val 1559 * @param {String} dateFormat 1560 * @param {Boolean} [addMissingLeadingZeros] 1561 * @return {Array}|{Boolean} 1562 */ 1563 parseDate: function (val, dateFormat, addMissingLeadingZeros) { 1564 var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0, 1), 1565 regexp = '^', 1566 formatParts = dateFormat.split(divider || null), 1567 matches, day, month, year; 1568 1569 $.each(formatParts, function (i, part) { 1570 regexp += (i > 0 ? '\\' + divider : '') + '(\\d{' + part.length + '})'; 1571 }); 1572 1573 regexp += '$'; 1574 1575 if (addMissingLeadingZeros) { 1576 var newValueParts = []; 1577 $.each(val.split(divider), function(i, part) { 1578 if(part.length === 1) { 1579 part = '0'+part; 1580 } 1581 newValueParts.push(part); 1582 }); 1583 val = newValueParts.join(divider); 1584 } 1585 1586 matches = val.match(new RegExp(regexp)); 1587 if (matches === null) { 1588 return false; 1589 } 1590 1591 var findDateUnit = function (unit, formatParts, matches) { 1592 for (var i = 0; i < formatParts.length; i++) { 1593 if (formatParts[i].substring(0, 1) === unit) { 1594 return $.formUtils.parseDateInt(matches[i + 1]); 1595 } 1596 } 1597 return -1; 1598 }; 1599 1600 month = findDateUnit('m', formatParts, matches); 1601 day = findDateUnit('d', formatParts, matches); 1602 year = findDateUnit('y', formatParts, matches); 1603 1604 if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 === 0 && year % 400 !== 0)) || 1605 (month === 2 && day > 29 && (year % 4 === 0 || year % 100 !== 0 && year % 400 === 0)) || 1606 month > 12 || month === 0) { 1607 return false; 1608 } 1609 if ((this.isShortMonth(month) && day > 30) || (!this.isShortMonth(month) && day > 31) || day === 0) { 1610 return false; 1611 } 1612 1613 return [year, month, day]; 1614 }, 1615 1616 /** 1617 * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får man 0 när man kör parseInt? 1618 * 1619 * @param {String} val 1620 * @return {Number} 1621 */ 1622 parseDateInt: function (val) { 1623 if (val.indexOf('0') === 0) { 1624 val = val.replace('0', ''); 1625 } 1626 return parseInt(val, 10); 1627 }, 1628 1629 /** 1630 * Has month only 30 days? 1631 * 1632 * @param {Number} m 1633 * @return {Boolean} 1634 */ 1635 isShortMonth: function (m) { 1636 return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7); 1637 }, 1638 1639 /** 1640 * Restrict input length 1641 * 1642 * @param {jQuery} $inputElement Jquery Html object 1643 * @param {jQuery} $maxLengthElement jQuery Html Object 1644 * @return void 1645 */ 1646 lengthRestriction: function ($inputElement, $maxLengthElement) { 1647 // read maxChars from counter display initial text value 1648 var maxChars = parseInt($maxLengthElement.text(), 10), 1649 charsLeft = 0, 1650 1651 // internal function does the counting and sets display value 1652 countCharacters = function () { 1653 var numChars = $inputElement.val().length; 1654 if (numChars > maxChars) { 1655 // get current scroll bar position 1656 var currScrollTopPos = $inputElement.scrollTop(); 1657 // trim value to max length 1658 $inputElement.val($inputElement.val().substring(0, maxChars)); 1659 $inputElement.scrollTop(currScrollTopPos); 1660 } 1661 charsLeft = maxChars - numChars; 1662 if (charsLeft < 0) { 1663 charsLeft = 0; 1664 } 1665 1666 // set counter text 1667 $maxLengthElement.text(charsLeft); 1668 }; 1669 1670 // bind events to this element 1671 // setTimeout is needed, cut or paste fires before val is available 1672 $($inputElement).bind('keydown keyup keypress focus blur', countCharacters) 1673 .bind('cut paste', function () { 1674 setTimeout(countCharacters, 100); 1675 }); 1676
1677 // count chars on pageload, if there are prefilled input-values 1678 $(document).bind('ready', countCharacters); 1679 }, 1680 1681 /** 1682 * Test numeric against allowed range 1683 * 1684 * @param $value int 1685 * @param $rangeAllowed str; (1-2, min1, max2, 10) 1686 * @return array 1687 */ 1688 numericRangeCheck: function (value, rangeAllowed) { 1689 // split by dash 1690 var range = $.split(rangeAllowed), 1691 // min or max 1692 minmax = parseInt(rangeAllowed.substr(3), 10); 1693 1694 if( range.length === 1 && rangeAllowed.indexOf('min') === -1 && rangeAllowed.indexOf('max') === -1 ) { 1695 range = [rangeAllowed, rangeAllowed]; // only a number, checking agains an exact number of characters 1696 } 1697 1698 // range ? 1699 if (range.length === 2 && (value < parseInt(range[0], 10) || value > parseInt(range[1], 10) )) { 1700 return [ 'out', range[0], range[1] ]; 1701 } // value is out of range 1702 else if (rangeAllowed.indexOf('min') === 0 && (value < minmax )) // min 1703 { 1704 return ['min', minmax]; 1705 } // value is below min 1706 else if (rangeAllowed.indexOf('max') === 0 && (value > minmax )) // max 1707 { 1708 return ['max', minmax]; 1709 } // value is above max 1710 // since no other returns executed, value is in allowed range 1711 return [ 'ok' ]; 1712 }, 1713 1714 1715 _numSuggestionElements: 0, 1716 _selectedSuggestion: null, 1717 _previousTypedVal: null, 1718 1719 /** 1720 * Utility function that can be used to create plugins that gives
1721 * suggestions when inputs is typed into 1722 * @param {jQuery} $elem 1723 * @param {Array} suggestions 1724 * @param {Object} settings - Optional 1725 * @return {jQuery} 1726 */ 1727 suggest: function ($elem, suggestions, settings) { 1728 var conf = { 1729 css: { 1730 maxHeight: '150px', 1731 background: '#FFF', 1732 lineHeight: '150%', 1733 textDecoration: 'underline', 1734 overflowX: 'hidden', 1735 overflowY: 'auto', 1736 border: '#CCC solid 1px', 1737 borderTop: 'none', 1738 cursor: 'pointer' 1739 }, 1740 activeSuggestionCSS: { 1741 background: '#E9E9E9' 1742 } 1743 }, 1744 setSuggsetionPosition = function ($suggestionContainer, $input) { 1745 var offset = $input.offset(); 1746 $suggestionContainer.css({ 1747 width: $input.outerWidth(), 1748 left: offset.left + 'px', 1749 top: (offset.top + $input.outerHeight()) + 'px' 1750 }); 1751 }; 1752 1753 if (settings) { 1754 $.extend(conf, settings); 1755 } 1756 1757 conf.css.position = 'absolute'; 1758 conf.css['z-index'] = 9999; 1759 $elem.attr('autocomplete', 'off'); 1760 1761 if (this._numSuggestionElements === 0) { 1762 // Re-position suggestion container if window size changes 1763 $win.bind('resize', function () { 1764 $('.jquery-form-suggestions').each(function () { 1765 var $container = $(this), 1766 suggestID = $container.attr('data-suggest-container'); 1767 setSuggsetionPosition($container, $('.suggestions-' + suggestID).eq(0)); 1768 }); 1769 }); 1770 } 1771 1772 this._numSuggestionElements++; 1773 1774 var onSelectSuggestion = function ($el) { 1775 var suggestionId = $el.valAttr('suggestion-nr'); 1776 $.formUtils._selectedSuggestion = null; 1777 $.formUtils._previousTypedVal = null; 1778 $('.jquery-form-suggestion-' + suggestionId).fadeOut('fast'); 1779 }; 1780 1781 $elem 1782 .data('suggestions', suggestions) 1783 .valAttr('suggestion-nr', this._numSuggestionElements) 1784 .unbind('focus.suggest') 1785 .bind('focus.suggest', function () { 1786 $(this).trigger('keyup'); 1787 $.formUtils._selectedSuggestion = null; 1788 }) 1789 .unbind('keyup.suggest') 1790 .bind('keyup.suggest', function () { 1791 var $input = $(this), 1792 foundSuggestions = [], 1793 val = $.trim($input.val()).toLocaleLowerCase(); 1794 1795 if (val === $.formUtils._previousTypedVal) { 1796 return; 1797 } 1798 else { 1799 $.formUtils._previousTypedVal = val; 1800 } 1801 1802 var hasTypedSuggestion = false, 1803 suggestionId = $input.valAttr('suggestion-nr'), 1804 $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId); 1805 1806 $suggestionContainer.scrollTop(0); 1807 1808 // Find the right suggestions 1809 if (val !== '') { 1810 var findPartial = val.length > 2; 1811 $.each($input.data('suggestions'), function (i, suggestion) { 1812 var lowerCaseVal = suggestion.toLocaleLowerCase(); 1813 if (lowerCaseVal === val) { 1814 foundSuggestions.push('<strong>' + suggestion + '</strong>'); 1815 hasTypedSuggestion = true; 1816 return false; 1817 } else if (lowerCaseVal.indexOf(val) === 0 || (findPartial && lowerCaseVal.indexOf(val) > -1)) { 1818 foundSuggestions.push(suggestion.replace(new RegExp(val, 'gi'), '<strong>$&</strong>')); 1819 } 1820 }); 1821 } 1822 1823 // Hide suggestion container 1824 if (hasTypedSuggestion || (foundSuggestions.length === 0 && $suggestionContainer.length > 0)) { 1825 $suggestionContainer.hide(); 1826 } 1827 1828 // Create suggestion container if not already exists 1829 else if (foundSuggestions.length > 0 && $suggestionContainer.length === 0) {
1830 $suggestionContainer = $('<div></div>').css(conf.css).appendTo('body'); 1831 $elem.addClass('suggestions-' + suggestionId); 1832 $suggestionContainer 1833 .attr('data-suggest-container', suggestionId) 1834 .addClass('jquery-form-suggestions') 1835 .addClass('jquery-form-suggestion-' + suggestionId); 1836 } 1837 1838 // Show hidden container 1839 else if (foundSuggestions.length > 0 && !$suggestionContainer.is(':visible')) { 1840 $suggestionContainer.show(); 1841 } 1842 1843 // add suggestions 1844 if (foundSuggestions.length > 0 && val.length !== foundSuggestions[0].length) { 1845 1846 // put container in place every time, just in case 1847 setSuggsetionPosition($suggestionContainer, $input); 1848 1849 // Add suggestions HTML to container 1850 $suggestionContainer.html(''); 1851 $.each(foundSuggestions, function (i, text) { 1852 $('<div></div>') 1853 .append(text) 1854 .css({ 1855 overflow: 'hidden', 1856 textOverflow: 'ellipsis', 1857 whiteSpace: 'nowrap', 1858 padding: '5px' 1859 }) 1860 .addClass('form-suggest-element') 1861 .appendTo($suggestionContainer) 1862 .click(function () { 1863 $input.focus(); 1864 $input.val($(this).text()); 1865 $input.trigger('change'); 1866 onSelectSuggestion($input); 1867 }); 1868 }); 1869 } 1870 }) 1871 .unbind('keydown.validation') 1872 .bind('keydown.validation', function (e) { 1873 var code = (e.keyCode ? e.keyCode : e.which), 1874 suggestionId, 1875 $suggestionContainer, 1876 $input = $(this); 1877 1878 if (code === 13 && $.formUtils._selectedSuggestion !== null) { 1879 suggestionId = $input.valAttr('suggestion-nr'); 1880 $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId); 1881 if ($suggestionContainer.length > 0) { 1882 var newText = $suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text(); 1883 $input.val(newText); 1884 $input.trigger('change'); 1885 onSelectSuggestion($input); 1886 e.preventDefault(); 1887 } 1888 } 1889 else { 1890 suggestionId = $input.valAttr('suggestion-nr'); 1891 $suggestionContainer = $('.jquery-form-suggestion-' + suggestionId); 1892 var $suggestions = $suggestionContainer.children(); 1893 if ($suggestions.length > 0 && $.inArray(code, [38, 40]) > -1) { 1894 if (code === 38) { // key up 1895 if ($.formUtils._selectedSuggestion === null) { 1896 $.formUtils._selectedSuggestion = $suggestions.length - 1; 1897 } 1898 else{ 1899 $.formUtils._selectedSuggestion--; 1900 } 1901 if ($.formUtils._selectedSuggestion < 0) { 1902 $.formUtils._selectedSuggestion = $suggestions.length - 1; 1903 } 1904 } 1905 else if (code === 40) { // key down 1906 if ($.formUtils._selectedSuggestion === null) { 1907 $.formUtils._selectedSuggestion = 0; 1908 } 1909 else { 1910 $.formUtils._selectedSuggestion++; 1911 } 1912 if ($.formUtils._selectedSuggestion > ($suggestions.length - 1)) { 1913 $.formUtils._selectedSuggestion = 0; 1914 } 1915 } 1916 1917 // Scroll in suggestion window 1918 var containerInnerHeight = $suggestionContainer.innerHeight(), 1919 containerScrollTop = $suggestionContainer.scrollTop(), 1920 suggestionHeight = $suggestionContainer.children().eq(0).outerHeight(), 1921 activeSuggestionPosY = suggestionHeight * ($.formUtils._selectedSuggestion); 1922 1923 if (activeSuggestionPosY < containerScrollTop || activeSuggestionPosY > (containerScrollTop + containerInnerHeight)) { 1924 $suggestionContainer.scrollTop(activeSuggestionPosY); 1925 } 1926 1927 $suggestions 1928 .removeClass('active-suggestion') 1929 .css('background', 'none') 1930 .eq($.formUtils._selectedSuggestion) 1931 .addClass('active-suggestion') 1932 .css(conf.activeSuggestionCSS); 1933 1934 e.preventDefault(); 1935 return false;
1936 } 1937 } 1938 }) 1939 .unbind('blur.suggest') 1940 .bind('blur.suggest', function () { 1941 onSelectSuggestion($(this)); 1942 }); 1943 1944 return $elem; 1945 }, 1946 1947 /** 1948 * Error dialogs 1949 * 1950 * @var {Object} 1951 */ 1952 LANG: { 1953 errorTitle: 'ÙÙØ´ÙÙ٠إرسا٠اÙÙÙ ÙØ°Ø¬', 1954 requiredField: '', 1955 requiredFields: 'ÙÙ ÙØªÙ Ù ÙØ£ Ø¬Ù ÙØ¹ Ø§ÙØÙÙ٠اÙÙ Ø·ÙÙØ¨Ø©.', 1956 badTime: 'ØÙ٠اÙÙÙØª Ø®Ø§Ø·ÙØ¡', 1957 badEmail: 'Ø§ÙØ¨Ø±Ùد Ø§ÙØ¥ÙÙØªØ±ÙÙ٠اÙ٠دخ٠خاطئ', 1958 badTelephone: 'رÙ٠اÙÙØ§ØªÙ اÙ٠دخ٠خاطئ', 1959 badSecurityAnswer: 'ÙÙ ÙØªÙ Ø§ÙØ¥Ø¬Ø§Ø¨Ø© Ø¹Ù Ø³Ø¤Ø§Ù Ø§ÙØ£Ù اÙ', 1960 badDate: 'ØªØ§Ø±ÙØ® ٠دخ٠خاطئ', 1961 lengthBadStart: 'اÙÙÙÙ Ø© اÙÙ Ø¯Ø®ÙØ© ÙØ¬Ø¨ أ٠تÙÙ٠بÙÙ ', 1962 lengthBadEnd: ' ØØ±ÙÙ', 1963 lengthTooLongStart: 'اÙÙÙÙ Ø© اÙ٠دخ٠أطÙÙ Ù Ù ', 1964 lengthTooShortStart: 'اÙÙÙÙ Ø© اÙÙ Ø¯Ø®Ù Ø£ÙØµØ± Ù Ù ', 1965 notConfirmed: 'ÙÙ ÙØªÙ تأÙÙØ¯ اÙÙÙÙ Ø© اÙÙ Ø¯Ø®ÙØ©', 1966 badDomain: 'ÙÙÙ Ø© ÙØ·Ø§Ù خاطئة', 1967 badUrl: 'اÙÙÙÙ Ø© اÙÙ Ø¯Ø®ÙØ© ÙÙØ³Øª Ø±Ø§Ø¨Ø·Ø§Ù ØµØ§ÙØØ§Ù', 1968 badCustomVal: 'اÙÙÙÙ Ø© اÙÙ Ø¯Ø®ÙØ© ØºÙØ± ØµØ§ÙØØ©', 1969 andSpaces: ' ÙÙ Ø³Ø§ÙØ§Øª ', 1970 badInt: 'اÙÙÙÙ Ø© اÙÙ Ø¯Ø®ÙØ© ÙÙØ³Øª رÙ٠ا٠صØÙØØ§Ù', 1971 badSecurityNumber: 'رÙÙ Ø¨Ø·Ø§ÙØ© اÙÙÙÙØ© ØºÙØ± صØÙØ', 1972 badUKVatAnswer: 'رÙÙ UK VAT ØºÙØ± صØÙØ', 1973 badUKNin: 'ØºÙØ± صØÙØ UK NINرÙÙ ', 1974 badUKUtr: 'ØºÙØ± صØÙØ UK UTR رÙÙ ', 1975 badStrength: 'ÙÙÙ Ø© اÙÙ Ø±ÙØ± ØºÙØ± ÙÙÙØ©', 1976 badNumberOfSelectedOptionsStart: 'ÙØ¬Ø¨ Ø§Ø®ØªÙØ§Ø± عÙÙ Ø§ÙØ£ÙÙ ', 1977 badNumberOfSelectedOptionsEnd: ' Ø£Ø¬ÙØ¨Ø©', 1978 badAlphaNumeric: 'اÙÙÙÙ Ø© اÙÙ Ø¯Ø®ÙØ© ÙØ¬Ø¨ Ø£Ù ØªØªØ¶Ù Ù ØØ±ÙÙ ÙØ£Ø±Ùا٠ÙÙØ· ', 1979 badAlphaNumericExtra: ' Ù ', 1980 wrongFileSize: 'اÙÙ Ù٠اÙ٠راد تØÙ ÙÙÙ ÙØ¨Ùر جدا٠(Ø§ÙØØ¯ اÙÙ Ø³Ù ÙØ¬ %s)', 1981 wrongFileType: 'Ù ÙÙØ§Øª Ù Ù ÙÙØ¹ %s ÙÙØ· Ù Ø³Ù ÙØØ©', 1982 groupCheckedRangeStart: 'Ù Ù ÙØ¶Ù٠اختر بÙÙ ', 1983 groupCheckedTooFewStart: 'Ù Ù ÙØ¶Ù٠اختر عÙÙ Ø§ÙØ£ÙÙ ', 1984 groupCheckedTooManyStart: 'Ù Ù ÙØ¶Ù٠اختر Ø¨ØØ¯ Ø£ÙØµÙ ', 1985 groupCheckedEnd: ' ٠رات', 1986 badCreditCard: 'رÙÙ Ø¨Ø·Ø§ÙØ© ائت٠اÙÙØ© Ø®Ø§Ø·ÙØ¡', 1987 badCVV: 'ر٠ز Ø§ÙØ£Ù ا٠خاطئ', 1988 wrongFileDim : 'ØØ¯Ùد Ø§ÙØµÙرة ØºÙØ± ØµØ§ÙØØ©', 1989 imageTooTall : 'Ø§ÙØµÙرة ÙÙ Ù٠أ٠تÙÙ٠أطÙÙ Ù Ù', 1990 imageTooWide : 'Ø§ÙØµÙرة ÙÙ Ù٠أ٠تÙÙ٠أعرض Ù Ù', 1991 imageTooSmall : 'ØµÙØ±Ø© ØµØºÙØ±Ø© جداÙ', 1992 min : 'أدÙÙ', 1993 max : 'Ø£ÙØµÙ', 1994 imageRatioNotAccepted : 'أبعاد ØµÙØ±Ø© ØºÙØ± Ù ÙØ¨ÙÙØ©', 1995 badBrazilTelephoneAnswer: 'رÙÙ ÙØ§ØªÙ Ù Ø¯Ø®Ù Ø®Ø§Ø·ÙØ¡', 1996 badBrazilCEPAnswer: 'ÙÙÙ Ø© CEP اÙÙ Ø¯Ø®ÙØ© ØºÙØ± صØÙØØ©', 1997 badBrazilCPFAnswer: 'ÙÙÙ Ø© CPF اÙÙ Ø¯Ø®ÙØ© ØºÙØ± صØÙØØ©', 1998 badPlPesel: 'ÙÙÙ Ø© Pl PESEL اÙÙ Ø¯Ø®ÙØ© ØºÙØ± صØÙØØ©', 1999 badPlNip: 'ÙÙÙ Ø© Pl NIP اÙÙ Ø¯Ø®ÙØ© ØºÙØ± صØÙØØ©', 2000 badPlRegon: 'ÙÙÙ Ø© Pl REGON اÙÙ Ø¯Ø®ÙØ© ØºÙØ± صØÙØØ©', 2001 badreCaptcha: 'Ù Ù ÙØ¶ÙÙ Ø£ÙØ¯ Ø£ÙÙ ÙØ³Øª Ø±ÙØ¨ÙتاÙ', 2002 passwordComplexityStart: 'ÙÙ ÙØ© اÙÙ Ø±ÙØ± تتÙÙ٠عÙÙ Ø§ÙØ£ÙÙ Ù Ù ', 2003 passwordComplexitySeparator: ', ', 2004 passwordComplexityUppercaseInfo: ' ØØ±ÙÙ ÙØ¨Ùرة', 2005 passwordComplexityLowercaseInfo: ' ØØ±ÙÙ ØµØºÙØ±Ø©', 2006 passwordComplexitySpecialCharsInfo: ' Ø±Ù ÙØ² خاصة', 2007 passwordComplexityNumericCharsInfo: ' Ø£Ø±ÙØ§Ù ', 2008 passwordComplexityEnd: '.' 2009 } 2010 }); 2011 2012})(jQuery, window); 2013 2014/** 2015 * File declaring all default validators. 2016 */ 2017(function($) { 2018 2019 /* 2020 * Validate email 2021 */ 2022 $.formUtils.addValidator({ 2023 name: 'email', 2024 validatorFunction: function (email) { 2025 2026 var emailParts = email.toLowerCase().split('@'), 2027 localPart = emailParts[0], 2028 domain = emailParts[1]; 2029 2030 if (localPart && domain) { 2031 2032 if( localPart.indexOf('"') === 0 ) { 2033 var len = localPart.length; 2034 localPart = localPart.replace(/\"/g, ''); 2035 if( localPart.length !== (len-2) ) { 2036 return false; // It was not allowed to have more than two apostrophes 2037 } 2038 } 2039 2040 return $.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) && 2041 localPart.indexOf('.') !== 0 && 2042 localPart.substring(localPart.length-1, localPart.length) !== '.' && 2043 localPart.indexOf('..') === -1 && 2044 !(/[^\w\+\.\-\#\-\_\~\!\$\&\'\(\)\*\+\,\;\=\:]/.test(localPart)); 2045 } 2046 2047 return false;
2048 }, 2049 errorMessage: '', 2050 errorMessageKey: 'badEmail' 2051 }); 2052 2053 /* 2054 * Validate domain name 2055 */ 2056 $.formUtils.addValidator({ 2057 name: 'domain', 2058 validatorFunction: function (val) { 2059 return val.length > 0 && 2060 val.length <= 253 && // Including sub domains 2061 !(/[^a-zA-Z0-9]/.test(val.slice(-2))) && !(/[^a-zA-Z0-9]/.test(val.substr(0, 1))) && !(/[^a-zA-Z0-9\.\-]/.test(val)) && 2062 val.split('..').length === 1 && 2063 val.split('.').length > 1; 2064 }, 2065 errorMessage: '', 2066 errorMessageKey: 'badDomain' 2067 }); 2068 2069 /* 2070 * Validate required 2071 */ 2072 $.formUtils.addValidator({ 2073 name: 'required', 2074 validatorFunction: function (val, $el, config, language, $form) { 2075 switch ($el.attr('type')) { 2076 case 'checkbox': 2077 return $el.is(':checked'); 2078 case 'radio': 2079 return $form.find('input[name="' + $el.attr('name') + '"]').filter(':checked').length > 0; 2080 default: 2081 return $.trim(val) !== ''; 2082 } 2083 }, 2084 errorMessage: '', 2085 errorMessageKey: function(config) { 2086 if (config.errorMessagePosition === 'top' || typeof config.errorMessagePosition === 'function') { 2087 return 'requiredFields'; 2088 } 2089 else { 2090 return 'requiredField'; 2091 } 2092 } 2093 }); 2094 2095 /* 2096 * Validate length range 2097 */ 2098 $.formUtils.addValidator({ 2099 name: 'length', 2100 validatorFunction: function (val, $el, conf, lang) { 2101 var lengthAllowed = $el.valAttr('length'), 2102 type = $el.attr('type'); 2103 2104 if (lengthAllowed === undefined) { 2105 alert('Please add attribute "data-validation-length" to ' + $el[0].nodeName + ' named ' + $el.attr('name')); 2106 return true; 2107 } 2108 2109 // check if length is above min, below max or within range. 2110 var len = type === 'file' && $el.get(0).files !== undefined ? $el.get(0).files.length : val.length, 2111 lengthCheckResults = $.formUtils.numericRangeCheck(len, lengthAllowed), 2112 checkResult; 2113 2114 switch (lengthCheckResults[0]) { // outside of allowed range 2115 case 'out': 2116 this.errorMessage = lang.lengthBadStart + lengthAllowed + lang.lengthBadEnd; 2117 checkResult = false;
2118 break; 2119 // too short 2120 case 'min': 2121 this.errorMessage = lang.lengthTooShortStart + lengthCheckResults[1] + lang.lengthBadEnd; 2122 checkResult = false; 2123 break; 2124 // too long 2125 case 'max': 2126 this.errorMessage = lang.lengthTooLongStart + lengthCheckResults[1] + lang.lengthBadEnd; 2127 checkResult = false; 2128 break; 2129 // ok 2130 default: 2131 checkResult = true; 2132 } 2133 2134 return checkResult; 2135 }, 2136 errorMessage: '', 2137 errorMessageKey: '' 2138 }); 2139 2140 /* 2141 * Validate url 2142 */ 2143 $.formUtils.addValidator({ 2144 name: 'url', 2145 validatorFunction: function (url) { 2146 // written by Scott Gonzalez: http://projects.scottsplayground.com/iri/ 2147 // - Victor Jonsson added support for arrays in the url ?arg[]=sdfsdf 2148 // - General improvements made by Stéphane Moureau <https://github.com/TraderStf> 2149 2150 var urlFilter = /^(https?|ftp):\/\/((((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|\[|\]|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i; 2151 if (urlFilter.test(url)) { 2152 var domain = url.split('://')[1], 2153 domainSlashPos = domain.indexOf('/'); 2154 2155 if (domainSlashPos > -1) { 2156 domain = domain.substr(0, domainSlashPos); 2157 } 2158 2159 return $.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add support for IP-addresses 2160 } 2161 return false; 2162 }, 2163 errorMessage: '', 2164 errorMessageKey: 'badUrl' 2165 }); 2166 2167 /* 2168 * Validate number (floating or integer) 2169 */ 2170 $.formUtils.addValidator({ 2171 name: 'number', 2172 validatorFunction: function (val, $el, conf) { 2173 if (val !== '') { 2174 var allowing = $el.valAttr('allowing') || '', 2175 decimalSeparator = $el.valAttr('decimal-separator') || conf.decimalSeparator, 2176 allowsRange = false, 2177 begin, end, 2178 steps = $el.valAttr('step') || '', 2179 allowsSteps = false, 2180 sanitize = $el.attr('data-sanitize') || '', 2181 isFormattedWithNumeral = sanitize.match(/(^|[\s])numberFormat([\s]|$)/i); 2182 2183 if (isFormattedWithNumeral) { 2184 if (!window.numeral) { 2185 throw new ReferenceError('The data-sanitize value numberFormat cannot be used without the numeral' + 2186 ' library. Please see Data Validation in http://www.formvalidator.net for more information.'); 2187 } 2188 //Unformat input first, then convert back to String 2189 if (val.length) { 2190 val = String(numeral().unformat(val)); 2191 } 2192 } 2193 2194 if (allowing.indexOf('number') === -1) { 2195 allowing += ',number'; 2196 } 2197 2198 if (allowing.indexOf('negative') === -1 && val.indexOf('-') === 0) { 2199 return false; 2200 } 2201 2202 if (allowing.indexOf('range') > -1) { 2203 begin = parseFloat(allowing.substring(allowing.indexOf('[') + 1, allowing.indexOf(';'))); 2204 end = parseFloat(allowing.substring(allowing.indexOf(';') + 1, allowing.indexOf(']'))); 2205 allowsRange = true; 2206 } 2207 2208 if (steps !== '') { 2209 allowsSteps = true; 2210 } 2211 2212 if (decimalSeparator === ',') { 2213 if (val.indexOf('.') > -1) { 2214 return false;
2215 } 2216 // Fix for checking range with floats using , 2217 val = val.replace(',', '.'); 2218 } 2219 if (val.replace(/[0-9-]/g, '') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) { 2220 return true; 2221 } 2222 2223 if (allowing.indexOf('float') > -1 && val.match(new RegExp('^([0-9-]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps || (val % steps === 0))) { 2224 return true; 2225 } 2226 } 2227 return false; 2228 }, 2229 errorMessage: '', 2230 errorMessageKey: 'badInt' 2231 }); 2232 2233 /* 2234 * Validate alpha numeric 2235 */ 2236 $.formUtils.addValidator({ 2237 name: 'alphanumeric', 2238 validatorFunction: function (val, $el, conf, language) { 2239 var patternStart = '^([a-zA-Z0-9', 2240 patternEnd = ']+)$', 2241 additionalChars = $el.valAttr('allowing'), 2242 pattern = '', 2243 hasSpaces = false; 2244 2245 if (additionalChars) { 2246 pattern = patternStart + additionalChars + patternEnd; 2247 var extra = additionalChars.replace(/\\/g, ''); 2248 if (extra.indexOf(' ') > -1) { 2249 hasSpaces = true; 2250 extra = extra.replace(' ', ''); 2251 extra += language.andSpaces || $.formUtils.LANG.andSpaces; 2252 } 2253 2254 if(language.badAlphaNumericAndExtraAndSpaces && language.badAlphaNumericAndExtra) { 2255 if(hasSpaces) { 2256 this.errorMessage = language.badAlphaNumericAndExtraAndSpaces + extra; 2257 } else { 2258 this.errorMessage = language.badAlphaNumericAndExtra + extra + language.badAlphaNumericExtra; 2259 } 2260 } else { 2261 this.errorMessage = language.badAlphaNumeric + language.badAlphaNumericExtra + extra; 2262 } 2263 } else { 2264 pattern = patternStart + patternEnd; 2265 this.errorMessage = language.badAlphaNumeric; 2266 } 2267 2268 return new RegExp(pattern).test(val); 2269 }, 2270 errorMessage: '', 2271 errorMessageKey: '' 2272 }); 2273 2274 /* 2275 * Validate against regexp 2276 */ 2277 $.formUtils.addValidator({ 2278 name: 'custom', 2279 validatorFunction: function (val, $el) { 2280 var regexp = new RegExp($el.valAttr('regexp')); 2281 return regexp.test(val); 2282 }, 2283 errorMessage: '', 2284 errorMessageKey: 'badCustomVal' 2285 }); 2286 2287 /* 2288 * Validate date 2289 */ 2290 $.formUtils.addValidator({ 2291 name: 'date', 2292 validatorFunction: function (date, $el, conf) { 2293 var dateFormat = $el.valAttr('format') || conf.dateFormat || 'yyyy-mm-dd', 2294 addMissingLeadingZeros = $el.valAttr('require-leading-zero') === 'false'; 2295 return $.formUtils.parseDate(date, dateFormat, addMissingLeadingZeros) !== false; 2296 }, 2297 errorMessage: '', 2298 errorMessageKey: 'badDate' 2299 }); 2300 2301 2302 /* 2303 * Validate group of checkboxes, validate qty required is checked 2304 * written by Steve Wasiura : http://stevewasiura.waztech.com 2305 * element attrs 2306 * data-validation="checkbox_group" 2307 * data-validation-qty="1-2" // min 1 max 2 2308 * data-validation-error-msg="chose min 1, max of 2 checkboxes" 2309 */ 2310 $.formUtils.addValidator({ 2311 name: 'checkbox_group', 2312 validatorFunction: function (val, $el, conf, lang, $form) { 2313 // preset return var 2314 var isValid = true, 2315 // get name of element. since it is a checkbox group, all checkboxes will have same name 2316 elname = $el.attr('name'), 2317 // get checkboxes and count the checked ones 2318 $checkBoxes = $('input[type=checkbox][name^="' + elname + '"]', $form), 2319 checkedCount = $checkBoxes.filter(':checked').length, 2320 // get el attr that specs qty required / allowed 2321 qtyAllowed = $el.valAttr('qty'); 2322 2323 if (qtyAllowed === undefined) { 2324 var elementType = $el.get(0).nodeName; 2325 alert('Attribute "data-validation-qty" is missing from ' + elementType + ' named ' + $el.attr('name')); 2326 } 2327 2328 // call Utility function to check if count is above min, below max, within range etc. 2329 var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount, qtyAllowed); 2330 2331 // results will be array, [0]=result str, [1]=qty int 2332 switch (qtyCheckResults[0]) { 2333 // outside allowed range 2334 case 'out': 2335 this.errorMessage = lang.groupCheckedRangeStart + qtyAllowed + lang.groupCheckedEnd; 2336 isValid = false;
2337 break; 2338 // below min qty 2339 case 'min': 2340 this.errorMessage = lang.groupCheckedTooFewStart + qtyCheckResults[1] + (lang.groupCheckedTooFewEnd || lang.groupCheckedEnd); 2341 isValid = false; 2342 break; 2343 // above max qty 2344 case 'max': 2345 this.errorMessage = lang.groupCheckedTooManyStart + qtyCheckResults[1] + (lang.groupCheckedTooManyEnd || lang.groupCheckedEnd); 2346 isValid = false; 2347 break; 2348 // ok 2349 default: 2350 isValid = true; 2351 } 2352 2353 if( !isValid ) { 2354 var _triggerOnBlur = function() { 2355 $checkBoxes.unbind('click', _triggerOnBlur); 2356 $checkBoxes.filter('*[data-validation]').validateInputOnBlur(lang, conf, false, 'blur'); 2357 }; 2358 $checkBoxes.bind('click', _triggerOnBlur); 2359 } 2360 2361 return isValid; 2362 } 2363 // errorMessage : '', // set above in switch statement 2364 // errorMessageKey: '' // not used 2365 }); 2366 2367})(jQuery); 2368 2369 2370}));
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.