1/* jqBootstrapValidation 2 * A plugin for automating validation on Twitter Bootstrap formatted forms. 3 * 4 * v1.3.6 5 * 6 * License: MIT <http://opensource.org/licenses/mit-license.php> - see LICENSE file 7 * 8 * http://ReactiveRaven.github.com/jqBootstrapValidation/ 9 */ 10 11(function( $ ){ 12 13 var createdElements = []; 14 15 var defaults = { 16 options: { 17 prependExistingHelpBlock: false, 18 sniffHtml: true, // sniff for 'required', 'maxlength', etc 19 preventSubmit: true, // stop the form submit event from firing if validation fails 20 submitError: false, // function called if there is an error when trying to submit 21 submitSuccess: false, // function called just before a successful submit event is sent to the server 22 semanticallyStrict: false, // set to true to tidy up generated HTML output 23 autoAdd: { 24 helpBlocks: true 25 }, 26 filter: function () { 27 // return $(this).is(":visible"); // only validate elements you can see 28 return true; // validate everything 29 } 30 }, 31 methods: { 32 init : function( options ) { 33 34 var settings = $.extend(true, {}, defaults); 35 36 settings.options = $.extend(true, settings.options, options); 37 38 var $siblingElements = this; 39 40 var uniqueForms = $.unique( 41 $siblingElements.map( function () { 42 return $(this).parents("form")[0]; 43 }).toArray() 44 ); 45 46 $(uniqueForms).bind("submit", function (e) { 47 var $form = $(this); 48 var warningsFound = 0; 49 var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter); 50 $inputs.trigger("submit.validation").trigger("validationLostFocus.validation"); 51 52 $inputs.each(function (i, el) { 53 var $this = $(el), 54 $controlGroup = $this.parents(".control-group").first(); 55 if ( 56 $controlGroup.hasClass("has-warning") 57 ) { 58 $controlGroup.removeClass("has-warning").addClass("has-error"); 59 warningsFound++; 60 } 61 }); 62 63 $inputs.trigger("validationLostFocus.validation"); 64 65 if (warningsFound) { 66 if (settings.options.preventSubmit) { 67 e.preventDefault(); 68 } 69 $form.addClass("has-error"); 70 if ($.isFunction(settings.options.submitError)) { 71 settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true)); 72 } 73 } else { 74 $form.removeClass("has-error"); 75 if ($.isFunction(settings.options.submitSuccess)) { 76 settings.options.submitSuccess($form, e); 77 } 78 } 79 }); 80 81 return this.each(function(){ 82 83 // Get references to everything we're interested in 84 var $this = $(this), 85 $controlGroup = $this.parents(".control-group").first(), 86 $helpBlock = $controlGroup.find(".help-block").first(), 87 $form = $this.parents("form").first(), 88 validatorNames = []; 89 90 // create message container if not exists 91 if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) { 92 $helpBlock = $('<div class="help-block" />'); 93 $controlGroup.find('.controls').append($helpBlock); 94 createdElements.push($helpBlock[0]); 95 } 96 97 // ============================================================= 98 // SNIFF HTML FOR VALIDATORS 99 // ============================================================= 100 101 // *snort sniff snuffle* 102 103 if (settings.options.sniffHtml) { 104 var message = ""; 105 // --------------------------------------------------------- 106 // PATTERN 107 // --------------------------------------------------------- 108 if ($this.attr("pattern") !== undefined) { 109 message = "Not in the expected format<!-- data-validation-pattern-message to override -->"; 110 if ($this.data("validationPatternMessage")) { 111 message = $this.data("validationPatternMessage"); 112 } 113 $this.data("validationPatternMessage", message); 114 $this.data("validationPatternRegex", $this.attr("pattern")); 115 } 116 // --------------------------------------------------------- 117 // MAX 118 // --------------------------------------------------------- 119 if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) { 120 var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax")); 121 message = "Too high: Maximum of '" + max + "'<!-- data-validation-max-message to override -->"; 122 if ($this.data("validationMaxMessage")) { 123 message = $this.data("validationMaxMessage"); 124 } 125 $this.data("validationMaxMessage", message); 126 $this.data("validationMaxMax", max); 127 } 128 // --------------------------------------------------------- 129 // MIN 130 // --------------------------------------------------------- 131 if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) { 132 var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin")); 133 message = "Too low: Minimum of '" + min + "'<!-- data-validation-min-message to override -->"; 134 if ($this.data("validationMinMessage")) { 135 message = $this.data("validationMinMessage"); 136 } 137 $this.data("validationMinMessage", message); 138 $this.data("validationMinMin", min); 139 } 140 // --------------------------------------------------------- 141 // MAXLENGTH 142 // --------------------------------------------------------- 143 if ($this.attr("maxlength") !== undefined) { 144 message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters<!-- data-validation-maxlength-message to override -->"; 145 if ($this.data("validationMaxlengthMessage")) { 146 message = $this.data("validationMaxlengthMessage"); 147 } 148 $this.data("validationMaxlengthMessage", message); 149 $this.data("validationMaxlengthMaxlength", $this.attr("maxlength")); 150 } 151 // --------------------------------------------------------- 152 // MINLENGTH 153 // --------------------------------------------------------- 154 if ($this.attr("minlength") !== undefined) { 155 message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters<!-- data-validation-minlength-message to override -->"; 156 if ($this.data("validationMinlengthMessage")) { 157 message = $this.data("validationMinlengthMessage"); 158 } 159 $this.data("validationMinlengthMessage", message); 160 $this.data("validationMinlengthMinlength", $this.attr("minlength")); 161 } 162 // --------------------------------------------------------- 163 // REQUIRED 164 // --------------------------------------------------------- 165 if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) { 166 message = settings.builtInValidators.required.message; 167 if ($this.data("validationRequiredMessage")) { 168 message = $this.data("validationRequiredMessage"); 169 } 170 $this.data("validationRequiredMessage", message); 171 } 172 // --------------------------------------------------------- 173 // NUMBER 174 // --------------------------------------------------------- 175 if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") { 176 message = settings.builtInValidators.number.message; 177 if ($this.data("validationNumberMessage")) { 178 message = $this.data("validationNumberMessage"); 179 } 180 $this.data("validationNumberMessage", message); 181 } 182 // --------------------------------------------------------- 183 // EMAIL 184 // --------------------------------------------------------- 185 if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") { 186 message = "Not a valid email address<!-- data-validator-validemail-message to override -->"; 187 if ($this.data("validationValidemailMessage")) { 188 message = $this.data("validationValidemailMessage"); 189 } else if ($this.data("validationEmailMessage")) { 190 message = $this.data("validationEmailMessage"); 191 } 192 $this.data("validationValidemailMessage", message); 193 } 194 // --------------------------------------------------------- 195 // MINCHECKED 196 // --------------------------------------------------------- 197 if ($this.attr("minchecked") !== undefined) { 198 message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required<!-- data-validation-minchecked-message to override -->"; 199 if ($this.data("validationMincheckedMessage")) { 200 message = $this.data("validationMincheckedMessage"); 201 } 202 $this.data("validationMincheckedMessage", message); 203 $this.data("validationMincheckedMinchecked", $this.attr("minchecked")); 204 } 205 // --------------------------------------------------------- 206 // MAXCHECKED 207 // --------------------------------------------------------- 208 if ($this.attr("maxchecked") !== undefined) { 209 message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required<!-- data-validation-maxchecked-message to override -->";
210 if ($this.data("validationMaxcheckedMessage")) { 211 message = $this.data("validationMaxcheckedMessage"); 212 } 213 $this.data("validationMaxcheckedMessage", message); 214 $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked")); 215 } 216 } 217 218 // ============================================================= 219 // COLLECT VALIDATOR NAMES 220 // ============================================================= 221 222 // Get named validators 223 if ($this.data("validation") !== undefined) { 224 validatorNames = $this.data("validation").split(","); 225 } 226 227 // Get extra ones defined on the element's data attributes 228 $.each($this.data(), function (i, el) { 229 var parts = i.replace(/([A-Z])/g, ",$1").split(","); 230 if (parts[0] === "validation" && parts[1]) { 231 validatorNames.push(parts[1]); 232 } 233 }); 234 235 // ============================================================= 236 // NORMALISE VALIDATOR NAMES 237 // ============================================================= 238 239 var validatorNamesToInspect = validatorNames; 240 var newValidatorNamesToInspect = []; 241 242 do // repeatedly expand 'shortcut' validators into their real validators 243 { 244 // Uppercase only the first letter of each name 245 $.each(validatorNames, function (i, el) { 246 validatorNames[i] = formatValidatorName(el); 247 }); 248 249 // Remove duplicate validator names 250 validatorNames = $.unique(validatorNames); 251 252 // Pull out the new validator names from each shortcut 253 newValidatorNamesToInspect = []; 254 $.each(validatorNamesToInspect, function(i, el) { 255 if ($this.data("validation" + el + "Shortcut") !== undefined) { 256 // Are these custom validators? 257 // Pull them out! 258 $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) { 259 newValidatorNamesToInspect.push(el2); 260 }); 261 } else if (settings.builtInValidators[el.toLowerCase()]) { 262 // Is this a recognised built-in? 263 // Pull it out! 264 var validator = settings.builtInValidators[el.toLowerCase()]; 265 if (validator.type.toLowerCase() === "shortcut") { 266 $.each(validator.shortcut.split(","), function (i, el) { 267 el = formatValidatorName(el); 268 newValidatorNamesToInspect.push(el); 269 validatorNames.push(el); 270 }); 271 } 272 } 273 }); 274 275 validatorNamesToInspect = newValidatorNamesToInspect; 276 277 } while (validatorNamesToInspect.length > 0) 278 279 // ============================================================= 280 // SET UP VALIDATOR ARRAYS 281 // ============================================================= 282 283 var validators = {}; 284 285 $.each(validatorNames, function (i, el) { 286 // Set up the 'override' message 287 var message = $this.data("validation" + el + "Message"); 288 var hasOverrideMessage = (message !== undefined); 289 var foundValidator = false; 290 message = 291 ( 292 message 293 ? message 294 : "'" + el + "' validation failed <!-- Add attribute 'data-validation-" + el.toLowerCase() + "-message' to input to change this message -->" 295 ) 296 ; 297 298 $.each( 299 settings.validatorTypes, 300 function (validatorType, validatorTemplate) { 301 if (validators[validatorType] === undefined) { 302 validators[validatorType] = []; 303 } 304 if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) { 305 validators[validatorType].push( 306 $.extend( 307 true, 308 { 309 name: formatValidatorName(validatorTemplate.name), 310 message: message 311 }, 312 validatorTemplate.init($this, el) 313 ) 314 ); 315 foundValidator = true; 316 } 317 } 318 ); 319 320 if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) { 321
322 var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]); 323 if (hasOverrideMessage) { 324 validator.message = message; 325 } 326 var validatorType = validator.type.toLowerCase(); 327 328 if (validatorType === "shortcut") { 329 foundValidator = true; 330 } else { 331 $.each( 332 settings.validatorTypes, 333 function (validatorTemplateType, validatorTemplate) { 334 if (validators[validatorTemplateType] === undefined) { 335 validators[validatorTemplateType] = []; 336 } 337 if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) { 338 $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]); 339 validators[validatorType].push( 340 $.extend( 341 validator, 342 validatorTemplate.init($this, el) 343 ) 344 ); 345 foundValidator = true; 346 } 347 } 348 ); 349 } 350 } 351 352 if (! foundValidator) { 353 $.error("Cannot find validation info for '" + el + "'"); 354 } 355 }); 356 357 // ============================================================= 358 // STORE FALLBACK VALUES 359 // ============================================================= 360 361 $helpBlock.data( 362 "original-contents", 363 ( 364 $helpBlock.data("original-contents") 365 ? $helpBlock.data("original-contents") 366 : $helpBlock.html() 367 ) 368 ); 369 370 $helpBlock.data( 371 "original-role", 372 ( 373 $helpBlock.data("original-role") 374 ? $helpBlock.data("original-role") 375 : $helpBlock.attr("role") 376 ) 377 ); 378 379 $controlGroup.data( 380 "original-classes", 381 ( 382 $controlGroup.data("original-clases") 383 ? $controlGroup.data("original-classes") 384 : $controlGroup.attr("class") 385 ) 386 ); 387 388 $this.data( 389 "original-aria-invalid", 390 ( 391 $this.data("original-aria-invalid") 392 ? $this.data("original-aria-invalid") 393 : $this.attr("aria-invalid") 394 ) 395 ); 396 397 // ============================================================= 398 // VALIDATION 399 // ============================================================= 400 401 $this.bind( 402 "validation.validation", 403 function (event, params) { 404 405 var value = getValue($this); 406 407 // Get a list of the errors to apply 408 var errorsFound = []; 409 410 $.each(validators, function (validatorType, validatorTypeArray) { 411 if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) { 412 $.each(validatorTypeArray, function (i, validator) { 413 if (settings.validatorTypes[validatorType].validate($this, value, validator)) { 414 errorsFound.push(validator.message); 415 } 416 }); 417 } 418 }); 419 420 return errorsFound; 421 } 422 ); 423 424 $this.bind( 425 "getValidators.validation", 426 function () { 427 return validators; 428 } 429 ); 430 431 // ============================================================= 432 // WATCH FOR CHANGES 433 // ============================================================= 434 $this.bind( 435 "submit.validation", 436 function () { 437 return $this.triggerHandler("change.validation", {submitting: true}); 438 } 439 ); 440 $this.bind( 441 [ 442 "keyup", 443 "focus", 444 "blur", 445 "click", 446 "keydown", 447 "keypress", 448 "change" 449 ].join(".validation ") + ".validation", 450 function (e, params) { 451 452 var value = getValue($this); 453 454 var errorsFound = []; 455 456 $controlGroup.find("input,textarea,select").each(function (i, el) { 457 var oldCount = errorsFound.length; 458 $.each($(el).triggerHandler("validation.validation", params), function (j, message) { 459 errorsFound.push(message); 460 }); 461 if (errorsFound.length > oldCount) { 462 $(el).attr("aria-invalid", "true"); 463 } else { 464 var original = $this.data("original-aria-invalid"); 465 $(el).attr("aria-invalid", (original !== undefined ? original : false)); 466 } 467 }); 468 469 $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation"); 470 471 errorsFound = $.unique(errorsFound.sort()); 472 473 // Were there any errors? 474 if (errorsFound.length) { 475 // Better flag it up as a warning. 476 $controlGroup.removeClass("has-success has-error").addClass("has-warning"); 477 478 // How many errors did we find? 479 if (settings.options.semanticallyStrict && errorsFound.length === 1) { 480 // Only one? Being strict? Just output it. 481 $helpBlock.html(errorsFound[0] + 482 ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" )); 483 } else { 484 // Multiple? Being sloppy? Glue them together into an UL. 485 $helpBlock.html("<ul role=\"alert\"><li>" + errorsFound.join("</li><li>") + "</li></ul>" + 486 ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" )); 487 } 488 } else { 489 $controlGroup.removeClass("has-warning has-error has-success"); 490 if (value.length > 0) { 491 $controlGroup.addClass("has-success"); 492 } 493 $helpBlock.html($helpBlock.data("original-contents")); 494 } 495 496 if (e.type === "blur") { 497 $controlGroup.removeClass("has-success"); 498 } 499 } 500 ); 501 $this.bind("validationLostFocus.validation", function () { 502 $controlGroup.removeClass("has-success"); 503 }); 504 }); 505 }, 506 destroy : function( ) { 507 508 return this.each( 509 function() { 510 511 var 512 $this = $(this), 513 $controlGroup = $this.parents(".control-group").first(), 514 $helpBlock = $controlGroup.find(".help-block").first(); 515 516 // remove our events 517 $this.unbind('.validation'); // events are namespaced. 518 // reset help text 519 $helpBlock.html($helpBlock.data("original-contents")); 520 // reset classes 521 $controlGroup.attr("class", $controlGroup.data("original-classes")); 522 // reset aria 523 $this.attr("aria-invalid", $this.data("original-aria-invalid")); 524 // reset role 525 $helpBlock.attr("role", $this.data("original-role")); 526 // remove all elements we created 527 if (createdElements.indexOf($helpBlock[0]) > -1) { 528 $helpBlock.remove(); 529 } 530 531 } 532 ); 533 534 }, 535 collectErrors : function(includeEmpty) { 536 537 var errorMessages = {}; 538 this.each(function (i, el) { 539 var $el = $(el); 540 var name = $el.attr("name"); 541 var errors = $el.triggerHandler("validation.validation", {includeEmpty: true}); 542 errorMessages[name] = $.extend(true, errors, errorMessages[name]); 543 }); 544 545 $.each(errorMessages, function (i, el) { 546 if (el.length === 0) { 547 delete errorMessages[i]; 548 } 549 }); 550 551 return errorMessages; 552 553 }, 554 hasErrors: function() { 555 556 var errorMessages = []; 557 558 this.each(function (i, el) { 559 errorMessages = errorMessages.concat( 560 $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : [] 561 ); 562 }); 563 564 return (errorMessages.length > 0); 565 }, 566 override : function (newDefaults) { 567 defaults = $.extend(true, defaults, newDefaults); 568 } 569 }, 570 validatorTypes: { 571 callback: { 572 name: "callback", 573 init: function ($this, name) { 574 return { 575 validatorName: name, 576 callback: $this.data("validation" + name + "Callback"),
577 lastValue: $this.val(), 578 lastValid: true, 579 lastFinished: true 580 }; 581 }, 582 validate: function ($this, value, validator) { 583 if (validator.lastValue === value && validator.lastFinished) { 584 return !validator.lastValid; 585 } 586 587 if (validator.lastFinished === true) 588 { 589 validator.lastValue = value; 590 validator.lastValid = true; 591 validator.lastFinished = false; 592 593 var rrjqbvValidator = validator; 594 var rrjqbvThis = $this; 595 executeFunctionByName( 596 validator.callback, 597 window, 598 $this, 599 value, 600 function (data) { 601 if (rrjqbvValidator.lastValue === data.value) { 602 rrjqbvValidator.lastValid = data.valid; 603 if (data.message) { 604 rrjqbvValidator.message = data.message; 605 } 606 rrjqbvValidator.lastFinished = true; 607 rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message); 608 // Timeout is set to avoid problems with the events being considered 'already fired' 609 setTimeout(function () { 610 rrjqbvThis.trigger("change.validation"); 611 }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 612 } 613 } 614 ); 615 } 616 617 return false; 618 619 } 620 }, 621 ajax: { 622 name: "ajax", 623 init: function ($this, name) { 624 return { 625 validatorName: name, 626 url: $this.data("validation" + name + "Ajax"), 627 lastValue: $this.val(), 628 lastValid: true, 629 lastFinished: true 630 }; 631 }, 632 validate: function ($this, value, validator) { 633 if (""+validator.lastValue === ""+value && validator.lastFinished === true) { 634 return validator.lastValid === false; 635 } 636 637 if (validator.lastFinished === true) 638 { 639 validator.lastValue = value; 640 validator.lastValid = true; 641 validator.lastFinished = false; 642 $.ajax({
643 url: validator.url, 644 data: "value=" + value + "&field=" + $this.attr("name"), 645 dataType: "json", 646 success: function (data) { 647 if (""+validator.lastValue === ""+data.value) { 648 validator.lastValid = !!(data.valid); 649 if (data.message) { 650 validator.message = data.message; 651 } 652 validator.lastFinished = true; 653 $this.data("validation" + validator.validatorName + "Message", validator.message); 654 // Timeout is set to avoid problems with the events being considered 'already fired' 655 setTimeout(function () { 656 $this.trigger("change.validation"); 657 }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 658 } 659 }, 660 failure: function () { 661 validator.lastValid = true; 662 validator.message = "ajax call failed"; 663 validator.lastFinished = true; 664 $this.data("validation" + validator.validatorName + "Message", validator.message); 665 // Timeout is set to avoid problems with the events being considered 'already fired' 666 setTimeout(function () { 667 $this.trigger("change.validation"); 668 }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 669 } 670 }); 671 } 672 673 return false; 674 675 } 676 }, 677 regex: { 678 name: "regex", 679 init: function ($this, name) { 680 return {regex: regexFromString($this.data("validation" + name + "Regex"))}; 681 }, 682 validate: function ($this, value, validator) { 683 return (!validator.regex.test(value) && ! validator.negative) 684 || (validator.regex.test(value) && validator.negative); 685 } 686 }, 687 required: { 688 name: "required", 689 init: function ($this, name) { 690 return {}; 691 }, 692 validate: function ($this, value, validator) { 693 return !!(value.length === 0 && ! validator.negative) 694 || !!(value.length > 0 && validator.negative); 695 }, 696 blockSubmit: true 697 }, 698 match: { 699 name: "match", 700 init: function ($this, name) { 701 var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first(); 702 element.bind("validation.validation", function () { 703 $this.trigger("change.validation", {submitting: true}); 704 }); 705 return {"element": element}; 706 }, 707 validate: function ($this, value, validator) { 708 return (value !== validator.element.val() && ! validator.negative) 709 || (value === validator.element.val() && validator.negative); 710 }, 711 blockSubmit: true 712 }, 713 max: { 714 name: "max", 715 init: function ($this, name) { 716 return {max: $this.data("validation" + name + "Max")}; 717 }, 718 validate: function ($this, value, validator) { 719 return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative) 720 || (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative); 721 } 722 }, 723 min: { 724 name: "min", 725 init: function ($this, name) { 726 return {min: $this.data("validation" + name + "Min")}; 727 }, 728 validate: function ($this, value, validator) { 729 return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative) 730 || (parseFloat(value) >= parseFloat(validator.min) && validator.negative); 731 } 732 }, 733 maxlength: { 734 name: "maxlength", 735 init: function ($this, name) { 736 return {maxlength: $this.data("validation" + name + "Maxlength")}; 737 }, 738 validate: function ($this, value, validator) { 739 return ((value.length > validator.maxlength) && ! validator.negative) 740 || ((value.length <= validator.maxlength) && validator.negative); 741 } 742 }, 743 minlength: { 744 name: "minlength", 745 init: function ($this, name) { 746 return {minlength: $this.data("validation" + name + "Minlength")}; 747 }, 748 validate: function ($this, value, validator) { 749 return ((value.length < validator.minlength) && ! validator.negative) 750 || ((value.length >= validator.minlength) && validator.negative); 751 } 752 }, 753 maxchecked: { 754 name: "maxchecked", 755 init: function ($this, name) { 756 var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); 757 elements.bind("click.validation", function () { 758 $this.trigger("change.validation", {includeEmpty: true}); 759 });
760 return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements}; 761 }, 762 validate: function ($this, value, validator) { 763 return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative) 764 || (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative); 765 }, 766 blockSubmit: true 767 }, 768 minchecked: { 769 name: "minchecked", 770 init: function ($this, name) { 771 var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); 772 elements.bind("click.validation", function () { 773 $this.trigger("change.validation", {includeEmpty: true}); 774 }); 775 return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements}; 776 }, 777 validate: function ($this, value, validator) { 778 return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative) 779 || (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative); 780 }, 781 blockSubmit: true 782 } 783 }, 784 builtInValidators: { 785 email: { 786 name: "Email", 787 type: "shortcut", 788 shortcut: "validemail" 789 }, 790 validemail: { 791 name: "Validemail", 792 type: "regex", 793 regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}", 794 message: "Not a valid email address<!-- data-validator-validemail-message to override -->" 795 }, 796 passwordagain: { 797 name: "Passwordagain", 798 type: "match", 799 match: "password", 800 message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->" 801 }, 802 positive: { 803 name: "Positive", 804 type: "shortcut", 805 shortcut: "number,positivenumber" 806 }, 807 negative: { 808 name: "Negative", 809 type: "shortcut", 810 shortcut: "number,negativenumber" 811 }, 812 number: { 813 name: "Number", 814 type: "regex", 815 regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?", 816 message: "Must be a number<!-- data-validator-number-message to override -->" 817 }, 818 integer: { 819 name: "Integer", 820 type: "regex", 821 regex: "[+-]?\\\d+", 822 message: "No decimal places allowed<!-- data-validator-integer-message to override -->" 823 }, 824 positivenumber: { 825 name: "Positivenumber", 826 type: "min", 827 min: 0, 828 message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->" 829 }, 830 negativenumber: { 831 name: "Negativenumber", 832 type: "max", 833 max: 0, 834 message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->" 835 }, 836 required: { 837 name: "Required", 838 type: "required", 839 message: "This is required<!-- data-validator-required-message to override -->" 840 }, 841 checkone: { 842 name: "Checkone", 843 type: "minchecked", 844 minchecked: 1, 845 message: "Check at least one option<!-- data-validation-checkone-message to override -->" 846 } 847 } 848 }; 849 850 var formatValidatorName = function (name) { 851 return name 852 .toLowerCase() 853 .replace( 854 /(^|\s)([a-z])/g , 855 function(m,p1,p2) { 856 return p1+p2.toUpperCase(); 857 } 858 ) 859 ; 860 }; 861 862 var getValue = function ($this) { 863 // Extract the value we're talking about 864 var value = $this.val(); 865 var type = $this.attr("type"); 866 if (type === "checkbox") { 867 value = ($this.is(":checked") ? value : ""); 868 } 869 if (type === "radio") { 870 value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : ""); 871 } 872 return value; 873 }; 874 875 function regexFromString(inputstring) {
876 return new RegExp("^" + inputstring + "$"); 877 } 878 879 /** 880 * Thanks to Jason Bunting via StackOverflow.com 881 * 882 * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910 883 * Short link: http://tinyurl.com/executeFunctionByName 884 **/ 885 function executeFunctionByName(functionName, context /*, args*/) { 886 var args = Array.prototype.slice.call(arguments).splice(2); 887 var namespaces = functionName.split("."); 888 var func = namespaces.pop(); 889 for(var i = 0; i < namespaces.length; i++) { 890 context = context[namespaces[i]]; 891 } 892 return context[func].apply(this, args); 893 } 894 895 $.fn.jqBootstrapValidation = function( method ) { 896 897 if ( defaults.methods[method] ) { 898 return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 899 } else if ( typeof method === 'object' || ! method ) { 900 return defaults.methods.init.apply( this, arguments ); 901 } else { 902 $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' ); 903 return null; 904 } 905 906 }; 907 908 $.jqBootstrapValidation = function (options) { 909 $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments); 910 }; 911 912})( 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.