Inspired by the reputable jQuery Validation plugin. I'll turn this into a proper plugin later... after I clean it up some.
Rule invocation by @class, so: @class="required", @class="e-mail", @class="digit", @class="zip", @class="min-length-10", @class="max-length-100"
Caveat: Error handling assumes that the input, select, etc field are wrapped in a division which distinguishes them from their respective label (and its wrapping division). My mark-up of form fields is a bit cumbersome, but I believe it gives me flexibility and structural consistency (it's irritating to only wrap the input[type='file'] in many divisions while the rest of the form fields don't receive the same service).
Invoke like so: var options = { livetype: true }; $proof.validator( $('#sms-form'), options );
Array.prototype.unique = function () { var r = new Array(); o:for(var i = 0, n = this.length; i < n; i++) { for(var x = 0, y = r.length; x < y; x++) { if(r[x]==this[i]) { continue o; } } r[r.length] = this[i]; } return r; } $proof = { errorStoreTest: [], options: { livetype: false }, pattern: { "required": { filter: /^\S+$/, msg: "Please fill in this field." }, "e-mail": { filter: /^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{2,4})+$/, msg: "Please provide a valid e-mail address." }, "digits": { filter: /^\d+$/, msg: "Please enter digits only." }, "zip": { filter: /(^\d{5}$)|(^\d{5}-\d{4}$)/, msg: "Please provide a valid zip or postal code." }, "min-length": { filter: /^.{0,}$/, msg: "Min length error." }, "max-length": { filter: /^.{0,65535}$/, msg: "Max length error." } }, validator: function(form, options) { var validate = this; var defaults = this.options; if(options) { //use custom options } else { //use defaults } form.submit(function(e) { var elems = form.find(':input[class*=required], :input[class*=e-mail], :input[class*=number], :input[class*=zip], :input[class*=min-length], :input[class*=max-length]'); //var elems = form.find(':input[class*=required], :input[class*=number], :input[class*=zip], :input[class*=min-length], :input[class*=max-length]'); //reset error business var errorStore = {}; validate.errorStoreTest = []; $('#error-container').remove(); var errorOutputHead = "<div id=\"error-container\"><div class=\"content\"><p></p><ul>"; var errorOutput = ""; var errorOutputFoot = "</ul></div></div>"; form.find('input.error, textarea.error, select.error').removeClass('error'); //validate options into array to isolate and test against only them var a = []; for (name in validate.pattern) { a.push(name); } //check for errors for (var i = 0; i < elems.length; i += 1) { var elem = $(elems[i]); var elemClass = elem.attr('class'); var elemClassSplit = elemClass.split(" "); for (var j = 0; j < elemClassSplit.length; j += 1) { //validate options into array to isolate and test against only them var newElemPatternType = elemClassSplit[j]; //for min/max (it's ugly, I know -- guh) var result = /min-length-\d|max-length-\d/.exec(elemClassSplit[j]); if(result) { if (result.toString().indexOf('min') != -1) { var min = elemClassSplit[j].toString().split("-")[2]; var newElemPatternType = newElemPatternType.replace("-"+min, ""); //reshapes to ping pattern name var newFilter = validate.pattern[newElemPatternType].filter.toString(); newFilter = newFilter.replace("0", min); } else { var max = elemClassSplit[j].toString().split("-")[2]; var newElemPatternType = newElemPatternType.replace("-"+max, ""); //reshapes to ping pattern name var newFilter = validate.pattern[newElemPatternType].filter.toString(); newFilter = newFilter.replace("65535", max); } } else { if ( $.inArray(newElemPatternType, a) != -1 ) { var newFilter = validate.pattern[newElemPatternType].filter.toString(); } } if ( $.inArray(newElemPatternType, a) != -1 ) { //parse out the modifier and slashes, since we cannot convert //valid regex [strings] back into regex objects newFilter = newFilter.replace("\\", "\\").replace("/", "").replace("/", "").replace("i", "").toString(); var reg = new RegExp(newFilter); if ( !reg.test(elem.val()) ) { //errors! - for inline presentation elem.parent().addClass('error'); elem.addClass('error'); //errors! - for error block //errorStore.names.push("#"+elem.attr('id')); //errorStore.types.push(validate.pattern[newElemPatternType]); //errorStore.messages.push(validate.pattern[newElemPatternType].msg); var error_name = elem.attr('id').toString(); validate.errorStoreTest.push({ error: { error_id: "#"+error_name, error_type: { error_type_name: newElemPatternType, error_filter: newFilter, error_msg: validate.pattern[newElemPatternType].msg } } }); errorOutput += "<li><label for=\""+elem.attr('id')+"\"><span class=\"field-name\">"+elem.parent().prev().find('label').text()+"</span> <span class=\"field-error-msg\">"+validate.pattern[newElemPatternType].msg+"</span></label></li>"; } } } } if(options.livetype) { var errStr = validate.errorStoreTest; for (var k = 0; k < errStr.length; k += 1) { var livereg = new RegExp(errStr[k].error.error_type.error_filter.toString()); $(errStr[k].error.error_id).queue(function() { $(this).change(function() { var valStr = $(this).val(); if ( !livereg.test(valStr) ) { $(this).addClass('error'); } else } else { delete errStr[k]; } //alert( errStr.length ); }); }); } } if(validate.errorStoreTest.length) { //display error block form.before(errorOutputHead+errorOutput+errorOutputFoot); e.preventDefault(); } else { //remove it if the array is empty $('#error-container').remove(); } //clean up? }); } };
You need to login to post a comment.
