From f72a2381d76bd876bd8075fcde71b1d30ac1f8c1 Mon Sep 17 00:00:00 2001 From: Craig Davis Date: Sun, 31 Mar 2013 13:54:56 -0500 Subject: [PATCH] Relocate validators to their own file * Create new validators.js file * Fix more unit test scoping and classname issues --- Gruntfile.js | 2 +- dist/uni-form-validation.jquery.js | 234 +++++++++---------- dist/uni-form-validation.jquery.min.js | 2 +- src/uni-form-validation.jquery.js | 299 ++++--------------------- src/validators.js | 214 ++++++++++++++++++ test/index.html | 36 +-- test/issues.js | 39 +--- test/validation.js | 20 +- 8 files changed, 414 insertions(+), 432 deletions(-) create mode 100644 src/validators.js diff --git a/Gruntfile.js b/Gruntfile.js index 98bae1e..03d988f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -44,7 +44,7 @@ module.exports = function (grunt) { dest: 'dist/uni-form.jquery.js' }, dist_validation: { - src: ['src/uni-form-validation.jquery.js', 'src/validators/*.js'], + src: ['src/uni-form-validation.jquery.js', 'src/validators.js'], dest: 'dist/uni-form-validation.jquery.js' } }, diff --git a/dist/uni-form-validation.jquery.js b/dist/uni-form-validation.jquery.js index 7645d0a..dc2fc13 100644 --- a/dist/uni-form-validation.jquery.js +++ b/dist/uni-form-validation.jquery.js @@ -33,9 +33,6 @@ // Static Method to hold config and options $.uniform = function () {}; - // Hold a collection of the various form validators - $.uniform.validators = {}; - // Get the value for a validator that takes parameters. // These are in the format of `val-{value}` $.uniform.get_val = function (name, classes, defaultValue) { @@ -69,7 +66,6 @@ $p = $input .closest('div.' + options.holder_class) .andSelf() - .toggleClass(options.invalid_class, !isValid) .toggleClass(options.error_class, !isValid) .toggleClass(options.valid_class, isValid) .find('p.form-hint'); @@ -96,21 +92,22 @@ if (errorMessage) { $p.html(errorMessage); } }; + // Collection method will ppply the uniform behavior to elements $.fn.uniform = function (options) { options = $.extend($.uniform.defaultOptions, options); return this.each(function () { - var form, errors, get_label_text, get_val, validate, initial_values; + var $form, errors, get_label_text, get_val, validate, initial_values; - form = $(this); + $form = $(this); errors = []; get_label_text = $.proxy($.uniform.get_label_text, this); get_val = $.proxy($.uniform.get_val, this); validate = $.proxy($.uniform.validate, this); // Select form fields and attach the highlighter functionality - form.find(options.field_selector).each(function () { + $form.find(options.field_selector).each(function () { var $input = $(this), value = $input.val(); @@ -132,20 +129,19 @@ // // Note that you can turn on `askOnLeave` with either uniform.settings // or with a form class. - if (options.ask_on_leave || form.hasClass('askOnLeave')) { - initial_values = form.serialize(); + if (options.ask_on_leave || $form.hasClass('askOnLeave')) { + initial_values = $form.serialize(); $(window).bind("beforeunload", function () { - if ((initial_values !== form.serialize()) && - (options.ask_on_leave || form.hasClass('askOnLeave')) + if ((initial_values !== $form.serialize()) && + (options.ask_on_leave || $form.hasClass('askOnLeave')) ) { return ($.isFunction(options.on_leave_callback)) ? - options.on_leave_callback(form): + options.on_leave_callback($form): window.confirm($.uniform.i18n('on_leave')); } }); } - // Attach the submit handler to the form // // Tasks @@ -154,18 +150,18 @@ // there are outstanding errors in the form // // TODO: Use prevent_submit to disable the submit in the blur handler - form.submit(function () { + $form.submit(function () { var return_val, callback_result = true; // In the case of a previously failed submit, we'll remove our marker - form.removeClass('failedSubmit'); + $form.removeClass('failedSubmit'); // Prevent the ask_on_leave from firing options.ask_on_leave = false; - form.removeClass('askOnLeave'); + $form.removeClass('askOnLeave'); // Remove the default values from the val() where they were being displayed - form.find(options.field_selector).each(function () { + $form.find(options.field_selector).each(function () { if ($(this).val() === $(this).data('default-value')) { $(this).val(''); } @@ -175,27 +171,25 @@ // perhaps if a field was filled in before uniform was initialized // or if blur failed to fire correctly // You can turn on prevent_submit with either a class or with the uniform.settings - if (options.prevent_submit || form.hasClass('preventSubmit')) { - // use blur to run the validators on each field - form.find(options.field_selector).each(function () { + if (options.prevent_submit || $form.hasClass('preventSubmit')) { + // Use blur to run the validators on each field + $form.find(options.field_selector).each(function () { $(this).blur(); }); - // if we have a submit callback, we'll give it a chance to inspect the data now + // If we have a submit callback, we'll give it a chance to inspect the data now if ($.isFunction(options.submit_callback)) { - callback_result = options.submit_callback(form); + callback_result = options.submit_callback($form); } - // if there are any error messages - if (form.find('.' + options.invalid_class).add('.' + options.error_class).length || - (!callback_result) - ) { + // If there are any error messages + if ($form.find('.' + options.error_class).length || (!callback_result)) { return_val = ($.isFunction(options.prevent_submit_callback)) ? - options.prevent_submit_callback(form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]): - $.fn.uniform.showFormError(form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]); - } // end form error counting + options.prevent_submit_callback($form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]): + $.uniform.showFormError($form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]); + } // End form error counting - } // end preventSubmit + } // End preventSubmit else { // We aren't preventing the submission when there are errors, so this function must // return true and allow the form to submit. @@ -204,28 +198,30 @@ // QUnit needs to run this submit function, and still prevent the submit. // This isn't ideal, but it prevents us from having to trap events - if (form.parents('#qunit-fixture').length) { + if ($form.parents('#qunit-fixture').length) { return_val = false; } - if (return_val === false) { form.addClass('failedSubmit'); } + if (return_val === false) { $form.addClass('failedSubmit'); } return return_val; }); // Set the form focus class and remove any classes other than the focus // class and then hide the default label text - form.delegate(options.field_selector, 'focus', function () { - form.find('.' + options.focused_class).removeClass(options.focused_class); + $form.delegate(options.field_selector, 'focus', function () { var $input = $(this); +window.console.log($input); + $form // Remove any other focus highlighting + .find('.' + options.focused_class) + .removeClass(options.focused_class); - $input - .parents() - .filter('.' + options.holder_class + ':first') + $input // Highlight the holder for this element + .closest('.' + options.holder_class) .addClass(options.focused_class); if ($input.val() === $input.data('default-value')) { - $input.val(''); + $input.val(''); // Hide any default data } $input.not('select').css('color', $input.data('default-color')); @@ -237,7 +233,7 @@ // validators, and run them as we find them // // If the validators fail, we trigger either 'success' or 'error' events - form.delegate(options.field_selector, 'blur', function () { + $form.delegate(options.field_selector, 'blur', function () { var $input = $(this), has_validation = false, validator, @@ -245,7 +241,7 @@ label = get_label_text($input, options); // Remove focus from form element - form.find('.' + options.focused_class).removeClass(options.focused_class); + $form.find('.' + options.focused_class).removeClass(options.focused_class); // (if empty or equal to default value) AND not required if (($input.val() === "" || $input.val() === $input.data('default-value')) && @@ -256,7 +252,7 @@ return; } - // run the validation and if they all pass, we mark the color and move on + // Run the validation and if they all pass, we mark the color and move on for (validator in $.uniform.validators) { if ($input.hasClass(validator)) { validation_result = $.uniform.validators[validator]($input, label, options); @@ -270,9 +266,7 @@ // If it had validation and we didn't return above, // then all validation passed - if (has_validation) { - $input.trigger('success'); - } + if (has_validation) { $input.trigger('success'); } // Return the color to the default $input.css('color', $input.data('default-color')); @@ -282,13 +276,13 @@ // Handle a validation error in the form element // This will set the field to have the error marker and update the // warning text - form.delegate(options.field_selector, 'error', function (e, text) { + $form.delegate(options.field_selector, 'error', function (e, text) { validate($(this), false, text, errors, options); }); // Handle a succesful validation in the form element // Remove any error messages and set the validation marker to be success - form.delegate(options.field_selector, 'success', function () { + $form.delegate(options.field_selector, 'success', function () { validate($(this), true, '', errors, options); }); @@ -298,11 +292,12 @@ // and any handling of the default data $('input[autofocus]:first').focus(); + return this; }); // end for each form }; // Display a Uni-Form form validation error - $.fn.uniform.showFormError = function ($form, errorTitle, errorMessages) { + $.uniform.showFormError = function ($form, errorTitle, errorMessages) { var m, $message; if ($('#errorMsg').length) { @@ -329,7 +324,7 @@ }; // Show the Uni-Form form success message - $.fn.uniform.showFormSuccess = function ($form, successMessage) { + $.uniform.showFormSuccess = function ($form, successMessage) { $('#okMsg').remove(); // Remove the old message $form.prepend( // The success message $('
').attr('id', 'okMsg').html("

" + successMessage + "

") @@ -342,6 +337,81 @@ }; + // Simple replacement for i18n + sprintf + // `$.uniform.i18n("string_key", sprintf style arguments)` + $.uniform.i18n = function (lang_key) { + var lang_string = $.uniform.language[lang_key], + bits = lang_string.split('%'), + out = bits[0], + re = /^([ds])(.*)$/, + p, i; + + for (i = 1; i < bits.length; i += 1) { + p = re.exec(bits[i]); + if (!p || arguments[i] === null) { + continue; + } + if (p[1] === 'd') { + out += parseInt(arguments[i], 10); + } else if (p[1] === 's') { + out += arguments[i]; + } + out += p[2]; + } + return out; + }; + + // Internationalized language strings for validation messages + $.uniform.language = { + required: '%s is required', + req_radio: 'Please make a selection', + req_checkbox: 'You must select this checkbox to continue', + minlength: '%s should be at least %d characters long', + min: '%s should be greater than or equal to %d', + maxlength: '%s should not be longer than %d characters', + max: '%s should be less than or equal to %d', + same_as: '%s is expected to be same as %s', + email: '%s is not a valid email address', + url: '%s is not a valid URL', + number: '%s needs to be a number', + integer: '%s needs to be a whole number', + alpha: '%s should contain only letters (without special characters or numbers)', + alphanum: '%s should contain only numbers and letters (without special characters)', + phrase: '%s should contain only alphabetic characters, numbers, spaces, and the following: . , - _ () * # :', + phone: '%s should be a phone number', + date: '%s should be a date (mm/dd/yyyy)', + callback: 'Failed to validate %s field. Validator function (%s) is not defined!', + on_leave: 'Are you sure you want to leave this page without saving this form?', + submit_msg: 'Sorry, this form needs corrections.', + submit_help: 'Please see the items marked below.', + submit_success: 'Thank you, this form has been sent.' + }; + + // Classnames and callback options + $.uniform.defaultOptions = { + submit_callback: false, + prevent_submit: false, + prevent_submit_callback: false, + ask_on_leave: false, + on_leave_callback: false, + valid_class: 'valid', + error_class: 'error', + focused_class: 'focused', + holder_class: 'ctrl-holder', + hint_class: 'form-hint', + field_selector: 'input, textarea, select', + default_value_color: '#afafaf' + }; + +}(jQuery)); + +(function ($) { + + $.uniform = $.uniform || {}; + + // Hold a collection of the various form validators + $.uniform.validators = {}; + // Value of field is not empty, whitespace will be counted as empty $.uniform.validators.required = function ($field, caption) { var name; @@ -399,7 +469,6 @@ return true; }; - // Element has same value as that of the target Element // // This does not use the val-{name} format, and instead @@ -547,71 +616,4 @@ return $.uniform.i18n('callback', caption, callback_function); }; - // Simple replacement for i18n + sprintf - // $.uniform.i18n("string_key", sprintf style arguments) - $.uniform.i18n = function (lang_key) { - var lang_string = $.uniform.language[lang_key], - bits = lang_string.split('%'), - out = bits[0], - re = /^([ds])(.*)$/, - p, i; - - for (i = 1; i < bits.length; i += 1) { - p = re.exec(bits[i]); - if (!p || arguments[i] === null) { - continue; - } - if (p[1] === 'd') { - out += parseInt(arguments[i], 10); - } else if (p[1] === 's') { - out += arguments[i]; - } - out += p[2]; - } - return out; - }; - - // Internationalized language strings for validation messages - $.uniform.language = { - required: '%s is required', - req_radio: 'Please make a selection', - req_checkbox: 'You must select this checkbox to continue', - minlength: '%s should be at least %d characters long', - min: '%s should be greater than or equal to %d', - maxlength: '%s should not be longer than %d characters', - max: '%s should be less than or equal to %d', - same_as: '%s is expected to be same as %s', - email: '%s is not a valid email address', - url: '%s is not a valid URL', - number: '%s needs to be a number', - integer: '%s needs to be a whole number', - alpha: '%s should contain only letters (without special characters or numbers)', - alphanum: '%s should contain only numbers and letters (without special characters)', - phrase: '%s should contain only alphabetic characters, numbers, spaces, and the following: . , - _ () * # :', - phone: '%s should be a phone number', - date: '%s should be a date (mm/dd/yyyy)', - callback: 'Failed to validate %s field. Validator function (%s) is not defined!', - on_leave: 'Are you sure you want to leave this page without saving this form?', - submit_msg: 'Sorry, this form needs corrections.', - submit_help: 'Please see the items marked below.', - submit_success: 'Thank you, this form has been sent.' - }; - - // Classnames and callback options - $.uniform.defaultOptions = { - submit_callback: false, - prevent_submit: false, - prevent_submit_callback: false, - ask_on_leave: false, - on_leave_callback: false, - valid_class: 'valid', - invalid_class: 'invalid', - error_class: 'error', - focused_class: 'focused', - holder_class: 'ctrl-holder', - hint_class: 'form-hint', - field_selector: 'input, textarea, select', - default_value_color: '#afafaf' - }; - }(jQuery)); diff --git a/dist/uni-form-validation.jquery.min.js b/dist/uni-form-validation.jquery.min.js index 712979e..dac0d80 100644 --- a/dist/uni-form-validation.jquery.min.js +++ b/dist/uni-form-validation.jquery.min.js @@ -1,4 +1,4 @@ /*! Uni-Form - v1.5.0 - 2013-03-31 * http://sprawsm.com/uni-form/ * Copyright (c) 2013 Dragan Babic; Licensed MIT */ -(function(a){a.uniform=function(){},a.uniform.validators={},a.uniform.get_val=function(a,e,t){var l,n=t;for(e=e.split(" "),l=0;e.length>l;l+=1)if(e[l]===a&&"undefined"!==e[l+1]&&"val-"===e[l+1].substr(0,4))return n=parseInt(e[l+1].substr(4),10);return n},a.uniform.get_label_text=function(e,t){var l=e.closest("label").text();return t=t||a.uniform.defaultOptions,""===l&&(l=e.closest("div."+t.holder_class).find("label").text()),l.replace("*","").replace(":","")},a.uniform.validate=function(e,t,l,n,s){var i,r;s=s||a.uniform.defaultOptions,i=e.closest("div."+s.holder_class).andSelf().toggleClass(s.invalid_class,!t).toggleClass(s.error_class,!t).toggleClass(s.valid_class,t).find("p.form-hint"),r=e.attr("name"),t?r in n&&delete n[r]:n[r]=l,t||i.data("info-text")?t&&(l=i.data("info-text")):i.data("info-text",i.html()),l&&i.html(l)},a.fn.uniform=function(e){return e=a.extend(a.uniform.defaultOptions,e),this.each(function(){var t,l,n,s,i,r;t=a(this),l=[],n=a.proxy(a.uniform.get_label_text,this),s=a.proxy(a.uniform.get_val,this),i=a.proxy(a.uniform.validate,this),t.find(e.field_selector).each(function(){var t=a(this),l=t.val();t.data("default-color",t.css("color")),l!==t.data("default-value")&&l||(t.not("select").css("color",e.default_value_color),t.val(t.attr("data-default-value")))}),(e.ask_on_leave||t.hasClass("askOnLeave"))&&(r=t.serialize(),a(window).bind("beforeunload",function(){return r!==t.serialize()&&(e.ask_on_leave||t.hasClass("askOnLeave"))?a.isFunction(e.on_leave_callback)?e.on_leave_callback(t):window.confirm(a.uniform.i18n("on_leave")):void 0})),t.submit(function(){var l,n=!0;return t.removeClass("failedSubmit"),e.ask_on_leave=!1,t.removeClass("askOnLeave"),t.find(e.field_selector).each(function(){a(this).val()===a(this).data("default-value")&&a(this).val("")}),e.prevent_submit||t.hasClass("preventSubmit")?(t.find(e.field_selector).each(function(){a(this).blur()}),a.isFunction(e.submit_callback)&&(n=e.submit_callback(t)),(t.find("."+e.invalid_class).add("."+e.error_class).length||!n)&&(l=a.isFunction(e.prevent_submit_callback)?e.prevent_submit_callback(t,a.uniform.i18n("submit_msg"),[a.uniform.i18n("submit_help")]):a.fn.uniform.showFormError(t,a.uniform.i18n("submit_msg"),[a.uniform.i18n("submit_help")]))):l=!0,t.parents("#qunit-fixture").length&&(l=!1),l===!1&&t.addClass("failedSubmit"),l}),t.delegate(e.field_selector,"focus",function(){t.find("."+e.focused_class).removeClass(e.focused_class);var l=a(this);l.parents().filter("."+e.holder_class+":first").addClass(e.focused_class),l.val()===l.data("default-value")&&l.val(""),l.not("select").css("color",l.data("default-color"))}),t.delegate(e.field_selector,"blur",function(){var l,s,i=a(this),r=!1,o=n(i,e);if(t.find("."+e.focused_class).removeClass(e.focused_class),(""===i.val()||i.val()===i.data("default-value"))&&!i.hasClass("required"))return i.not("select").css("color",e.default_value_color),i.val(i.data("default-value")),void 0;for(l in a.uniform.validators)if(i.hasClass(l)&&(s=a.uniform.validators[l](i,o,e),r=!0,"string"==typeof s))return i.trigger("error",s),void 0;r&&i.trigger("success"),i.css("color",i.data("default-color"))}),t.delegate(e.field_selector,"error",function(t,n){i(a(this),!1,n,l,e)}),t.delegate(e.field_selector,"success",function(){i(a(this),!0,"",l,e)}),a("input[autofocus]:first").focus()})},a.fn.uniform.showFormError=function(e,t,l){var n,s;if(a("#errorMsg").length&&a("#errorMsg").remove(),s=a("
").attr("id","errorMsg").html("

"+t+"

"),l.length){s.append(a("
    "));for(n in l)l.hasOwnProperty(n)&&a("ol",s).append(a("
  1. ").text(l[n]))}return e.prepend(s),a("html, body").animate({scrollTop:e.offset().top},500),a("#errorMsg").slideDown(),!1},a.fn.uniform.showFormSuccess=function(e,t){return a("#okMsg").remove(),e.prepend(a("
    ").attr("id","okMsg").html("

    "+t+"

    ")),a("html, body").animate({scrollTop:e.offset().top},500),a("#okMsg").slideDown(),!1},a.uniform.validators.required=function(e,t){var l;return e.is(":radio")?(l=e.attr("name"),a("input[name="+l+"]:checked").length?!0:a.uniform.i18n("req_radio",t)):e.is(":checkbox")?(l=e.attr("name"),e.is(":checked")?!0:a.uniform.i18n("req_checkbox",t)):""===a.trim(e.val())?a.uniform.i18n("required",t):!0},a.uniform.validators.validateMinLength=function(e,t){var l=a.uniform.get_val("validateMinLength",e.attr("class"),0);return l>0&&l>e.val().length?a.uniform.i18n("minlength",t,l):!0},a.uniform.validators.validateMin=function(e,t){var l=a.uniform.get_val("validateMin",e.attr("class"),0);return l>parseInt(e.val(),10)?a.uniform.i18n("min",t,l):!0},a.uniform.validators.validateMaxLength=function(e,t){var l=a.uniform.get_val("validateMaxLength",e.attr("class"),0);return l>0&&e.val().length>l?a.uniform.i18n("maxlength",t,l):!0},a.uniform.validators.validateMax=function(e,t){var l=a.uniform.get_val("validateMax",e.attr("class"),0);return parseInt(e.val(),10)>l?a.uniform.i18n("max",t,l):!0},a.uniform.validators.validateSameAs=function(e,t,l){var n,s,i=e.attr("class").split(" "),r="",o="",u=e.closest("form");for(l=l||a.uniform.defaultOptions,s=0;i.length>s;s+=1)if("validateSameAs"===i[s]&&"undefined"!==i[s+1]){r=i[s+1];break}return r&&(n=u.find('input[name="'+r+'"]'),n.val()!==e.val())?(o=a.uniform.get_label_text(n,l),a.uniform.i18n("same_as",t,o)):!0},a.uniform.validators.validateEmail=function(e,t){return e.val().match(/^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)?!0:a.uniform.i18n("email",t)},a.uniform.validators.validateUrl=function(e,t){return e.val().match(/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_\-]*)(\.[A-Z0-9][A-Z0-9_\-]*)+)(:(\d+))?\/?/i)?!0:a.uniform.i18n("url",t)},a.uniform.validators.validateNumber=function(e,t){return e.val().match(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/)||""===e.val()?!0:a.uniform.i18n("number",t)},a.uniform.validators.validateInteger=function(e,t){return e.val().match(/(^-?\d\d*$)/)||""===e.val()?!0:a.uniform.i18n("integer",t)},a.uniform.validators.validateAlpha=function(e,t){return e.val().match(/^[a-zA-Z]+$/)?!0:a.uniform.i18n("alpha",t)},a.uniform.validators.validateAlphaNum=function(e,t){return e.val().match(/\W/)?a.uniform.i18n("alphanum",t):!0},a.uniform.validators.validatePhrase=function(e,t){return""===e.val()||e.val().match(/^[\w\d\.\-_\(\)\*'# :,]+$/i)?!0:a.uniform.i18n("phrase",t)},a.uniform.validators.validatePhone=function(e,t){var l=/^\(?(\d{3})\)?[\- ]?(\d{3})[\- ]?(\d{4})$/;return l.test(e.val())?!0:a.uniform.i18n("phone",t)},a.uniform.validators.validateDate=function(e,t){return e.val().match("([0]?[1-9]|[1][0-2])/([0]?[1-9]|[1|2][0-9]|[3][0|1])/([0-9]{4}|[0-9]{2})$")?!0:a.uniform.i18n("date",t)},a.uniform.validators.validateCallback=function(e,t){var l,n=e.attr("class").split(" "),s="";for(l=0;n.length>l;l+=1)if("validateCallback"===n[l]&&"undefined"!==n[l+1]){s=n[l+1];break}return"undefined"!==window[s]&&"function"==typeof window[s]?window[s](e,t):a.uniform.i18n("callback",t,s)},a.uniform.i18n=function(e){var t,l,n=a.uniform.language[e],s=n.split("%"),i=s[0],r=/^([ds])(.*)$/;for(l=1;s.length>l;l+=1)t=r.exec(s[l]),t&&null!==arguments[l]&&("d"===t[1]?i+=parseInt(arguments[l],10):"s"===t[1]&&(i+=arguments[l]),i+=t[2]);return i},a.uniform.language={required:"%s is required",req_radio:"Please make a selection",req_checkbox:"You must select this checkbox to continue",minlength:"%s should be at least %d characters long",min:"%s should be greater than or equal to %d",maxlength:"%s should not be longer than %d characters",max:"%s should be less than or equal to %d",same_as:"%s is expected to be same as %s",email:"%s is not a valid email address",url:"%s is not a valid URL",number:"%s needs to be a number",integer:"%s needs to be a whole number",alpha:"%s should contain only letters (without special characters or numbers)",alphanum:"%s should contain only numbers and letters (without special characters)",phrase:"%s should contain only alphabetic characters, numbers, spaces, and the following: . , - _ () * # :",phone:"%s should be a phone number",date:"%s should be a date (mm/dd/yyyy)",callback:"Failed to validate %s field. Validator function (%s) is not defined!",on_leave:"Are you sure you want to leave this page without saving this form?",submit_msg:"Sorry, this form needs corrections.",submit_help:"Please see the items marked below.",submit_success:"Thank you, this form has been sent."},a.uniform.defaultOptions={submit_callback:!1,prevent_submit:!1,prevent_submit_callback:!1,ask_on_leave:!1,on_leave_callback:!1,valid_class:"valid",invalid_class:"invalid",error_class:"error",focused_class:"focused",holder_class:"ctrl-holder",hint_class:"form-hint",field_selector:"input, textarea, select",default_value_color:"#afafaf"}})(jQuery); \ No newline at end of file +(function(a){a.uniform=function(){},a.uniform.get_val=function(a,e,t){var l,n=t;for(e=e.split(" "),l=0;e.length>l;l+=1)if(e[l]===a&&"undefined"!==e[l+1]&&"val-"===e[l+1].substr(0,4))return n=parseInt(e[l+1].substr(4),10);return n},a.uniform.get_label_text=function(e,t){var l=e.closest("label").text();return t=t||a.uniform.defaultOptions,""===l&&(l=e.closest("div."+t.holder_class).find("label").text()),l.replace("*","").replace(":","")},a.uniform.validate=function(e,t,l,n,r){var s,i;r=r||a.uniform.defaultOptions,s=e.closest("div."+r.holder_class).andSelf().toggleClass(r.error_class,!t).toggleClass(r.valid_class,t).find("p.form-hint"),i=e.attr("name"),t?i in n&&delete n[i]:n[i]=l,t||s.data("info-text")?t&&(l=s.data("info-text")):s.data("info-text",s.html()),l&&s.html(l)},a.fn.uniform=function(e){return e=a.extend(a.uniform.defaultOptions,e),this.each(function(){var t,l,n,r,s,i;return t=a(this),l=[],n=a.proxy(a.uniform.get_label_text,this),r=a.proxy(a.uniform.get_val,this),s=a.proxy(a.uniform.validate,this),t.find(e.field_selector).each(function(){var t=a(this),l=t.val();t.data("default-color",t.css("color")),l!==t.data("default-value")&&l||(t.not("select").css("color",e.default_value_color),t.val(t.attr("data-default-value")))}),(e.ask_on_leave||t.hasClass("askOnLeave"))&&(i=t.serialize(),a(window).bind("beforeunload",function(){return i!==t.serialize()&&(e.ask_on_leave||t.hasClass("askOnLeave"))?a.isFunction(e.on_leave_callback)?e.on_leave_callback(t):window.confirm(a.uniform.i18n("on_leave")):void 0})),t.submit(function(){var l,n=!0;return t.removeClass("failedSubmit"),e.ask_on_leave=!1,t.removeClass("askOnLeave"),t.find(e.field_selector).each(function(){a(this).val()===a(this).data("default-value")&&a(this).val("")}),e.prevent_submit||t.hasClass("preventSubmit")?(t.find(e.field_selector).each(function(){a(this).blur()}),a.isFunction(e.submit_callback)&&(n=e.submit_callback(t)),(t.find("."+e.error_class).length||!n)&&(l=a.isFunction(e.prevent_submit_callback)?e.prevent_submit_callback(t,a.uniform.i18n("submit_msg"),[a.uniform.i18n("submit_help")]):a.uniform.showFormError(t,a.uniform.i18n("submit_msg"),[a.uniform.i18n("submit_help")]))):l=!0,t.parents("#qunit-fixture").length&&(l=!1),l===!1&&t.addClass("failedSubmit"),l}),t.delegate(e.field_selector,"focus",function(){var l=a(this);window.console.log(l),t.find("."+e.focused_class).removeClass(e.focused_class),l.closest("."+e.holder_class).addClass(e.focused_class),l.val()===l.data("default-value")&&l.val(""),l.not("select").css("color",l.data("default-color"))}),t.delegate(e.field_selector,"blur",function(){var l,r,s=a(this),i=!1,o=n(s,e);if(t.find("."+e.focused_class).removeClass(e.focused_class),(""===s.val()||s.val()===s.data("default-value"))&&!s.hasClass("required"))return s.not("select").css("color",e.default_value_color),s.val(s.data("default-value")),void 0;for(l in a.uniform.validators)if(s.hasClass(l)&&(r=a.uniform.validators[l](s,o,e),i=!0,"string"==typeof r))return s.trigger("error",r),void 0;i&&s.trigger("success"),s.css("color",s.data("default-color"))}),t.delegate(e.field_selector,"error",function(t,n){s(a(this),!1,n,l,e)}),t.delegate(e.field_selector,"success",function(){s(a(this),!0,"",l,e)}),a("input[autofocus]:first").focus(),this})},a.uniform.showFormError=function(e,t,l){var n,r;if(a("#errorMsg").length&&a("#errorMsg").remove(),r=a("
    ").attr("id","errorMsg").html("

    "+t+"

    "),l.length){r.append(a("
      "));for(n in l)l.hasOwnProperty(n)&&a("ol",r).append(a("
    1. ").text(l[n]))}return e.prepend(r),a("html, body").animate({scrollTop:e.offset().top},500),a("#errorMsg").slideDown(),!1},a.uniform.showFormSuccess=function(e,t){return a("#okMsg").remove(),e.prepend(a("
      ").attr("id","okMsg").html("

      "+t+"

      ")),a("html, body").animate({scrollTop:e.offset().top},500),a("#okMsg").slideDown(),!1},a.uniform.i18n=function(e){var t,l,n=a.uniform.language[e],r=n.split("%"),s=r[0],i=/^([ds])(.*)$/;for(l=1;r.length>l;l+=1)t=i.exec(r[l]),t&&null!==arguments[l]&&("d"===t[1]?s+=parseInt(arguments[l],10):"s"===t[1]&&(s+=arguments[l]),s+=t[2]);return s},a.uniform.language={required:"%s is required",req_radio:"Please make a selection",req_checkbox:"You must select this checkbox to continue",minlength:"%s should be at least %d characters long",min:"%s should be greater than or equal to %d",maxlength:"%s should not be longer than %d characters",max:"%s should be less than or equal to %d",same_as:"%s is expected to be same as %s",email:"%s is not a valid email address",url:"%s is not a valid URL",number:"%s needs to be a number",integer:"%s needs to be a whole number",alpha:"%s should contain only letters (without special characters or numbers)",alphanum:"%s should contain only numbers and letters (without special characters)",phrase:"%s should contain only alphabetic characters, numbers, spaces, and the following: . , - _ () * # :",phone:"%s should be a phone number",date:"%s should be a date (mm/dd/yyyy)",callback:"Failed to validate %s field. Validator function (%s) is not defined!",on_leave:"Are you sure you want to leave this page without saving this form?",submit_msg:"Sorry, this form needs corrections.",submit_help:"Please see the items marked below.",submit_success:"Thank you, this form has been sent."},a.uniform.defaultOptions={submit_callback:!1,prevent_submit:!1,prevent_submit_callback:!1,ask_on_leave:!1,on_leave_callback:!1,valid_class:"valid",error_class:"error",focused_class:"focused",holder_class:"ctrl-holder",hint_class:"form-hint",field_selector:"input, textarea, select",default_value_color:"#afafaf"}})(jQuery),function(a){a.uniform=a.uniform||{},a.uniform.validators={},a.uniform.validators.required=function(e,t){var l;return e.is(":radio")?(l=e.attr("name"),a("input[name="+l+"]:checked").length?!0:a.uniform.i18n("req_radio",t)):e.is(":checkbox")?(l=e.attr("name"),e.is(":checked")?!0:a.uniform.i18n("req_checkbox",t)):""===a.trim(e.val())?a.uniform.i18n("required",t):!0},a.uniform.validators.validateMinLength=function(e,t){var l=a.uniform.get_val("validateMinLength",e.attr("class"),0);return l>0&&l>e.val().length?a.uniform.i18n("minlength",t,l):!0},a.uniform.validators.validateMin=function(e,t){var l=a.uniform.get_val("validateMin",e.attr("class"),0);return l>parseInt(e.val(),10)?a.uniform.i18n("min",t,l):!0},a.uniform.validators.validateMaxLength=function(e,t){var l=a.uniform.get_val("validateMaxLength",e.attr("class"),0);return l>0&&e.val().length>l?a.uniform.i18n("maxlength",t,l):!0},a.uniform.validators.validateMax=function(e,t){var l=a.uniform.get_val("validateMax",e.attr("class"),0);return parseInt(e.val(),10)>l?a.uniform.i18n("max",t,l):!0},a.uniform.validators.validateSameAs=function(e,t,l){var n,r,s=e.attr("class").split(" "),i="",o="",u=e.closest("form");for(l=l||a.uniform.defaultOptions,r=0;s.length>r;r+=1)if("validateSameAs"===s[r]&&"undefined"!==s[r+1]){i=s[r+1];break}return i&&(n=u.find('input[name="'+i+'"]'),n.val()!==e.val())?(o=a.uniform.get_label_text(n,l),a.uniform.i18n("same_as",t,o)):!0},a.uniform.validators.validateEmail=function(e,t){return e.val().match(/^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)?!0:a.uniform.i18n("email",t)},a.uniform.validators.validateUrl=function(e,t){return e.val().match(/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_\-]*)(\.[A-Z0-9][A-Z0-9_\-]*)+)(:(\d+))?\/?/i)?!0:a.uniform.i18n("url",t)},a.uniform.validators.validateNumber=function(e,t){return e.val().match(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/)||""===e.val()?!0:a.uniform.i18n("number",t)},a.uniform.validators.validateInteger=function(e,t){return e.val().match(/(^-?\d\d*$)/)||""===e.val()?!0:a.uniform.i18n("integer",t)},a.uniform.validators.validateAlpha=function(e,t){return e.val().match(/^[a-zA-Z]+$/)?!0:a.uniform.i18n("alpha",t)},a.uniform.validators.validateAlphaNum=function(e,t){return e.val().match(/\W/)?a.uniform.i18n("alphanum",t):!0},a.uniform.validators.validatePhrase=function(e,t){return""===e.val()||e.val().match(/^[\w\d\.\-_\(\)\*'# :,]+$/i)?!0:a.uniform.i18n("phrase",t)},a.uniform.validators.validatePhone=function(e,t){var l=/^\(?(\d{3})\)?[\- ]?(\d{3})[\- ]?(\d{4})$/;return l.test(e.val())?!0:a.uniform.i18n("phone",t)},a.uniform.validators.validateDate=function(e,t){return e.val().match("([0]?[1-9]|[1][0-2])/([0]?[1-9]|[1|2][0-9]|[3][0|1])/([0-9]{4}|[0-9]{2})$")?!0:a.uniform.i18n("date",t)},a.uniform.validators.validateCallback=function(e,t){var l,n=e.attr("class").split(" "),r="";for(l=0;n.length>l;l+=1)if("validateCallback"===n[l]&&"undefined"!==n[l+1]){r=n[l+1];break}return"undefined"!==window[r]&&"function"==typeof window[r]?window[r](e,t):a.uniform.i18n("callback",t,r)}}(jQuery); \ No newline at end of file diff --git a/src/uni-form-validation.jquery.js b/src/uni-form-validation.jquery.js index c21e869..2f1cd5a 100644 --- a/src/uni-form-validation.jquery.js +++ b/src/uni-form-validation.jquery.js @@ -30,9 +30,6 @@ // Static Method to hold config and options $.uniform = function () {}; - // Hold a collection of the various form validators - $.uniform.validators = {}; - // Get the value for a validator that takes parameters. // These are in the format of `val-{value}` $.uniform.get_val = function (name, classes, defaultValue) { @@ -66,7 +63,6 @@ $p = $input .closest('div.' + options.holder_class) .andSelf() - .toggleClass(options.invalid_class, !isValid) .toggleClass(options.error_class, !isValid) .toggleClass(options.valid_class, isValid) .find('p.form-hint'); @@ -93,21 +89,22 @@ if (errorMessage) { $p.html(errorMessage); } }; + // Collection method will ppply the uniform behavior to elements $.fn.uniform = function (options) { options = $.extend($.uniform.defaultOptions, options); return this.each(function () { - var form, errors, get_label_text, get_val, validate, initial_values; + var $form, errors, get_label_text, get_val, validate, initial_values; - form = $(this); + $form = $(this); errors = []; get_label_text = $.proxy($.uniform.get_label_text, this); get_val = $.proxy($.uniform.get_val, this); validate = $.proxy($.uniform.validate, this); // Select form fields and attach the highlighter functionality - form.find(options.field_selector).each(function () { + $form.find(options.field_selector).each(function () { var $input = $(this), value = $input.val(); @@ -129,20 +126,19 @@ // // Note that you can turn on `askOnLeave` with either uniform.settings // or with a form class. - if (options.ask_on_leave || form.hasClass('askOnLeave')) { - initial_values = form.serialize(); + if (options.ask_on_leave || $form.hasClass('askOnLeave')) { + initial_values = $form.serialize(); $(window).bind("beforeunload", function () { - if ((initial_values !== form.serialize()) && - (options.ask_on_leave || form.hasClass('askOnLeave')) + if ((initial_values !== $form.serialize()) && + (options.ask_on_leave || $form.hasClass('askOnLeave')) ) { return ($.isFunction(options.on_leave_callback)) ? - options.on_leave_callback(form): + options.on_leave_callback($form): window.confirm($.uniform.i18n('on_leave')); } }); } - // Attach the submit handler to the form // // Tasks @@ -151,18 +147,18 @@ // there are outstanding errors in the form // // TODO: Use prevent_submit to disable the submit in the blur handler - form.submit(function () { + $form.submit(function () { var return_val, callback_result = true; // In the case of a previously failed submit, we'll remove our marker - form.removeClass('failedSubmit'); + $form.removeClass('failedSubmit'); // Prevent the ask_on_leave from firing options.ask_on_leave = false; - form.removeClass('askOnLeave'); + $form.removeClass('askOnLeave'); // Remove the default values from the val() where they were being displayed - form.find(options.field_selector).each(function () { + $form.find(options.field_selector).each(function () { if ($(this).val() === $(this).data('default-value')) { $(this).val(''); } @@ -172,27 +168,25 @@ // perhaps if a field was filled in before uniform was initialized // or if blur failed to fire correctly // You can turn on prevent_submit with either a class or with the uniform.settings - if (options.prevent_submit || form.hasClass('preventSubmit')) { - // use blur to run the validators on each field - form.find(options.field_selector).each(function () { + if (options.prevent_submit || $form.hasClass('preventSubmit')) { + // Use blur to run the validators on each field + $form.find(options.field_selector).each(function () { $(this).blur(); }); - // if we have a submit callback, we'll give it a chance to inspect the data now + // If we have a submit callback, we'll give it a chance to inspect the data now if ($.isFunction(options.submit_callback)) { - callback_result = options.submit_callback(form); + callback_result = options.submit_callback($form); } - // if there are any error messages - if (form.find('.' + options.invalid_class).add('.' + options.error_class).length || - (!callback_result) - ) { + // If there are any error messages + if ($form.find('.' + options.error_class).length || (!callback_result)) { return_val = ($.isFunction(options.prevent_submit_callback)) ? - options.prevent_submit_callback(form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]): - $.fn.uniform.showFormError(form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]); - } // end form error counting + options.prevent_submit_callback($form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]): + $.uniform.showFormError($form, $.uniform.i18n('submit_msg'), [$.uniform.i18n('submit_help')]); + } // End form error counting - } // end preventSubmit + } // End preventSubmit else { // We aren't preventing the submission when there are errors, so this function must // return true and allow the form to submit. @@ -201,28 +195,30 @@ // QUnit needs to run this submit function, and still prevent the submit. // This isn't ideal, but it prevents us from having to trap events - if (form.parents('#qunit-fixture').length) { + if ($form.parents('#qunit-fixture').length) { return_val = false; } - if (return_val === false) { form.addClass('failedSubmit'); } + if (return_val === false) { $form.addClass('failedSubmit'); } return return_val; }); // Set the form focus class and remove any classes other than the focus // class and then hide the default label text - form.delegate(options.field_selector, 'focus', function () { - form.find('.' + options.focused_class).removeClass(options.focused_class); + $form.delegate(options.field_selector, 'focus', function () { var $input = $(this); +window.console.log($input); + $form // Remove any other focus highlighting + .find('.' + options.focused_class) + .removeClass(options.focused_class); - $input - .parents() - .filter('.' + options.holder_class + ':first') + $input // Highlight the holder for this element + .closest('.' + options.holder_class) .addClass(options.focused_class); if ($input.val() === $input.data('default-value')) { - $input.val(''); + $input.val(''); // Hide any default data } $input.not('select').css('color', $input.data('default-color')); @@ -234,7 +230,7 @@ // validators, and run them as we find them // // If the validators fail, we trigger either 'success' or 'error' events - form.delegate(options.field_selector, 'blur', function () { + $form.delegate(options.field_selector, 'blur', function () { var $input = $(this), has_validation = false, validator, @@ -242,7 +238,7 @@ label = get_label_text($input, options); // Remove focus from form element - form.find('.' + options.focused_class).removeClass(options.focused_class); + $form.find('.' + options.focused_class).removeClass(options.focused_class); // (if empty or equal to default value) AND not required if (($input.val() === "" || $input.val() === $input.data('default-value')) && @@ -253,7 +249,7 @@ return; } - // run the validation and if they all pass, we mark the color and move on + // Run the validation and if they all pass, we mark the color and move on for (validator in $.uniform.validators) { if ($input.hasClass(validator)) { validation_result = $.uniform.validators[validator]($input, label, options); @@ -267,9 +263,7 @@ // If it had validation and we didn't return above, // then all validation passed - if (has_validation) { - $input.trigger('success'); - } + if (has_validation) { $input.trigger('success'); } // Return the color to the default $input.css('color', $input.data('default-color')); @@ -279,13 +273,13 @@ // Handle a validation error in the form element // This will set the field to have the error marker and update the // warning text - form.delegate(options.field_selector, 'error', function (e, text) { + $form.delegate(options.field_selector, 'error', function (e, text) { validate($(this), false, text, errors, options); }); // Handle a succesful validation in the form element // Remove any error messages and set the validation marker to be success - form.delegate(options.field_selector, 'success', function () { + $form.delegate(options.field_selector, 'success', function () { validate($(this), true, '', errors, options); }); @@ -295,11 +289,12 @@ // and any handling of the default data $('input[autofocus]:first').focus(); + return this; }); // end for each form }; // Display a Uni-Form form validation error - $.fn.uniform.showFormError = function ($form, errorTitle, errorMessages) { + $.uniform.showFormError = function ($form, errorTitle, errorMessages) { var m, $message; if ($('#errorMsg').length) { @@ -326,7 +321,7 @@ }; // Show the Uni-Form form success message - $.fn.uniform.showFormSuccess = function ($form, successMessage) { + $.uniform.showFormSuccess = function ($form, successMessage) { $('#okMsg').remove(); // Remove the old message $form.prepend( // The success message $('
      ').attr('id', 'okMsg').html("

      " + successMessage + "

      ") @@ -339,213 +334,8 @@ }; - // Value of field is not empty, whitespace will be counted as empty - $.uniform.validators.required = function ($field, caption) { - var name; - if ($field.is(':radio')) { - name = $field.attr('name'); - if ($("input[name=" + name + "]:checked").length) { - return true; - } - return $.uniform.i18n('req_radio', caption); - } - if ($field.is(':checkbox')) { - name = $field.attr('name'); - if ($field.is(":checked")) { return true; } - return $.uniform.i18n('req_checkbox', caption); - } - if ($.trim($field.val()) === '') { - return $.uniform.i18n('required', caption); - } - return true; - }; - - // Value is shorter than allowed - $.uniform.validators.validateMinLength = function ($field, caption) { - var min_length = $.uniform.get_val('validateMinLength', $field.attr('class'), 0); - if ((min_length > 0) && ($field.val().length < min_length)) { - return $.uniform.i18n('minlength', caption, min_length); - } - return true; - }; - - // Value is less than min - $.uniform.validators.validateMin = function ($field, caption) { - var min_val = $.uniform.get_val('validateMin', $field.attr('class'), 0); - if ((parseInt($field.val(), 10) < min_val)) { - return $.uniform.i18n('min', caption, min_val); - } - return true; - }; - - // Value is longer than allowed - $.uniform.validators.validateMaxLength = function ($field, caption) { - var max_length = $.uniform.get_val('validateMaxLength', $field.attr('class'), 0); - if ((max_length > 0) && ($field.val().length > max_length)) { - return $.uniform.i18n('maxlength', caption, max_length); - } - return true; - }; - - // Value is greater than max - $.uniform.validators.validateMax = function ($field, caption) { - var max_val = $.uniform.get_val('validateMax', $field.attr('class'), 0); - if ((parseInt($field.val(), 10) > max_val)) { - return $.uniform.i18n('max', caption, max_val); - } - return true; - }; - - - // Element has same value as that of the target Element - // - // This does not use the val-{name} format, and instead - // is only the __name__ of the element - // - // `class="validateSameAs field_id"` - $.uniform.validators.validateSameAs = function ($field, caption, options) { - var classes = $field.attr('class').split(' '), - target_field_name = '', - target_field_caption = '', - $form = $field.closest('form'), - $target_field, i; - - options = options || $.uniform.defaultOptions; - for (i = 0; i < classes.length; i += 1) { - if (classes[i] === 'validateSameAs') { - if (classes[i + 1] !== 'undefined') { - target_field_name = classes[i + 1]; - break; - } - } - } - - if (target_field_name) { - $target_field = $form.find('input[name="' + target_field_name + '"]'); - if ($target_field.val() !== $field.val()) { - target_field_caption = $.uniform.get_label_text($target_field, options); - return $.uniform.i18n('same_as', caption, target_field_caption); - } - } - - return true; - }; - - // Valid email address - $.uniform.validators.validateEmail = function ($field, caption) { - if ($field.val().match(/^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) { - return true; - } - return $.uniform.i18n('email', caption); - }; - - // Valid URL (http://,https://,ftp://) - $.uniform.validators.validateUrl = function ($field, caption) { - if ($field.val().match(/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_\-]*)(\.[A-Z0-9][A-Z0-9_\-]*)+)(:(\d+))?\/?/i)) { - return true; - } - return $.uniform.i18n('url', caption); - }; - - // Number is only valid value (integers and floats) - $.uniform.validators.validateNumber = function ($field, caption) { - if ($field.val().match(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/) || $field.val() === '') { - return true; - } - return $.uniform.i18n('number', caption); - }; - - // Whole numbers are allowed - $.uniform.validators.validateInteger = function ($field, caption) { - if ($field.val().match(/(^-?\d\d*$)/) || $field.val() === '') { - return true; - } - return $.uniform.i18n('integer', caption); - }; - - // Letters only - $.uniform.validators.validateAlpha = function ($field, caption) { - if ($field.val().match(/^[a-zA-Z]+$/)) { - return true; - } - return $.uniform.i18n('alpha', caption); - }; - - // Letters and numbers - $.uniform.validators.validateAlphaNum = function ($field, caption) { - if ($field.val().match(/\W/)) { - return $.uniform.i18n('alphanum', caption); - } - return true; - }; - - // Simple phrases of words, numbers and punctuation - $.uniform.validators.validatePhrase = function ($field, caption) { - if (($field.val() === '') || $field.val().match(/^[\w\d\.\-_\(\)\*'# :,]+$/i)) { - return true; - } - return $.uniform.i18n('phrase', caption); - }; - - // Phone number - $.uniform.validators.validatePhone = function ($field, caption) { - var phoneNumber = /^\(?(\d{3})\)?[\- ]?(\d{3})[\- ]?(\d{4})$/; - if (phoneNumber.test($field.val())) { - return true; - } - return $.uniform.i18n('phone', caption); - }; - - // Date in MM/DD/YYYY format - $.uniform.validators.validateDate = function ($field, caption) { - if ($field.val().match('([0]?[1-9]|[1][0-2])/([0]?[1-9]|[1|2][0-9]|[3][0|1])/([0-9]{4}|[0-9]{2})$')) { - return true; - } - return $.uniform.i18n('date', caption); - }; - - // Callback validator - // - // Lets you define your own validators. Usage: - // - // `` - // - // This will result in UniForm searching for `window.my_callback` function and - // executing it with field and caption arguments. Sample implementation: - // - // window.my_callback = function (field, caption) { - // if (field.val() === '34') { - // return true; - // } else { - // return caption + ' value should be "34"'; - // } - // } - // - $.uniform.validators.validateCallback = function ($field, caption) { - var classes = $field.attr('class').split(' '), - callback_function = '', - i; - - for (i = 0; i < classes.length; i += 1) { - if (classes[i] === 'validateCallback') { - if (classes[i + 1] !== 'undefined') { - callback_function = classes[i + 1]; - break; - } - } - } - - if (window[callback_function] !== 'undefined' && - (typeof window[callback_function] === 'function') - ) { - return window[callback_function]($field, caption); - } - - return $.uniform.i18n('callback', caption, callback_function); - }; - // Simple replacement for i18n + sprintf - // $.uniform.i18n("string_key", sprintf style arguments) + // `$.uniform.i18n("string_key", sprintf style arguments)` $.uniform.i18n = function (lang_key) { var lang_string = $.uniform.language[lang_key], bits = lang_string.split('%'), @@ -602,7 +392,6 @@ ask_on_leave: false, on_leave_callback: false, valid_class: 'valid', - invalid_class: 'invalid', error_class: 'error', focused_class: 'focused', holder_class: 'ctrl-holder', diff --git a/src/validators.js b/src/validators.js new file mode 100644 index 0000000..8b8c97f --- /dev/null +++ b/src/validators.js @@ -0,0 +1,214 @@ +/* global jQuery:false */ + +(function ($) { + + $.uniform = $.uniform || {}; + + // Hold a collection of the various form validators + $.uniform.validators = {}; + + // Value of field is not empty, whitespace will be counted as empty + $.uniform.validators.required = function ($field, caption) { + var name; + if ($field.is(':radio')) { + name = $field.attr('name'); + if ($("input[name=" + name + "]:checked").length) { + return true; + } + return $.uniform.i18n('req_radio', caption); + } + if ($field.is(':checkbox')) { + name = $field.attr('name'); + if ($field.is(":checked")) { return true; } + return $.uniform.i18n('req_checkbox', caption); + } + if ($.trim($field.val()) === '') { + return $.uniform.i18n('required', caption); + } + return true; + }; + + // Value is shorter than allowed + $.uniform.validators.validateMinLength = function ($field, caption) { + var min_length = $.uniform.get_val('validateMinLength', $field.attr('class'), 0); + if ((min_length > 0) && ($field.val().length < min_length)) { + return $.uniform.i18n('minlength', caption, min_length); + } + return true; + }; + + // Value is less than min + $.uniform.validators.validateMin = function ($field, caption) { + var min_val = $.uniform.get_val('validateMin', $field.attr('class'), 0); + if ((parseInt($field.val(), 10) < min_val)) { + return $.uniform.i18n('min', caption, min_val); + } + return true; + }; + + // Value is longer than allowed + $.uniform.validators.validateMaxLength = function ($field, caption) { + var max_length = $.uniform.get_val('validateMaxLength', $field.attr('class'), 0); + if ((max_length > 0) && ($field.val().length > max_length)) { + return $.uniform.i18n('maxlength', caption, max_length); + } + return true; + }; + + // Value is greater than max + $.uniform.validators.validateMax = function ($field, caption) { + var max_val = $.uniform.get_val('validateMax', $field.attr('class'), 0); + if ((parseInt($field.val(), 10) > max_val)) { + return $.uniform.i18n('max', caption, max_val); + } + return true; + }; + + // Element has same value as that of the target Element + // + // This does not use the val-{name} format, and instead + // is only the __name__ of the element + // + // `class="validateSameAs field_id"` + $.uniform.validators.validateSameAs = function ($field, caption, options) { + var classes = $field.attr('class').split(' '), + target_field_name = '', + target_field_caption = '', + $form = $field.closest('form'), + $target_field, i; + + options = options || $.uniform.defaultOptions; + for (i = 0; i < classes.length; i += 1) { + if (classes[i] === 'validateSameAs') { + if (classes[i + 1] !== 'undefined') { + target_field_name = classes[i + 1]; + break; + } + } + } + + if (target_field_name) { + $target_field = $form.find('input[name="' + target_field_name + '"]'); + if ($target_field.val() !== $field.val()) { + target_field_caption = $.uniform.get_label_text($target_field, options); + return $.uniform.i18n('same_as', caption, target_field_caption); + } + } + + return true; + }; + + // Valid email address + $.uniform.validators.validateEmail = function ($field, caption) { + if ($field.val().match(/^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) { + return true; + } + return $.uniform.i18n('email', caption); + }; + + // Valid URL (http://,https://,ftp://) + $.uniform.validators.validateUrl = function ($field, caption) { + if ($field.val().match(/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_\-]*)(\.[A-Z0-9][A-Z0-9_\-]*)+)(:(\d+))?\/?/i)) { + return true; + } + return $.uniform.i18n('url', caption); + }; + + // Number is only valid value (integers and floats) + $.uniform.validators.validateNumber = function ($field, caption) { + if ($field.val().match(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/) || $field.val() === '') { + return true; + } + return $.uniform.i18n('number', caption); + }; + + // Whole numbers are allowed + $.uniform.validators.validateInteger = function ($field, caption) { + if ($field.val().match(/(^-?\d\d*$)/) || $field.val() === '') { + return true; + } + return $.uniform.i18n('integer', caption); + }; + + // Letters only + $.uniform.validators.validateAlpha = function ($field, caption) { + if ($field.val().match(/^[a-zA-Z]+$/)) { + return true; + } + return $.uniform.i18n('alpha', caption); + }; + + // Letters and numbers + $.uniform.validators.validateAlphaNum = function ($field, caption) { + if ($field.val().match(/\W/)) { + return $.uniform.i18n('alphanum', caption); + } + return true; + }; + + // Simple phrases of words, numbers and punctuation + $.uniform.validators.validatePhrase = function ($field, caption) { + if (($field.val() === '') || $field.val().match(/^[\w\d\.\-_\(\)\*'# :,]+$/i)) { + return true; + } + return $.uniform.i18n('phrase', caption); + }; + + // Phone number + $.uniform.validators.validatePhone = function ($field, caption) { + var phoneNumber = /^\(?(\d{3})\)?[\- ]?(\d{3})[\- ]?(\d{4})$/; + if (phoneNumber.test($field.val())) { + return true; + } + return $.uniform.i18n('phone', caption); + }; + + // Date in MM/DD/YYYY format + $.uniform.validators.validateDate = function ($field, caption) { + if ($field.val().match('([0]?[1-9]|[1][0-2])/([0]?[1-9]|[1|2][0-9]|[3][0|1])/([0-9]{4}|[0-9]{2})$')) { + return true; + } + return $.uniform.i18n('date', caption); + }; + + // Callback validator + // + // Lets you define your own validators. Usage: + // + // `` + // + // This will result in UniForm searching for `window.my_callback` function and + // executing it with field and caption arguments. Sample implementation: + // + // window.my_callback = function (field, caption) { + // if (field.val() === '34') { + // return true; + // } else { + // return caption + ' value should be "34"'; + // } + // } + // + $.uniform.validators.validateCallback = function ($field, caption) { + var classes = $field.attr('class').split(' '), + callback_function = '', + i; + + for (i = 0; i < classes.length; i += 1) { + if (classes[i] === 'validateCallback') { + if (classes[i + 1] !== 'undefined') { + callback_function = classes[i + 1]; + break; + } + } + } + + if (window[callback_function] !== 'undefined' && + (typeof window[callback_function] === 'function') + ) { + return window[callback_function]($field, caption); + } + + return $.uniform.i18n('callback', caption, callback_function); + }; + +}(jQuery)); diff --git a/test/index.html b/test/index.html index ee5cc0a..fbda7fc 100755 --- a/test/index.html +++ b/test/index.html @@ -8,7 +8,7 @@ - + @@ -16,7 +16,7 @@
      -
      +

      Validation Testing

      @@ -26,58 +26,58 @@

      Validation Testing

      Client side form demonstration

      -
      +
      -

      Required element

      +

      Required element

      -
      +
      -

      A valid email address

      +

      A valid email address

      -
      +
      -

      +

      -
      +
      -

      This should display as 100.000

      +

      This should display as 100.000

      -
      +
      -

      A random number that you like

      +

      A random number that you like

      -
      +

      * Your preferred color

      -

      Select a color

      +

      Select a color

      -
      +

      Privacy agreement

      -

      This is a form hint.

      +

      This is a form hint.

      -
      - +
      +
      diff --git a/test/issues.js b/test/issues.js index bfc5e7b..cee7e53 100644 --- a/test/issues.js +++ b/test/issues.js @@ -33,7 +33,7 @@ * * @link https://github.com/LearningStation/uni-form/issues/issue/1 */ - test("Case 1 : Prevent submit fails for existing data", function() { + test("Case 1: Prevent submit fails for existing data", function() { var $form = jQuery('#qunit-form'); jQuery('#email', $form).val('invalid@example'); @@ -60,7 +60,7 @@ * * @link https://github.com/LearningStation/uni-form/issues/issue/2 */ - test("Case 2 : Required validation for radio button", function() { + test("Case 2: Required validation for radio button", function() { var hasError = false, $form = jQuery('#qunit-form'); @@ -103,7 +103,7 @@ * * @link https://github.com/LearningStation/uni-form/issues/issue/3 */ - test("Case 3 : data-default-value should not be submitted", function() { + test("Case 3: data-default-value should not be submitted", function() { var $form = jQuery('#qunit-form'); @@ -132,7 +132,7 @@ * * @link https://github.com/LearningStation/uni-form/issues/issue/4 */ - test("Case 4 : Required validation for checkbox", function() { + test("Case 4: Required validation for checkbox", function() { var hasError = false, $form = jQuery('#qunit-form'); @@ -151,20 +151,12 @@ }) .trigger('submit'); - equal( - hasError, - true, - "Checkbox has invalid class after submit" - ); + equal(hasError, true, "Checkbox has invalid class after submit"); $('input[name="agreement"]:checkbox', $form).attr('checked', true); $form.trigger('submit'); - equal( - hasError, - false, - "Checkbox validated after selection and second submit" - ); + equal(hasError, false, "Validated after selection and second submit"); }); @@ -175,10 +167,10 @@ * * @link https://github.com/LearningStation/uni-form/issues/issue/15 */ - test("Case 9 : Autofocus field works with highlight and default data", function() { + test("Case 9: Autofocus field works with highlight and default data", function() { var $input = $('#name'), - $form = jQuery('#qunit-form'); + $form = $('#qunit-form'); function supports_input_autofocus() { var i = document.createElement('input'); @@ -195,22 +187,15 @@ if (supports_input_autofocus()) { // the ctrlHolder should be focused. ok( - $input.parents('div.ctrlHolder').hasClass('focused'), + $input.parents('div.ctrl-holder').hasClass('focused'), 'The autofocus form element should be highlighted.' ); // the default text should also be removed - equal( - $input.val(), - '', - 'The default text should be removed on autofocused fields.' - ); + equal($input.val(), '', 'The default text should be removed on autofocused fields.'); } else { - ok( - true, - "This browser does not support autofocus" - ); + ok(true, "This browser does not support autofocus"); } @@ -224,7 +209,7 @@ * * @link https://github.com/LearningStation/uni-form/issues/issue/15 */ - test("Case 15 : Default value with a period should not be rounded", function() { + test("Case 15: Default value with a period should not be rounded", function() { var $input = $('#issue_15_a'), $form = $('#qunit-form'); diff --git a/test/validation.js b/test/validation.js index c4a332b..975be9e 100644 --- a/test/validation.js +++ b/test/validation.js @@ -57,7 +57,6 @@ return ok((typeof a === "string"), message); }; - module("Test fixtures", { setup: function() { // This will run before each test in this module. this.elems = $('#qunit-fixture').children(); @@ -70,6 +69,7 @@ }); var validators; + module("Validation unit tests", { setup: function () { validators = jQuery.uniform.validators; @@ -429,26 +429,18 @@ }); test("Default data hides correctly", function () { - var default_text = 'This is a sample', $input = $('#issue_15_a'), - $form = jQuery('#qunit-form'); + $form = $('#qunit-form'); $input.attr('data-default-value', default_text); - $form.uniform(); - // should be showing the default - equal($input.val(), default_text, - "The default value has not been displayed correctly" - ); - - $input.focus(); + // Should be showing the default + equal($input.val(), default_text, "Initially display default data"); - // should now be empty - equal($input.val(), '', - "The default value has not been displayed correctly" - ); + $input.focus(); // Should empty on focus + equal($input.val(), '', "Hide default data on focus"); });