diff --git a/jquery.h5validate.js b/jquery.h5validate.js index b151b06..0efb9be 100644 --- a/jquery.h5validate.js +++ b/jquery.h5validate.js @@ -92,6 +92,9 @@ // Callback stubs invalidCallback: function () {}, validCallback: function () {}, + + // Array of Validator Functions. View the comment for addValidator for more information. + validators: [], // Elements to validate with allValid (only validating visible elements) allValidSelectors: ':input:visible:not(:button):not(:disabled):not(.novalidate)', @@ -139,7 +142,7 @@ $element.removeClass(options.errorClass).removeClass(options.validClass); $element.form.find("#" + options.element.id).removeClass(options.errorClass).removeClass(options.validClass); return $element; - } + }, } }, @@ -150,17 +153,75 @@ createValidity = function createValidity(validity) { return $.extend({ customError: validity.customError || false, - patternMismatch: validity.patternMismatch || false, + failedValidatorNames: [], rangeOverflow: validity.rangeOverflow || false, rangeUnderflow: validity.rangeUnderflow || false, stepMismatch: validity.stepMismatch || false, - tooLong: validity.tooLong || false, typeMismatch: validity.typeMismatch || false, valid: validity.valid || true, - valueMissing: validity.valueMissing || false }, validity); }, + /** + * Add builtin validators to h5Validate. Currently, this adds the following validators: + * Required + * Maxlength + * Pattern + * @param {object} settings instance settings + */ + addBuiltinValidators = function (settings) { + settings.validators.push({selector: "*", validator: function(value) { + var maxlength = parseInt($(this).attr('maxlength'), 10); + return isNaN(maxlength) || value.length <= maxlength; + }, options: { + validityFailureFlag: 'tooLong', + name: 'maxlength', + }}); + + settings.validators.push({selector: "*", validator: function(value) { + var required = false, + $checkRequired = $(''), + $this = $(this); + + /* If the required attribute exists, set it required to true, unless it's set 'false'. + * This is a minor deviation from the spec, but it seems some browsers have falsey + * required values if the attribute is empty (should be true). The more conformant + * version of this failed sanity checking in the browser environment. + * This plugin is meant to be practical, not ideologically married to the spec. + */ + if ($checkRequired.filter('[required]') && $checkRequired.filter('[required]').length) { + required = ($this.filter('[required]').length && $this.attr('required') !== 'false'); + } else { + required = ($this.attr('required') !== undefined); + } + + return !required || value; + }, options: { + validityFailureFlag: 'valueMissing', + name: 'required', + }}); + + settings.validators.push({selector: "*", validator: function(value) { + // Get the HTML5 pattern attribute if it exists. + // ** TODO: If a pattern class exists, grab the pattern from the patternLibrary, but the pattern attrib should override that value. + var $this = $(this), + pattern = $this.filter('[pattern]')[0] ? $this.attr('pattern') : false, + // The pattern attribute must match the whole value, not just a subset: + // "...as if it implied a ^(?: at the start of the pattern and a )$ at the end." + re = new RegExp('^(?:' + pattern + ')$'); + + if (settings.debug && window.console) { + console.log('Validate called on "' + value + '" with regex "' + re + '".'); // **DEBUG + console.log('Regex test: ' + re.test(value) + ', Pattern: ' + pattern); // **DEBUG + } + + return !pattern || re.test(value) || !value; + }, options: { + validityFailureFlag: 'patternMismatch', + name: 'pattern', + }}); + }, + methods = { /** * Check the validity of the current field @@ -231,14 +292,7 @@ return valid; }, validate: function (settings) { - // Get the HTML5 pattern attribute if it exists. - // ** TODO: If a pattern class exists, grab the pattern from the patternLibrary, but the pattern attrib should override that value. var $this = $(this), - pattern = $this.filter('[pattern]')[0] ? $this.attr('pattern') : false, - - // The pattern attribute must match the whole value, not just a subset: - // "...as if it implied a ^(?: at the start of the pattern and a )$ at the end." - re = new RegExp('^(?:' + pattern + ')$'), $radiosWithSameName = null, value = ($this.is('[type=checkbox]')) ? $this.is(':checked') : ($this.is('[type=radio]') ? @@ -252,66 +306,53 @@ validClass = settings.validClass, errorIDbare = $this.attr(settings.errorAttribute) || false, // Get the ID of the error element. errorID = errorIDbare ? '#' + errorIDbare.replace(/(:|\.|\[|\])/g,'\\$1') : false, // Add the hash for convenience. This is done in two steps to avoid two attribute lookups. - required = false, - validity = createValidity({element: this, valid: true}), - $checkRequired = $(''), - maxlength; - - /* If the required attribute exists, set it required to true, unless it's set 'false'. - * This is a minor deviation from the spec, but it seems some browsers have falsey - * required values if the attribute is empty (should be true). The more conformant - * version of this failed sanity checking in the browser environment. - * This plugin is meant to be practical, not ideologically married to the spec. - */ - // Feature fork - if ($checkRequired.filter('[required]') && $checkRequired.filter('[required]').length) { - required = ($this.filter('[required]').length && $this.attr('required') !== 'false'); - } else { - required = ($this.attr('required') !== undefined); - } - - if (settings.debug && window.console) { - console.log('Validate called on "' + value + '" with regex "' + re + '". Required: ' + required); // **DEBUG - console.log('Regex test: ' + re.test(value) + ', Pattern: ' + pattern); // **DEBUG - } - - maxlength = parseInt($this.attr('maxlength'), 10); - if (!isNaN(maxlength) && value.length > maxlength) { - validity.valid = false; - validity.tooLong = true; - } - - if (required && !value) { - validity.valid = false; - validity.valueMissing = true; - } else if (pattern && !re.test(value) && value) { - validity.valid = false; - validity.patternMismatch = true; - } else { - if (!settings.RODom) { - settings.markValid({ - element: this, - validity: validity, - errorClass: errorClass, - validClass: validClass, - errorID: errorID, - settings: settings - }); + validity = createValidity({element: this, valid: true}); + + // Iterate through the validators. If any fail, the field fails. + for (var i = 0;iHTMTL5 pattern attribute. e.g.

Hint: It's expecting mm/dd/yyyy. Try typing "jQuery rocks!" instead.

- +

HTMTL5 maxlength attribute. e.g.

+ +
+ + +

Pattern Library

@@ -259,6 +264,21 @@

Bypassing Validation tests (via 'formnovalidate')

+ +
+

Form Validation Tests

+
+ + + + + + +
+
+ +
+
diff --git a/test/test.h5validate.js b/test/test.h5validate.js index 8446eb4..4cf4947 100644 --- a/test/test.h5validate.js +++ b/test/test.h5validate.js @@ -9,6 +9,45 @@ ok((typeof $('
').h5Validate === 'function'), 'h5Validate exists'); }); + test('Required validation failure flag false by default:', function () { + var $form = $('
'), + $input = $('