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(".form-group").first(); 55 if ( 56 $controlGroup.hasClass("warning") 57 ) { 58 $controlGroup.removeClass("warning").addClass("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("error"); 70 if ($.isFunction(settings.options.submitError)) { 71 settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true)); 72 } 73 } else { 74 $form.removeClass("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(".form-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 $.each( 298 settings.validatorTypes, 299 function(validatorType, validatorTemplate) { 300 if (validators[validatorType] === undefined) { 301 validators[validatorType] = []; 302 } 303 if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) { 304 validators[validatorType].push( 305 $.extend( 306 true, { 307 name: formatValidatorName(validatorTemplate.name), 308 message: message 309 }, 310 validatorTemplate.init($this, el) 311 ) 312 ); 313 foundValidator = true; 314 } 315 } 316 ); 317 318 if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) { 319
320 var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]); 321 if (hasOverrideMessage) { 322 validator.message = message; 323 } 324 var validatorType = validator.type.toLowerCase(); 325 326 if (validatorType === "shortcut") { 327 foundValidator = true; 328 } else { 329 $.each( 330 settings.validatorTypes, 331 function(validatorTemplateType, validatorTemplate) { 332 if (validators[validatorTemplateType] === undefined) { 333 validators[validatorTemplateType] = []; 334 } 335 if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) { 336 $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]); 337 validators[validatorType].push( 338 $.extend( 339 validator, 340 validatorTemplate.init($this, el) 341 ) 342 ); 343 foundValidator = true; 344 } 345 } 346 ); 347 } 348 } 349 350 if (!foundValidator) { 351 $.error("Cannot find validation info for '" + el + "'"); 352 } 353 }); 354 355 // ============================================================= 356 // STORE FALLBACK VALUES 357 // ============================================================= 358 359 $helpBlock.data( 360 "original-contents", 361 ( 362 $helpBlock.data("original-contents") ? 363 $helpBlock.data("original-contents") : 364 $helpBlock.html() 365 ) 366 ); 367 368 $helpBlock.data( 369 "original-role", 370 ( 371 $helpBlock.data("original-role") ? 372 $helpBlock.data("original-role") : 373 $helpBlock.attr("role") 374 ) 375 ); 376 377 $controlGroup.data( 378 "original-classes", 379 ( 380 $controlGroup.data("original-clases") ? 381 $controlGroup.data("original-classes") : 382 $controlGroup.attr("class") 383 ) 384 ); 385 386 $this.data( 387 "original-aria-invalid", 388 ( 389 $this.data("original-aria-invalid") ? 390 $this.data("original-aria-invalid") : 391 $this.attr("aria-invalid") 392 ) 393 ); 394 395 // ============================================================= 396 // VALIDATION 397 // ============================================================= 398 399 $this.bind( 400 "validation.validation", 401 function(event, params) { 402 403 var value = getValue($this); 404 405 // Get a list of the errors to apply 406 var errorsFound = []; 407 408 $.each(validators, function(validatorType, validatorTypeArray) { 409 if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) { 410 $.each(validatorTypeArray, function(i, validator) { 411 if (settings.validatorTypes[validatorType].validate($this, value, validator)) { 412 errorsFound.push(validator.message); 413 } 414 }); 415 } 416 }); 417 418 return errorsFound; 419 } 420 ); 421 422 $this.bind( 423 "getValidators.validation", 424 function() { 425 return validators; 426 } 427 ); 428 429 // ============================================================= 430 // WATCH FOR CHANGES 431 // ============================================================= 432 $this.bind( 433 "submit.validation", 434 function() { 435 return $this.triggerHandler("change.validation", { 436 submitting: true 437 }); 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("success error").addClass("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("warning error success"); 490 if (value.length > 0) { 491 $controlGroup.addClass("success"); 492 } 493 $helpBlock.html($helpBlock.data("original-contents")); 494 } 495 496 if (e.type === "blur") { 497 $controlGroup.removeClass("success"); 498 } 499 } 500 ); 501 $this.bind("validationLostFocus.validation", function() { 502 $controlGroup.removeClass("success"); 503 }); 504 }); 505 }, 506 destroy: function() { 507 508 return this.each( 509 function() { 510 511 var 512 $this = $(this), 513 $controlGroup = $this.parents(".form-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", { 542 includeEmpty: true 543 }); 544 errorMessages[name] = $.extend(true, errors, errorMessages[name]); 545 }); 546 547 $.each(errorMessages, function(i, el) { 548 if (el.length === 0) { 549 delete errorMessages[i]; 550 } 551 }); 552 553 return errorMessages; 554 555 }, 556 hasErrors: function() { 557 558 var errorMessages = []; 559 560 this.each(function(i, el) { 561 errorMessages = errorMessages.concat( 562 $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", { 563 submitting: true 564 }) : [] 565 ); 566 }); 567 568 return (errorMessages.length > 0); 569 }, 570 override: function(newDefaults) { 571 defaults = $.extend(true, defaults, newDefaults); 572 } 573 }, 574 validatorTypes: { 575 callback: { 576 name: "callback", 577 init: function($this, name) { 578 return { 579 validatorName: name, 580 callback: $this.data("validation" + name + "Callback"), 581 lastValue: $this.val(), 582 lastValid: true, 583 lastFinished: true 584 }; 585 }, 586 validate: function($this, value, validator) { 587 if (validator.lastValue === value && validator.lastFinished) { 588 return !validator.lastValid; 589 } 590 591 if (validator.lastFinished === true) { 592 validator.lastValue = value; 593 validator.lastValid = true; 594 validator.lastFinished = false; 595 596 var rrjqbvValidator = validator; 597 var rrjqbvThis = $this; 598 executeFunctionByName( 599 validator.callback, 600 window, 601 $this, 602 value, 603 function(data) { 604 if (rrjqbvValidator.lastValue === data.value) { 605 rrjqbvValidator.lastValid = data.valid; 606 if (data.message) { 607 rrjqbvValidator.message = data.message; 608 } 609 rrjqbvValidator.lastFinished = true; 610 rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message); 611 // Timeout is set to avoid problems with the events being considered 'already fired' 612 setTimeout(function() { 613 rrjqbvThis.trigger("change.validation"); 614 }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 615 } 616 } 617 ); 618 } 619 620 return false;
621 622 } 623 }, 624 ajax: { 625 name: "ajax", 626 init: function($this, name) { 627 return { 628 validatorName: name, 629 url: $this.data("validation" + name + "Ajax"), 630 lastValue: $this.val(), 631 lastValid: true, 632 lastFinished: true 633 }; 634 }, 635 validate: function($this, value, validator) { 636 if ("" + validator.lastValue === "" + value && validator.lastFinished === true) { 637 return validator.lastValid === false; 638 } 639 640 if (validator.lastFinished === true) { 641 validator.lastValue = value; 642 validator.lastValid = true; 643 validator.lastFinished = false; 644 $.ajax({ 645 url: validator.url, 646 data: "value=" + value + "&field=" + $this.attr("name"), 647 dataType: "json", 648 success: function(data) { 649 if ("" + validator.lastValue === "" + data.value) { 650 validator.lastValid = !!(data.valid); 651 if (data.message) { 652 validator.message = data.message; 653 } 654 validator.lastFinished = true; 655 $this.data("validation" + validator.validatorName + "Message", validator.message); 656 // Timeout is set to avoid problems with the events being considered 'already fired' 657 setTimeout(function() { 658 $this.trigger("change.validation"); 659 }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 660 } 661 }, 662 failure: function() { 663 validator.lastValid = true; 664 validator.message = "ajax call failed"; 665 validator.lastFinished = true; 666 $this.data("validation" + validator.validatorName + "Message", validator.message); 667 // Timeout is set to avoid problems with the events being considered 'already fired' 668 setTimeout(function() { 669 $this.trigger("change.validation"); 670 }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 671 } 672 }); 673 } 674 675 return false; 676 677 } 678 }, 679 regex: { 680 name: "regex", 681 init: function($this, name) { 682 return { 683 regex: regexFromString($this.data("validation" + name + "Regex")) 684 }; 685 }, 686 validate: function($this, value, validator) { 687 return (!validator.regex.test(value) && !validator.negative) || 688 (validator.regex.test(value) && validator.negative); 689 } 690 }, 691 required: { 692 name: "required", 693 init: function($this, name) { 694 return {}; 695 }, 696 validate: function($this, value, validator) { 697 return !!(value.length === 0 && !validator.negative) || 698 !!(value.length > 0 && validator.negative); 699 }, 700 blockSubmit: true 701 }, 702 match: { 703 name: "match", 704 init: function($this, name) { 705 var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first(); 706 element.bind("validation.validation", function() { 707 $this.trigger("change.validation", { 708 submitting: true 709 }); 710 }); 711 return { 712 "element": element 713 }; 714 }, 715 validate: function($this, value, validator) { 716 return (value !== validator.element.val() && !validator.negative) || 717 (value === validator.element.val() && validator.negative); 718 }, 719 blockSubmit: true 720 }, 721 max: { 722 name: "max", 723 init: function($this, name) { 724 return { 725 max: $this.data("validation" + name + "Max") 726 }; 727 }, 728 validate: function($this, value, validator) { 729 return (parseFloat(value, 10) > parseFloat(validator.max, 10) && !validator.negative) || 730 (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative); 731 } 732 }, 733 min: { 734 name: "min", 735 init: function($this, name) { 736 return { 737 min: $this.data("validation" + name + "Min") 738 }; 739 }, 740 validate: function($this, value, validator) { 741 return (parseFloat(value) < parseFloat(validator.min) && !validator.negative) || 742 (parseFloat(value) >= parseFloat(validator.min) && validator.negative); 743 } 744 }, 745 maxlength: { 746 name: "maxlength", 747 init: function($this, name) { 748 return { 749 maxlength: $this.data("validation" + name + "Maxlength") 750 }; 751 }, 752 validate: function($this, value, validator) { 753 return ((value.length > validator.maxlength) && !validator.negative) || 754 ((value.length <= validator.maxlength) && validator.negative); 755 } 756 }, 757 minlength: { 758 name: "minlength", 759 init: function($this, name) { 760 return { 761 minlength: $this.data("validation" + name + "Minlength") 762 }; 763 }, 764 validate: function($this, value, validator) { 765 return ((value.length < validator.minlength) && !validator.negative) || 766 ((value.length >= validator.minlength) && validator.negative); 767 } 768 }, 769 maxchecked: { 770 name: "maxchecked", 771 init: function($this, name) { 772 var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); 773 elements.bind("click.validation", function() { 774 $this.trigger("change.validation", { 775 includeEmpty: true 776 }); 777 }); 778 return { 779 maxchecked: $this.data("validation" + name + "Maxchecked"), 780 elements: elements 781 }; 782 }, 783 validate: function($this, value, validator) { 784 return (validator.elements.filter(":checked").length > validator.maxchecked && !validator.negative) || 785 (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative); 786 }, 787 blockSubmit: true 788 }, 789 minchecked: { 790 name: "minchecked", 791 init: function($this, name) { 792 var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); 793 elements.bind("click.validation", function() { 794 $this.trigger("change.validation", { 795 includeEmpty: true 796 }); 797 }); 798 return { 799 minchecked: $this.data("validation" + name + "Minchecked"), 800 elements: elements 801 }; 802 }, 803 validate: function($this, value, validator) { 804 return (validator.elements.filter(":checked").length < validator.minchecked && !validator.negative) || 805 (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative); 806 }, 807 blockSubmit: true 808 } 809 }, 810 builtInValidators: { 811 email: { 812 name: "Email", 813 type: "shortcut", 814 shortcut: "validemail" 815 }, 816 validemail: { 817 name: "Validemail", 818 type: "regex", 819 regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}", 820 message: "Not a valid email address<!-- data-validator-validemail-message to override -->" 821 }, 822 passwordagain: { 823 name: "Passwordagain", 824 type: "match", 825 match: "password", 826 message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->" 827 }, 828 positive: { 829 name: "Positive", 830 type: "shortcut", 831 shortcut: "number,positivenumber" 832 }, 833 negative: { 834 name: "Negative", 835 type: "shortcut", 836 shortcut: "number,negativenumber" 837 }, 838 number: { 839 name: "Number", 840 type: "regex", 841 regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?", 842 message: "Must be a number<!-- data-validator-number-message to override -->" 843 }, 844 integer: { 845 name: "Integer", 846 type: "regex", 847 regex: "[+-]?\\\d+", 848 message: "No decimal places allowed<!-- data-validator-integer-message to override -->" 849 }, 850 positivenumber: { 851 name: "Positivenumber", 852 type: "min", 853 min: 0, 854 message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->" 855 }, 856 negativenumber: { 857 name: "Negativenumber", 858 type: "max", 859 max: 0, 860 message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->" 861 }, 862 required: { 863 name: "Required", 864 type: "required", 865 message: "This is required<!-- data-validator-required-message to override -->" 866 }, 867 checkone: { 868 name: "Checkone", 869 type: "minchecked", 870 minchecked: 1, 871 message: "Check at least one option<!-- data-validation-checkone-message to override -->" 872 } 873 } 874 }; 875 876 var formatValidatorName = function(name) { 877 return name 878 .toLowerCase() 879 .replace( 880 /(^|\s)([a-z])/g, 881 function(m, p1, p2) { 882 return p1 + p2.toUpperCase(); 883 } 884 ); 885 }; 886 887 var getValue = function($this) { 888 // Extract the value we're talking about 889 var value = $this.val(); 890 var type = $this.attr("type"); 891 if (type === "checkbox") { 892 value = ($this.is(":checked") ? value : ""); 893 } 894 if (type === "radio") { 895 value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : ""); 896 } 897 return value; 898 }; 899 900 function regexFromString(inputstring) {
901 return new RegExp("^" + inputstring + "$"); 902 } 903 904 /** 905 * Thanks to Jason Bunting via StackOverflow.com 906 * 907 * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910 908 * Short link: http://tinyurl.com/executeFunctionByName 909 **/ 910 function executeFunctionByName(functionName, context /*, args*/ ) { 911 var args = Array.prototype.slice.call(arguments).splice(2); 912 var namespaces = functionName.split("."); 913 var func = namespaces.pop(); 914 for (var i = 0; i < namespaces.length; i++) { 915 context = context[namespaces[i]]; 916 } 917 return context[func].apply(this, args); 918 } 919 920 $.fn.jqBootstrapValidation = function(method) { 921 922 if (defaults.methods[method]) { 923 return defaults.methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 924 } else if (typeof method === 'object' || !method) { 925 return defaults.methods.init.apply(this, arguments); 926 } else { 927 $.error('Method ' + method + ' does not exist on jQuery.jqBootstrapValidation'); 928 return null; 929 } 930 931 }; 932 933 $.jqBootstrapValidation = function(options) { 934 $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this, arguments); 935 }; 936 937})(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.