├── .DS_Store
├── LICENSE
├── README.md
├── attrvalidate.jquery.js
├── attrvalidate.jquery.min.js
└── example.html
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fraddski/attrvalidate/dc8f7274e6a899be60566622c0f43853b4943158/.DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 fraddski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # attrvalidate
2 |
3 | A lightweight jQuery plugin for basic form validation using HTML5 form attributes. Recommended as a polyfill for older browsers which do not provide built-in validation.
4 |
5 | See http://skyefradd.me/attrvalidate for usage details.
6 |
--------------------------------------------------------------------------------
/attrvalidate.jquery.js:
--------------------------------------------------------------------------------
1 | /**
2 | * attrvalidate jQuery plugin v1.1
3 | * http://github.com/fraddski/attrvalidate
4 | * Licensed under MIT
5 | */
6 | (function($){
7 |
8 | var functions = {
9 | reset: resetValidation
10 | };
11 |
12 | var settings;
13 | var _reqForm;
14 | var _indicatorTemplate = ' ';
15 | var _summaryTemplate = '
';
16 | var _validationTypes = {
17 | required: {msg: ' is required' },
18 | tel: {msg: ' is not a valid phone number' },
19 | email: {msg: ' is not a valid email address' },
20 | date: {msg: ' is not a valid date'},
21 | number: {msg: ' is not a valid number'}
22 | };
23 |
24 | $.fn.attrvalidate = function() {
25 | if (!this.is('form')) {
26 | return this;
27 | }
28 |
29 | if (typeof arguments[0] === 'string') {
30 | var property = arguments[1];
31 | var newArgs = Array.prototype.slice.call(arguments);
32 | newArgs.splice(0, 1);
33 | functions[arguments[0]].apply(this, newArgs);
34 | } else {
35 | setupFormValidation.apply(this, arguments);
36 | }
37 |
38 | return this;
39 | };
40 |
41 |
42 | function resetValidation(){
43 | $(_reqForm).find('input, select, textarea, fieldset').removeClass('invalid');
44 | $(_reqForm).find('.error-indicator').attr('aria-hidden', true);
45 | $(_reqForm).find('#errorSummary').remove();
46 | }
47 |
48 | function setupFormValidation(options){
49 | settings = $.extend({
50 | showFieldIndicator: true,
51 | showErrorSummary: true,
52 | errorSummaryMsg: 'Please fix the following issues before continuing:',
53 | validateTel: true,
54 | telRegex: /^\+*[\d-()]{7,20}$/,
55 | validateEmail: true,
56 | emailRegex: /^(\S+@\S+)*$/,
57 | validateDate: true,
58 | validateNumber: true
59 | }, options);
60 |
61 | _reqForm = this;
62 | initialiseValidation();
63 | $(_reqForm).bind('submit', handleSubmit);
64 | }
65 |
66 | function initialiseValidation(){
67 | var _groupsInitialised = [];
68 | $(_reqForm).find('input, select[required], textarea[required]').each(function(){
69 | if (isRadioGroup($(this)) && $(this).is('[required]')) {
70 | var groupName = $(this).attr('name');
71 | if ($.inArray(groupName, _groupsInitialised) === -1) {
72 | $(this).attr('data-do-validate', true);
73 | setFieldName($(this));
74 |
75 | if (settings.showFieldIndicator){
76 | $(this).parents('fieldset').first().append($(_indicatorTemplate));
77 | }
78 |
79 | $(_reqForm).find('input[name="' + $(this).attr('name') + '"]').each(function(){
80 | $(this).change(function(){
81 | handleFieldChanged($(this));
82 | });
83 | });
84 | _groupsInitialised.push(groupName);
85 | }
86 | } else {
87 | if ($(this).is('[required]') ||
88 | (settings.validateTel && $(this).is('input[type="tel"]')) ||
89 | (settings.validateEmail && $(this).is('input[type="email"]')) ||
90 | (settings.validateDate && $(this).is('input[type="date"]')) ||
91 | (settings.validateNumber && $(this).is('input[type="number"]'))){
92 |
93 | $(this).attr('data-do-validate', true);
94 | setFieldName($(this));
95 |
96 | if (settings.showFieldIndicator){
97 | if (($(this).is('input[type="radio"]') || $(this).is('input[type="checkbox"]')) && $(this).next('label').length > 0) {
98 | $(this).next('label').after($(_indicatorTemplate));
99 | } else {
100 | $(this).after($(_indicatorTemplate));
101 | }
102 | }
103 |
104 | $(this).change(function(){
105 | handleFieldChanged($(this));
106 | });
107 | }
108 | }
109 | });
110 | }
111 |
112 | function handleFieldChanged(elem){
113 | var validationResult = validateField(elem);
114 | if (validationResult.isValid) {
115 | clearFieldError(elem);
116 | } else {
117 | var fieldMsg = getFieldMessage(elem, validationResult.type);
118 | showFieldError(elem, fieldMsg);
119 | }
120 | }
121 |
122 | function handleSubmit(e){
123 | e.preventDefault();
124 | var formValid = true;
125 | var errorMessages = [];
126 |
127 | $(_reqForm).find('#errorSummary').remove();
128 |
129 | $(_reqForm).find('[data-do-validate="true"]').each(function(){
130 | var validationResult = validateField($(this));
131 | if (!validationResult.isValid) {
132 | var fieldMsg = getFieldMessage($(this), validationResult.type);
133 | errorMessages.push({ elem: $(this).prop('id'), msg: fieldMsg });
134 | showFieldError($(this), fieldMsg);
135 | formValid = false;
136 | } else {
137 | clearFieldError($(this));
138 | }
139 | });
140 |
141 | if (!formValid) {
142 | if (settings.showErrorSummary) {
143 | showErrorSummary(errorMessages);
144 | }
145 | return false;
146 | } else {
147 | if (typeof(settings.submitFunction) !== 'undefined') {
148 | settings.submitFunction();
149 | } else {
150 | _reqForm[0].submit();
151 | }
152 | }
153 | }
154 |
155 | function validateField(elem){
156 | if (!elem.is(':visible') || elem.parents('[aria-hidden="true"]').length > 0){
157 | return { isValid: true };
158 | }
159 |
160 | if (elem.is('input[type="radio"]')) {
161 | if (elem.is('[required]')){
162 | if (isRadioGroup(elem)) {
163 | return { isValid: ($(_reqForm).find('input[name="' + elem.attr('name') + '"]:checked').length > 0), type: _validationTypes.required };
164 | } else {
165 | return { isValid: elem.is(':checked'), type: _validationTypes.required };
166 | }
167 | } else {
168 | return { isValid: true };
169 | }
170 | } else if (elem.is('input[type="checkbox"]')) {
171 | return { isValid: (!elem.is('[required]') || elem.is(':checked')), type: _validationTypes.required };
172 | } else {
173 | if (elem.is('[required]') && (elem.val() === '')) {
174 | return { isValid: false, type: _validationTypes.required };
175 | } else if (settings.validateTel && elem.is('input[type="tel"]')) {
176 | return { isValid: settings.telRegex.test(elem.val().replace(/ /g, '')), type: _validationTypes.tel };
177 | } else if (settings.validateEmail && elem.is('input[type="email"]')) {
178 | return { isValid: settings.emailRegex.test(elem.val().trim()), type: _validationTypes.email };
179 | } else if (settings.validateDate && elem.is('input[type="date"]')) {
180 | var doesPass;
181 | if (elem.val().trim() === '') {
182 | doesPass = true;
183 | } else if (isNaN(Date.parse(elem.val()))) {
184 | doesPass = false;
185 | } else if (elem.prop('max') && !isNaN(Date.parse(elem.prop('max'))) && Date.parse(elem.val()) > Date.parse(elem.prop('max'))) {
186 | doesPass = false;
187 | } else if (elem.prop('min') && !isNaN(Date.parse(elem.prop('min'))) && Date.parse(elem.val()) < Date.parse(elem.prop('min'))) {
188 | doesPass = false;
189 | } else {
190 | doesPass = true;
191 | }
192 | return { isValid: doesPass, type: _validationTypes.date };
193 | } else if (settings.validateNumber && elem.is('input[type="number"]')) {
194 | var doesPass;
195 | if (elem.val().trim() === '') {
196 | doesPass = true;
197 | } else if (isNaN(parseFloat(elem.val()))) {
198 | doesPass = false;
199 | } else if (elem.prop('max') && !isNaN(parseFloat(elem.prop('max'))) && parseFloat(elem.val()) > parseFloat(elem.prop('max'))) {
200 | doesPass = false;
201 | } else if (elem.prop('min') && !isNaN(parseFloat(elem.prop('min'))) && parseFloat(elem.val()) < parseFloat(elem.prop('min'))) {
202 | doesPass = false;
203 | } else {
204 | doesPass = true;
205 | }
206 | return { isValid: doesPass, type: _validationTypes.number };
207 | } else {
208 | return { isValid: true };
209 | }
210 | }
211 | }
212 |
213 | function setFieldName(elem){
214 | if (typeof(elem.data('error-msg')) !== 'undefined' && elem.data('error-msg') !== '') {
215 | return;
216 | }
217 | var elemName;
218 | var forLabel = $(_reqForm).find('label[for="' + elem.attr('id') + '"]');
219 | if (forLabel.length > 0 && $(forLabel[0]).text() !== '') {
220 | elemName = $(forLabel[0]).text();
221 | } else {
222 | elemName = elem.attr('name');
223 | }
224 | elem.data('error-name', elemName);
225 | }
226 |
227 | function getFieldMessage(elem, resultType){
228 | var elemMsg;
229 | if (typeof(elem.data('error-msg')) !== 'undefined' && elem.data('error-msg') !== '') {
230 | elemMsg = elem.data('error-msg');
231 | } else {
232 | elemMsg = elem.data('error-name') + resultType.msg;
233 | }
234 | return elemMsg;
235 | }
236 |
237 | function showFieldError(elem, fieldMsg){
238 | if (isRadioGroup(elem)) {
239 | elem.parents('fieldset').first().addClass('invalid');
240 | if (settings.showFieldIndicator){
241 | elem.parents('fieldset').first().find('.error-indicator').first().text(fieldMsg).attr('aria-hidden', false);
242 | }
243 | } else {
244 | elem.addClass('invalid');
245 | if (settings.showFieldIndicator){
246 | elem.nextAll('.error-indicator').first().text(fieldMsg).attr('aria-hidden', false);
247 | }
248 | }
249 | }
250 |
251 | function clearFieldError(elem){
252 | if (isRadioGroup(elem)) {
253 | elem.parents('fieldset').removeClass('invalid');
254 | if (settings.showFieldIndicator){
255 | elem.parents('fieldset').first().find('.error-indicator').first().attr('aria-hidden', true);
256 | }
257 | var firstInGroup = $(_reqForm).find('input[name="' + elem.attr('name') + '"]').first();
258 | var summaryItem = $('#errorSummary li a[data-field="' + firstInGroup.attr('id') + '"]');
259 | if (summaryItem.length > 0) {
260 | summaryItem.parent('li').remove();
261 | if ($('#errorSummary ul li').length === 0) {
262 | $('#errorSummary').remove();
263 | }
264 | }
265 | } else {
266 | elem.removeClass('invalid');
267 | if (settings.showFieldIndicator){
268 | elem.nextAll('.error-indicator').first().attr('aria-hidden', true);
269 | }
270 | var summaryItem = $('#errorSummary li a[data-field="' + elem.attr('id') + '"]');
271 | if (summaryItem.length > 0) {
272 | summaryItem.parent('li').remove();
273 | if ($('#errorSummary ul li').length === 0) {
274 | $('#errorSummary').remove();
275 | }
276 | }
277 | }
278 | }
279 |
280 | function showErrorSummary(errorMsgList){
281 | var errorSummary = $(_summaryTemplate.replace('{0}', settings.errorSummaryMsg));
282 | var errorList = $('');
283 |
284 | for (var i=0; i < errorMsgList.length; i++) {
285 | var errorLink = $('' + errorMsgList[i].msg + ' ');
286 | errorLink.click(function(){ jumpToElem($(this).data('field')); return false; });
287 | var errorItm = $(' ');
288 | errorItm.append(errorLink);
289 | errorList.append(errorItm);
290 | }
291 |
292 | errorSummary.append(errorList).prependTo($(_reqForm));
293 | errorSummary.focus();
294 | }
295 |
296 | function isRadioGroup(elem){
297 | return (elem.is('input[type="radio"]') && typeof(elem.attr('name')) !== 'undefined' && elem.attr('name') !== '');
298 | }
299 |
300 | function jumpToElem(fieldId){
301 | $(_reqForm).find('#' + fieldId).focus();
302 | }
303 |
304 | }(jQuery));
305 |
--------------------------------------------------------------------------------
/attrvalidate.jquery.min.js:
--------------------------------------------------------------------------------
1 | !function(e){function i(){e(v).find("input, select, textarea, fieldset").removeClass("invalid"),e(v).find(".error-indicator").attr("aria-hidden",!0),e(v).find("#errorSummary").remove()}function t(i){h=e.extend({showFieldIndicator:!0,showErrorSummary:!0,errorSummaryMsg:"Please fix the following issues before continuing:",validateTel:!0,telRegex:/^\+*[\d-()]{7,20}$/,validateEmail:!0,emailRegex:/^(\S+@\S+)*$/,validateDate:!0,validateNumber:!0},i),v=this,a(),e(v).bind("submit",n)}function a(){var i=[];e(v).find("input, select[required], textarea[required]").each(function(){if(m(e(this))&&e(this).is("[required]")){var t=e(this).attr("name");-1===e.inArray(t,i)&&(e(this).attr("data-do-validate",!0),d(e(this)),h.showFieldIndicator&&e(this).parents("fieldset").first().append(e(y)),e(v).find('input[name="'+e(this).attr("name")+'"]').each(function(){e(this).change(function(){r(e(this))})}),i.push(t))}else(e(this).is("[required]")||h.validateTel&&e(this).is('input[type="tel"]')||h.validateEmail&&e(this).is('input[type="email"]')||h.validateDate&&e(this).is('input[type="date"]')||h.validateNumber&&e(this).is('input[type="number"]'))&&(e(this).attr("data-do-validate",!0),d(e(this)),h.showFieldIndicator&&((e(this).is('input[type="radio"]')||e(this).is('input[type="checkbox"]'))&&e(this).next("label").length>0?e(this).next("label").after(e(y)):e(this).after(e(y))),e(this).change(function(){r(e(this))}))})}function r(e){var i=s(e);if(i.isValid)p(e);else{var t=l(e,i.type);o(e,t)}}function n(i){i.preventDefault();var t=!0,a=[];return e(v).find("#errorSummary").remove(),e(v).find('[data-do-validate="true"]').each(function(){var i=s(e(this));if(i.isValid)p(e(this));else{var r=l(e(this),i.type);a.push({elem:e(this).prop("id"),msg:r}),o(e(this),r),t=!1}}),t?void("undefined"!=typeof h.submitFunction?h.submitFunction():v[0].submit()):(h.showErrorSummary&&u(a),!1)}function s(i){if(!i.is(":visible")||i.parents('[aria-hidden="true"]').length>0)return{isValid:!0};if(i.is('input[type="radio"]'))return i.is("[required]")?m(i)?{isValid:e(v).find('input[name="'+i.attr("name")+'"]:checked').length>0,type:x.required}:{isValid:i.is(":checked"),type:x.required}:{isValid:!0};if(i.is('input[type="checkbox"]'))return{isValid:!i.is("[required]")||i.is(":checked"),type:x.required};if(i.is("[required]")&&""===i.val())return{isValid:!1,type:x.required};if(h.validateTel&&i.is('input[type="tel"]'))return{isValid:h.telRegex.test(i.val().replace(/ /g,"")),type:x.tel};if(h.validateEmail&&i.is('input[type="email"]'))return{isValid:h.emailRegex.test(i.val().trim()),type:x.email};if(h.validateDate&&i.is('input[type="date"]')){var t;return t=""===i.val().trim()?!0:isNaN(Date.parse(i.val()))?!1:i.prop("max")&&!isNaN(Date.parse(i.prop("max")))&&Date.parse(i.val())>Date.parse(i.prop("max"))?!1:i.prop("min")&&!isNaN(Date.parse(i.prop("min")))&&Date.parse(i.val())parseFloat(i.prop("max"))?!1:i.prop("min")&&!isNaN(parseFloat(i.prop("min")))&&parseFloat(i.val())0&&""!==e(a[0]).text()?e(a[0]).text():i.attr("name"),i.data("error-name",t)}}function l(e,i){var t;return t="undefined"!=typeof e.data("error-msg")&&""!==e.data("error-msg")?e.data("error-msg"):e.data("error-name")+i.msg}function o(e,i){m(e)?(e.parents("fieldset").first().addClass("invalid"),h.showFieldIndicator&&e.parents("fieldset").first().find(".error-indicator").first().text(i).attr("aria-hidden",!1)):(e.addClass("invalid"),h.showFieldIndicator&&e.nextAll(".error-indicator").first().text(i).attr("aria-hidden",!1))}function p(i){if(m(i)){i.parents("fieldset").removeClass("invalid"),h.showFieldIndicator&&i.parents("fieldset").first().find(".error-indicator").first().attr("aria-hidden",!0);var t=e(v).find('input[name="'+i.attr("name")+'"]').first(),a=e('#errorSummary li a[data-field="'+t.attr("id")+'"]');a.length>0&&(a.parent("li").remove(),0===e("#errorSummary ul li").length&&e("#errorSummary").remove())}else{i.removeClass("invalid"),h.showFieldIndicator&&i.nextAll(".error-indicator").first().attr("aria-hidden",!0);var a=e('#errorSummary li a[data-field="'+i.attr("id")+'"]');a.length>0&&(a.parent("li").remove(),0===e("#errorSummary ul li").length&&e("#errorSummary").remove())}}function u(i){for(var t=e(g.replace("{0}",h.errorSummaryMsg)),a=e(""),r=0;r'+i[r].msg+"");n.click(function(){return f(e(this).data("field")),!1});var s=e(" ");s.append(n),a.append(s)}t.append(a).prependTo(e(v)),t.focus()}function m(e){return e.is('input[type="radio"]')&&"undefined"!=typeof e.attr("name")&&""!==e.attr("name")}function f(i){e(v).find("#"+i).focus()}var h,v,c={reset:i},y=' ',g='',x={required:{msg:" is required"},tel:{msg:" is not a valid phone number"},email:{msg:" is not a valid email address"},date:{msg:" is not a valid date"},number:{msg:" is not a valid number"}};e.fn.attrvalidate=function(){if(!this.is("form"))return this;if("string"==typeof arguments[0]){var e=(arguments[1],Array.prototype.slice.call(arguments));e.splice(0,1),c[arguments[0]].apply(this,e)}else t.apply(this,arguments);return this}}(jQuery);
2 |
--------------------------------------------------------------------------------
/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Attr Validation
6 |
7 |
8 |
286 |
287 |
288 |
337 |
338 |
339 |
340 |
352 |
353 |
354 |
355 |
--------------------------------------------------------------------------------