diff --git a/.travis.yml b/.travis.yml
index f90e8b9..6ef04eb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: node_js
node_js:
- - "0.9"
+ - "0.10"
before_script:
- npm install -g grunt-cli
diff --git a/dist/jqBootstrapValidation-1.3.7.js b/dist/jqBootstrapValidation-1.3.7.js
index 3944a41..1ebad0a 100644
--- a/dist/jqBootstrapValidation-1.3.7.js
+++ b/dist/jqBootstrapValidation-1.3.7.js
@@ -1,667 +1,668 @@
-/*! jqBootstrapValidation - v1.3.7 - 2013-05-07
+/*! jqBootstrapValidation - v1.3.7 - 2014-08-15
* http://reactiveraven.github.com/jqBootstrapValidation
-* Copyright (c) 2013 David Godfrey; Licensed MIT */
-
-(function( $ ){
-
- var createdElements = [];
-
- var defaults = {
- options: {
- prependExistingHelpBlock: false,
- sniffHtml: true, // sniff for 'required', 'maxlength', etc
- preventSubmit: true, // stop the form submit event from firing if validation fails
- submitError: false, // function called if there is an error when trying to submit
- submitSuccess: false, // function called just before a successful submit event is sent to the server
+* Copyright (c) 2014 David Godfrey; Licensed MIT */
+(function ($) {
+
+ var createdElements = [];
+
+ var defaults = {
+ options: {
+ prependExistingHelpBlock: false,
+ sniffHtml: true, // sniff for 'required', 'maxlength', etc
+ preventSubmit: true, // stop the form submit event from firing if validation fails
+ submitError: false, // function called if there is an error when trying to submit
+ submitSuccess: false, // function called just before a successful submit event is sent to the server
semanticallyStrict: false, // set to true to tidy up generated HTML output
+ removeSuccess : true,
bindEvents: [],
- autoAdd: {
- helpBlocks: true
- },
- filter: function () {
- // return $(this).is(":visible"); // only validate elements you can see
- return true; // validate everything
- }
- },
- methods: {
- init : function( options ) {
-
- // Get a clean copy of the defaults for extending
- var settings = $.extend(true, {}, defaults);
- // Set up the options based on the input
- settings.options = $.extend(true, settings.options, options);
-
- var $siblingElements = this;
-
- var uniqueForms = $.unique(
- $siblingElements.map( function () {
- return $(this).parents("form")[0];
- }).toArray()
- );
-
- $(uniqueForms).bind("submit.validationSubmit", function (e) {
- var $form = $(this);
- var warningsFound = 0;
- // Get all inputs
- var $allInputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
- var $allControlGroups = $form.find(".control-group");
-
- // Only trigger validation on the ones that actually _have_ validation
- var $inputsWithValidators = $allInputs.filter(function () {
- return $(this).triggerHandler("getValidatorCount.validation") > 0;
- });
- $inputsWithValidators.trigger("submit.validation");
-
- // But all of them are out-of-focus now, because we're submitting.
- $allInputs.trigger("validationLostFocus.validation");
-
- // Okay, now check each controlgroup for errors (or warnings)
- $allControlGroups.each(function (i, el) {
- var $controlGroup = $(el);
- if ($controlGroup.hasClass("warning") || $controlGroup.hasClass("error")) {
- $controlGroup.removeClass("warning").addClass("error");
- warningsFound++;
- }
- });
-
- if (warningsFound) {
- // If we found any warnings, maybe we should prevent the submit
- // event, and trigger 'submitError' (if they're set up)
- if (settings.options.preventSubmit) {
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- $form.addClass("error");
- if ($.isFunction(settings.options.submitError)) {
- settings.options.submitError($form, e, $inputsWithValidators.jqBootstrapValidation("collectErrors", true));
- }
- } else {
- // Woo! No errors! We can pass the submit event to submitSuccess
- // (if it has been set up)
- $form.removeClass("error");
- if ($.isFunction(settings.options.submitSuccess)) {
- settings.options.submitSuccess($form, e);
- }
- }
- });
-
- return this.each(function(){
-
- // Get references to everything we're interested in
- var $this = $(this),
- $controlGroup = $this.parents(".control-group").first(),
- $helpBlock = $controlGroup.find(".help-block").first(),
- $form = $this.parents("form").first(),
- validatorNames = [];
-
- // create message container if not exists
- if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
- $helpBlock = $('
');
- $controlGroup.find('.controls').append($helpBlock);
- createdElements.push($helpBlock[0]);
- }
-
- // =============================================================
- // SNIFF HTML FOR VALIDATORS
- // =============================================================
-
- // *snort sniff snuffle*
-
- if (settings.options.sniffHtml) {
- var message;
- // ---------------------------------------------------------
- // PATTERN
- // ---------------------------------------------------------
- if ($this.data("validationPatternPattern")) {
- $this.attr("pattern", $this.data("validationPatternPattern"));
- }
- if ($this.attr("pattern") !== undefined) {
- message = "Not in the expected format";
- if ($this.data("validationPatternMessage")) {
- message = $this.data("validationPatternMessage");
- }
- $this.data("validationPatternMessage", message);
- $this.data("validationPatternRegex", $this.attr("pattern"));
- }
- // ---------------------------------------------------------
- // MAX
- // ---------------------------------------------------------
- if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
- var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
- message = "Too high: Maximum of '" + max + "'";
- if ($this.data("validationMaxMessage")) {
- message = $this.data("validationMaxMessage");
- }
- $this.data("validationMaxMessage", message);
- $this.data("validationMaxMax", max);
- }
- // ---------------------------------------------------------
- // MIN
- // ---------------------------------------------------------
- if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
- var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
- message = "Too low: Minimum of '" + min + "'";
- if ($this.data("validationMinMessage")) {
- message = $this.data("validationMinMessage");
- }
- $this.data("validationMinMessage", message);
- $this.data("validationMinMin", min);
- }
- // ---------------------------------------------------------
- // MAXLENGTH
- // ---------------------------------------------------------
- if ($this.attr("maxlength") !== undefined) {
- message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters";
- if ($this.data("validationMaxlengthMessage")) {
- message = $this.data("validationMaxlengthMessage");
- }
- $this.data("validationMaxlengthMessage", message);
- $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
- }
- // ---------------------------------------------------------
- // MINLENGTH
- // ---------------------------------------------------------
- if ($this.attr("minlength") !== undefined) {
- message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters";
- if ($this.data("validationMinlengthMessage")) {
- message = $this.data("validationMinlengthMessage");
- }
- $this.data("validationMinlengthMessage", message);
- $this.data("validationMinlengthMinlength", $this.attr("minlength"));
- }
- // ---------------------------------------------------------
- // REQUIRED
- // ---------------------------------------------------------
- if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
- message = settings.builtInValidators.required.message;
- if ($this.data("validationRequiredMessage")) {
- message = $this.data("validationRequiredMessage");
- }
- $this.data("validationRequiredMessage", message);
- }
- // ---------------------------------------------------------
- // NUMBER
- // ---------------------------------------------------------
- if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
- message = settings.validatorTypes.number.message; // TODO: fix this
- if ($this.data("validationNumberMessage")) {
- message = $this.data("validationNumberMessage");
- }
- $this.data("validationNumberMessage", message);
-
- var step = settings.validatorTypes.number.step; // TODO: and this
- if ($this.data("validationNumberStep")) {
- step = $this.data("validationNumberStep");
- }
- $this.data("validationNumberStep", step);
-
- var decimal = settings.validatorTypes.number.decimal;
- if ($this.data("validationNumberDecimal")) {
- decimal = $this.data("validationNumberDecimal");
- }
- $this.data("validationNumberDecimal", decimal);
- }
- // ---------------------------------------------------------
- // EMAIL
- // ---------------------------------------------------------
- if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
- message = "Not a valid email address";
- if ($this.data("validationEmailMessage")) {
- message = $this.data("validationEmailMessage");
- }
- $this.data("validationEmailMessage", message);
- }
- // ---------------------------------------------------------
- // MINCHECKED
- // ---------------------------------------------------------
- if ($this.attr("minchecked") !== undefined) {
- message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required";
- if ($this.data("validationMincheckedMessage")) {
- message = $this.data("validationMincheckedMessage");
- }
- $this.data("validationMincheckedMessage", message);
- $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
+ autoAdd: {
+ helpBlocks: true
+ },
+ filter: function () {
+ // return $(this).is(":visible"); // only validate elements you can see
+ return true; // validate everything
}
- // ---------------------------------------------------------
- // MAXCHECKED
- // ---------------------------------------------------------
- if ($this.attr("maxchecked") !== undefined) {
- message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required";
- if ($this.data("validationMaxcheckedMessage")) {
- message = $this.data("validationMaxcheckedMessage");
- }
- $this.data("validationMaxcheckedMessage", message);
- $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
- }
- }
-
- // =============================================================
- // COLLECT VALIDATOR NAMES
- // =============================================================
-
- // Get named validators
- if ($this.data("validation") !== undefined) {
- validatorNames = $this.data("validation").split(",");
- }
-
- // Get extra ones defined on the element's data attributes
- $.each($this.data(), function (i, el) {
- var parts = i.replace(/([A-Z])/g, ",$1").split(",");
- if (parts[0] === "validation" && parts[1]) {
- validatorNames.push(parts[1]);
- }
- });
-
- // =============================================================
- // NORMALISE VALIDATOR NAMES
- // =============================================================
-
- var validatorNamesToInspect = validatorNames;
- var newValidatorNamesToInspect = [];
-
- var uppercaseEachValidatorName = function (i, el) {
- validatorNames[i] = formatValidatorName(el);
- };
-
- var inspectValidators = function(i, el) {
- if ($this.data("validation" + el + "Shortcut") !== undefined) {
- // Are these custom validators?
- // Pull them out!
- $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
- newValidatorNamesToInspect.push(el2);
- });
- } else if (settings.builtInValidators[el.toLowerCase()]) {
- // Is this a recognised built-in?
- // Pull it out!
- var validator = settings.builtInValidators[el.toLowerCase()];
- if (validator.type.toLowerCase() === "shortcut") {
- $.each(validator.shortcut.split(","), function (i, el) {
- el = formatValidatorName(el);
- newValidatorNamesToInspect.push(el);
- validatorNames.push(el);
+ },
+ methods: {
+ init: function (options) {
+
+ // Get a clean copy of the defaults for extending
+ var settings = $.extend(true, {}, defaults);
+ // Set up the options based on the input
+ settings.options = $.extend(true, settings.options, options);
+
+ var $siblingElements = this;
+
+ var uniqueForms = $.unique(
+ $siblingElements.map(function () {
+ return $(this).parents("form")[0];
+ }).toArray()
+ );
+
+ $(uniqueForms).bind("submit.validationSubmit", function (e) {
+ var $form = $(this);
+ var warningsFound = 0;
+ // Get all inputs
+ var $allInputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
+ var $allControlGroups = $form.find(".form-group");
+
+ // Only trigger validation on the ones that actually _have_ validation
+ var $inputsWithValidators = $allInputs.filter(function () {
+ return $(this).triggerHandler("getValidatorCount.validation") > 0;
+ });
+ $inputsWithValidators.trigger("submit.validation");
+
+ // But all of them are out-of-focus now, because we're submitting.
+ $allInputs.trigger("validationLostFocus.validation");
+
+ // Okay, now check each controlgroup for errors (or warnings)
+ $allControlGroups.each(function (i, el) {
+ var $controlGroup = $(el);
+ if ($controlGroup.hasClass("warning") || $controlGroup.hasClass("error")) {
+ $controlGroup.removeClass("warning").addClass("error");
+ warningsFound++;
+ }
+ });
+
+ if (warningsFound) {
+ // If we found any warnings, maybe we should prevent the submit
+ // event, and trigger 'submitError' (if they're set up)
+ if (settings.options.preventSubmit) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+ $form.addClass("error");
+ if ($.isFunction(settings.options.submitError)) {
+ settings.options.submitError($form, e, $inputsWithValidators.jqBootstrapValidation("collectErrors", true));
+ }
+ } else {
+ // Woo! No errors! We can pass the submit event to submitSuccess
+ // (if it has been set up)
+ $form.removeClass("error");
+ if ($.isFunction(settings.options.submitSuccess)) {
+ settings.options.submitSuccess($form, e);
+ }
+ }
});
- }
- }
- };
-
- do // repeatedly expand 'shortcut' validators into their real validators
- {
- // Uppercase only the first letter of each name
- $.each(validatorNames, uppercaseEachValidatorName);
-
- // Remove duplicate validator names
- validatorNames = $.unique(validatorNames);
-
- // Pull out the new validator names from each shortcut
- newValidatorNamesToInspect = [];
- $.each(validatorNamesToInspect, inspectValidators);
-
- validatorNamesToInspect = newValidatorNamesToInspect;
-
- } while (validatorNamesToInspect.length > 0);
-
- // =============================================================
- // SET UP VALIDATOR ARRAYS
- // =============================================================
-
- /* We're gonna generate something like
- *
- * {
- * "regex": [
- * { -- a validator object here --},
- * { -- a validator object here --}
- * ],
- * "required": [
- * { -- a validator object here --},
- * { -- a validator object here --}
- * ]
- * }
- *
- * with a few more entries.
- *
- * Because we only add a few validators to each field, most of the
- * keys will be empty arrays with no validator objects in them, and
- * thats fine.
- */
-
- var validators = {};
-
- $.each(validatorNames, function (i, el) {
- // Set up the 'override' message
- var message = $this.data("validation" + el + "Message");
- var hasOverrideMessage = !!message;
- var foundValidator = false;
- if (!message) {
- message = "'" + el + "' validation failed ";
- }
- $.each(
- settings.validatorTypes,
- function (validatorType, validatorTemplate) {
- if (validators[validatorType] === undefined) {
- validators[validatorType] = [];
- }
- if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
- var initted = validatorTemplate.init($this, el);
- if (hasOverrideMessage) {
- initted.message = message;
- }
-
- validators[validatorType].push(
- $.extend(
- true,
- {
- name: formatValidatorName(validatorTemplate.name),
- message: message
- },
- initted
- )
- );
- foundValidator = true;
- }
- }
- );
-
- if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
-
- var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
- if (hasOverrideMessage) {
- validator.message = message;
- }
- var validatorType = validator.type.toLowerCase();
-
- if (validatorType === "shortcut") {
- foundValidator = true;
- } else {
- $.each(
- settings.validatorTypes,
- function (validatorTemplateType, validatorTemplate) {
- if (validators[validatorTemplateType] === undefined) {
- validators[validatorTemplateType] = [];
+ return this.each(function () {
+
+ // Get references to everything we're interested in
+ var $this = $(this),
+ $controlGroup = $this.parents(".form-group").first(),
+ $helpBlock = $controlGroup.find(".help-block").first(),
+ $form = $this.parents("form").first(),
+ validatorNames = [];
+
+ // create message container if not exists
+ if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
+ $helpBlock = $('');
+ $controlGroup.find('.controls').append($helpBlock);
+ createdElements.push($helpBlock[0]);
}
- if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
- $this.data(
- "validation" + el + formatValidatorName(validatorTemplate.name),
- validator[validatorTemplate.name.toLowerCase()]
- );
- validators[validatorType].push(
- $.extend(
- validator,
- validatorTemplate.init($this, el)
- )
- );
- foundValidator = true;
+
+ // =============================================================
+ // SNIFF HTML FOR VALIDATORS
+ // =============================================================
+
+ // *snort sniff snuffle*
+
+ if (settings.options.sniffHtml) {
+ var message;
+ // ---------------------------------------------------------
+ // PATTERN
+ // ---------------------------------------------------------
+ if ($this.data("validationPatternPattern")) {
+ $this.attr("pattern", $this.data("validationPatternPattern"));
+ }
+ if ($this.attr("pattern") !== undefined) {
+ message = "Not in the expected format";
+ if ($this.data("validationPatternMessage")) {
+ message = $this.data("validationPatternMessage");
+ }
+ $this.data("validationPatternMessage", message);
+ $this.data("validationPatternRegex", $this.attr("pattern"));
+ }
+ // ---------------------------------------------------------
+ // MAX
+ // ---------------------------------------------------------
+ if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
+ var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
+ message = "Too high: Maximum of '" + max + "'";
+ if ($this.data("validationMaxMessage")) {
+ message = $this.data("validationMaxMessage");
+ }
+ $this.data("validationMaxMessage", message);
+ $this.data("validationMaxMax", max);
+ }
+ // ---------------------------------------------------------
+ // MIN
+ // ---------------------------------------------------------
+ if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
+ var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
+ message = "Too low: Minimum of '" + min + "'";
+ if ($this.data("validationMinMessage")) {
+ message = $this.data("validationMinMessage");
+ }
+ $this.data("validationMinMessage", message);
+ $this.data("validationMinMin", min);
+ }
+ // ---------------------------------------------------------
+ // MAXLENGTH
+ // ---------------------------------------------------------
+ if ($this.attr("maxlength") !== undefined) {
+ message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters";
+ if ($this.data("validationMaxlengthMessage")) {
+ message = $this.data("validationMaxlengthMessage");
+ }
+ $this.data("validationMaxlengthMessage", message);
+ $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
+ }
+ // ---------------------------------------------------------
+ // MINLENGTH
+ // ---------------------------------------------------------
+ if ($this.attr("minlength") !== undefined) {
+ message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters";
+ if ($this.data("validationMinlengthMessage")) {
+ message = $this.data("validationMinlengthMessage");
+ }
+ $this.data("validationMinlengthMessage", message);
+ $this.data("validationMinlengthMinlength", $this.attr("minlength"));
+ }
+ // ---------------------------------------------------------
+ // REQUIRED
+ // ---------------------------------------------------------
+ if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
+ message = settings.builtInValidators.required.message;
+ if ($this.data("validationRequiredMessage")) {
+ message = $this.data("validationRequiredMessage");
+ }
+ $this.data("validationRequiredMessage", message);
+ }
+ // ---------------------------------------------------------
+ // NUMBER
+ // ---------------------------------------------------------
+ if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
+ message = settings.validatorTypes.number.message; // TODO: fix this
+ if ($this.data("validationNumberMessage")) {
+ message = $this.data("validationNumberMessage");
+ }
+ $this.data("validationNumberMessage", message);
+
+ var step = settings.validatorTypes.number.step; // TODO: and this
+ if ($this.data("validationNumberStep")) {
+ step = $this.data("validationNumberStep");
+ }
+ $this.data("validationNumberStep", step);
+
+ var decimal = settings.validatorTypes.number.decimal;
+ if ($this.data("validationNumberDecimal")) {
+ decimal = $this.data("validationNumberDecimal");
+ }
+ $this.data("validationNumberDecimal", decimal);
+ }
+ // ---------------------------------------------------------
+ // EMAIL
+ // ---------------------------------------------------------
+ if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
+ message = "Not a valid email address";
+ if ($this.data("validationEmailMessage")) {
+ message = $this.data("validationEmailMessage");
+ }
+ $this.data("validationEmailMessage", message);
+ }
+ // ---------------------------------------------------------
+ // MINCHECKED
+ // ---------------------------------------------------------
+ if ($this.attr("minchecked") !== undefined) {
+ message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required";
+ if ($this.data("validationMincheckedMessage")) {
+ message = $this.data("validationMincheckedMessage");
+ }
+ $this.data("validationMincheckedMessage", message);
+ $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
+ }
+ // ---------------------------------------------------------
+ // MAXCHECKED
+ // ---------------------------------------------------------
+ if ($this.attr("maxchecked") !== undefined) {
+ message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required";
+ if ($this.data("validationMaxcheckedMessage")) {
+ message = $this.data("validationMaxcheckedMessage");
+ }
+ $this.data("validationMaxcheckedMessage", message);
+ $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
+ }
}
- }
- );
- }
- }
- if (! foundValidator) {
- $.error("Cannot find validation info for '" + el + "'");
- }
- });
-
- // =============================================================
- // STORE FALLBACK VALUES
- // =============================================================
-
- $helpBlock.data(
- "original-contents",
- (
- $helpBlock.data("original-contents") ?
- $helpBlock.data("original-contents") :
- $helpBlock.html()
- )
- );
-
- $helpBlock.data(
- "original-role",
- (
- $helpBlock.data("original-role") ?
- $helpBlock.data("original-role") :
- $helpBlock.attr("role")
- )
- );
-
- $controlGroup.data(
- "original-classes",
- (
- $controlGroup.data("original-clases") ?
- $controlGroup.data("original-classes") :
- $controlGroup.attr("class")
- )
- );
-
- $this.data(
- "original-aria-invalid",
- (
- $this.data("original-aria-invalid") ?
- $this.data("original-aria-invalid") :
- $this.attr("aria-invalid")
- )
- );
-
- // =============================================================
- // VALIDATION
- // =============================================================
-
- $this.bind(
- "validation.validation",
- function (event, params) {
-
- var value = getValue($this);
-
- // Get a list of the errors to apply
- var errorsFound = [];
-
- $.each(validators, function (validatorType, validatorTypeArray) {
- if (
- value || // has a truthy value
- value.length || // not an empty string
- ( // am including empty values
- (
- params &&
- params.includeEmpty
- ) ||
- !!settings.validatorTypes[validatorType].includeEmpty
- ) ||
- ( // validator is blocking submit
- !!settings.validatorTypes[validatorType].blockSubmit &&
- params &&
- !!params.submitting
- )
- )
- {
- $.each(
- validatorTypeArray,
- function (i, validator) {
- if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
- errorsFound.push(validator.message);
- }
+ // =============================================================
+ // COLLECT VALIDATOR NAMES
+ // =============================================================
+
+ // Get named validators
+ if ($this.data("validation") !== undefined) {
+ validatorNames = $this.data("validation").split(",");
}
- );
- }
- });
- return errorsFound;
- }
- );
+ // Get extra ones defined on the element's data attributes
+ $.each($this.data(), function (i, el) {
+ var parts = i.replace(/([A-Z])/g, ",$1").split(",");
+ if (parts[0] === "validation" && parts[1]) {
+ validatorNames.push(parts[1]);
+ }
+ });
- $this.bind(
- "getValidators.validation",
- function () {
- return validators;
- }
- );
-
- var numValidators = 0;
-
- $.each(validators, function (i, el) {
- numValidators += el.length;
- });
-
- $this.bind("getValidatorCount.validation", function () {
- return numValidators;
- });
-
- // =============================================================
- // WATCH FOR CHANGES
- // =============================================================
- $this.bind(
- "submit.validation",
- function () {
- return $this.triggerHandler("change.validation", {submitting: true});
- }
- );
- $this.bind(
- (
- settings.options.bindEvents.length > 0 ?
- settings.options.bindEvents :
- [
- "keyup",
- "focus",
- "blur",
- "click",
- "keydown",
- "keypress",
- "change"
- ]
- ).concat(["revalidate"]).join(".validation ") + ".validation",
- function (e, params) {
-
- var value = getValue($this);
-
- var errorsFound = [];
-
- if (params && !!params.submitting) {
- $controlGroup.data("jqbvIsSubmitting", true);
- } else if (e.type !== "revalidate") {
- $controlGroup.data("jqbvIsSubmitting", false);
- }
-
- var formIsSubmitting = !!$controlGroup.data("jqbvIsSubmitting");
-
- $controlGroup.find("input,textarea,select").each(function (i, el) {
- var oldCount = errorsFound.length;
- $.each($(el).triggerHandler("validation.validation", params), function (j, message) {
- errorsFound.push(message);
+ // =============================================================
+ // NORMALISE VALIDATOR NAMES
+ // =============================================================
+
+ var validatorNamesToInspect = validatorNames;
+ var newValidatorNamesToInspect = [];
+
+ var uppercaseEachValidatorName = function (i, el) {
+ validatorNames[i] = formatValidatorName(el);
+ };
+
+ var inspectValidators = function (i, el) {
+ if ($this.data("validation" + el + "Shortcut") !== undefined) {
+ // Are these custom validators?
+ // Pull them out!
+ $.each($this.data("validation" + el + "Shortcut").split(","), function (i2, el2) {
+ newValidatorNamesToInspect.push(el2);
+ });
+ } else if (settings.builtInValidators[el.toLowerCase()]) {
+ // Is this a recognised built-in?
+ // Pull it out!
+ var validator = settings.builtInValidators[el.toLowerCase()];
+ if (validator.type.toLowerCase() === "shortcut") {
+ $.each(validator.shortcut.split(","), function (i, el) {
+ el = formatValidatorName(el);
+ newValidatorNamesToInspect.push(el);
+ validatorNames.push(el);
+ });
+ }
+ }
+ };
+
+ do // repeatedly expand 'shortcut' validators into their real validators
+ {
+ // Uppercase only the first letter of each name
+ $.each(validatorNames, uppercaseEachValidatorName);
+
+ // Remove duplicate validator names
+ validatorNames = $.unique(validatorNames);
+
+ // Pull out the new validator names from each shortcut
+ newValidatorNamesToInspect = [];
+ $.each(validatorNamesToInspect, inspectValidators);
+
+ validatorNamesToInspect = newValidatorNamesToInspect;
+
+ } while (validatorNamesToInspect.length > 0);
+
+ // =============================================================
+ // SET UP VALIDATOR ARRAYS
+ // =============================================================
+
+ /* We're gonna generate something like
+ *
+ * {
+ * "regex": [
+ * { -- a validator object here --},
+ * { -- a validator object here --}
+ * ],
+ * "required": [
+ * { -- a validator object here --},
+ * { -- a validator object here --}
+ * ]
+ * }
+ *
+ * with a few more entries.
+ *
+ * Because we only add a few validators to each field, most of the
+ * keys will be empty arrays with no validator objects in them, and
+ * thats fine.
+ */
+
+ var validators = {};
+
+ $.each(validatorNames, function (i, el) {
+ // Set up the 'override' message
+ var message = $this.data("validation" + el + "Message");
+ var hasOverrideMessage = !!message;
+ var foundValidator = false;
+ if (!message) {
+ message = "'" + el + "' validation failed ";
+ }
+
+ $.each(
+ settings.validatorTypes,
+ function (validatorType, validatorTemplate) {
+ if (validators[validatorType] === undefined) {
+ validators[validatorType] = [];
+ }
+ if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
+ var initted = validatorTemplate.init($this, el);
+ if (hasOverrideMessage) {
+ initted.message = message;
+ }
+
+ validators[validatorType].push(
+ $.extend(
+ true,
+ {
+ name: formatValidatorName(validatorTemplate.name),
+ message: message
+ },
+ initted
+ )
+ );
+ foundValidator = true;
+ }
+ }
+ );
+
+ if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
+
+ var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
+ if (hasOverrideMessage) {
+ validator.message = message;
+ }
+ var validatorType = validator.type.toLowerCase();
+
+ if (validatorType === "shortcut") {
+ foundValidator = true;
+ } else {
+ $.each(
+ settings.validatorTypes,
+ function (validatorTemplateType, validatorTemplate) {
+ if (validators[validatorTemplateType] === undefined) {
+ validators[validatorTemplateType] = [];
+ }
+ if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
+ $this.data(
+ "validation" + el + formatValidatorName(validatorTemplate.name),
+ validator[validatorTemplate.name.toLowerCase()]
+ );
+ validators[validatorType].push(
+ $.extend(
+ validator,
+ validatorTemplate.init($this, el)
+ )
+ );
+ foundValidator = true;
+ }
+ }
+ );
+ }
+ }
+
+ if (!foundValidator) {
+ $.error("Cannot find validation info for '" + el + "'");
+ }
+ });
+
+ // =============================================================
+ // STORE FALLBACK VALUES
+ // =============================================================
+
+ $helpBlock.data(
+ "original-contents",
+ (
+ $helpBlock.data("original-contents") ?
+ $helpBlock.data("original-contents") :
+ $helpBlock.html()
+ )
+ );
+
+ $helpBlock.data(
+ "original-role",
+ (
+ $helpBlock.data("original-role") ?
+ $helpBlock.data("original-role") :
+ $helpBlock.attr("role")
+ )
+ );
+
+ $controlGroup.data(
+ "original-classes",
+ (
+ $controlGroup.data("original-clases") ?
+ $controlGroup.data("original-classes") :
+ $controlGroup.attr("class")
+ )
+ );
+
+ $this.data(
+ "original-aria-invalid",
+ (
+ $this.data("original-aria-invalid") ?
+ $this.data("original-aria-invalid") :
+ $this.attr("aria-invalid")
+ )
+ );
+
+ // =============================================================
+ // VALIDATION
+ // =============================================================
+
+ $this.bind(
+ "validation.validation",
+ function (event, params) {
+
+ var value = getValue($this);
+
+ // Get a list of the errors to apply
+ var errorsFound = [];
+
+ $.each(validators, function (validatorType, validatorTypeArray) {
+ if (
+ value || // has a truthy value
+ value.length || // not an empty string
+ ( // am including empty values
+ (
+ params &&
+ params.includeEmpty
+ ) || !!settings.validatorTypes[validatorType].includeEmpty
+ ) ||
+ ( // validator is blocking submit
+ !!settings.validatorTypes[validatorType].blockSubmit &&
+ params && !!params.submitting
+ )
+ ) {
+ $.each(
+ validatorTypeArray,
+ function (i, validator) {
+ if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
+ errorsFound.push(validator.message);
+ }
+ }
+ );
+ }
+ });
+
+ return errorsFound;
+ }
+ );
+
+ $this.bind(
+ "getValidators.validation",
+ function () {
+ return validators;
+ }
+ );
+
+ var numValidators = 0;
+
+ $.each(validators, function (i, el) {
+ numValidators += el.length;
+ });
+
+ $this.bind("getValidatorCount.validation", function () {
+ return numValidators;
+ });
+
+ // =============================================================
+ // WATCH FOR CHANGES
+ // =============================================================
+ $this.bind(
+ "submit.validation",
+ function () {
+ return $this.triggerHandler("change.validation", {submitting: true});
+ }
+ );
+ $this.bind(
+ (
+ settings.options.bindEvents.length > 0 ?
+ settings.options.bindEvents :
+ [
+ "keyup",
+ "focus",
+ "blur",
+ "click",
+ "keydown",
+ "keypress",
+ "change"
+ ]
+ ).concat(["revalidate"]).join(".validation ") + ".validation",
+ function (e, params) {
+
+ var value = getValue($this);
+
+ var errorsFound = [];
+
+ if (params && !!params.submitting) {
+ $controlGroup.data("jqbvIsSubmitting", true);
+ } else if (e.type !== "revalidate") {
+ $controlGroup.data("jqbvIsSubmitting", false);
+ }
+
+ var formIsSubmitting = !!$controlGroup.data("jqbvIsSubmitting");
+
+ $controlGroup.find("input,textarea,select").not('[type=submit]').each(function (i, el) {
+ var oldCount = errorsFound.length;
+ $.each($(el).triggerHandler("validation.validation", params) || [], function (j, message) {
+ errorsFound.push(message);
+ });
+ if (errorsFound.length > oldCount) {
+ $(el).attr("aria-invalid", "true");
+ } else {
+ var original = $this.data("original-aria-invalid");
+ $(el).attr("aria-invalid", (original !== undefined ? original : false));
+ }
+ });
+
+ $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
+
+ errorsFound = $.unique(errorsFound.sort());
+
+ // Were there any errors?
+ if (errorsFound.length) {
+ // Better flag it up as a warning.
+ $controlGroup.removeClass("success error warning").addClass(formIsSubmitting ? "error" : "warning");
+
+ // How many errors did we find?
+ if (settings.options.semanticallyStrict && errorsFound.length === 1) {
+ // Only one? Being strict? Just output it.
+ $helpBlock.html(errorsFound[0] +
+ ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
+ } else {
+ // Multiple? Being sloppy? Glue them together into an UL.
+ $helpBlock.html("- " + errorsFound.join("
- ") + "
" +
+ ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
+ }
+ } else {
+ $controlGroup.removeClass("warning error success");
+ if (value.length > 0) {
+ $controlGroup.addClass("success");
+ }
+ $helpBlock.html($helpBlock.data("original-contents"));
+ }
+
+ if (e.type === "blur") {
+ if( settings.options.removeSuccess ){
+ $controlGroup.removeClass("success");
+ }
+ }
+ }
+ );
+ $this.bind("validationLostFocus.validation", function () {
+ if( settings.options.removeSuccess ){
+ $controlGroup.removeClass("success");
+ }
+ });
});
- if (errorsFound.length > oldCount) {
- $(el).attr("aria-invalid", "true");
- } else {
- var original = $this.data("original-aria-invalid");
- $(el).attr("aria-invalid", (original !== undefined ? original : false));
- }
- });
+ },
+ destroy: function () {
+
+ return this.each(
+ function () {
+
+ var
+ $this = $(this),
+ $controlGroup = $this.parents(".form-group").first(),
+ $helpBlock = $controlGroup.find(".help-block").first(),
+ $form = $this.parents("form").first();
+
+ // remove our events
+ $this.unbind('.validation'); // events are namespaced.
+ $form.unbind(".validationSubmit");
+ // reset help text
+ $helpBlock.html($helpBlock.data("original-contents"));
+ // reset classes
+ $controlGroup.attr("class", $controlGroup.data("original-classes"));
+ // reset aria
+ $this.attr("aria-invalid", $this.data("original-aria-invalid"));
+ // reset role
+ $helpBlock.attr("role", $this.data("original-role"));
+ // remove all elements we created
+ if ($.inArray($helpBlock[0], createdElements) > -1) {
+ $helpBlock.remove();
+ }
- $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
+ }
+ );
- errorsFound = $.unique(errorsFound.sort());
+ },
+ collectErrors: function (includeEmpty) {
- // Were there any errors?
- if (errorsFound.length) {
- // Better flag it up as a warning.
- $controlGroup.removeClass("success error warning").addClass(formIsSubmitting ? "error" : "warning");
+ var errorMessages = {};
+ this.each(function (i, el) {
+ var $el = $(el);
+ var name = $el.attr("name");
+ var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
+ errorMessages[name] = $.extend(true, errors, errorMessages[name]);
+ });
- // How many errors did we find?
- if (settings.options.semanticallyStrict && errorsFound.length === 1) {
- // Only one? Being strict? Just output it.
- $helpBlock.html(errorsFound[0] +
- ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
- } else {
- // Multiple? Being sloppy? Glue them together into an UL.
- $helpBlock.html("- " + errorsFound.join("
- ") + "
" +
- ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
- }
- } else {
- $controlGroup.removeClass("warning error success");
- if (value.length > 0) {
- $controlGroup.addClass("success");
- }
- $helpBlock.html($helpBlock.data("original-contents"));
- }
+ $.each(errorMessages, function (i, el) {
+ if (el.length === 0) {
+ delete errorMessages[i];
+ }
+ });
- if (e.type === "blur") {
- $controlGroup.removeClass("success");
- }
- }
- );
- $this.bind("validationLostFocus.validation", function () {
- $controlGroup.removeClass("success");
- });
- });
- },
- destroy : function( ) {
-
- return this.each(
- function() {
-
- var
- $this = $(this),
- $controlGroup = $this.parents(".control-group").first(),
- $helpBlock = $controlGroup.find(".help-block").first(),
- $form = $this.parents("form").first();
-
- // remove our events
- $this.unbind('.validation'); // events are namespaced.
- $form.unbind(".validationSubmit");
- // reset help text
- $helpBlock.html($helpBlock.data("original-contents"));
- // reset classes
- $controlGroup.attr("class", $controlGroup.data("original-classes"));
- // reset aria
- $this.attr("aria-invalid", $this.data("original-aria-invalid"));
- // reset role
- $helpBlock.attr("role", $this.data("original-role"));
- // remove all elements we created
- if ($.inArray($helpBlock[0], createdElements) > -1) {
- $helpBlock.remove();
- }
+ return errorMessages;
+
+ },
+ hasErrors: function () {
+
+ var errorMessages = [];
+
+ this.find('input,select,textarea').add(this).each(function (i, el) {
+ errorMessages = errorMessages.concat(
+ $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
+ );
+ });
- }
- );
-
- },
- collectErrors : function(includeEmpty) {
-
- var errorMessages = {};
- this.each(function (i, el) {
- var $el = $(el);
- var name = $el.attr("name");
- var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
- errorMessages[name] = $.extend(true, errors, errorMessages[name]);
- });
-
- $.each(errorMessages, function (i, el) {
- if (el.length === 0) {
- delete errorMessages[i];
- }
- });
-
- return errorMessages;
-
- },
- hasErrors: function() {
-
- var errorMessages = [];
-
- this.find('input,select,textarea').add(this).each(function (i, el) {
- errorMessages = errorMessages.concat(
- $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
- );
- });
-
- return (errorMessages.length > 0);
- },
- override : function (newDefaults) {
- defaults = $.extend(true, defaults, newDefaults);
- }
- },
- validatorTypes: {
- callback: {
+ return (errorMessages.length > 0);
+ },
+ override: function (newDefaults) {
+ defaults = $.extend(true, defaults, newDefaults);
+ }
+ },
+ validatorTypes: {
+ callback: {
name: "callback",
- init: function($this, name) {
+ init: function ($this, name) {
var result = {
validatorName: name,
callback: $this.data("validation" + name + "Callback"),
@@ -678,13 +679,12 @@
return result;
},
- validate: function($this, value, validator) {
+ validate: function ($this, value, validator) {
if (validator.lastValue === value && validator.lastFinished) {
return !validator.lastValid;
}
- if (validator.lastFinished === true)
- {
+ if (validator.lastFinished === true) {
validator.lastValue = value;
validator.lastValid = true;
validator.lastFinished = false;
@@ -696,7 +696,7 @@
window,
$this,
value,
- function(data) {
+ function (data) {
if (rrjqbvValidator.lastValue === data.value) {
rrjqbvValidator.lastValid = data.valid;
if (data.message) {
@@ -704,12 +704,12 @@
}
rrjqbvValidator.lastFinished = true;
rrjqbvThis.data(
- "validation" + rrjqbvValidator.validatorName + "Message",
+ "validation" + rrjqbvValidator.validatorName + "Message",
rrjqbvValidator.message
);
-
+
// Timeout is set to avoid problems with the events being considered 'already fired'
- setTimeout(function() {
+ setTimeout(function () {
if (!$this.is(":focus") && $this.parents("form").first().data("jqbvIsSubmitting")) {
rrjqbvThis.trigger("blur.validation");
} else {
@@ -724,481 +724,493 @@
return false;
}
- },
- ajax: {
- name: "ajax",
- init: function ($this, name) {
- return {
- validatorName: name,
- url: $this.data("validation" + name + "Ajax"),
- lastValue: $this.val(),
- lastValid: true,
- lastFinished: true
- };
- },
- validate: function ($this, value, validator) {
- if (""+validator.lastValue === ""+value && validator.lastFinished === true) {
- return validator.lastValid === false;
- }
-
- if (validator.lastFinished === true)
- {
- validator.lastValue = value;
- validator.lastValid = true;
- validator.lastFinished = false;
- $.ajax({
- url: validator.url,
- data: "value=" + encodeURIComponent(value) + "&field=" + $this.attr("name"),
- dataType: "json",
- success: function (data) {
- if (""+validator.lastValue === ""+data.value) {
- validator.lastValid = !!(data.valid);
- if (data.message) {
- validator.message = data.message;
- }
- validator.lastFinished = true;
- $this.data("validation" + validator.validatorName + "Message", validator.message);
- // Timeout is set to avoid problems with the events being considered 'already fired'
- setTimeout(function () {
- $this.trigger("revalidate.validation");
- }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
+ },
+ ajax: {
+ name: "ajax",
+ init: function ($this, name) {
+ return {
+ validatorName: name,
+ url: $this.data("validation" + name + "Ajax"),
+ lastValue: $this.val(),
+ lastValid: true,
+ lastFinished: true
+ };
+ },
+ validate: function ($this, value, validator) {
+ if ("" + validator.lastValue === "" + value && validator.lastFinished === true) {
+ return validator.lastValid === false;
+ }
+
+ if (validator.lastFinished === true) {
+ validator.lastValue = value;
+ validator.lastValid = true;
+ validator.lastFinished = false;
+ $.ajax({
+ url: validator.url,
+ data: "value=" + encodeURIComponent(value) + "&field=" + $this.attr("name"),
+ dataType: "json",
+ success: function (data) {
+ if ("" + validator.lastValue === "" + data.value) {
+ validator.lastValid = !!(data.valid);
+ if (data.message) {
+ validator.message = data.message;
+ }
+ validator.lastFinished = true;
+ $this.data("validation" + validator.validatorName + "Message", validator.message);
+ // Timeout is set to avoid problems with the events being considered 'already fired'
+ setTimeout(function () {
+ $this.trigger("revalidate.validation");
+ }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
+ }
+ },
+ failure: function () {
+ validator.lastValid = true;
+ validator.message = "ajax call failed";
+ validator.lastFinished = true;
+ $this.data("validation" + validator.validatorName + "Message", validator.message);
+ // Timeout is set to avoid problems with the events being considered 'already fired'
+ setTimeout(function () {
+ $this.trigger("revalidate.validation");
+ }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
+ }
+ });
+ }
+
+ return false;
+
}
- },
- failure: function () {
- validator.lastValid = true;
- validator.message = "ajax call failed";
- validator.lastFinished = true;
- $this.data("validation" + validator.validatorName + "Message", validator.message);
- // Timeout is set to avoid problems with the events being considered 'already fired'
- setTimeout(function () {
- $this.trigger("revalidate.validation");
- }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
- }
- });
- }
-
- return false;
+ },
+ regex: {
+ name: "regex",
+ init: function ($this, name) {
+ var result = {};
+ var regexString = $this.data("validation" + name + "Regex");
+ result.regex = regexFromString(regexString);
+ if (regexString === undefined) {
+ $.error("Can't find regex for '" + name + "' validator on '" + $this.attr("name") + "'");
+ }
- }
- },
- regex: {
- name: "regex",
- init: function ($this, name) {
- var result = {};
- var regexString = $this.data("validation" + name + "Regex");
- result.regex = regexFromString(regexString);
- if (regexString === undefined) {
- $.error("Can't find regex for '" + name + "' validator on '" + $this.attr("name") + "'");
- }
-
- var message = "Not in the expected format";
- if ($this.data("validation" + name + "Message")) {
- message = $this.data("validation" + name + "Message");
- }
-
- result.message = message;
-
- result.originalName = name;
- return result;
- },
- validate: function ($this, value, validator) {
- return (!validator.regex.test(value) && ! validator.negative) ||
- (validator.regex.test(value) && validator.negative);
- }
- },
- email: {
- name: "email",
- init: function ($this, name) {
- var result = {};
- result.regex = regexFromString('[a-zA-Z0-9.!#$%&\u2019*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}');
-
- var message = "Not a valid email address";
- if ($this.data("validation" + name + "Message")) {
- message = $this.data("validation" + name + "Message");
- }
-
- result.message = message;
-
- result.originalName = name;
- return result;
- },
- validate: function ($this, value, validator) {
- return (!validator.regex.test(value) && ! validator.negative) ||
- (validator.regex.test(value) && validator.negative);
- }
- },
- required: {
- name: "required",
- init: function ($this, name) {
- var message = "This is required";
- if ($this.data("validation" + name + "Message")) {
- message = $this.data("validation" + name + "Message");
- }
-
- return {message: message, includeEmpty: true};
- },
- validate: function ($this, value, validator) {
- return !!(
- (value.length === 0 && !validator.negative) ||
- (value.length > 0 && validator.negative)
- );
- },
- blockSubmit: true
- },
- match: {
- name: "match",
- init: function ($this, name) {
- var elementName = $this.data("validation" + name + "Match");
- var $form = $this.parents("form").first();
- var $element = $form.find("[name=\"" + elementName + "\"]").first();
- $element.bind("validation.validation", function () {
- $this.trigger("revalidate.validation", {submitting: true});
- });
- var result = {};
- result.element = $element;
-
- if ($element.length === 0) {
- $.error("Can't find field '" + elementName + "' to match '" + $this.attr("name") + "' against in '" + name + "' validator");
- }
-
- var message = "Must match";
- var $label = null;
- if (($label = $form.find("label[for=\"" + elementName + "\"]")).length) {
- message += " '" + $label.text() + "'";
- } else if (($label = $element.parents(".control-group").first().find("label")).length) {
- message += " '" + $label.first().text() + "'";
- }
-
- if ($this.data("validation" + name + "Message")) {
- message = $this.data("validation" + name + "Message");
- }
-
- result.message = message;
-
- return result;
- },
- validate: function ($this, value, validator) {
- return (value !== validator.element.val() && ! validator.negative) ||
- (value === validator.element.val() && validator.negative);
- },
- blockSubmit: true,
- includeEmpty: true
- },
- max: {
- name: "max",
- init: function ($this, name) {
- var result = {};
-
- result.max = $this.data("validation" + name + "Max");
-
- result.message = "Too high: Maximum of '" + result.max + "'";
- if ($this.data("validation" + name + "Message")) {
- result.message = $this.data("validation" + name + "Message");
- }
-
- return result;
- },
- validate: function ($this, value, validator) {
- return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative) ||
- (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
- }
- },
- min: {
- name: "min",
- init: function ($this, name) {
- var result = {};
-
- result.min = $this.data("validation" + name + "Min");
-
- result.message = "Too low: Minimum of '" + result.min + "'";
- if ($this.data("validation" + name + "Message")) {
- result.message = $this.data("validation" + name + "Message");
- }
-
- return result;
- },
- validate: function ($this, value, validator) {
- return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative) ||
- (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
- }
- },
- maxlength: {
- name: "maxlength",
- init: function ($this, name) {
- var result = {};
-
- result.maxlength = $this.data("validation" + name + "Maxlength");
-
- result.message = "Too long: Maximum of '" + result.maxlength + "' characters";
- if ($this.data("validation" + name + "Message")) {
- result.message = $this.data("validation" + name + "Message");
- }
-
- return result;
- },
- validate: function ($this, value, validator) {
- return ((value.length > validator.maxlength) && ! validator.negative) ||
- ((value.length <= validator.maxlength) && validator.negative);
- }
- },
- minlength: {
- name: "minlength",
- init: function ($this, name) {
- var result = {};
-
- result.minlength = $this.data("validation" + name + "Minlength");
-
- result.message = "Too short: Minimum of '" + result.minlength + "' characters";
- if ($this.data("validation" + name + "Message")) {
- result.message = $this.data("validation" + name + "Message");
- }
-
- return result;
- },
- validate: function ($this, value, validator) {
- return ((value.length < validator.minlength) && ! validator.negative) ||
- ((value.length >= validator.minlength) && validator.negative);
- }
- },
- maxchecked: {
- name: "maxchecked",
- init: function ($this, name) {
- var result = {};
-
- var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
- elements.bind("change.validation click.validation", function () {
- $this.trigger("revalidate.validation", {includeEmpty: true});
- });
-
- result.elements = elements;
- result.maxchecked = $this.data("validation" + name + "Maxchecked");
-
- var message = "Too many: Max '" + result.maxchecked + "' checked";
- if ($this.data("validation" + name + "Message")) {
- message = $this.data("validation" + name + "Message");
- }
- result.message = message;
-
- return result;
- },
- validate: function ($this, value, validator) {
- return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative) ||
- (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
- },
- blockSubmit: true
- },
- minchecked: {
- name: "minchecked",
- init: function ($this, name) {
- var result = {};
-
- var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
- elements.bind("change.validation click.validation", function () {
- $this.trigger("revalidate.validation", {includeEmpty: true});
- });
-
- result.elements = elements;
- result.minchecked = $this.data("validation" + name + "Minchecked");
-
- var message = "Too few: Min '" + result.minchecked + "' checked";
- if ($this.data("validation" + name + "Message")) {
- message = $this.data("validation" + name + "Message");
- }
- result.message = message;
-
- return result;
- },
- validate: function ($this, value, validator) {
- return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative) ||
- (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
- },
- blockSubmit: true,
- includeEmpty: true
- },
- number: {
- name: "number",
- init: function ($this, name) {
- var result = {};
- result.step = 1;
- if ($this.attr("step")) {
- result.step = $this.attr("step");
- }
- if ($this.data("validation" + name + "Step")) {
- result.step = $this.data("validation" + name + "Step");
- }
-
- result.decimal = ".";
- if ($this.data("validation" + name + "Decimal")) {
- result.decimal = $this.data("validation" + name + "Decimal");
- }
-
- result.thousands = "";
- if ($this.data("validation" + name + "Thousands")) {
- result.thousands = $this.data("validation" + name + "Thousands");
- }
-
- result.regex = regexFromString("([+-]?\\d+(\\" + result.decimal + "\\d+)?)?");
-
- result.message = "Must be a number";
- var dataMessage = $this.data("validation" + name + "Message");
- if (dataMessage) {
- result.message = dataMessage;
- }
-
- return result;
- },
- validate: function ($this, value, validator) {
- var globalValue = value.replace(validator.decimal, ".").replace(validator.thousands, "");
- var multipliedValue = parseFloat(globalValue);
- var multipliedStep = parseFloat(validator.step);
- while (multipliedStep % 1 !== 0) {
- /* thanks to @jkey #57 */
- multipliedStep = parseFloat(multipliedStep.toPrecision(12)) * 10;
- multipliedValue = parseFloat(multipliedValue.toPrecision(12)) * 10;
- }
- var regexResult = validator.regex.test(value);
- var stepResult = parseFloat(multipliedValue) % parseFloat(multipliedStep) === 0;
- var typeResult = !isNaN(parseFloat(globalValue)) && isFinite(globalValue);
- var result = !(regexResult && stepResult && typeResult);
- return result;
+ var message = "Not in the expected format";
+ if ($this.data("validation" + name + "Message")) {
+ message = $this.data("validation" + name + "Message");
+ }
+
+ result.message = message;
+
+ result.originalName = name;
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (!validator.regex.test(value) && !validator.negative) ||
+ (validator.regex.test(value) && validator.negative);
+ }
+ },
+ email: {
+ name: "email",
+ init: function ($this, name) {
+ var result = {};
+ result.regex = regexFromString('[a-zA-Z0-9.!#$%&\u2019*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}');
+
+ var message = "Not a valid email address";
+ if ($this.data("validation" + name + "Message")) {
+ message = $this.data("validation" + name + "Message");
+ }
+
+ result.message = message;
+
+ result.originalName = name;
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (!validator.regex.test(value) && !validator.negative) ||
+ (validator.regex.test(value) && validator.negative);
+ }
+ },
+ required: {
+ name: "required",
+ init: function ($this, name) {
+ var message = "This is required";
+ if ($this.data("validation" + name + "Message")) {
+ message = $this.data("validation" + name + "Message");
+ }
+
+ return {message: message, includeEmpty: true};
+ },
+ validate: function ($this, value, validator) {
+ return !!(
+ (value.length === 0 && !validator.negative) ||
+ (value.length > 0 && validator.negative)
+ );
+ },
+ blockSubmit: true
+ },
+ match: {
+ name: "match",
+ init: function ($this, name) {
+ var elementName = $this.data("validation" + name + "Match");
+ var $form = $this.parents("form").first();
+ var $element = $form.find("[name=\"" + elementName + "\"]").first();
+ $element.bind("validation.validation", function () {
+ $this.trigger("revalidate.validation", {submitting: true});
+ });
+ var result = {};
+ result.element = $element;
+
+ if ($element.length === 0) {
+ $.error("Can't find field '" + elementName + "' to match '" + $this.attr("name") + "' against in '" + name + "' validator");
+ }
+
+ var message = "Must match";
+ var $label = null;
+ if (($label = $form.find("label[for=\"" + elementName + "\"]")).length) {
+ message += " '" + $label.text() + "'";
+ } else if (($label = $element.parents(".form-group").first().find("label")).length) {
+ message += " '" + $label.first().text() + "'";
+ }
+
+ if ($this.data("validation" + name + "Message")) {
+ message = $this.data("validation" + name + "Message");
+ }
+
+ result.message = message;
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (value !== validator.element.val() && !validator.negative) ||
+ (value === validator.element.val() && validator.negative);
+ },
+ blockSubmit: true,
+ includeEmpty: true
+ },
+ max: {
+ name: "max",
+ init: function ($this, name) {
+ var result = {};
+
+ result.max = $this.data("validation" + name + "Max");
+
+ result.message = "Too high: Maximum of '" + result.max + "'";
+ if ($this.data("validation" + name + "Message")) {
+ result.message = $this.data("validation" + name + "Message");
+ }
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (parseFloat(value, 10) > parseFloat(validator.max, 10) && !validator.negative) ||
+ (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
+ }
+ },
+ min: {
+ name: "min",
+ init: function ($this, name) {
+ var result = {};
+
+ result.min = $this.data("validation" + name + "Min");
+
+ result.message = "Too low: Minimum of '" + result.min + "'";
+ if ($this.data("validation" + name + "Message")) {
+ result.message = $this.data("validation" + name + "Message");
+ }
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (parseFloat(value) < parseFloat(validator.min) && !validator.negative) ||
+ (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
+ }
+ },
+ maxlength: {
+ name: "maxlength",
+ init: function ($this, name) {
+ var result = {};
+
+ result.maxlength = $this.data("validation" + name + "Maxlength");
+
+ result.message = "Too long: Maximum of '" + result.maxlength + "' characters";
+ if ($this.data("validation" + name + "Message")) {
+ result.message = $this.data("validation" + name + "Message");
+ }
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return ((value.length > validator.maxlength) && !validator.negative) ||
+ ((value.length <= validator.maxlength) && validator.negative);
+ }
+ },
+ minlength: {
+ name: "minlength",
+ init: function ($this, name) {
+ var result = {};
+
+ result.minlength = $this.data("validation" + name + "Minlength");
+
+ result.message = "Too short: Minimum of '" + result.minlength + "' characters";
+ if ($this.data("validation" + name + "Message")) {
+ result.message = $this.data("validation" + name + "Message");
+ }
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return ((value.length < validator.minlength) && !validator.negative) ||
+ ((value.length >= validator.minlength) && validator.negative);
+ }
+ },
+ maxchecked: {
+ name: "maxchecked",
+ init: function ($this, name) {
+ var result = {};
+
+ var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
+ elements.bind("change.validation click.validation", function () {
+ $this.trigger("revalidate.validation", {includeEmpty: true});
+ });
+
+ result.elements = elements;
+ result.maxchecked = $this.data("validation" + name + "Maxchecked");
+
+ var message = "Too many: Max '" + result.maxchecked + "' checked";
+ if ($this.data("validation" + name + "Message")) {
+ message = $this.data("validation" + name + "Message");
+ }
+ result.message = message;
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (validator.elements.filter(":checked").length > validator.maxchecked && !validator.negative) ||
+ (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
+ },
+ blockSubmit: true
+ },
+ minchecked: {
+ name: "minchecked",
+ init: function ($this, name) {
+ var result = {};
+
+ var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
+ elements.bind("change.validation click.validation", function () {
+ $this.trigger("revalidate.validation", {includeEmpty: true});
+ });
+
+ result.elements = elements;
+ result.minchecked = $this.data("validation" + name + "Minchecked");
+
+ var message = "Too few: Min '" + result.minchecked + "' checked";
+ if ($this.data("validation" + name + "Message")) {
+ message = $this.data("validation" + name + "Message");
+ }
+ result.message = message;
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ return (validator.elements.filter(":checked").length < validator.minchecked && !validator.negative) ||
+ (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
+ },
+ blockSubmit: true,
+ includeEmpty: true
+ },
+ number: {
+ name: "number",
+ init: function ($this, name) {
+ var result = {};
+ result.step = 1;
+ if ($this.attr("step")) {
+ result.step = $this.attr("step");
+ }
+ if ($this.data("validation" + name + "Step")) {
+ result.step = $this.data("validation" + name + "Step");
+ }
+
+ result.decimal = ".";
+ if ($this.data("validation" + name + "Decimal")) {
+ result.decimal = $this.data("validation" + name + "Decimal");
+ }
+
+ result.thousands = "";
+ if ($this.data("validation" + name + "Thousands")) {
+ result.thousands = $this.data("validation" + name + "Thousands");
+ }
+
+ result.regex = regexFromString("([+-]?\\d+(\\" + result.decimal + "\\d+)?)?");
+
+ result.message = "Must be a number";
+ var dataMessage = $this.data("validation" + name + "Message");
+ if (dataMessage) {
+ result.message = dataMessage;
+ }
+
+ return result;
+ },
+ validate: function ($this, value, validator) {
+ var globalValue = value.replace(validator.decimal, ".").replace(validator.thousands, "");
+ var multipliedValue = parseFloat(globalValue);
+ var multipliedStep = parseFloat(validator.step);
+ while (multipliedStep % 1 !== 0) {
+ /* thanks to @jkey #57 */
+ multipliedStep = parseFloat(multipliedStep.toPrecision(12)) * 10;
+ multipliedValue = parseFloat(multipliedValue.toPrecision(12)) * 10;
+ }
+ var regexResult = validator.regex.test(value);
+ var stepResult = parseFloat(multipliedValue) % parseFloat(multipliedStep) === 0;
+ var typeResult = !isNaN(parseFloat(globalValue)) && isFinite(globalValue);
+ var result = !(regexResult && stepResult && typeResult);
+ return result;
+ },
+ message: "Must be a number"
+ }
},
- message: "Must be a number"
- }
- },
- builtInValidators: {
- email: {
- name: "Email",
- type: "email"
- },
- passwordagain: {
- name: "Passwordagain",
- type: "match",
- match: "password",
- message: "Does not match the given password"
- },
- positive: {
- name: "Positive",
- type: "shortcut",
- shortcut: "number,positivenumber"
- },
- negative: {
- name: "Negative",
- type: "shortcut",
- shortcut: "number,negativenumber"
- },
- integer: {
- name: "Integer",
- type: "regex",
- regex: "[+-]?\\d+",
- message: "No decimal places allowed"
- },
- positivenumber: {
- name: "Positivenumber",
- type: "min",
- min: 0,
- message: "Must be a positive number"
- },
- negativenumber: {
- name: "Negativenumber",
- type: "max",
- max: 0,
- message: "Must be a negative number"
- },
- required: {
- name: "Required",
- type: "required",
- message: "This is required"
- },
- checkone: {
- name: "Checkone",
- type: "minchecked",
- minchecked: 1,
- message: "Check at least one option"
- },
- number: {
- name: "Number",
- type: "number",
- decimal: ".",
- step: "1"
- },
- pattern: {
- name: "Pattern",
- type: "regex",
- message: "Not in expected format"
- }
- }
- };
-
- var formatValidatorName = function (name) {
- return name
- .toLowerCase()
- .replace(
- /(^|\s)([a-z])/g ,
- function(m,p1,p2) {
- return p1+p2.toUpperCase();
- }
- )
- ;
- };
-
- var getValue = function ($this) {
- // Extract the value we're talking about
- var value = null;
- var type = $this.attr("type");
- if (type === "checkbox") {
- value = ($this.is(":checked") ? value : "");
- var checkboxParent = $this.parents("form").first() || $this.parents(".control-group").first();
- if (checkboxParent) {
- value = checkboxParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) { return $(el).val(); }).toArray().join(",");
- }
- }
- else if (type === "radio") {
- value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? $this.val() : "");
- var radioParent = $this.parents("form").first() || $this.parents(".control-group").first();
- if (radioParent) {
- value = radioParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) { return $(el).val(); }).toArray().join(",");
- }
- }
- else {
- value = $this.val();
+ builtInValidators: {
+ email: {
+ name: "Email",
+ type: "email"
+ },
+ passwordagain: {
+ name: "Passwordagain",
+ type: "match",
+ match: "password",
+ message: "Does not match the given password"
+ },
+ positive: {
+ name: "Positive",
+ type: "shortcut",
+ shortcut: "number,positivenumber"
+ },
+ negative: {
+ name: "Negative",
+ type: "shortcut",
+ shortcut: "number,negativenumber"
+ },
+ integer: {
+ name: "Integer",
+ type: "regex",
+ regex: "[+-]?\\d+",
+ message: "No decimal places allowed"
+ },
+ positivenumber: {
+ name: "Positivenumber",
+ type: "min",
+ min: 0,
+ message: "Must be a positive number"
+ },
+ negativenumber: {
+ name: "Negativenumber",
+ type: "max",
+ max: 0,
+ message: "Must be a negative number"
+ },
+ required: {
+ name: "Required",
+ type: "required",
+ message: "This is required"
+ },
+ checkone: {
+ name: "Checkone",
+ type: "minchecked",
+ minchecked: 1,
+ message: "Check at least one option"
+ },
+ number: {
+ name: "Number",
+ type: "number",
+ decimal: ".",
+ step: "1"
+ },
+ pattern: {
+ name: "Pattern",
+ type: "regex",
+ message: "Not in expected format"
+ }
+ }
+ };
+
+ var formatValidatorName = function (name) {
+ return name
+ .toLowerCase()
+ .replace(
+ /(^|\s)([a-z])/g,
+ function (m, p1, p2) {
+ return p1 + p2.toUpperCase();
+ }
+ )
+ ;
+ };
+
+ var getValue = function ($this) {
+ // Extract the value we're talking about
+ var value = null;
+ var type = $this.attr("type");
+ if (type === "checkbox") {
+ value = ($this.is(":checked") ? value : "");
+ var checkboxParent = $this.parents("form").first() || $this.parents(".form-group").first();
+ if (checkboxParent) {
+ value = checkboxParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) {
+ return $(el).val();
+ }).toArray().join(",");
+ }
+ }
+ else if (type === "radio") {
+ value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? $this.val() : "");
+ var radioParent = $this.parents("form").first() || $this.parents(".form-group").first();
+ if (radioParent) {
+ value = radioParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) {
+ return $(el).val();
+ }).toArray().join(",");
+ }
+ } else if (type === "number") {
+ if ($this[0].validity.valid) {
+ value = $this.val();
+ } else {
+ if ($this[0].validity.badInput || $this[0].validity.stepMismatch) {
+ value = "NaN";
+ } else {
+ value = "";
+ }
+ }
+ } else {
+ value = $this.val();
+ }
+ return value;
+ };
+
+ function regexFromString(inputstring) {
+ return new RegExp("^" + inputstring + "$");
}
- return value;
- };
-
- function regexFromString(inputstring) {
- return new RegExp("^" + inputstring + "$");
- }
-
- /**
- * Thanks to Jason Bunting / Alex Nazarov via StackOverflow.com
- *
- * http://stackoverflow.com/a/4351575
- **/
-function executeFunctionByName(functionName, context /*, args */) {
- var args = Array.prototype.slice.call(arguments, 2);
- var namespaces = functionName.split(".");
- var func = namespaces.pop();
- for (var i = 0; i < namespaces.length; i++) {
- context = context[namespaces[i]];
+
+ /**
+ * Thanks to Jason Bunting / Alex Nazarov via StackOverflow.com
+ *
+ * http://stackoverflow.com/a/4351575
+ **/
+ function executeFunctionByName(functionName, context /*, args */) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ var namespaces = functionName.split(".");
+ var func = namespaces.pop();
+ for (var i = 0; i < namespaces.length; i++) {
+ context = context[namespaces[i]];
+ }
+ return context[func].apply(context, args);
}
- return context[func].apply(context, args);
-}
-$.fn.jqBootstrapValidation = function( method ) {
+ $.fn.jqBootstrapValidation = function (method) {
- if ( defaults.methods[method] ) {
- return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
- } else if ( typeof method === 'object' || ! method ) {
- return defaults.methods.init.apply( this, arguments );
- } else {
- $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' );
- return null;
- }
+ if (defaults.methods[method]) {
+ return defaults.methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method) {
+ return defaults.methods.init.apply(this, arguments);
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.jqBootstrapValidation');
+ return null;
+ }
-};
+ };
- $.jqBootstrapValidation = function (options) {
- $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments);
- };
+ $.jqBootstrapValidation = function (options) {
+ $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this, arguments);
+ };
-})( jQuery );
\ No newline at end of file
+})(jQuery);
diff --git a/dist/jqBootstrapValidation-1.3.7.min.js b/dist/jqBootstrapValidation-1.3.7.min.js
index c5d5236..28c195b 100644
--- a/dist/jqBootstrapValidation-1.3.7.min.js
+++ b/dist/jqBootstrapValidation-1.3.7.min.js
@@ -1,4 +1,4 @@
-/*! jqBootstrapValidation - v1.3.7 - 2013-05-07
+/*! jqBootstrapValidation - v1.3.7 - 2014-08-15
* http://reactiveraven.github.com/jqBootstrapValidation
-* Copyright (c) 2013 David Godfrey; Licensed MIT */
-(function(e){function s(e){return new RegExp("^"+e+"$")}function o(e,t){var n=Array.prototype.slice.call(arguments,2),r=e.split("."),i=r.pop();for(var s=0;s0});u.trigger("submit.validation"),i.trigger("validationLostFocus.validation"),s.each(function(t,n){var i=e(n);if(i.hasClass("warning")||i.hasClass("error"))i.removeClass("warning").addClass("error"),r++}),r?(o.options.preventSubmit&&(t.preventDefault(),t.stopImmediatePropagation()),n.addClass("error"),e.isFunction(o.options.submitError)&&o.options.submitError(n,t,u.jqBootstrapValidation("collectErrors",!0))):(n.removeClass("error"),e.isFunction(o.options.submitSuccess)&&o.options.submitSuccess(n,t))}),this.each(function(){var n=e(this),s=n.parents(".control-group").first(),u=s.find(".help-block").first(),a=n.parents("form").first(),f=[];!u.length&&o.options.autoAdd&&o.options.autoAdd.helpBlocks&&(u=e(''),s.find(".controls").append(u),t.push(u[0]));if(o.options.sniffHtml){var l;n.data("validationPatternPattern")&&n.attr("pattern",n.data("validationPatternPattern")),n.attr("pattern")!==undefined&&(l="Not in the expected format",n.data("validationPatternMessage")&&(l=n.data("validationPatternMessage")),n.data("validationPatternMessage",l),n.data("validationPatternRegex",n.attr("pattern")));if(n.attr("max")!==undefined||n.attr("aria-valuemax")!==undefined){var c=n.attr("max")!==undefined?n.attr("max"):n.attr("aria-valuemax");l="Too high: Maximum of '"+c+"'",n.data("validationMaxMessage")&&(l=n.data("validationMaxMessage")),n.data("validationMaxMessage",l),n.data("validationMaxMax",c)}if(n.attr("min")!==undefined||n.attr("aria-valuemin")!==undefined){var h=n.attr("min")!==undefined?n.attr("min"):n.attr("aria-valuemin");l="Too low: Minimum of '"+h+"'",n.data("validationMinMessage")&&(l=n.data("validationMinMessage")),n.data("validationMinMessage",l),n.data("validationMinMin",h)}n.attr("maxlength")!==undefined&&(l="Too long: Maximum of '"+n.attr("maxlength")+"' characters",n.data("validationMaxlengthMessage")&&(l=n.data("validationMaxlengthMessage")),n.data("validationMaxlengthMessage",l),n.data("validationMaxlengthMaxlength",n.attr("maxlength"))),n.attr("minlength")!==undefined&&(l="Too short: Minimum of '"+n.attr("minlength")+"' characters",n.data("validationMinlengthMessage")&&(l=n.data("validationMinlengthMessage")),n.data("validationMinlengthMessage",l),n.data("validationMinlengthMinlength",n.attr("minlength")));if(n.attr("required")!==undefined||n.attr("aria-required")!==undefined)l=o.builtInValidators.required.message,n.data("validationRequiredMessage")&&(l=n.data("validationRequiredMessage")),n.data("validationRequiredMessage",l);if(n.attr("type")!==undefined&&n.attr("type").toLowerCase()==="number"){l=o.validatorTypes.number.message,n.data("validationNumberMessage")&&(l=n.data("validationNumberMessage")),n.data("validationNumberMessage",l);var p=o.validatorTypes.number.step;n.data("validationNumberStep")&&(p=n.data("validationNumberStep")),n.data("validationNumberStep",p);var d=o.validatorTypes.number.decimal;n.data("validationNumberDecimal")&&(d=n.data("validationNumberDecimal")),n.data("validationNumberDecimal",d)}n.attr("type")!==undefined&&n.attr("type").toLowerCase()==="email"&&(l="Not a valid email address",n.data("validationEmailMessage")&&(l=n.data("validationEmailMessage")),n.data("validationEmailMessage",l)),n.attr("minchecked")!==undefined&&(l="Not enough options checked; Minimum of '"+n.attr("minchecked")+"' required",n.data("validationMincheckedMessage")&&(l=n.data("validationMincheckedMessage")),n.data("validationMincheckedMessage",l),n.data("validationMincheckedMinchecked",n.attr("minchecked"))),n.attr("maxchecked")!==undefined&&(l="Too many options checked; Maximum of '"+n.attr("maxchecked")+"' required",n.data("validationMaxcheckedMessage")&&(l=n.data("validationMaxcheckedMessage")),n.data("validationMaxcheckedMessage",l),n.data("validationMaxcheckedMaxchecked",n.attr("maxchecked")))}n.data("validation")!==undefined&&(f=n.data("validation").split(",")),e.each(n.data(),function(e,t){var n=e.replace(/([A-Z])/g,",$1").split(",");n[0]==="validation"&&n[1]&&f.push(n[1])});var v=f,m=[],g=function(e,t){f[e]=r(t)},y=function(t,i){if(n.data("validation"+i+"Shortcut")!==undefined)e.each(n.data("validation"+i+"Shortcut").split(","),function(e,t){m.push(t)});else if(o.builtInValidators[i.toLowerCase()]){var s=o.builtInValidators[i.toLowerCase()];s.type.toLowerCase()==="shortcut"&&e.each(s.shortcut.split(","),function(e,t){t=r(t),m.push(t),f.push(t)})}};do e.each(f,g),f=e.unique(f),m=[],e.each(v,y),v=m;while(v.length>0);var b={};e.each(f,function(t,i){var s=n.data("validation"+i+"Message"),u=!!s,a=!1;s||(s="'"+i+"' validation failed "),e.each(o.validatorTypes,function(t,o){b[t]===undefined&&(b[t]=[]);if(!a&&n.data("validation"+i+r(o.name))!==undefined){var f=o.init(n,i);u&&(f.message=s),b[t].push(e.extend(!0,{name:r(o.name),message:s},f)),a=!0}});if(!a&&o.builtInValidators[i.toLowerCase()]){var f=e.extend(!0,{},o.builtInValidators[i.toLowerCase()]);u&&(f.message=s);var l=f.type.toLowerCase();l==="shortcut"?a=!0:e.each(o.validatorTypes,function(t,s){b[t]===undefined&&(b[t]=[]),!a&&l===t.toLowerCase()&&(n.data("validation"+i+r(s.name),f[s.name.toLowerCase()]),b[l].push(e.extend(f,s.init(n,i))),a=!0)})}a||e.error("Cannot find validation info for '"+i+"'")}),u.data("original-contents",u.data("original-contents")?u.data("original-contents"):u.html()),u.data("original-role",u.data("original-role")?u.data("original-role"):u.attr("role")),s.data("original-classes",s.data("original-clases")?s.data("original-classes"):s.attr("class")),n.data("original-aria-invalid",n.data("original-aria-invalid")?n.data("original-aria-invalid"):n.attr("aria-invalid")),n.bind("validation.validation",function(t,r){var s=i(n),u=[];return e.each(b,function(t,i){(s||s.length||r&&r.includeEmpty||!!o.validatorTypes[t].includeEmpty||!!o.validatorTypes[t].blockSubmit&&r&&!!r.submitting)&&e.each(i,function(e,r){o.validatorTypes[t].validate(n,s,r)&&u.push(r.message)})}),u}),n.bind("getValidators.validation",function(){return b});var w=0;e.each(b,function(e,t){w+=t.length}),n.bind("getValidatorCount.validation",function(){return w}),n.bind("submit.validation",function(){return n.triggerHandler("change.validation",{submitting:!0})}),n.bind((o.options.bindEvents.length>0?o.options.bindEvents:["keyup","focus","blur","click","keydown","keypress","change"]).concat(["revalidate"]).join(".validation ")+".validation",function(t,r){var f=i(n),l=[];r&&!!r.submitting?s.data("jqbvIsSubmitting",!0):t.type!=="revalidate"&&s.data("jqbvIsSubmitting",!1);var c=!!s.data("jqbvIsSubmitting");s.find("input,textarea,select").each(function(t,i){var s=l.length;e.each(e(i).triggerHandler("validation.validation",r),function(e,t){l.push(t)});if(l.length>s)e(i).attr("aria-invalid","true");else{var o=n.data("original-aria-invalid");e(i).attr("aria-invalid",o!==undefined?o:!1)}}),a.find("input,select,textarea").not(n).not('[name="'+n.attr("name")+'"]').trigger("validationLostFocus.validation"),l=e.unique(l.sort()),l.length?(s.removeClass("success error warning").addClass(c?"error":"warning"),o.options.semanticallyStrict&&l.length===1?u.html(l[0]+(o.options.prependExistingHelpBlock?u.data("original-contents"):"")):u.html('"+(o.options.prependExistingHelpBlock?u.data("original-contents"):""))):(s.removeClass("warning error success"),f.length>0&&s.addClass("success"),u.html(u.data("original-contents"))),t.type==="blur"&&s.removeClass("success")}),n.bind("validationLostFocus.validation",function(){s.removeClass("success")})})},destroy:function(){return this.each(function(){var n=e(this),r=n.parents(".control-group").first(),i=r.find(".help-block").first(),s=n.parents("form").first();n.unbind(".validation"),s.unbind(".validationSubmit"),i.html(i.data("original-contents")),r.attr("class",r.data("original-classes")),n.attr("aria-invalid",n.data("original-aria-invalid")),i.attr("role",n.data("original-role")),e.inArray(i[0],t)>-1&&i.remove()})},collectErrors:function(t){var n={};return this.each(function(t,r){var i=e(r),s=i.attr("name"),o=i.triggerHandler("validation.validation",{includeEmpty:!0});n[s]=e.extend(!0,o,n[s])}),e.each(n,function(e,t){t.length===0&&delete n[e]}),n},hasErrors:function(){var t=[];return this.find("input,select,textarea").add(this).each(function(n,r){t=t.concat(e(r).triggerHandler("getValidators.validation")?e(r).triggerHandler("validation.validation",{submitting:!0}):[])}),t.length>0},override:function(t){n=e.extend(!0,n,t)}},validatorTypes:{callback:{name:"callback",init:function(e,t){var n={validatorName:t,callback:e.data("validation"+t+"Callback"),lastValue:e.val(),lastValid:!0,lastFinished:!0},r="Not valid";return e.data("validation"+t+"Message")&&(r=e.data("validation"+t+"Message")),n.message=r,n},validate:function(e,t,n){if(n.lastValue===t&&n.lastFinished)return!n.lastValid;if(n.lastFinished===!0){n.lastValue=t,n.lastValid=!0,n.lastFinished=!1;var r=n,i=e;o(n.callback,window,e,t,function(t){r.lastValue===t.value&&(r.lastValid=t.valid,t.message&&(r.message=t.message),r.lastFinished=!0,i.data("validation"+r.validatorName+"Message",r.message),setTimeout(function(){!e.is(":focus")&&e.parents("form").first().data("jqbvIsSubmitting")?i.trigger("blur.validation"):i.trigger("revalidate.validation")},1))})}return!1}},ajax:{name:"ajax",init:function(e,t){return{validatorName:t,url:e.data("validation"+t+"Ajax"),lastValue:e.val(),lastValid:!0,lastFinished:!0}},validate:function(t,n,r){return""+r.lastValue==""+n&&r.lastFinished===!0?r.lastValid===!1:(r.lastFinished===!0&&(r.lastValue=n,r.lastValid=!0,r.lastFinished=!1,e.ajax({url:r.url,data:"value="+encodeURIComponent(n)+"&field="+t.attr("name"),dataType:"json",success:function(e){""+r.lastValue==""+e.value&&(r.lastValid=!!e.valid,e.message&&(r.message=e.message),r.lastFinished=!0,t.data("validation"+r.validatorName+"Message",r.message),setTimeout(function(){t.trigger("revalidate.validation")},1))},failure:function(){r.lastValid=!0,r.message="ajax call failed",r.lastFinished=!0,t.data("validation"+r.validatorName+"Message",r.message),setTimeout(function(){t.trigger("revalidate.validation")},1)}})),!1)}},regex:{name:"regex",init:function(t,n){var r={},i=t.data("validation"+n+"Regex");r.regex=s(i),i===undefined&&e.error("Can't find regex for '"+n+"' validator on '"+t.attr("name")+"'");var o="Not in the expected format";return t.data("validation"+n+"Message")&&(o=t.data("validation"+n+"Message")),r.message=o,r.originalName=n,r},validate:function(e,t,n){return!n.regex.test(t)&&!n.negative||n.regex.test(t)&&n.negative}},email:{name:"email",init:function(e,t){var n={};n.regex=s("[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}");var r="Not a valid email address";return e.data("validation"+t+"Message")&&(r=e.data("validation"+t+"Message")),n.message=r,n.originalName=t,n},validate:function(e,t,n){return!n.regex.test(t)&&!n.negative||n.regex.test(t)&&n.negative}},required:{name:"required",init:function(e,t){var n="This is required";return e.data("validation"+t+"Message")&&(n=e.data("validation"+t+"Message")),{message:n,includeEmpty:!0}},validate:function(e,t,n){return!!(t.length===0&&!n.negative||t.length>0&&n.negative)},blockSubmit:!0},match:{name:"match",init:function(t,n){var r=t.data("validation"+n+"Match"),i=t.parents("form").first(),s=i.find('[name="'+r+'"]').first();s.bind("validation.validation",function(){t.trigger("revalidate.validation",{submitting:!0})});var o={};o.element=s,s.length===0&&e.error("Can't find field '"+r+"' to match '"+t.attr("name")+"' against in '"+n+"' validator");var u="Must match",a=null;return(a=i.find('label[for="'+r+'"]')).length?u+=" '"+a.text()+"'":(a=s.parents(".control-group").first().find("label")).length&&(u+=" '"+a.first().text()+"'"),t.data("validation"+n+"Message")&&(u=t.data("validation"+n+"Message")),o.message=u,o},validate:function(e,t,n){return t!==n.element.val()&&!n.negative||t===n.element.val()&&n.negative},blockSubmit:!0,includeEmpty:!0},max:{name:"max",init:function(e,t){var n={};return n.max=e.data("validation"+t+"Max"),n.message="Too high: Maximum of '"+n.max+"'",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return parseFloat(t,10)>parseFloat(n.max,10)&&!n.negative||parseFloat(t,10)<=parseFloat(n.max,10)&&n.negative}},min:{name:"min",init:function(e,t){var n={};return n.min=e.data("validation"+t+"Min"),n.message="Too low: Minimum of '"+n.min+"'",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return parseFloat(t)=parseFloat(n.min)&&n.negative}},maxlength:{name:"maxlength",init:function(e,t){var n={};return n.maxlength=e.data("validation"+t+"Maxlength"),n.message="Too long: Maximum of '"+n.maxlength+"' characters",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return t.length>n.maxlength&&!n.negative||t.length<=n.maxlength&&n.negative}},minlength:{name:"minlength",init:function(e,t){var n={};return n.minlength=e.data("validation"+t+"Minlength"),n.message="Too short: Minimum of '"+n.minlength+"' characters",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return t.length=n.minlength&&n.negative}},maxchecked:{name:"maxchecked",init:function(e,t){var n={},r=e.parents("form").first().find('[name="'+e.attr("name")+'"]');r.bind("change.validation click.validation",function(){e.trigger("revalidate.validation",{includeEmpty:!0})}),n.elements=r,n.maxchecked=e.data("validation"+t+"Maxchecked");var i="Too many: Max '"+n.maxchecked+"' checked";return e.data("validation"+t+"Message")&&(i=e.data("validation"+t+"Message")),n.message=i,n},validate:function(e,t,n){return n.elements.filter(":checked").length>n.maxchecked&&!n.negative||n.elements.filter(":checked").length<=n.maxchecked&&n.negative},blockSubmit:!0},minchecked:{name:"minchecked",init:function(e,t){var n={},r=e.parents("form").first().find('[name="'+e.attr("name")+'"]');r.bind("change.validation click.validation",function(){e.trigger("revalidate.validation",{includeEmpty:!0})}),n.elements=r,n.minchecked=e.data("validation"+t+"Minchecked");var i="Too few: Min '"+n.minchecked+"' checked";return e.data("validation"+t+"Message")&&(i=e.data("validation"+t+"Message")),n.message=i,n},validate:function(e,t,n){return n.elements.filter(":checked").length=n.minchecked&&n.negative},blockSubmit:!0,includeEmpty:!0},number:{name:"number",init:function(e,t){var n={};n.step=1,e.attr("step")&&(n.step=e.attr("step")),e.data("validation"+t+"Step")&&(n.step=e.data("validation"+t+"Step")),n.decimal=".",e.data("validation"+t+"Decimal")&&(n.decimal=e.data("validation"+t+"Decimal")),n.thousands="",e.data("validation"+t+"Thousands")&&(n.thousands=e.data("validation"+t+"Thousands")),n.regex=s("([+-]?\\d+(\\"+n.decimal+"\\d+)?)?"),n.message="Must be a number";var r=e.data("validation"+t+"Message");return r&&(n.message=r),n},validate:function(e,t,n){var r=t.replace(n.decimal,".").replace(n.thousands,""),i=parseFloat(r),s=parseFloat(n.step);while(s%1!==0)s=parseFloat(s.toPrecision(12))*10,i=parseFloat(i.toPrecision(12))*10;var o=n.regex.test(t),u=parseFloat(i)%parseFloat(s)===0,a=!isNaN(parseFloat(r))&&isFinite(r),f=!(o&&u&&a);return f},message:"Must be a number"}},builtInValidators:{email:{name:"Email",type:"email"},passwordagain:{name:"Passwordagain",type:"match",match:"password",message:"Does not match the given password"},positive:{name:"Positive",type:"shortcut",shortcut:"number,positivenumber"},negative:{name:"Negative",type:"shortcut",shortcut:"number,negativenumber"},integer:{name:"Integer",type:"regex",regex:"[+-]?\\d+",message:"No decimal places allowed"},positivenumber:{name:"Positivenumber",type:"min",min:0,message:"Must be a positive number"},negativenumber:{name:"Negativenumber",type:"max",max:0,message:"Must be a negative number"},required:{name:"Required",type:"required",message:"This is required"},checkone:{name:"Checkone",type:"minchecked",minchecked:1,message:"Check at least one option"},number:{name:"Number",type:"number",decimal:".",step:"1"},pattern:{name:"Pattern",type:"regex",message:"Not in expected format"}}},r=function(e){return e.toLowerCase().replace(/(^|\s)([a-z])/g,function(e,t,n){return t+n.toUpperCase()})},i=function(t){var n=null,r=t.attr("type");if(r==="checkbox"){n=t.is(":checked")?n:"";var i=t.parents("form").first()||t.parents(".control-group").first();i&&(n=i.find("input[name='"+t.attr("name")+"']:checked").map(function(t,n){return e(n).val()}).toArray().join(","))}else if(r==="radio"){n=e('input[name="'+t.attr("name")+'"]:checked').length>0?t.val():"";var s=t.parents("form").first()||t.parents(".control-group").first();s&&(n=s.find("input[name='"+t.attr("name")+"']:checked").map(function(t,n){return e(n).val()}).toArray().join(","))}else n=t.val();return n};e.fn.jqBootstrapValidation=function(t){return n.methods[t]?n.methods[t].apply(this,Array.prototype.slice.call(arguments,1)):typeof t=="object"||!t?n.methods.init.apply(this,arguments):(e.error("Method "+t+" does not exist on jQuery.jqBootstrapValidation"),null)},e.jqBootstrapValidation=function(t){e(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments)}})(jQuery);
\ No newline at end of file
+* Copyright (c) 2014 David Godfrey; Licensed MIT */
+!function(a){function b(a){return new RegExp("^"+a+"$")}function c(a,b){for(var c=Array.prototype.slice.call(arguments,2),d=a.split("."),e=d.pop(),f=0;f0});h.trigger("submit.validation"),f.trigger("validationLostFocus.validation"),g.each(function(b,c){var d=a(c);(d.hasClass("warning")||d.hasClass("error"))&&(d.removeClass("warning").addClass("error"),e++)}),e?(c.options.preventSubmit&&(b.preventDefault(),b.stopImmediatePropagation()),d.addClass("error"),a.isFunction(c.options.submitError)&&c.options.submitError(d,b,h.jqBootstrapValidation("collectErrors",!0))):(d.removeClass("error"),a.isFunction(c.options.submitSuccess)&&c.options.submitSuccess(d,b))}),this.each(function(){var b=a(this),e=b.parents(".form-group").first(),h=e.find(".help-block").first(),i=b.parents("form").first(),j=[];if(!h.length&&c.options.autoAdd&&c.options.autoAdd.helpBlocks&&(h=a(''),e.find(".controls").append(h),d.push(h[0])),c.options.sniffHtml){var k;if(b.data("validationPatternPattern")&&b.attr("pattern",b.data("validationPatternPattern")),void 0!==b.attr("pattern")&&(k="Not in the expected format",b.data("validationPatternMessage")&&(k=b.data("validationPatternMessage")),b.data("validationPatternMessage",k),b.data("validationPatternRegex",b.attr("pattern"))),void 0!==b.attr("max")||void 0!==b.attr("aria-valuemax")){var l=b.attr(void 0!==b.attr("max")?"max":"aria-valuemax");k="Too high: Maximum of '"+l+"'",b.data("validationMaxMessage")&&(k=b.data("validationMaxMessage")),b.data("validationMaxMessage",k),b.data("validationMaxMax",l)}if(void 0!==b.attr("min")||void 0!==b.attr("aria-valuemin")){var m=b.attr(void 0!==b.attr("min")?"min":"aria-valuemin");k="Too low: Minimum of '"+m+"'",b.data("validationMinMessage")&&(k=b.data("validationMinMessage")),b.data("validationMinMessage",k),b.data("validationMinMin",m)}if(void 0!==b.attr("maxlength")&&(k="Too long: Maximum of '"+b.attr("maxlength")+"' characters",b.data("validationMaxlengthMessage")&&(k=b.data("validationMaxlengthMessage")),b.data("validationMaxlengthMessage",k),b.data("validationMaxlengthMaxlength",b.attr("maxlength"))),void 0!==b.attr("minlength")&&(k="Too short: Minimum of '"+b.attr("minlength")+"' characters",b.data("validationMinlengthMessage")&&(k=b.data("validationMinlengthMessage")),b.data("validationMinlengthMessage",k),b.data("validationMinlengthMinlength",b.attr("minlength"))),(void 0!==b.attr("required")||void 0!==b.attr("aria-required"))&&(k=c.builtInValidators.required.message,b.data("validationRequiredMessage")&&(k=b.data("validationRequiredMessage")),b.data("validationRequiredMessage",k)),void 0!==b.attr("type")&&"number"===b.attr("type").toLowerCase()){k=c.validatorTypes.number.message,b.data("validationNumberMessage")&&(k=b.data("validationNumberMessage")),b.data("validationNumberMessage",k);var n=c.validatorTypes.number.step;b.data("validationNumberStep")&&(n=b.data("validationNumberStep")),b.data("validationNumberStep",n);var o=c.validatorTypes.number.decimal;b.data("validationNumberDecimal")&&(o=b.data("validationNumberDecimal")),b.data("validationNumberDecimal",o)}void 0!==b.attr("type")&&"email"===b.attr("type").toLowerCase()&&(k="Not a valid email address",b.data("validationEmailMessage")&&(k=b.data("validationEmailMessage")),b.data("validationEmailMessage",k)),void 0!==b.attr("minchecked")&&(k="Not enough options checked; Minimum of '"+b.attr("minchecked")+"' required",b.data("validationMincheckedMessage")&&(k=b.data("validationMincheckedMessage")),b.data("validationMincheckedMessage",k),b.data("validationMincheckedMinchecked",b.attr("minchecked"))),void 0!==b.attr("maxchecked")&&(k="Too many options checked; Maximum of '"+b.attr("maxchecked")+"' required",b.data("validationMaxcheckedMessage")&&(k=b.data("validationMaxcheckedMessage")),b.data("validationMaxcheckedMessage",k),b.data("validationMaxcheckedMaxchecked",b.attr("maxchecked")))}void 0!==b.data("validation")&&(j=b.data("validation").split(",")),a.each(b.data(),function(a){var b=a.replace(/([A-Z])/g,",$1").split(",");"validation"===b[0]&&b[1]&&j.push(b[1])});var p=j,q=[],r=function(a,b){j[a]=f(b)},s=function(d,e){if(void 0!==b.data("validation"+e+"Shortcut"))a.each(b.data("validation"+e+"Shortcut").split(","),function(a,b){q.push(b)});else if(c.builtInValidators[e.toLowerCase()]){var g=c.builtInValidators[e.toLowerCase()];"shortcut"===g.type.toLowerCase()&&a.each(g.shortcut.split(","),function(a,b){b=f(b),q.push(b),j.push(b)})}};do a.each(j,r),j=a.unique(j),q=[],a.each(p,s),p=q;while(p.length>0);var t={};a.each(j,function(d,e){var g=b.data("validation"+e+"Message"),h=!!g,i=!1;if(g||(g="'"+e+"' validation failed "),a.each(c.validatorTypes,function(c,d){if(void 0===t[c]&&(t[c]=[]),!i&&void 0!==b.data("validation"+e+f(d.name))){var j=d.init(b,e);h&&(j.message=g),t[c].push(a.extend(!0,{name:f(d.name),message:g},j)),i=!0}}),!i&&c.builtInValidators[e.toLowerCase()]){var j=a.extend(!0,{},c.builtInValidators[e.toLowerCase()]);h&&(j.message=g);var k=j.type.toLowerCase();"shortcut"===k?i=!0:a.each(c.validatorTypes,function(c,d){void 0===t[c]&&(t[c]=[]),i||k!==c.toLowerCase()||(b.data("validation"+e+f(d.name),j[d.name.toLowerCase()]),t[k].push(a.extend(j,d.init(b,e))),i=!0)})}i||a.error("Cannot find validation info for '"+e+"'")}),h.data("original-contents",h.data("original-contents")?h.data("original-contents"):h.html()),h.data("original-role",h.data("original-role")?h.data("original-role"):h.attr("role")),e.data("original-classes",e.data("original-clases")?e.data("original-classes"):e.attr("class")),b.data("original-aria-invalid",b.data("original-aria-invalid")?b.data("original-aria-invalid"):b.attr("aria-invalid")),b.bind("validation.validation",function(d,e){var f=g(b),h=[];return a.each(t,function(d,g){(f||f.length||e&&e.includeEmpty||c.validatorTypes[d].includeEmpty||c.validatorTypes[d].blockSubmit&&e&&e.submitting)&&a.each(g,function(a,e){c.validatorTypes[d].validate(b,f,e)&&h.push(e.message)})}),h}),b.bind("getValidators.validation",function(){return t});var u=0;a.each(t,function(a,b){u+=b.length}),b.bind("getValidatorCount.validation",function(){return u}),b.bind("submit.validation",function(){return b.triggerHandler("change.validation",{submitting:!0})}),b.bind((c.options.bindEvents.length>0?c.options.bindEvents:["keyup","focus","blur","click","keydown","keypress","change"]).concat(["revalidate"]).join(".validation ")+".validation",function(d,f){var j=g(b),k=[];f&&f.submitting?e.data("jqbvIsSubmitting",!0):"revalidate"!==d.type&&e.data("jqbvIsSubmitting",!1);var l=!!e.data("jqbvIsSubmitting");e.find("input,textarea,select").not("[type=submit]").each(function(c,d){var e=k.length;if(a.each(a(d).triggerHandler("validation.validation",f)||[],function(a,b){k.push(b)}),k.length>e)a(d).attr("aria-invalid","true");else{var g=b.data("original-aria-invalid");a(d).attr("aria-invalid",void 0!==g?g:!1)}}),i.find("input,select,textarea").not(b).not('[name="'+b.attr("name")+'"]').trigger("validationLostFocus.validation"),k=a.unique(k.sort()),k.length?(e.removeClass("success error warning").addClass(l?"error":"warning"),h.html(c.options.semanticallyStrict&&1===k.length?k[0]+(c.options.prependExistingHelpBlock?h.data("original-contents"):""):'"+(c.options.prependExistingHelpBlock?h.data("original-contents"):""))):(e.removeClass("warning error success"),j.length>0&&e.addClass("success"),h.html(h.data("original-contents"))),"blur"===d.type&&c.options.removeSuccess&&e.removeClass("success")}),b.bind("validationLostFocus.validation",function(){c.options.removeSuccess&&e.removeClass("success")})})},destroy:function(){return this.each(function(){var b=a(this),c=b.parents(".form-group").first(),e=c.find(".help-block").first(),f=b.parents("form").first();b.unbind(".validation"),f.unbind(".validationSubmit"),e.html(e.data("original-contents")),c.attr("class",c.data("original-classes")),b.attr("aria-invalid",b.data("original-aria-invalid")),e.attr("role",b.data("original-role")),a.inArray(e[0],d)>-1&&e.remove()})},collectErrors:function(){var b={};return this.each(function(c,d){var e=a(d),f=e.attr("name"),g=e.triggerHandler("validation.validation",{includeEmpty:!0});b[f]=a.extend(!0,g,b[f])}),a.each(b,function(a,c){0===c.length&&delete b[a]}),b},hasErrors:function(){var b=[];return this.find("input,select,textarea").add(this).each(function(c,d){b=b.concat(a(d).triggerHandler("getValidators.validation")?a(d).triggerHandler("validation.validation",{submitting:!0}):[])}),b.length>0},override:function(b){e=a.extend(!0,e,b)}},validatorTypes:{callback:{name:"callback",init:function(a,b){var c={validatorName:b,callback:a.data("validation"+b+"Callback"),lastValue:a.val(),lastValid:!0,lastFinished:!0},d="Not valid";return a.data("validation"+b+"Message")&&(d=a.data("validation"+b+"Message")),c.message=d,c},validate:function(a,b,d){if(d.lastValue===b&&d.lastFinished)return!d.lastValid;if(d.lastFinished===!0){d.lastValue=b,d.lastValid=!0,d.lastFinished=!1;var e=d,f=a;c(d.callback,window,a,b,function(b){e.lastValue===b.value&&(e.lastValid=b.valid,b.message&&(e.message=b.message),e.lastFinished=!0,f.data("validation"+e.validatorName+"Message",e.message),setTimeout(function(){f.trigger(!a.is(":focus")&&a.parents("form").first().data("jqbvIsSubmitting")?"blur.validation":"revalidate.validation")},1))})}return!1}},ajax:{name:"ajax",init:function(a,b){return{validatorName:b,url:a.data("validation"+b+"Ajax"),lastValue:a.val(),lastValid:!0,lastFinished:!0}},validate:function(b,c,d){return""+d.lastValue==""+c&&d.lastFinished===!0?d.lastValid===!1:(d.lastFinished===!0&&(d.lastValue=c,d.lastValid=!0,d.lastFinished=!1,a.ajax({url:d.url,data:"value="+encodeURIComponent(c)+"&field="+b.attr("name"),dataType:"json",success:function(a){""+d.lastValue==""+a.value&&(d.lastValid=!!a.valid,a.message&&(d.message=a.message),d.lastFinished=!0,b.data("validation"+d.validatorName+"Message",d.message),setTimeout(function(){b.trigger("revalidate.validation")},1))},failure:function(){d.lastValid=!0,d.message="ajax call failed",d.lastFinished=!0,b.data("validation"+d.validatorName+"Message",d.message),setTimeout(function(){b.trigger("revalidate.validation")},1)}})),!1)}},regex:{name:"regex",init:function(c,d){var e={},f=c.data("validation"+d+"Regex");e.regex=b(f),void 0===f&&a.error("Can't find regex for '"+d+"' validator on '"+c.attr("name")+"'");var g="Not in the expected format";return c.data("validation"+d+"Message")&&(g=c.data("validation"+d+"Message")),e.message=g,e.originalName=d,e},validate:function(a,b,c){return!c.regex.test(b)&&!c.negative||c.regex.test(b)&&c.negative}},email:{name:"email",init:function(a,c){var d={};d.regex=b("[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}");var e="Not a valid email address";return a.data("validation"+c+"Message")&&(e=a.data("validation"+c+"Message")),d.message=e,d.originalName=c,d},validate:function(a,b,c){return!c.regex.test(b)&&!c.negative||c.regex.test(b)&&c.negative}},required:{name:"required",init:function(a,b){var c="This is required";return a.data("validation"+b+"Message")&&(c=a.data("validation"+b+"Message")),{message:c,includeEmpty:!0}},validate:function(a,b,c){return!!(0===b.length&&!c.negative||b.length>0&&c.negative)},blockSubmit:!0},match:{name:"match",init:function(b,c){var d=b.data("validation"+c+"Match"),e=b.parents("form").first(),f=e.find('[name="'+d+'"]').first();f.bind("validation.validation",function(){b.trigger("revalidate.validation",{submitting:!0})});var g={};g.element=f,0===f.length&&a.error("Can't find field '"+d+"' to match '"+b.attr("name")+"' against in '"+c+"' validator");var h="Must match",i=null;return(i=e.find('label[for="'+d+'"]')).length?h+=" '"+i.text()+"'":(i=f.parents(".form-group").first().find("label")).length&&(h+=" '"+i.first().text()+"'"),b.data("validation"+c+"Message")&&(h=b.data("validation"+c+"Message")),g.message=h,g},validate:function(a,b,c){return b!==c.element.val()&&!c.negative||b===c.element.val()&&c.negative},blockSubmit:!0,includeEmpty:!0},max:{name:"max",init:function(a,b){var c={};return c.max=a.data("validation"+b+"Max"),c.message="Too high: Maximum of '"+c.max+"'",a.data("validation"+b+"Message")&&(c.message=a.data("validation"+b+"Message")),c},validate:function(a,b,c){return parseFloat(b,10)>parseFloat(c.max,10)&&!c.negative||parseFloat(b,10)<=parseFloat(c.max,10)&&c.negative}},min:{name:"min",init:function(a,b){var c={};return c.min=a.data("validation"+b+"Min"),c.message="Too low: Minimum of '"+c.min+"'",a.data("validation"+b+"Message")&&(c.message=a.data("validation"+b+"Message")),c},validate:function(a,b,c){return parseFloat(b)=parseFloat(c.min)&&c.negative}},maxlength:{name:"maxlength",init:function(a,b){var c={};return c.maxlength=a.data("validation"+b+"Maxlength"),c.message="Too long: Maximum of '"+c.maxlength+"' characters",a.data("validation"+b+"Message")&&(c.message=a.data("validation"+b+"Message")),c},validate:function(a,b,c){return b.length>c.maxlength&&!c.negative||b.length<=c.maxlength&&c.negative}},minlength:{name:"minlength",init:function(a,b){var c={};return c.minlength=a.data("validation"+b+"Minlength"),c.message="Too short: Minimum of '"+c.minlength+"' characters",a.data("validation"+b+"Message")&&(c.message=a.data("validation"+b+"Message")),c},validate:function(a,b,c){return b.length=c.minlength&&c.negative}},maxchecked:{name:"maxchecked",init:function(a,b){var c={},d=a.parents("form").first().find('[name="'+a.attr("name")+'"]');d.bind("change.validation click.validation",function(){a.trigger("revalidate.validation",{includeEmpty:!0})}),c.elements=d,c.maxchecked=a.data("validation"+b+"Maxchecked");var e="Too many: Max '"+c.maxchecked+"' checked";return a.data("validation"+b+"Message")&&(e=a.data("validation"+b+"Message")),c.message=e,c},validate:function(a,b,c){return c.elements.filter(":checked").length>c.maxchecked&&!c.negative||c.elements.filter(":checked").length<=c.maxchecked&&c.negative},blockSubmit:!0},minchecked:{name:"minchecked",init:function(a,b){var c={},d=a.parents("form").first().find('[name="'+a.attr("name")+'"]');d.bind("change.validation click.validation",function(){a.trigger("revalidate.validation",{includeEmpty:!0})}),c.elements=d,c.minchecked=a.data("validation"+b+"Minchecked");var e="Too few: Min '"+c.minchecked+"' checked";return a.data("validation"+b+"Message")&&(e=a.data("validation"+b+"Message")),c.message=e,c},validate:function(a,b,c){return c.elements.filter(":checked").length=c.minchecked&&c.negative},blockSubmit:!0,includeEmpty:!0},number:{name:"number",init:function(a,c){var d={};d.step=1,a.attr("step")&&(d.step=a.attr("step")),a.data("validation"+c+"Step")&&(d.step=a.data("validation"+c+"Step")),d.decimal=".",a.data("validation"+c+"Decimal")&&(d.decimal=a.data("validation"+c+"Decimal")),d.thousands="",a.data("validation"+c+"Thousands")&&(d.thousands=a.data("validation"+c+"Thousands")),d.regex=b("([+-]?\\d+(\\"+d.decimal+"\\d+)?)?"),d.message="Must be a number";var e=a.data("validation"+c+"Message");return e&&(d.message=e),d},validate:function(a,b,c){for(var d=b.replace(c.decimal,".").replace(c.thousands,""),e=parseFloat(d),f=parseFloat(c.step);f%1!==0;)f=10*parseFloat(f.toPrecision(12)),e=10*parseFloat(e.toPrecision(12));var g=c.regex.test(b),h=parseFloat(e)%parseFloat(f)===0,i=!isNaN(parseFloat(d))&&isFinite(d),j=!(g&&h&&i);return j},message:"Must be a number"}},builtInValidators:{email:{name:"Email",type:"email"},passwordagain:{name:"Passwordagain",type:"match",match:"password",message:"Does not match the given password"},positive:{name:"Positive",type:"shortcut",shortcut:"number,positivenumber"},negative:{name:"Negative",type:"shortcut",shortcut:"number,negativenumber"},integer:{name:"Integer",type:"regex",regex:"[+-]?\\d+",message:"No decimal places allowed"},positivenumber:{name:"Positivenumber",type:"min",min:0,message:"Must be a positive number"},negativenumber:{name:"Negativenumber",type:"max",max:0,message:"Must be a negative number"},required:{name:"Required",type:"required",message:"This is required"},checkone:{name:"Checkone",type:"minchecked",minchecked:1,message:"Check at least one option"},number:{name:"Number",type:"number",decimal:".",step:"1"},pattern:{name:"Pattern",type:"regex",message:"Not in expected format"}}},f=function(a){return a.toLowerCase().replace(/(^|\s)([a-z])/g,function(a,b,c){return b+c.toUpperCase()})},g=function(b){var c=null,d=b.attr("type");if("checkbox"===d){c=b.is(":checked")?c:"";var e=b.parents("form").first()||b.parents(".form-group").first();e&&(c=e.find("input[name='"+b.attr("name")+"']:checked").map(function(b,c){return a(c).val()}).toArray().join(","))}else if("radio"===d){c=a('input[name="'+b.attr("name")+'"]:checked').length>0?b.val():"";var f=b.parents("form").first()||b.parents(".form-group").first();f&&(c=f.find("input[name='"+b.attr("name")+"']:checked").map(function(b,c){return a(c).val()}).toArray().join(","))}else c="number"===d?b[0].validity.valid?b.val():b[0].validity.badInput||b[0].validity.stepMismatch?"NaN":"":b.val();return c};a.fn.jqBootstrapValidation=function(b){return e.methods[b]?e.methods[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?(a.error("Method "+b+" does not exist on jQuery.jqBootstrapValidation"),null):e.methods.init.apply(this,arguments)},a.jqBootstrapValidation=function(){a(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments)}}(jQuery);
\ No newline at end of file
diff --git a/dist/jqBootstrapValidation.zip b/dist/jqBootstrapValidation.zip
index 188aabe..3f2e84a 100644
Binary files a/dist/jqBootstrapValidation.zip and b/dist/jqBootstrapValidation.zip differ
diff --git a/src/jqBootstrapValidation.js b/src/jqBootstrapValidation.js
index 79f3048..0e3a503 100644
--- a/src/jqBootstrapValidation.js
+++ b/src/jqBootstrapValidation.js
@@ -41,7 +41,7 @@
var warningsFound = 0;
// Get all inputs
var $allInputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
- var $allControlGroups = $form.find(".control-group");
+ var $allControlGroups = $form.find(".form-group");
// Only trigger validation on the ones that actually _have_ validation
var $inputsWithValidators = $allInputs.filter(function () {
@@ -86,7 +86,7 @@
// Get references to everything we're interested in
var $this = $(this),
- $controlGroup = $this.parents(".control-group").first(),
+ $controlGroup = $this.parents(".form-group").first(),
$helpBlock = $controlGroup.find(".help-block").first(),
$form = $this.parents("form").first(),
validatorNames = [];
@@ -597,7 +597,7 @@
var
$this = $(this),
- $controlGroup = $this.parents(".control-group").first(),
+ $controlGroup = $this.parents(".form-group").first(),
$helpBlock = $controlGroup.find(".help-block").first(),
$form = $this.parents("form").first();
@@ -861,7 +861,7 @@
var $label = null;
if (($label = $form.find("label[for=\"" + elementName + "\"]")).length) {
message += " '" + $label.text() + "'";
- } else if (($label = $element.parents(".control-group").first().find("label")).length) {
+ } else if (($label = $element.parents(".form-group").first().find("label")).length) {
message += " '" + $label.first().text() + "'";
}
@@ -1143,7 +1143,7 @@
var type = $this.attr("type");
if (type === "checkbox") {
value = ($this.is(":checked") ? value : "");
- var checkboxParent = $this.parents("form").first() || $this.parents(".control-group").first();
+ var checkboxParent = $this.parents("form").first() || $this.parents(".form-group").first();
if (checkboxParent) {
value = checkboxParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) {
return $(el).val();
@@ -1152,7 +1152,7 @@
}
else if (type === "radio") {
value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? $this.val() : "");
- var radioParent = $this.parents("form").first() || $this.parents(".control-group").first();
+ var radioParent = $this.parents("form").first() || $this.parents(".form-group").first();
if (radioParent) {
value = radioParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) {
return $(el).val();
diff --git a/test/issues/39/test.js b/test/issues/39/test.js
index 8b17107..fda1f88 100644
--- a/test/issues/39/test.js
+++ b/test/issues/39/test.js
@@ -29,7 +29,7 @@
setup: function() {
$("#qunit-fixture").append("\