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