diff --git a/dist/validatr.js b/dist/validatr.js index 4be8dd0..7910dc4 100644 --- a/dist/validatr.js +++ b/dist/validatr.js @@ -1,4 +1,4 @@ -/*! Validatr - v0.5.1 - 2013-03-12 +/*! Validatr - v0.5.1 - 2013-05-17 * http://jaymorrow.github.com/validatr/ * Copyright (c) 2013 Jay Morrow; Licensed MIT */ (function(window, document, $, undefined) { @@ -11,23 +11,23 @@ var Support = {}, - docElement = document.documentElement, + docElement = document.documentElement, - inputElem = document.createElement('input'), + inputElem = document.createElement('input'), - selectElem = document.createElement('select'), + selectElem = document.createElement('select'), - textareaElem = document.createElement('textarea'), + textareaElem = document.createElement('textarea'), - smile = ':)', + smile = ':)', - tests = {}, + tests = {}, - inputs = {}, + inputs = {}, - attrs = {}, + attrs = {}, - testElem; + testElem; Support.attributes = (function( props ) { for ( var i = 0, len = props.length; i < len; i++ ) { @@ -38,7 +38,7 @@ Support.inputtypes = (function(props) { - + for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { inputElem.setAttribute('type', inputElemType = props[i]); bool = inputElem.type !== 'text'; @@ -73,10 +73,10 @@ return inputs; })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); - (function(props) { + (function(props) { for ( var i = 0, len = props.length; i < len; i++ ) { testElem = inputElem; - + try { testElem.setAttribute('type', props[i]); } catch (e) { @@ -99,26 +99,74 @@ return Support; }()), + /* + * Really simple date/time logic + * Mostly taken from moment.js version : 2.0.0 + * author : Tim Wood + * license : MIT + * momentjs.com + */ Format = (function () { - var rules = { - isoDate: /^(\d{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/ - }, + var tokens = /(d?d|w?w|m?m|(?:yy)?yy|M?M)/g, - utils = { - separators: /(\/|\-|\.)/g, - separatorsNoGroup: /\/|\-|\./g, - dateParts: { - dd: '(0[1-9]|[12][0-9]|3[01])', - mm: '(0[1-9]|1[012])', - yyyy: '(\\d{4})' + tokenOneTwo = /\d{1,2}/, + tokenTwo = /\d{2}/, + tokenFour = /\d{4}/, + + _monthFullNames = 'January|February|March|April|May|June|July|August|September|October|November|December', + _monthShortNames = 'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec', + + monthFullNames = new RegExp(_monthFullNames, 'i'), + monthShortNames = new RegExp(_monthShortNames, 'i'), + + fullMonths = _monthFullNames.toLowerCase().split('|'), + shortMonths = _monthShortNames.toLowerCase().split('|'), + + formatParts = { + d: function () { + return this.getDate(); + }, + dd: function () { + return pad(this.getDate()); + }, + w: function () { + return getWeek(this); + }, + ww: function () { + return pad(getWeek(this)); + }, + m: function () { + return this.getMonth() + 1; + }, + mm: function () { + return pad(this.getMonth() + 1); + }, + yy: function () { + return this.getFullYear().toString().substr(2); + }, + yyyy: function () { + return this.getFullYear(); + }, + M: function () { + return proper(shortMonths[this.getMonth()]); + }, + MM: function () { + return proper(fullMonths[this.getMonth()]); } }; + function proper(m) { + return m.substr(0,1).toUpperCase() + m.substr(1); + } + + function pad(n) { + return n < 10 ? '0' + n : n; + } + function indexOf(array, value) { var index = -1, length = array ? array.length : 0; - while (++index < length) { if (array[index] === value) { return index; @@ -128,58 +176,163 @@ return -1; } + function getParts(token) { + switch(token) { + case 'd' : + case 'w' : + case 'm' : + return tokenOneTwo; + case 'dd': + case 'ww': + case 'mm': + case 'yy': + return tokenTwo; + case 'M': + return monthShortNames; + case 'MM': + return monthFullNames; + case 'yyyy': + return tokenFour; + } + } + + function createDateArray(token, input, dateArray) { + if (input === undefined) { + return; + } - function parseDate(element) { - var format = element.getAttribute('data-format') || $.fn.validatr.defaultOptions.dateFormat, - split = format.split(utils.separatorsNoGroup), - dateSplit = element.value.split(utils.separatorsNoGroup), - isoSplit = 'yyyy-mm-dd'.split('-'), - rule = format.replace(utils.separators, '\\$1') - .replace('yyyy', utils.dateParts.yyyy) - .replace('mm', utils.dateParts.mm) - .replace('dd', utils.dateParts.dd), - index = -1, - length = isoSplit.length, - iso = []; - - rule = new RegExp(rule); - if (!rule.test(element.value)) { - return false; + switch(token) { + case 'd' : + case 'dd': + dateArray[2] = ~~input; + break; + case 'w' : + case 'ww': + dateArray[3] = ~~input; + break; + case 'm' : + case 'mm': + dateArray[1] = ~~input - 1; + break; + case 'M': + dateArray[1] = indexOf(shortMonths, input.toLowerCase()); + break; + case 'MM': + dateArray[1] = indexOf(fullMonths, input.toLowerCase()); + break; + case 'yy' : + dateArray[0] = ~~('20' + input); + break; + case 'yyyy': + dateArray[0] = ~~input; + break; } + } - while (++index < length) { - iso[index] = dateSplit[ indexOf(split, isoSplit[index]) ]; + function getWeek(date) { + var first = new Date(date.getFullYear(), 0, 1, 0, 0, 0); + + return Math.ceil((((date - first) / 86400000) + first.getDay() + 1) / 7); + } + + function createDateFromWeek(dateArray) { + var date = dayOfWeek(dateArray[0]), + weekTime = 1000 * 60 * 60 * 24 * 7 * (dateArray[3] - 1), + targetTime = date.getTime() + weekTime - (86400000 * (date.getDay() - $.fn.validatr.defaultOptions.weekStart)), + result = new Date(targetTime); + result.setHours(0); + + return result; + } + + function dayOfWeek(year) { + var date = new Date(year, 0, 1, 0, 0, 0), + day = ($.fn.validatr.defaultOptions.yearStart - date.getDay()) + date.getDate(); + + date.setDate(day); + return date; + } + + function createDate(dateArray) { + var i = 0, + date = [], + isNum = false; + + for (i; i < 7; i += 1) { + isNum = typeof dateArray[i] === 'number'; + + if (!isNum && i < 2) { + return false; + } + + date[i] = !isNum ? (i === 2 ? 1 : 0) : dateArray[i]; } - - return parseISODate(iso.join('-')); + + return new Date(date[0], date[1], date[2], date[3], date[4], date[5], date[6]); } - function parseISODate(dateString) { - if (!rules.isoDate.test(dateString)) { - return false; + function parseDate(string, format) { + var parts = format.match(tokens) || [], + dateArray = [], + length = parts.length, + i = 0, + input; + + if (!length) { + throw new Error('Ivalid date format.'); + } + for (i; i < length; i += 1) { + input = (getParts(parts[i]).exec(string) || [])[0]; + + if (!input) { + continue; + } + + string = string.slice(string.indexOf(input) + input.length); + createDateArray(parts[i], input, dateArray); } - var date = rules.isoDate.exec(dateString); - return new Date(parseInt(date[1], 10), parseInt(date[2], 10) - 1, parseInt(date[3], 10)); + if (/w?w/.test(format)) { + return createDateFromWeek(dateArray); + } + + if (dateArray.length && dateArray.length === length) { + return createDate(dateArray); + } } - function formatISODate(dateObj, element) { - function pad(n) { - return n < 10 ? '0' + n : n; + function formatDate(dateObj, format) { + if (dateObj === false) { + return false; } - var date = pad(dateObj.getDate()), - month = pad(dateObj.getMonth() + 1), - year = dateObj.getFullYear(), - dateString = (element.getAttribute('data-format') || $.fn.validatr.defaultOptions.dateFormat).replace('mm', month).replace('yyyy', year).replace('dd', date); + if (format === undefined) { + format = 'yyyy-mm-dd'; + } + + var parts = format.match(tokens) || [], + length = parts.length, + i = 0; - return dateString; + if (!length) { + throw new Error('Ivalid date format.'); + } + + for (i; i < length; i += 1) { + if ( formatParts[ parts[i] ]) { + format = format.replace(parts[i], formatParts[ parts[i] ].call(dateObj)); + } + } + + return format; } return { - formatISODate: formatISODate, - parseDate: parseDate, - parseISODate: parseISODate + date: parseDate, + isoDate: function (string) { + return parseDate(string, 'yyyy-mm-dd'); + }, + toString: formatDate }; }()), @@ -187,9 +340,7 @@ var rules = { color: /^#[0-9A-F]{6}$/i, email: /^[a-zA-Z0-9.!#$%&’*+\/=?\^_`{|}~\-]+@[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*$/, - isoDate: /^(\d{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/, number: /^-?\d*\.?\d*$/, - time: /^([01][0-9]|2[0-3])(:([0-5][0-9])){2}$/, url: /^\s*https?:\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?\s*$/ }, @@ -198,16 +349,9 @@ spaces: /,\s*/ }, - minMax = function (value, min, max, step, type) { + minMax = function (value, min, max, step) { var result = true, - msg = $.validatr.messages.range.base, - minString = min, - maxString = max; - - if (type === 'date') { - minString = min && Format.formatISODate(min, this); - maxString = max && Format.formatISODate(max, this); - } + msg = $.validatr.messages.range.base; if (value !== false) { if (step !== false) { @@ -225,14 +369,33 @@ } else if (max !== false) { result = value <= max; msg = $.validatr.messages.range.underflow; - } + } } } return { valid: value !== false && result, - message: msg.replace('{{type}}', type).replace('{{min}}', minString).replace('{{max}}', maxString) - }; + message: msg + }; + }, + + getFormat = function (element, type) { + type += 'Format'; + return element.getAttribute('data-format') || ( $.data(element.form, 'validatr').options[type] || $.fn.validatr.defaultOptions[type] ); + }, + + formatMessage = function (message, type, min, max) { + message = message.replace('{{type}}', type); + + if (min) { + message = message.replace('{{min}}', min); + } + + if (max) { + message = message.replace('{{max}}', max); + } + + return message; }; return { @@ -252,12 +415,17 @@ date: function (element) { var $element = $(element), - value = Support.inputtypes.date ? Format.parseISODate(element.value) : Format.parseDate(element), - min = $element.attr('min') ? Format.parseISODate($element.attr('min')) : false, - max = $element.attr('max') ? Format.parseISODate($element.attr('max')) : false, - step = false; - - return minMax.call(element, value, min, max, step, 'date'); + format = getFormat(element, 'date'), + value = Format.date(element.value, format) || false, + min = $element.attr('min') ? Format.isoDate($element.attr('min')) : false, + max = $element.attr('max') ? Format.isoDate($element.attr('max')) : false, + step = false, + result = minMax(value, min, max, step); + + if (!result.valid) { + result.message = formatMessage(result.message, 'date', Format.toString(min, format), Format.toString(max, format)); + } + return result; }, email: function (element) { @@ -285,18 +453,39 @@ }; }, + month: function (element) { + var $element = $(element), + format = getFormat(element, 'month'), + value = Format.date(element.value, format) || false, + min = $element.attr('min') ? Format.isoDate($element.attr('min') + '01') : false, + max = $element.attr('max') ? Format.isoDate($element.attr('max') + '01') : false, + step = false, + result = minMax(value, min, max, step); + + if (!result.valid) { + result.message = formatMessage(result.message, 'month', Format.toString(min, format), Format.toString(max, format)); + } + return result; + }, + number: function (element) { var value = element.value.replace(',', ''), num = rules.number.test(value) ? parseFloat(value) : false, min = rules.number.test( element.getAttribute('min') ) ? parseFloat( element.getAttribute('min') ) : false, max = rules.number.test( element.getAttribute('max') ) ? parseFloat( element.getAttribute('max') ) : false, - step = rules.number.test( element.getAttribute('step') ) ? parseFloat( element.getAttribute('step') ) : element.getAttribute('step') === 'any' ? 'any' : false; - + step = rules.number.test( element.getAttribute('step') ) ? parseFloat( element.getAttribute('step') ) : element.getAttribute('step') === 'any' ? 'any' : false, + result; + if (step === false || step <= 0) { step = 1; } - return minMax.call(element, value, min, max, step, 'number'); + result = minMax(value, min, max, step, 'number'); + + if (!result.valid) { + result.message = formatMessage(result.message, 'number', min, max); + } + return result; }, pattern: function (element) { @@ -308,7 +497,7 @@ radio: function (element) { return { - valid: $(document.getElementsByName(element.name)).is(':checked'), + valid: $(element).closest('form').find('[name=' + element.name + ']' ).is(':checked'), message: $.validatr.messages.radio }; }, @@ -328,13 +517,6 @@ }; }, - time: function (element) { - return { - valid: rules.time.test(element.value), - message: $.validatr.messages.time - }; - }, - url: function (element) { return { valid: rules.url.test(element.value), @@ -504,7 +686,7 @@ this.template = (function (options) { var template = $(options.template).addClass('validatr-message'); - + if (options.theme.length) { template.addClass(theme[options.theme] || options.theme); } else { @@ -540,7 +722,7 @@ this.formElements.on({ 'focus.validatrelement': bindEvents, - 'blur.validatrelement': unbindEvents + 'blur.validatrelement': unbindEvents }); $('input[type=radio], input[type=checkbox]').on('click.validatrelement', function (e) { @@ -561,19 +743,19 @@ if (target.nodeName.toLowerCase() === 'select') { $target.on('change.validatrinput', function () { setTimeout(function () { - validateElement(target); + validateElement(target); }, 1); }); } $target.on({ 'blur.validatrinput': function () { - validateElement(target); + validateElement(target); }, 'keyup.validatrinput': function (event) { - if (target.value.length && $.inArray(keyCodes, event.keyCode) === -1) { + if (target.value.length && $.inArray(event.keyCode, keyCodes) === -1) { validateElement(target); - } + } } }); } @@ -584,7 +766,9 @@ function validateElement(element) { if (element.type === 'radio') { - var radio = $(document.getElementsByName(element.name)).filter('[required]'); + // use form context in case of extra form(s) with input that has + // same name on the page. + var radio = $(element).closest('form').find('[name=' + element.name + ']' ).filter('[required]'); if (radio.length) { element = radio[0]; } @@ -604,7 +788,7 @@ } else { if (required) { check = Tests.required(element); - } + } if (check.valid && element.value.length && !filters.boxes.test(type)) { if (element.pattern) { @@ -631,16 +815,16 @@ if (check.valid) { $element.trigger('valid'); return true; - } - + } + $.data(element, 'validationMessage', check.message); $element.trigger('invalid'); - + return false; } function validateForm (elements) { - var valid = true; + var valid = true; elements.each(function (i, element) { if (!validateElement(element)) { @@ -729,7 +913,7 @@ if (location === 'bottom') { error.offset({top: offset.top + error.outerHeight()}); - } + } } else if (filters.leftright.test(location)) { error.offset({top: (offset.top + $target.outerHeight() / 2) - (error.outerHeight() / 2)}); @@ -739,13 +923,13 @@ if (location === 'right') { error.offset({left: offset.left + $target.outerWidth() + 2}); - } - } + } + } } /*! Inspired by jQuery UI - v1.9.2 - 2012-12-04 * http://jqueryui.com - * Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT + * Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ $.fn.validatr = function(options) { var isMethod = typeof options === 'string', @@ -756,7 +940,7 @@ if (isMethod) { this.each(function() { var methodValue; - + instance = $.data(this, 'validatr'); if (!instance) { throw new Error("cannot call methods on validatr prior to initialization; attempted to call method '" + options + "'" ); @@ -787,17 +971,21 @@ }; $.fn.validatr.defaultOptions = { - dateFormat: 'yyyy-mm-dd', + dateFormat: 'yyyy-mm-d', location: 'right', + monthFormat: 'yyyy-mm', position: position, showall: false, template: '
{{message}}
', theme: '', - valid: $.noop + valid: $.noop, + weekFormat: 'yyyy-Www', + weekStart: 0, + yearStart: 6 }; $.validatr = new Validatr(); - + $.validatr.messages = { checkbox: 'Please check this box if you want to proceed.', color: 'Please enter a color in the format #xxxxxx', @@ -809,7 +997,7 @@ radio: 'Please select one of these options.', range: { base: 'Please enter a {{type}}', - overflow: 'Please enter a {{type}} greater than or equal to {{min}}.', + overflow: 'Please enter a {{type}} greater than or equal to {{min}}.', overUnder: 'Please enter a {{type}} greater than or equal to {{min}}
and less than or equal to {{max}}.', invalid: 'Invalid {{type}}', underflow: 'Please enter a {{type}} less than or equal to {{max}}.' @@ -819,10 +1007,10 @@ time: 'Please enter a time in the format hh:mm:ss', url: 'Please enter a url.' }; - + $.validatr.debug = function () { /*global QUnit */ - + if (!QUnit) { throw new Error('QUnit is required for debugging'); } @@ -837,5 +1025,4 @@ $.expr[':'].validatr = function(elem) { return !!$.data(elem, 'validatr'); }; - }(this, this.document, jQuery)); diff --git a/dist/validatr.min.js b/dist/validatr.min.js index c58837c..a13a3c7 100644 --- a/dist/validatr.min.js +++ b/dist/validatr.min.js @@ -1,4 +1,4 @@ -/*! Validatr - v0.5.1 - 2013-03-12 +/*! Validatr - v0.5.1 - 2013-05-17 * http://jaymorrow.github.com/validatr/ * Copyright (c) 2013 Jay Morrow; Licensed MIT */ -(function(t,e,a,r){"use strict";function i(t,e){if(this.el=t,this.$el=a(t),!this.$el.length||!this.$el.is("form"))throw Error("validatr needs a form to work.");this.isSubmit=!1,this.firstError=!1,this.options=a.extend({},a.fn.validatr.defaultOptions,e),this.template=function(t){var e=a(t.template).addClass("validatr-message");return t.theme.length?e.addClass(w[t.theme]||t.theme):e.css(k),e[0].outerHTML}(this.options),this.option=function(t,e){return arguments.length?e===r?this.options[t]===r?null:this.options[t]:(this.options[t]=e,r):a.extend({},this.options)},this.formElements=this.getElements(this.el).on("valid.validatr",a.proxy(f,this)).on("invalid.validatr",a.proxy(c,this)),this.el.noValidate=!0,this.$el.on("submit.validatr",a.proxy(m,this)),this.$el.on("reset.validatr",a.proxy(p,this))}function s(){this.formElements.on({"focus.validatrelement":o,"blur.validatrelement":l}),a("input[type=radio], input[type=checkbox]").on("click.validatrelement",function(t){u(t.target)})}function n(){this.formElements.off(".validatrelement")}function o(t){var e=t.target,r=a(e);"select"===e.nodeName.toLowerCase()&&r.on("change.validatrinput",function(){setTimeout(function(){u(e)},1)}),r.on({"blur.validatrinput":function(){u(e)},"keyup.validatrinput":function(t){e.value.length&&-1===a.inArray(E,t.keyCode)&&u(e)}})}function l(t){a(t.target).off(".validatrinput")}function u(t){if("radio"===t.type){var r=a(e.getElementsByName(t.name)).filter("[required]");r.length&&(t=r[0])}var i=a(t),s=x.notInput.test(t.nodeName)?t.nodeName.toLowerCase():t.getAttribute("type"),n=v.attributes.required?t.required:a(t).is("[required]"),o={valid:!0,message:""};if(v.inputtypes[s]?(o.valid=t.validity.valid,o.message=t.validationMessage):(n&&(o=y.required(t)),o.valid&&t.value.length&&!x.boxes.test(s)&&(t.pattern&&(s="pattern"),y[s]&&(o=y[s](t)))),o.valid)for(var l in b)if(b.hasOwnProperty(l)&&i.is("[data-"+l+"]")&&(o=b[l](t),!o.valid))break;return o.valid?(i.trigger("valid"),!0):(a.data(t,"validationMessage",o.message),i.trigger("invalid"),!1)}function d(t){var e=!0;return t.each(function(t,a){u(a)||(e=!1)}),e}function m(){this.isSubmit=!0,p.call(this);var t=d(this.formElements);return t?this.options.valid.call(this.el,this.el):(s.call(this),this.isSubmit=!1,t)}function p(){n.call(this),this.firstError=!1,this.formElements.next(".validatr-message").remove()}function c(t){if(!A){t.preventDefault();var e=t.target,i=a(e),s=this.options,n=e.getAttribute("data-message")||a.data(e,"validationMessage"),o=a(this.template.replace("{{message}}",n));return this.isSubmit&&!this.firstError?(this.firstError=i.after(o),s.position.call(this,o,i),r):((!this.isSubmit||s.showall)&&(f(t),i.after(o),s.position.call(this,o,i)),r)}}function f(t){A||a(t.target).next(".validatr-message").remove()}function h(t,e){t.css("position","absolute");var a=e.offset(),r=e[0].getAttribute("data-location")||this.options.location;x.topbottom.test(r)?(t.offset({left:a.left}),"top"===r&&t.offset({top:a.top-t.outerHeight()-2}),"bottom"===r&&t.offset({top:a.top+t.outerHeight()})):x.leftright.test(r)&&(t.offset({top:a.top+e.outerHeight()/2-t.outerHeight()/2}),"left"===r&&t.offset({left:a.left-t.outerWidth()-2}),"right"===r&&t.offset({left:a.left+e.outerWidth()+2}))}var v=function(){var t,a={},i=e.documentElement,s=e.createElement("input"),n=e.createElement("select"),o=e.createElement("textarea"),l=":)",u={},d={};return a.attributes=function(t){for(var e=0,a=t.length;a>e;e++)d[t[e]]=!!(t[e]in s);return d}("max min multiple pattern required step".split(" ")),a.inputtypes=function(t){for(var a,n,o,d=0,m=t.length;m>d;d++)s.setAttribute("type",n=t[d]),a="text"!==s.type,a&&(s.value=l,s.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(n)&&s.style.WebkitAppearance!==r?(i.appendChild(s),o=e.defaultView,a=o.getComputedStyle&&"textfield"!==o.getComputedStyle(s,null).WebkitAppearance&&0!==s.offsetHeight,i.removeChild(s)):/^(search|tel)$/.test(n)||(a=/^(url|email)$/.test(n)?s.checkValidity&&s.checkValidity()===!1:s.value!==l)),u[t[d]]=!!a;return u}("search tel url email datetime date month week time datetime-local number range color".split(" ")),function(r){for(var i=0,n=r.length;n>i;i++){t=s;try{t.setAttribute("type",r[i])}catch(o){t=e.createElement('')}t.style.cssText="position:absolute;visibility:hidden;",a.inputtypes[r[i]]=!!t.checkValidity}}("text password radio checkbox".split(" ")),a.inputtypes.select=!!n.checkValidity,a.inputtypes.textarea=!!o.checkValidity,s=null,t=null,n=null,o=null,a}(),g=function(){function t(t,e){for(var a=-1,r=t?t.length:0;r>++a;)if(t[a]===e)return a;return-1}function e(e){var i=e.getAttribute("data-format")||a.fn.validatr.defaultOptions.dateFormat,s=i.split(n.separatorsNoGroup),o=e.value.split(n.separatorsNoGroup),l="yyyy-mm-dd".split("-"),u=i.replace(n.separators,"\\$1").replace("yyyy",n.dateParts.yyyy).replace("mm",n.dateParts.mm).replace("dd",n.dateParts.dd),d=-1,m=l.length,p=[];if(u=RegExp(u),!u.test(e.value))return!1;for(;m>++d;)p[d]=o[t(s,l[d])];return r(p.join("-"))}function r(t){if(!s.isoDate.test(t))return!1;var e=s.isoDate.exec(t);return new Date(parseInt(e[1],10),parseInt(e[2],10)-1,parseInt(e[3],10))}function i(t,e){function r(t){return 10>t?"0"+t:t}var i=r(t.getDate()),s=r(t.getMonth()+1),n=t.getFullYear(),o=(e.getAttribute("data-format")||a.fn.validatr.defaultOptions.dateFormat).replace("mm",s).replace("yyyy",n).replace("dd",i);return o}var s={isoDate:/^(\d{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/},n={separators:/(\/|\-|\.)/g,separatorsNoGroup:/\/|\-|\./g,dateParts:{dd:"(0[1-9]|[12][0-9]|3[01])",mm:"(0[1-9]|1[012])",yyyy:"(\\d{4})"}};return{formatISODate:i,parseDate:e,parseISODate:r}}(),y=function(){var t={color:/^#[0-9A-F]{6}$/i,email:/^[a-zA-Z0-9.!#$%&’*+\/=?\^_`{|}~\-]+@[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*$/,isoDate:/^(\d{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$/,number:/^-?\d*\.?\d*$/,time:/^([01][0-9]|2[0-3])(:([0-5][0-9])){2}$/,url:/^\s*https?:\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?\s*$/},i={boxes:/checkbox|radio/i,spaces:/,\s*/},s=function(t,e,r,i,s){var n=!0,o=a.validatr.messages.range.base,l=e,u=r;return"date"===s&&(l=e&&g.formatISODate(e,this),u=r&&g.formatISODate(r,this)),t!==!1&&(i!==!1&&(n="any"===i?!0:0===(t-e)%i,o=a.validatr.messages.range.invalid),n&&(e!==!1&&r!==!1?(n=t>=e&&r>=t,o=a.validatr.messages.range.overUnder):e!==!1?(n=t>=e,o=a.validatr.messages.range.overflow):r!==!1&&(n=r>=t,o=a.validatr.messages.range.underflow))),{valid:t!==!1&&n,message:o.replace("{{type}}",s).replace("{{min}}",l).replace("{{max}}",u)}};return{checkbox:function(t){return{valid:t.checked,message:a.validatr.messages.checkbox}},color:function(e){return{valid:t.color.test(e.value),message:a.validatr.messages.color}},date:function(t){var e=a(t),r=v.inputtypes.date?g.parseISODate(t.value):g.parseDate(t),i=e.attr("min")?g.parseISODate(e.attr("min")):!1,n=e.attr("max")?g.parseISODate(e.attr("max")):!1,o=!1;return s.call(t,r,i,n,o,"date")},email:function(e){var s=!0,n=a.validatr.messages.email.single,o=v.attributes.multiple?e.multiple:a(e).is("[multiple]");if(o){var l=e.value.split(i.spaces);a.each(l,function(e,i){return t.email.test(i)?r:(s=!1,n=a.validatr.messages.email.multiple,r)})}else s=t.email.test(e.value);return{valid:s,message:n}},number:function(e){var a=e.value.replace(",",""),r=(t.number.test(a)?parseFloat(a):!1,t.number.test(e.getAttribute("min"))?parseFloat(e.getAttribute("min")):!1),i=t.number.test(e.getAttribute("max"))?parseFloat(e.getAttribute("max")):!1,n=t.number.test(e.getAttribute("step"))?parseFloat(e.getAttribute("step")):"any"===e.getAttribute("step")?"any":!1;return(n===!1||0>=n)&&(n=1),s.call(e,a,r,i,n,"number")},pattern:function(t){return{valid:RegExp(t.getAttribute("pattern")).test(t.value),message:a.validatr.messages.pattern}},radio:function(t){return{valid:a(e.getElementsByName(t.name)).is(":checked"),message:a.validatr.messages.radio}},range:function(t){return this.number(t)},required:function(t){return i.boxes.test(t.type)?this[t.type](t):{valid:!!t.value.length,message:"select"===t.nodeName.toLowerCase()?a.validatr.messages.select:a.validatr.messages.required}},time:function(e){return{valid:t.time.test(e.value),message:a.validatr.messages.time}},url:function(e){return{valid:t.url.test(e.value),message:a.validatr.messages.url}}}}(),b=function(){function t(t){if("text"!==t.type)throw Error("element must have a type of text");var e=t.getAttribute("data-as");return y[e]?y[e](t):r}function i(t){var r=t.getAttribute("data-match"),i=e.getElementById(r)||e.getElementsByName(r)[0];return i?(a(i).off("valid.validatrinput").on("valid.validatrinput",function(){t.value===i.value&&u(t)}),{valid:t.value===i.value,message:"'"+t.name+"' does not equal '"+i.name+"'"}):{valid:!1,message:"'"+r+"' can not be found"}}return{as:t,match:i}}(),x={boxes:/checkbox|radio/i,leftright:/left|right/i,notInput:/select|textarea/i,topbottom:/top|bottom/i},E=[16,17,18,19,20,33,34,35,36,37,39],w={bootstrap:"alert alert-error",jqueryui:"ui-state-error ui-corner-all"},k={color:"#f0444d",backgroundColor:"#ffcbcb",border:"1px solid #e4a6af",padding:"2px 6px",borderRadius:"2px"},A=!1,q=function(){};q.prototype={addTest:function(t){var e="string"!=typeof t,r=Array.prototype.slice.call(arguments,1)[0];if(e)a.extend(b,t);else{if(!r)throw Error("You must include a callback function");b[t]=r}},getElements:function(t){if(this.formElements)return this.formElements;var e=a(t).map(function(){return a.makeArray(this.elements)}).not("fieldset, button, input[type=submit], input[type=button], input[type=reset]");return t.id&&(e=e.add(a('[form="'+t.id+'"]'))),e},validateElement:function(t){if(!t)throw Error("method requires an element");A=!0;var e=u(t[0]||t);return A=!1,e},validateForm:function(t){var e,a=this.el||(t instanceof jQuery?t[0]:t);if("form"!==a.nodeName.toLowerCase())throw Error("you must pass a form to this method");return A=!0,e=d(this.formElements||this.getElements(a)),A=!1,e}},a.fn.validatr=function(t){var e,s="string"==typeof t,n=Array.prototype.slice.call(arguments,1),o=this;if(s)this.each(function(){var i;if(e=a.data(this,"validatr"),!e)throw Error("cannot call methods on validatr prior to initialization; attempted to call method '"+t+"'");if(!a.isFunction(e[t]))throw Error("no such method '"+t+"' for validatr instance");return i=e[t].apply(e,n),i!==e&&i!==r?(o=i&&i.jquery?o.pushStack(i.get()):i,!1):r});else{var l;this.each(function(){e=a.data(this,"validatr"),e||(l=new q,i.call(l,this,t||{}),a.data(this,"validatr",l))})}return o},a.fn.validatr.defaultOptions={dateFormat:"yyyy-mm-dd",location:"right",position:h,showall:!1,template:"
{{message}}
",theme:"",valid:a.noop},a.validatr=new q,a.validatr.messages={checkbox:"Please check this box if you want to proceed.",color:"Please enter a color in the format #xxxxxx",email:{single:"Please enter an email address.",multiple:"Please enter a comma separated list of email addresses."},pattern:"Please match the requested format.",radio:"Please select one of these options.",range:{base:"Please enter a {{type}}",overflow:"Please enter a {{type}} greater than or equal to {{min}}.",overUnder:"Please enter a {{type}} greater than or equal to {{min}}
and less than or equal to {{max}}.",invalid:"Invalid {{type}}",underflow:"Please enter a {{type}} less than or equal to {{max}}."},required:"Please fill out this field.",select:"Please select an item in the list.",time:"Please enter a time in the format hh:mm:ss",url:"Please enter a url."},a.validatr.debug=function(){if(!QUnit)throw Error("QUnit is required for debugging");this.Support=v,this.Tests=y,this.CustomTests=b,this.Format=g},a.expr[":"].validatr=function(t){return!!a.data(t,"validatr")}})(this,this.document,jQuery); \ No newline at end of file +(function(t,e,a,r){"use strict";function i(t,e){if(this.el=t,this.$el=a(t),!this.$el.length||!this.$el.is("form"))throw Error("validatr needs a form to work.");this.isSubmit=!1,this.firstError=!1,this.options=a.extend({},a.fn.validatr.defaultOptions,e),this.template=function(t){var e=a(t.template).addClass("validatr-message");return t.theme.length?e.addClass(k[t.theme]||t.theme):e.css(E),e[0].outerHTML}(this.options),this.option=function(t,e){return arguments.length?e===r?this.options[t]===r?null:this.options[t]:(this.options[t]=e,r):a.extend({},this.options)},this.formElements=this.getElements(this.el).on("valid.validatr",a.proxy(h,this)).on("invalid.validatr",a.proxy(f,this)),this.el.noValidate=!0,this.$el.on("submit.validatr",a.proxy(m,this)),this.$el.on("reset.validatr",a.proxy(c,this))}function n(){this.formElements.on({"focus.validatrelement":o,"blur.validatrelement":l}),a("input[type=radio], input[type=checkbox]").on("click.validatrelement",function(t){u(t.target)})}function s(){this.formElements.off(".validatrelement")}function o(t){var e=t.target,r=a(e);"select"===e.nodeName.toLowerCase()&&r.on("change.validatrinput",function(){setTimeout(function(){u(e)},1)}),r.on({"blur.validatrinput":function(){u(e)},"keyup.validatrinput":function(t){e.value.length&&-1===a.inArray(t.keyCode,x)&&u(e)}})}function l(t){a(t.target).off(".validatrinput")}function u(t){if("radio"===t.type){var e=a(t).closest("form").find("[name="+t.name+"]").filter("[required]");e.length&&(t=e[0])}var r=a(t),i=w.notInput.test(t.nodeName)?t.nodeName.toLowerCase():t.getAttribute("type"),n=v.attributes.required?t.required:a(t).is("[required]"),s={valid:!0,message:""};if(v.inputtypes[i]?(s.valid=t.validity.valid,s.message=t.validationMessage):(n&&(s=y.required(t)),s.valid&&t.value.length&&!w.boxes.test(i)&&(t.pattern&&(i="pattern"),y[i]&&(s=y[i](t)))),s.valid)for(var o in b)if(b.hasOwnProperty(o)&&r.is("[data-"+o+"]")&&(s=b[o](t),!s.valid))break;return s.valid?(r.trigger("valid"),!0):(a.data(t,"validationMessage",s.message),r.trigger("invalid"),!1)}function d(t){var e=!0;return t.each(function(t,a){u(a)||(e=!1)}),e}function m(){this.isSubmit=!0,c.call(this);var t=d(this.formElements);return t?this.options.valid.call(this.el,this.el):(n.call(this),this.isSubmit=!1,t)}function c(){s.call(this),this.firstError=!1,this.formElements.next(".validatr-message").remove()}function f(t){if(!A){t.preventDefault();var e=t.target,i=a(e),n=this.options,s=e.getAttribute("data-message")||a.data(e,"validationMessage"),o=a(this.template.replace("{{message}}",s));return this.isSubmit&&!this.firstError?(this.firstError=i.after(o),n.position.call(this,o,i),r):((!this.isSubmit||n.showall)&&(h(t),i.after(o),n.position.call(this,o,i)),r)}}function h(t){A||a(t.target).next(".validatr-message").remove()}function p(t,e){t.css("position","absolute");var a=e.offset(),r=e[0].getAttribute("data-location")||this.options.location;w.topbottom.test(r)?(t.offset({left:a.left}),"top"===r&&t.offset({top:a.top-t.outerHeight()-2}),"bottom"===r&&t.offset({top:a.top+t.outerHeight()})):w.leftright.test(r)&&(t.offset({top:a.top+e.outerHeight()/2-t.outerHeight()/2}),"left"===r&&t.offset({left:a.left-t.outerWidth()-2}),"right"===r&&t.offset({left:a.left+e.outerWidth()+2}))}var v=function(){var t,a={},i=e.documentElement,n=e.createElement("input"),s=e.createElement("select"),o=e.createElement("textarea"),l=":)",u={},d={};return a.attributes=function(t){for(var e=0,a=t.length;a>e;e++)d[t[e]]=!!(t[e]in n);return d}("max min multiple pattern required step".split(" ")),a.inputtypes=function(t){for(var a,s,o,d=0,m=t.length;m>d;d++)n.setAttribute("type",s=t[d]),a="text"!==n.type,a&&(n.value=l,n.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(s)&&n.style.WebkitAppearance!==r?(i.appendChild(n),o=e.defaultView,a=o.getComputedStyle&&"textfield"!==o.getComputedStyle(n,null).WebkitAppearance&&0!==n.offsetHeight,i.removeChild(n)):/^(search|tel)$/.test(s)||(a=/^(url|email)$/.test(s)?n.checkValidity&&n.checkValidity()===!1:n.value!==l)),u[t[d]]=!!a;return u}("search tel url email datetime date month week time datetime-local number range color".split(" ")),function(r){for(var i=0,s=r.length;s>i;i++){t=n;try{t.setAttribute("type",r[i])}catch(o){t=e.createElement('')}t.style.cssText="position:absolute;visibility:hidden;",a.inputtypes[r[i]]=!!t.checkValidity}}("text password radio checkbox".split(" ")),a.inputtypes.select=!!s.checkValidity,a.inputtypes.textarea=!!o.checkValidity,n=null,t=null,s=null,o=null,a}(),g=function(){function t(t){return t.substr(0,1).toUpperCase()+t.substr(1)}function e(t){return 10>t?"0"+t:t}function i(t,e){for(var a=-1,r=t?t.length:0;r>++a;)if(t[a]===e)return a;return-1}function n(t){switch(t){case"d":case"w":case"m":return h;case"dd":case"ww":case"mm":case"yy":return p;case"M":return w;case"MM":return b;case"yyyy":return v}}function s(t,e,a){if(e!==r)switch(t){case"d":case"dd":a[2]=~~e;break;case"w":case"ww":a[3]=~~e;break;case"m":case"mm":a[1]=~~e-1;break;case"M":a[1]=i(k,e.toLowerCase());break;case"MM":a[1]=i(x,e.toLowerCase());break;case"yy":a[0]=~~("20"+e);break;case"yyyy":a[0]=~~e}}function o(t){var e=new Date(t.getFullYear(),0,1,0,0,0);return Math.ceil(((t-e)/864e5+e.getDay()+1)/7)}function l(t){var e=u(t[0]),r=6048e5*(t[3]-1),i=e.getTime()+r-864e5*(e.getDay()-a.fn.validatr.defaultOptions.weekStart),n=new Date(i);return n.setHours(0),n}function u(t){var e=new Date(t,0,1,0,0,0),r=a.fn.validatr.defaultOptions.yearStart-e.getDay()+e.getDate();return e.setDate(r),e}function d(t){var e=0,a=[],r=!1;for(e;7>e;e+=1){if(r="number"==typeof t[e],!r&&2>e)return!1;a[e]=r?t[e]:2===e?1:0}return new Date(a[0],a[1],a[2],a[3],a[4],a[5],a[6])}function m(t,e){var a,i=e.match(f)||[],o=[],u=i.length,m=0;if(!u)throw Error("Ivalid date format.");for(m;u>m;m+=1)a=(n(i[m]).exec(t)||[])[0],a&&(t=t.slice(t.indexOf(a)+a.length),s(i[m],a,o));return/w?w/.test(e)?l(o):o.length&&o.length===u?d(o):r}function c(t,e){if(t===!1)return!1;e===r&&(e="yyyy-mm-dd");var a=e.match(f)||[],i=a.length,n=0;if(!i)throw Error("Ivalid date format.");for(n;i>n;n+=1)E[a[n]]&&(e=e.replace(a[n],E[a[n]].call(t)));return e}var f=/(d?d|w?w|m?m|(?:yy)?yy|M?M)/g,h=/\d{1,2}/,p=/\d{2}/,v=/\d{4}/,g="January|February|March|April|May|June|July|August|September|October|November|December",y="Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",b=RegExp(g,"i"),w=RegExp(y,"i"),x=g.toLowerCase().split("|"),k=y.toLowerCase().split("|"),E={d:function(){return this.getDate()},dd:function(){return e(this.getDate())},w:function(){return o(this)},ww:function(){return e(o(this))},m:function(){return this.getMonth()+1},mm:function(){return e(this.getMonth()+1)},yy:function(){return(""+this.getFullYear()).substr(2)},yyyy:function(){return this.getFullYear()},M:function(){return t(k[this.getMonth()])},MM:function(){return t(x[this.getMonth()])}};return{date:m,isoDate:function(t){return m(t,"yyyy-mm-dd")},toString:c}}(),y=function(){var t={color:/^#[0-9A-F]{6}$/i,email:/^[a-zA-Z0-9.!#$%&’*+\/=?\^_`{|}~\-]+@[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*$/,number:/^-?\d*\.?\d*$/,url:/^\s*https?:\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?\s*$/},e={boxes:/checkbox|radio/i,spaces:/,\s*/},i=function(t,e,r,i){var n=!0,s=a.validatr.messages.range.base;return t!==!1&&(i!==!1&&(n="any"===i?!0:0===(t-e)%i,s=a.validatr.messages.range.invalid),n&&(e!==!1&&r!==!1?(n=t>=e&&r>=t,s=a.validatr.messages.range.overUnder):e!==!1?(n=t>=e,s=a.validatr.messages.range.overflow):r!==!1&&(n=r>=t,s=a.validatr.messages.range.underflow))),{valid:t!==!1&&n,message:s}},n=function(t,e){return e+="Format",t.getAttribute("data-format")||a.data(t.form,"validatr").options[e]||a.fn.validatr.defaultOptions[e]},s=function(t,e,a,r){return t=t.replace("{{type}}",e),a&&(t=t.replace("{{min}}",a)),r&&(t=t.replace("{{max}}",r)),t};return{checkbox:function(t){return{valid:t.checked,message:a.validatr.messages.checkbox}},color:function(e){return{valid:t.color.test(e.value),message:a.validatr.messages.color}},date:function(t){var e=a(t),r=n(t,"date"),o=g.date(t.value,r)||!1,l=e.attr("min")?g.isoDate(e.attr("min")):!1,u=e.attr("max")?g.isoDate(e.attr("max")):!1,d=!1,m=i(o,l,u,d);return m.valid||(m.message=s(m.message,"date",g.toString(l,r),g.toString(u,r))),m},email:function(i){var n=!0,s=a.validatr.messages.email.single,o=v.attributes.multiple?i.multiple:a(i).is("[multiple]");if(o){var l=i.value.split(e.spaces);a.each(l,function(e,i){return t.email.test(i)?r:(n=!1,s=a.validatr.messages.email.multiple,r)})}else n=t.email.test(i.value);return{valid:n,message:s}},month:function(t){var e=a(t),r=n(t,"month"),o=g.date(t.value,r)||!1,l=e.attr("min")?g.isoDate(e.attr("min")+"01"):!1,u=e.attr("max")?g.isoDate(e.attr("max")+"01"):!1,d=!1,m=i(o,l,u,d);return m.valid||(m.message=s(m.message,"month",g.toString(l,r),g.toString(u,r))),m},number:function(e){var a,r=e.value.replace(",",""),n=(t.number.test(r)?parseFloat(r):!1,t.number.test(e.getAttribute("min"))?parseFloat(e.getAttribute("min")):!1),o=t.number.test(e.getAttribute("max"))?parseFloat(e.getAttribute("max")):!1,l=t.number.test(e.getAttribute("step"))?parseFloat(e.getAttribute("step")):"any"===e.getAttribute("step")?"any":!1;return(l===!1||0>=l)&&(l=1),a=i(r,n,o,l,"number"),a.valid||(a.message=s(a.message,"number",n,o)),a},pattern:function(t){return{valid:RegExp(t.getAttribute("pattern")).test(t.value),message:a.validatr.messages.pattern}},radio:function(t){return{valid:a(t).closest("form").find("[name="+t.name+"]").is(":checked"),message:a.validatr.messages.radio}},range:function(t){return this.number(t)},required:function(t){return e.boxes.test(t.type)?this[t.type](t):{valid:!!t.value.length,message:"select"===t.nodeName.toLowerCase()?a.validatr.messages.select:a.validatr.messages.required}},url:function(e){return{valid:t.url.test(e.value),message:a.validatr.messages.url}}}}(),b=function(){function t(t){if("text"!==t.type)throw Error("element must have a type of text");var e=t.getAttribute("data-as");return y[e]?y[e](t):r}function i(t){var r=t.getAttribute("data-match"),i=e.getElementById(r)||e.getElementsByName(r)[0];return i?(a(i).off("valid.validatrinput").on("valid.validatrinput",function(){t.value===i.value&&u(t)}),{valid:t.value===i.value,message:"'"+t.name+"' does not equal '"+i.name+"'"}):{valid:!1,message:"'"+r+"' can not be found"}}return{as:t,match:i}}(),w={boxes:/checkbox|radio/i,leftright:/left|right/i,notInput:/select|textarea/i,topbottom:/top|bottom/i},x=[16,17,18,19,20,33,34,35,36,37,39],k={bootstrap:"alert alert-error",jqueryui:"ui-state-error ui-corner-all"},E={color:"#f0444d",backgroundColor:"#ffcbcb",border:"1px solid #e4a6af",padding:"2px 6px",borderRadius:"2px"},A=!1,M=function(){};M.prototype={addTest:function(t){var e="string"!=typeof t,r=Array.prototype.slice.call(arguments,1)[0];if(e)a.extend(b,t);else{if(!r)throw Error("You must include a callback function");b[t]=r}},getElements:function(t){if(this.formElements)return this.formElements;var e=a(t).map(function(){return a.makeArray(this.elements)}).not("fieldset, button, input[type=submit], input[type=button], input[type=reset]");return t.id&&(e=e.add(a('[form="'+t.id+'"]'))),e},validateElement:function(t){if(!t)throw Error("method requires an element");A=!0;var e=u(t[0]||t);return A=!1,e},validateForm:function(t){var e,a=this.el||(t instanceof jQuery?t[0]:t);if("form"!==a.nodeName.toLowerCase())throw Error("you must pass a form to this method");return A=!0,e=d(this.formElements||this.getElements(a)),A=!1,e}},a.fn.validatr=function(t){var e,n="string"==typeof t,s=Array.prototype.slice.call(arguments,1),o=this;if(n)this.each(function(){var i;if(e=a.data(this,"validatr"),!e)throw Error("cannot call methods on validatr prior to initialization; attempted to call method '"+t+"'");if(!a.isFunction(e[t]))throw Error("no such method '"+t+"' for validatr instance");return i=e[t].apply(e,s),i!==e&&i!==r?(o=i&&i.jquery?o.pushStack(i.get()):i,!1):r});else{var l;this.each(function(){e=a.data(this,"validatr"),e||(l=new M,i.call(l,this,t||{}),a.data(this,"validatr",l))})}return o},a.fn.validatr.defaultOptions={dateFormat:"yyyy-mm-d",location:"right",monthFormat:"yyyy-mm",position:p,showall:!1,template:"
{{message}}
",theme:"",valid:a.noop,weekFormat:"yyyy-Www",weekStart:0,yearStart:6},a.validatr=new M,a.validatr.messages={checkbox:"Please check this box if you want to proceed.",color:"Please enter a color in the format #xxxxxx",email:{single:"Please enter an email address.",multiple:"Please enter a comma separated list of email addresses."},pattern:"Please match the requested format.",radio:"Please select one of these options.",range:{base:"Please enter a {{type}}",overflow:"Please enter a {{type}} greater than or equal to {{min}}.",overUnder:"Please enter a {{type}} greater than or equal to {{min}}
and less than or equal to {{max}}.",invalid:"Invalid {{type}}",underflow:"Please enter a {{type}} less than or equal to {{max}}."},required:"Please fill out this field.",select:"Please select an item in the list.",time:"Please enter a time in the format hh:mm:ss",url:"Please enter a url."},a.validatr.debug=function(){if(!QUnit)throw Error("QUnit is required for debugging");this.Support=v,this.Tests=y,this.CustomTests=b,this.Format=g},a.expr[":"].validatr=function(t){return!!a.data(t,"validatr")}})(this,this.document,jQuery); \ No newline at end of file diff --git a/src/js/validatr.js b/src/js/validatr.js index 805355f..e071277 100644 --- a/src/js/validatr.js +++ b/src/js/validatr.js @@ -502,7 +502,9 @@ radio: function (element) { return { - valid: $(document.getElementsByName(element.name)).is(':checked'), + // use form context in case of extra form(s) with input that has + // same name on the page. + valid: $(element).closest('form').find('[name=' + element.name + ']' ).is(':checked'), message: $.validatr.messages.radio }; }, @@ -771,7 +773,9 @@ function validateElement(element) { if (element.type === 'radio') { - var radio = $(document.getElementsByName(element.name)).filter('[required]'); + // use form context in case of extra form(s) with input that has + // same name on the page. + var radio = $(element).closest('form').find('[name=' + element.name + ']' ).filter('[required]'); if (radio.length) { element = radio[0]; }