From 2b83fcec4722f3670f61635ff6808ed2c1fac4b5 Mon Sep 17 00:00:00 2001 From: Jack Lukic Date: Tue, 28 May 2013 17:25:01 -0400 Subject: [PATCH] Adds missing files to src --- build/minified/modules/form.js | 536 ++++++++++++++++++ build/minified/modules/form.min.js | 1 + build/packaged/modules/form.js | 536 ++++++++++++++++++ build/uncompressed/modules/form.js | 536 ++++++++++++++++++ node/src/documents/modules/form.html | 253 +++++++++ .../files/components/semantic/modules/form.js | 536 ++++++++++++++++++ node/src/files/javascript/form.js | 29 + node/src/files/javascript/validate-form.js | 56 ++ 8 files changed, 2483 insertions(+) create mode 100644 build/minified/modules/form.js create mode 100644 build/minified/modules/form.min.js create mode 100644 build/packaged/modules/form.js create mode 100644 build/uncompressed/modules/form.js create mode 100755 node/src/documents/modules/form.html create mode 100644 node/src/files/components/semantic/modules/form.js create mode 100755 node/src/files/javascript/form.js create mode 100755 node/src/files/javascript/validate-form.js diff --git a/build/minified/modules/form.js b/build/minified/modules/form.js new file mode 100644 index 000000000..68e0fa814 --- /dev/null +++ b/build/minified/modules/form.js @@ -0,0 +1,536 @@ +/* ****************************** + Form Validation Components + Author: Jack Lukic + Notes: First Commit April 08, 2012 + + Refactored May 28, 2013 + + Allows you to validate forms based on a form validation object + Form validation objects are bound by either data-validate="" metadata, or form id or name tags + +****************************** */ + +;(function ( $, window, document, undefined ) { + +$.fn.form = function(fields, parameters) { + var + $allModules = $(this), + $document = $(document), + + settings = $.extend(true, {}, $.fn.form.settings, parameters), + + eventNamespace = '.' + settings.namespace, + moduleNamespace = 'module-' + settings.namespace, + + selector = $allModules.selector || '', + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + invokedResponse + ; + $allModules + .each(function() { + var + $module = $(this), + $group = $(this).find(settings.selector.group), + $field = $(this).find(settings.selector.field), + $errorPrompt = $(this).find(settings.selector.prompt), + + formErrors = [], + + element = this, + instance = $module.data('module-' + settings.namespace), + + namespace = settings.namespace, + metadata = settings.metadata, + className = settings.className, + errors = settings.errors, + module + ; + + module = { + + initialize: function() { + module.verbose('Initializing form validation'); + if(fields !== undefined || !$.isEmptyObject(fields) ) { + // attach event handler + if(settings.on == 'submit') { + $module + .on('submit.' + namespace, module.validate.form) + ; + } + } + else { + module.error(errors.noFields, $module); + } + }, + + destroy: function() { + $module + .off(namespace) + ; + }, + + refresh: function() { + $field = $module.find(settings.selector.field); + }, + + field: { + find: function(identifier) { + module.refresh(); + if( $field.filter('#' + identifier).size() > 0 ) { + return $field.filter('#' + identifier); + } + else if( $field.filter('[name="' + identifier +'"]').size() > 0 ) { + return $field.filter('[name="' + identifier +'"]'); + } + else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').size() > 0 ) { + return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]'); + } + return $(''); + }, + add: { + error: function(field, errors) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt), + promptExists = ($errorPrompt.size() !== 0) + ; + $errorGroup + .addClass(className.error) + ; + if(settings.inlineError) { + // create message container on first invalid validation attempt + if(!promptExists) { + $errorPrompt = $('
') + .addClass(className.prompt) + .insertBefore($field) + ; + } + // add prompt message + $errorPrompt + .html(errors[0]) + .fadeIn(settings.animateSpeed) + ; + } + } + }, + remove: { + error: function(field) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt) + ; + $errorGroup + .removeClass(className.error) + ; + if(settings.inlineError) { + $errorPrompt.hide(); + } + } + } + }, + + validate: { + + form: function(event) { + var + allValid = true + ; + // reset errors + formErrors = []; + $.each(fields, function(fieldName, field){ + // form is invalid after first bad field, but keep checking + if( !( module.validate.field(field) ) ) { + allValid = false; + } + }); + // Evaluate form callbacks + return (allValid) + ? $.proxy(settings.onSuccess, this)(event) + : $.proxy(settings.onFailure, this)(formErrors) + ; + }, + + // takes a validation object and returns whether field passes validation + field: function(field) { + var + $field = module.field.find(field.identifier), + fieldValid = true, + fieldErrors = [] + ; + if(field.rules !== undefined) { + // iterate over all validation types for a certain field + $.each(field.rules, function(index, rule) { + if( !( module.validate.rule(field, rule) ) ) { + module.debug('Field is invalid', field.identifier, rule.type); + fieldErrors.push(rule.prompt); + fieldValid = false; + } + }); + } + if(fieldValid) { + module.field.remove.error(field, fieldErrors); + settings.onValid($field); + } + else { + formErrors = formErrors.concat(fieldErrors); + module.field.add.error(field, fieldErrors); + $.proxy(settings.onInvalid, $field)(fieldErrors); + return false; + } + return true; + }, + + // takes validation rule and returns whether field passes rule + rule: function(field, validation) { + var + $field = module.field.find(field.identifier), + type = validation.type, + value = $field.val(), + + bracketRegExp = /\[(.*?)\]/i, + bracket = bracketRegExp.exec(type), + isValid = true, + ancillary, + functionType + ; + // if bracket notation is used, pass in extra parameters + if(bracket !== undefined && bracket != null) { + ancillary = bracket[1]; + functionType = type.replace(bracket[0], ''); + isValid = $.proxy(settings.rules[functionType], $module)(value, ancillary); + } + // normal notation + else { + isValid = (type == 'checked') + ? $field.filter(':checked').size() > 0 + : settings.rules[type](value) + ; + } + return isValid; + } + }, + + setting: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, settings, name); + } + else { + settings[name] = value; + } + } + else { + return settings[name]; + } + }, + internal: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, module, name); + } + else { + module[name] = value; + } + } + else { + return module[name]; + } + }, + debug: function() { + if(settings.debug) { + module.performance.log(arguments[0]); + module.debug = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + } + }, + verbose: function() { + if(settings.verbose && settings.debug) { + module.performance.log(arguments[0]); + module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':'); + } + }, + error: function() { + module.error = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + }, + performance: { + log: function(message) { + var + currentTime, + executionTime, + previousTime + ; + if(settings.performance) { + currentTime = new Date().getTime(); + previousTime = time || currentTime, + executionTime = currentTime - previousTime; + time = currentTime; + performance.push({ + 'Element' : element, + 'Name' : message, + 'Execution Time' : executionTime + }); + clearTimeout(module.performance.timer); + module.performance.timer = setTimeout(module.performance.display, 100); + } + }, + display: function() { + var + title = settings.moduleName, + caption = settings.moduleName + ': ' + selector + '(' + $allModules.size() + ' elements)', + totalExecutionTime = 0 + ; + if(selector) { + title += 'Performance (' + selector + ')'; + } + if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { + console.groupCollapsed(title); + if(console.table) { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + console.table(performance); + } + else { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + } + console.log('Total Execution Time:', totalExecutionTime +'ms'); + console.groupEnd(); + performance = []; + time = false; + } + } + }, + invoke: function(query, passedArguments, context) { + var + maxDepth, + found + ; + passedArguments = passedArguments || queryArguments; + context = element || context; + if(typeof query == 'string' && instance !== undefined) { + query = query.split('.'); + maxDepth = query.length - 1; + $.each(query, function(depth, value) { + if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { + instance = instance[value]; + return true; + } + else if( instance[value] !== undefined ) { + found = instance[value]; + return true; + } + module.error(errors.method); + return false; + }); + } + if ( $.isFunction( found ) ) { + module.verbose('Executing invoked function', found); + return found.apply(context, passedArguments); + } + return found || false; + } + }; + + if(methodInvoked) { + if(instance === undefined) { + module.initialize(); + } + invokedResponse = module.invoke(query); + } + else { + if(instance !== undefined) { + module.destroy(); + } + module.initialize(); + } + }) + ; + return (invokedResponse) + ? invokedResponse + : this + ; +}; + +$.fn.form.settings = { + + // module info + moduleName : 'Validate Form Module', + debug : true, + verbose : false, + namespace : 'validate', + + animateSpeed : 150, + inlineError : false, + + on: 'submit', + + onValid : function() {}, + onInvalid : function() {}, + onSuccess : function() { return true; }, + onFailure : function() { return false; }, + + metadata : { + validate: 'validate' + }, + + // errors + errors: { + method : 'The method you called is not defined.', + noFields : 'No validation object specified.' + }, + + + selector : { + group : '.field', + prompt : '.prompt', + field : 'input, textarea, select' + }, + + className : { + error : 'error', + prompt : 'prompt' + }, + + defaults: { + firstName: { + identifier : 'first-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your first name' + } + ] + }, + lastName: { + identifier : 'last-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your last name' + } + ] + }, + username: { + identifier : 'username', + rules: [ + { + type : 'email', + prompt : 'Please enter a username' + } + ] + }, + email: { + identifier : 'email', + rules: [ + { + type : 'empty', + prompt : 'Please enter your email' + }, + { + type : 'email', + prompt : 'Please enter a valid email' + } + ] + }, + password: { + identifier : 'password', + rules: [ + { + type : 'empty', + prompt : 'Please enter a password' + }, + { + type : 'length[6]', + prompt : 'Your password must be at least 6 characters' + } + ] + }, + passwordConfirm: { + identifier : 'password-confirm', + rules: [ + { + type : 'empty', + prompt : 'Please confirm your password' + }, + { + identifier : 'password-confirm', + type : 'match[password]', + prompt : 'Please verify password matches' + } + ] + }, + terms: { + identifier : 'terms', + rules: [ + { + type : 'checked', + prompt : 'You must agree to the terms and conditions' + } + ] + } + }, + + rules: { + empty: function(value) { + return !(value === undefined || '' === value); + }, + email: function(value){ + var + emailRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") + ; + return emailRegExp.test(value); + }, + length: function(value, requiredLength) { + return (value !== undefined) + ? (value.length >= requiredLength) + : false + ; + }, + not: function(value, notValue) { + return (value != notValue); + }, + maxLength: function(value, maxLength) { + return (value !== undefined) + ? (value.length <= maxLength) + : false + ; + }, + match: function(value, matchingField) { + // use either id or name of field + var + $form = $(this), + matchingValue + ; + if($form.find('#' + matchingField).size() > 0) { + matchingValue = $form.find('#' + matchingField).val(); + } + else if($form.find('[name=' + matchingField +']').size() > 0) { + matchingValue = $form.find('[name=' + matchingField + ']').val(); + } + else if( $form.find('[data-validate="'+ matchingField +'"]').size() > 0 ) { + matchingValue = $form.find('[data-validate="'+ matchingField +'"]').val(); + } + return (matchingValue !== undefined) + ? ( value.toString() == matchingValue.toString() ) + : false + ; + }, + url: function(value) { + var + urlRegExp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ + ; + return urlRegExp.test(value); + } + } + +}; + +})( jQuery, window , document ); diff --git a/build/minified/modules/form.min.js b/build/minified/modules/form.min.js new file mode 100644 index 000000000..bebaed194 --- /dev/null +++ b/build/minified/modules/form.min.js @@ -0,0 +1 @@ +(function(e,t,n,o){e.fn.form=function(t,i){var a,r=e(this),s=(e(n),e.extend(!0,{},e.fn.form.settings,i)),l=("."+s.namespace,"module-"+s.namespace,r.selector||""),c=(new Date).getTime(),u=[],d=arguments[0],m="string"==typeof d,f=[].slice.call(arguments,1);return r.each(function(){var n,i=e(this),p=e(this).find(s.selector.group),g=e(this).find(s.selector.field),h=(e(this).find(s.selector.prompt),[]),v=this,b=i.data("module-"+s.namespace),y=s.namespace,x=s.metadata,w=s.className,C=s.errors;n={initialize:function(){n.verbose("Initializing form validation"),t===o&&e.isEmptyObject(t)?n.error(C.noFields,i):"submit"==s.on&&i.on("submit."+y,n.validate.form)},destroy:function(){i.off(y)},refresh:function(){g=i.find(s.selector.field)},field:{find:function(t){return n.refresh(),g.filter("#"+t).size()>0?g.filter("#"+t):g.filter('[name="'+t+'"]').size()>0?g.filter('[name="'+t+'"]'):g.filter("[data-"+x.validate+'="'+t+'"]').size()>0?g.filter("[data-"+x.validate+'="'+t+'"]'):e("")},add:{error:function(t,o){var i=n.field.find(t.identifier),a=i.closest(p),r=p.find(r),l=0!==r.size();a.addClass(w.error),s.inlineError&&(l||(r=e("
").addClass(w.prompt).insertBefore(i)),r.html(o[0]).fadeIn(s.animateSpeed))}},remove:{error:function(e){var t=n.field.find(e.identifier),o=t.closest(p),i=p.find(i);o.removeClass(w.error),s.inlineError&&i.hide()}}},validate:{form:function(o){var i=!0;return h=[],e.each(t,function(e,t){n.validate.field(t)||(i=!1)}),i?e.proxy(s.onSuccess,this)(o):e.proxy(s.onFailure,this)(h)},field:function(t){var i=n.field.find(t.identifier),a=!0,r=[];return t.rules!==o&&e.each(t.rules,function(e,o){n.validate.rule(t,o)||(n.debug("Field is invalid",t.identifier,o.type),r.push(o.prompt),a=!1)}),a?(n.field.remove.error(t,r),s.onValid(i),!0):(h=h.concat(r),n.field.add.error(t,r),e.proxy(s.onInvalid,i)(r),!1)},rule:function(t,a){var r,l,c=n.field.find(t.identifier),u=a.type,d=c.val(),m=/\[(.*?)\]/i,f=m.exec(u),p=!0;return f!==o&&null!=f?(r=f[1],l=u.replace(f[0],""),p=e.proxy(s.rules[l],i)(d,r)):p="checked"==u?c.filter(":checked").size()>0:s.rules[u](d),p}},setting:function(t,n){return n===o?s[t]:(e.isPlainObject(t)?e.extend(!0,s,t):s[t]=n,o)},internal:function(t,i){return i===o?n[t]:(e.isPlainObject(t)?e.extend(!0,n,t):n[t]=i,o)},debug:function(){s.debug&&(n.performance.log(arguments[0]),n.debug=Function.prototype.bind.call(console.log,console,s.moduleName+":"))},verbose:function(){s.verbose&&s.debug&&(n.performance.log(arguments[0]),n.verbose=Function.prototype.bind.call(console.info,console,s.moduleName+":"))},error:function(){n.error=Function.prototype.bind.call(console.log,console,s.moduleName+":")},performance:{log:function(e){var t,o,i;s.performance&&(t=(new Date).getTime(),i=c||t,o=t-i,c=t,u.push({Element:v,Name:e,"Execution Time":o}),clearTimeout(n.performance.timer),n.performance.timer=setTimeout(n.performance.display,100))},display:function(){var t=s.moduleName,n=(s.moduleName+": "+l+"("+r.size()+" elements)",0);l&&(t+="Performance ("+l+")"),(console.group!==o||console.table!==o)&&u.length>0&&(console.groupCollapsed(t),console.table?(e.each(u,function(e,t){n+=t["Execution Time"]}),console.table(u)):e.each(u,function(e,t){n+=t["Execution Time"]}),console.log("Total Execution Time:",n+"ms"),console.groupEnd(),u=[],c=!1)}},invoke:function(t,i,a){var r,s;return i=i||f,a=v||a,"string"==typeof t&&b!==o&&(t=t.split("."),r=t.length-1,e.each(t,function(t,i){return e.isPlainObject(b[i])&&t!=r?(b=b[i],!0):b[i]!==o?(s=b[i],!0):(n.error(C.method),!1)})),e.isFunction(s)?(n.verbose("Executing invoked function",s),s.apply(a,i)):s||!1}},m?(b===o&&n.initialize(),a=n.invoke(d)):(b!==o&&n.destroy(),n.initialize())}),a?a:this},e.fn.form.settings={moduleName:"Validate Form Module",debug:!0,verbose:!1,namespace:"validate",animateSpeed:150,inlineError:!1,on:"submit",onValid:function(){},onInvalid:function(){},onSuccess:function(){return!0},onFailure:function(){return!1},metadata:{validate:"validate"},errors:{method:"The method you called is not defined.",noFields:"No validation object specified."},selector:{group:".field",prompt:".prompt",field:"input, textarea, select"},className:{error:"error",prompt:"prompt"},defaults:{firstName:{identifier:"first-name",rules:[{type:"empty",prompt:"Please enter your first name"}]},lastName:{identifier:"last-name",rules:[{type:"empty",prompt:"Please enter your last name"}]},username:{identifier:"username",rules:[{type:"email",prompt:"Please enter a username"}]},email:{identifier:"email",rules:[{type:"empty",prompt:"Please enter your email"},{type:"email",prompt:"Please enter a valid email"}]},password:{identifier:"password",rules:[{type:"empty",prompt:"Please enter a password"},{type:"length[6]",prompt:"Your password must be at least 6 characters"}]},passwordConfirm:{identifier:"password-confirm",rules:[{type:"empty",prompt:"Please confirm your password"},{identifier:"password-confirm",type:"match[password]",prompt:"Please verify password matches"}]},terms:{identifier:"terms",rules:[{type:"checked",prompt:"You must agree to the terms and conditions"}]}},rules:{empty:function(e){return!(e===o||""===e)},email:function(e){var t=RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");return t.test(e)},length:function(e,t){return e!==o?e.length>=t:!1},not:function(e,t){return e!=t},maxLength:function(e,t){return e!==o?t>=e.length:!1},match:function(t,n){var i,a=e(this);return a.find("#"+n).size()>0?i=a.find("#"+n).val():a.find("[name="+n+"]").size()>0?i=a.find("[name="+n+"]").val():a.find('[data-validate="'+n+'"]').size()>0&&(i=a.find('[data-validate="'+n+'"]').val()),i!==o?""+t==""+i:!1},url:function(e){var t=/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;return t.test(e)}}}})(jQuery,window,document); \ No newline at end of file diff --git a/build/packaged/modules/form.js b/build/packaged/modules/form.js new file mode 100644 index 000000000..68e0fa814 --- /dev/null +++ b/build/packaged/modules/form.js @@ -0,0 +1,536 @@ +/* ****************************** + Form Validation Components + Author: Jack Lukic + Notes: First Commit April 08, 2012 + + Refactored May 28, 2013 + + Allows you to validate forms based on a form validation object + Form validation objects are bound by either data-validate="" metadata, or form id or name tags + +****************************** */ + +;(function ( $, window, document, undefined ) { + +$.fn.form = function(fields, parameters) { + var + $allModules = $(this), + $document = $(document), + + settings = $.extend(true, {}, $.fn.form.settings, parameters), + + eventNamespace = '.' + settings.namespace, + moduleNamespace = 'module-' + settings.namespace, + + selector = $allModules.selector || '', + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + invokedResponse + ; + $allModules + .each(function() { + var + $module = $(this), + $group = $(this).find(settings.selector.group), + $field = $(this).find(settings.selector.field), + $errorPrompt = $(this).find(settings.selector.prompt), + + formErrors = [], + + element = this, + instance = $module.data('module-' + settings.namespace), + + namespace = settings.namespace, + metadata = settings.metadata, + className = settings.className, + errors = settings.errors, + module + ; + + module = { + + initialize: function() { + module.verbose('Initializing form validation'); + if(fields !== undefined || !$.isEmptyObject(fields) ) { + // attach event handler + if(settings.on == 'submit') { + $module + .on('submit.' + namespace, module.validate.form) + ; + } + } + else { + module.error(errors.noFields, $module); + } + }, + + destroy: function() { + $module + .off(namespace) + ; + }, + + refresh: function() { + $field = $module.find(settings.selector.field); + }, + + field: { + find: function(identifier) { + module.refresh(); + if( $field.filter('#' + identifier).size() > 0 ) { + return $field.filter('#' + identifier); + } + else if( $field.filter('[name="' + identifier +'"]').size() > 0 ) { + return $field.filter('[name="' + identifier +'"]'); + } + else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').size() > 0 ) { + return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]'); + } + return $(''); + }, + add: { + error: function(field, errors) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt), + promptExists = ($errorPrompt.size() !== 0) + ; + $errorGroup + .addClass(className.error) + ; + if(settings.inlineError) { + // create message container on first invalid validation attempt + if(!promptExists) { + $errorPrompt = $('
') + .addClass(className.prompt) + .insertBefore($field) + ; + } + // add prompt message + $errorPrompt + .html(errors[0]) + .fadeIn(settings.animateSpeed) + ; + } + } + }, + remove: { + error: function(field) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt) + ; + $errorGroup + .removeClass(className.error) + ; + if(settings.inlineError) { + $errorPrompt.hide(); + } + } + } + }, + + validate: { + + form: function(event) { + var + allValid = true + ; + // reset errors + formErrors = []; + $.each(fields, function(fieldName, field){ + // form is invalid after first bad field, but keep checking + if( !( module.validate.field(field) ) ) { + allValid = false; + } + }); + // Evaluate form callbacks + return (allValid) + ? $.proxy(settings.onSuccess, this)(event) + : $.proxy(settings.onFailure, this)(formErrors) + ; + }, + + // takes a validation object and returns whether field passes validation + field: function(field) { + var + $field = module.field.find(field.identifier), + fieldValid = true, + fieldErrors = [] + ; + if(field.rules !== undefined) { + // iterate over all validation types for a certain field + $.each(field.rules, function(index, rule) { + if( !( module.validate.rule(field, rule) ) ) { + module.debug('Field is invalid', field.identifier, rule.type); + fieldErrors.push(rule.prompt); + fieldValid = false; + } + }); + } + if(fieldValid) { + module.field.remove.error(field, fieldErrors); + settings.onValid($field); + } + else { + formErrors = formErrors.concat(fieldErrors); + module.field.add.error(field, fieldErrors); + $.proxy(settings.onInvalid, $field)(fieldErrors); + return false; + } + return true; + }, + + // takes validation rule and returns whether field passes rule + rule: function(field, validation) { + var + $field = module.field.find(field.identifier), + type = validation.type, + value = $field.val(), + + bracketRegExp = /\[(.*?)\]/i, + bracket = bracketRegExp.exec(type), + isValid = true, + ancillary, + functionType + ; + // if bracket notation is used, pass in extra parameters + if(bracket !== undefined && bracket != null) { + ancillary = bracket[1]; + functionType = type.replace(bracket[0], ''); + isValid = $.proxy(settings.rules[functionType], $module)(value, ancillary); + } + // normal notation + else { + isValid = (type == 'checked') + ? $field.filter(':checked').size() > 0 + : settings.rules[type](value) + ; + } + return isValid; + } + }, + + setting: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, settings, name); + } + else { + settings[name] = value; + } + } + else { + return settings[name]; + } + }, + internal: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, module, name); + } + else { + module[name] = value; + } + } + else { + return module[name]; + } + }, + debug: function() { + if(settings.debug) { + module.performance.log(arguments[0]); + module.debug = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + } + }, + verbose: function() { + if(settings.verbose && settings.debug) { + module.performance.log(arguments[0]); + module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':'); + } + }, + error: function() { + module.error = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + }, + performance: { + log: function(message) { + var + currentTime, + executionTime, + previousTime + ; + if(settings.performance) { + currentTime = new Date().getTime(); + previousTime = time || currentTime, + executionTime = currentTime - previousTime; + time = currentTime; + performance.push({ + 'Element' : element, + 'Name' : message, + 'Execution Time' : executionTime + }); + clearTimeout(module.performance.timer); + module.performance.timer = setTimeout(module.performance.display, 100); + } + }, + display: function() { + var + title = settings.moduleName, + caption = settings.moduleName + ': ' + selector + '(' + $allModules.size() + ' elements)', + totalExecutionTime = 0 + ; + if(selector) { + title += 'Performance (' + selector + ')'; + } + if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { + console.groupCollapsed(title); + if(console.table) { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + console.table(performance); + } + else { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + } + console.log('Total Execution Time:', totalExecutionTime +'ms'); + console.groupEnd(); + performance = []; + time = false; + } + } + }, + invoke: function(query, passedArguments, context) { + var + maxDepth, + found + ; + passedArguments = passedArguments || queryArguments; + context = element || context; + if(typeof query == 'string' && instance !== undefined) { + query = query.split('.'); + maxDepth = query.length - 1; + $.each(query, function(depth, value) { + if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { + instance = instance[value]; + return true; + } + else if( instance[value] !== undefined ) { + found = instance[value]; + return true; + } + module.error(errors.method); + return false; + }); + } + if ( $.isFunction( found ) ) { + module.verbose('Executing invoked function', found); + return found.apply(context, passedArguments); + } + return found || false; + } + }; + + if(methodInvoked) { + if(instance === undefined) { + module.initialize(); + } + invokedResponse = module.invoke(query); + } + else { + if(instance !== undefined) { + module.destroy(); + } + module.initialize(); + } + }) + ; + return (invokedResponse) + ? invokedResponse + : this + ; +}; + +$.fn.form.settings = { + + // module info + moduleName : 'Validate Form Module', + debug : true, + verbose : false, + namespace : 'validate', + + animateSpeed : 150, + inlineError : false, + + on: 'submit', + + onValid : function() {}, + onInvalid : function() {}, + onSuccess : function() { return true; }, + onFailure : function() { return false; }, + + metadata : { + validate: 'validate' + }, + + // errors + errors: { + method : 'The method you called is not defined.', + noFields : 'No validation object specified.' + }, + + + selector : { + group : '.field', + prompt : '.prompt', + field : 'input, textarea, select' + }, + + className : { + error : 'error', + prompt : 'prompt' + }, + + defaults: { + firstName: { + identifier : 'first-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your first name' + } + ] + }, + lastName: { + identifier : 'last-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your last name' + } + ] + }, + username: { + identifier : 'username', + rules: [ + { + type : 'email', + prompt : 'Please enter a username' + } + ] + }, + email: { + identifier : 'email', + rules: [ + { + type : 'empty', + prompt : 'Please enter your email' + }, + { + type : 'email', + prompt : 'Please enter a valid email' + } + ] + }, + password: { + identifier : 'password', + rules: [ + { + type : 'empty', + prompt : 'Please enter a password' + }, + { + type : 'length[6]', + prompt : 'Your password must be at least 6 characters' + } + ] + }, + passwordConfirm: { + identifier : 'password-confirm', + rules: [ + { + type : 'empty', + prompt : 'Please confirm your password' + }, + { + identifier : 'password-confirm', + type : 'match[password]', + prompt : 'Please verify password matches' + } + ] + }, + terms: { + identifier : 'terms', + rules: [ + { + type : 'checked', + prompt : 'You must agree to the terms and conditions' + } + ] + } + }, + + rules: { + empty: function(value) { + return !(value === undefined || '' === value); + }, + email: function(value){ + var + emailRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") + ; + return emailRegExp.test(value); + }, + length: function(value, requiredLength) { + return (value !== undefined) + ? (value.length >= requiredLength) + : false + ; + }, + not: function(value, notValue) { + return (value != notValue); + }, + maxLength: function(value, maxLength) { + return (value !== undefined) + ? (value.length <= maxLength) + : false + ; + }, + match: function(value, matchingField) { + // use either id or name of field + var + $form = $(this), + matchingValue + ; + if($form.find('#' + matchingField).size() > 0) { + matchingValue = $form.find('#' + matchingField).val(); + } + else if($form.find('[name=' + matchingField +']').size() > 0) { + matchingValue = $form.find('[name=' + matchingField + ']').val(); + } + else if( $form.find('[data-validate="'+ matchingField +'"]').size() > 0 ) { + matchingValue = $form.find('[data-validate="'+ matchingField +'"]').val(); + } + return (matchingValue !== undefined) + ? ( value.toString() == matchingValue.toString() ) + : false + ; + }, + url: function(value) { + var + urlRegExp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ + ; + return urlRegExp.test(value); + } + } + +}; + +})( jQuery, window , document ); diff --git a/build/uncompressed/modules/form.js b/build/uncompressed/modules/form.js new file mode 100644 index 000000000..68e0fa814 --- /dev/null +++ b/build/uncompressed/modules/form.js @@ -0,0 +1,536 @@ +/* ****************************** + Form Validation Components + Author: Jack Lukic + Notes: First Commit April 08, 2012 + + Refactored May 28, 2013 + + Allows you to validate forms based on a form validation object + Form validation objects are bound by either data-validate="" metadata, or form id or name tags + +****************************** */ + +;(function ( $, window, document, undefined ) { + +$.fn.form = function(fields, parameters) { + var + $allModules = $(this), + $document = $(document), + + settings = $.extend(true, {}, $.fn.form.settings, parameters), + + eventNamespace = '.' + settings.namespace, + moduleNamespace = 'module-' + settings.namespace, + + selector = $allModules.selector || '', + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + invokedResponse + ; + $allModules + .each(function() { + var + $module = $(this), + $group = $(this).find(settings.selector.group), + $field = $(this).find(settings.selector.field), + $errorPrompt = $(this).find(settings.selector.prompt), + + formErrors = [], + + element = this, + instance = $module.data('module-' + settings.namespace), + + namespace = settings.namespace, + metadata = settings.metadata, + className = settings.className, + errors = settings.errors, + module + ; + + module = { + + initialize: function() { + module.verbose('Initializing form validation'); + if(fields !== undefined || !$.isEmptyObject(fields) ) { + // attach event handler + if(settings.on == 'submit') { + $module + .on('submit.' + namespace, module.validate.form) + ; + } + } + else { + module.error(errors.noFields, $module); + } + }, + + destroy: function() { + $module + .off(namespace) + ; + }, + + refresh: function() { + $field = $module.find(settings.selector.field); + }, + + field: { + find: function(identifier) { + module.refresh(); + if( $field.filter('#' + identifier).size() > 0 ) { + return $field.filter('#' + identifier); + } + else if( $field.filter('[name="' + identifier +'"]').size() > 0 ) { + return $field.filter('[name="' + identifier +'"]'); + } + else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').size() > 0 ) { + return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]'); + } + return $(''); + }, + add: { + error: function(field, errors) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt), + promptExists = ($errorPrompt.size() !== 0) + ; + $errorGroup + .addClass(className.error) + ; + if(settings.inlineError) { + // create message container on first invalid validation attempt + if(!promptExists) { + $errorPrompt = $('
') + .addClass(className.prompt) + .insertBefore($field) + ; + } + // add prompt message + $errorPrompt + .html(errors[0]) + .fadeIn(settings.animateSpeed) + ; + } + } + }, + remove: { + error: function(field) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt) + ; + $errorGroup + .removeClass(className.error) + ; + if(settings.inlineError) { + $errorPrompt.hide(); + } + } + } + }, + + validate: { + + form: function(event) { + var + allValid = true + ; + // reset errors + formErrors = []; + $.each(fields, function(fieldName, field){ + // form is invalid after first bad field, but keep checking + if( !( module.validate.field(field) ) ) { + allValid = false; + } + }); + // Evaluate form callbacks + return (allValid) + ? $.proxy(settings.onSuccess, this)(event) + : $.proxy(settings.onFailure, this)(formErrors) + ; + }, + + // takes a validation object and returns whether field passes validation + field: function(field) { + var + $field = module.field.find(field.identifier), + fieldValid = true, + fieldErrors = [] + ; + if(field.rules !== undefined) { + // iterate over all validation types for a certain field + $.each(field.rules, function(index, rule) { + if( !( module.validate.rule(field, rule) ) ) { + module.debug('Field is invalid', field.identifier, rule.type); + fieldErrors.push(rule.prompt); + fieldValid = false; + } + }); + } + if(fieldValid) { + module.field.remove.error(field, fieldErrors); + settings.onValid($field); + } + else { + formErrors = formErrors.concat(fieldErrors); + module.field.add.error(field, fieldErrors); + $.proxy(settings.onInvalid, $field)(fieldErrors); + return false; + } + return true; + }, + + // takes validation rule and returns whether field passes rule + rule: function(field, validation) { + var + $field = module.field.find(field.identifier), + type = validation.type, + value = $field.val(), + + bracketRegExp = /\[(.*?)\]/i, + bracket = bracketRegExp.exec(type), + isValid = true, + ancillary, + functionType + ; + // if bracket notation is used, pass in extra parameters + if(bracket !== undefined && bracket != null) { + ancillary = bracket[1]; + functionType = type.replace(bracket[0], ''); + isValid = $.proxy(settings.rules[functionType], $module)(value, ancillary); + } + // normal notation + else { + isValid = (type == 'checked') + ? $field.filter(':checked').size() > 0 + : settings.rules[type](value) + ; + } + return isValid; + } + }, + + setting: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, settings, name); + } + else { + settings[name] = value; + } + } + else { + return settings[name]; + } + }, + internal: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, module, name); + } + else { + module[name] = value; + } + } + else { + return module[name]; + } + }, + debug: function() { + if(settings.debug) { + module.performance.log(arguments[0]); + module.debug = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + } + }, + verbose: function() { + if(settings.verbose && settings.debug) { + module.performance.log(arguments[0]); + module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':'); + } + }, + error: function() { + module.error = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + }, + performance: { + log: function(message) { + var + currentTime, + executionTime, + previousTime + ; + if(settings.performance) { + currentTime = new Date().getTime(); + previousTime = time || currentTime, + executionTime = currentTime - previousTime; + time = currentTime; + performance.push({ + 'Element' : element, + 'Name' : message, + 'Execution Time' : executionTime + }); + clearTimeout(module.performance.timer); + module.performance.timer = setTimeout(module.performance.display, 100); + } + }, + display: function() { + var + title = settings.moduleName, + caption = settings.moduleName + ': ' + selector + '(' + $allModules.size() + ' elements)', + totalExecutionTime = 0 + ; + if(selector) { + title += 'Performance (' + selector + ')'; + } + if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { + console.groupCollapsed(title); + if(console.table) { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + console.table(performance); + } + else { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + } + console.log('Total Execution Time:', totalExecutionTime +'ms'); + console.groupEnd(); + performance = []; + time = false; + } + } + }, + invoke: function(query, passedArguments, context) { + var + maxDepth, + found + ; + passedArguments = passedArguments || queryArguments; + context = element || context; + if(typeof query == 'string' && instance !== undefined) { + query = query.split('.'); + maxDepth = query.length - 1; + $.each(query, function(depth, value) { + if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { + instance = instance[value]; + return true; + } + else if( instance[value] !== undefined ) { + found = instance[value]; + return true; + } + module.error(errors.method); + return false; + }); + } + if ( $.isFunction( found ) ) { + module.verbose('Executing invoked function', found); + return found.apply(context, passedArguments); + } + return found || false; + } + }; + + if(methodInvoked) { + if(instance === undefined) { + module.initialize(); + } + invokedResponse = module.invoke(query); + } + else { + if(instance !== undefined) { + module.destroy(); + } + module.initialize(); + } + }) + ; + return (invokedResponse) + ? invokedResponse + : this + ; +}; + +$.fn.form.settings = { + + // module info + moduleName : 'Validate Form Module', + debug : true, + verbose : false, + namespace : 'validate', + + animateSpeed : 150, + inlineError : false, + + on: 'submit', + + onValid : function() {}, + onInvalid : function() {}, + onSuccess : function() { return true; }, + onFailure : function() { return false; }, + + metadata : { + validate: 'validate' + }, + + // errors + errors: { + method : 'The method you called is not defined.', + noFields : 'No validation object specified.' + }, + + + selector : { + group : '.field', + prompt : '.prompt', + field : 'input, textarea, select' + }, + + className : { + error : 'error', + prompt : 'prompt' + }, + + defaults: { + firstName: { + identifier : 'first-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your first name' + } + ] + }, + lastName: { + identifier : 'last-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your last name' + } + ] + }, + username: { + identifier : 'username', + rules: [ + { + type : 'email', + prompt : 'Please enter a username' + } + ] + }, + email: { + identifier : 'email', + rules: [ + { + type : 'empty', + prompt : 'Please enter your email' + }, + { + type : 'email', + prompt : 'Please enter a valid email' + } + ] + }, + password: { + identifier : 'password', + rules: [ + { + type : 'empty', + prompt : 'Please enter a password' + }, + { + type : 'length[6]', + prompt : 'Your password must be at least 6 characters' + } + ] + }, + passwordConfirm: { + identifier : 'password-confirm', + rules: [ + { + type : 'empty', + prompt : 'Please confirm your password' + }, + { + identifier : 'password-confirm', + type : 'match[password]', + prompt : 'Please verify password matches' + } + ] + }, + terms: { + identifier : 'terms', + rules: [ + { + type : 'checked', + prompt : 'You must agree to the terms and conditions' + } + ] + } + }, + + rules: { + empty: function(value) { + return !(value === undefined || '' === value); + }, + email: function(value){ + var + emailRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") + ; + return emailRegExp.test(value); + }, + length: function(value, requiredLength) { + return (value !== undefined) + ? (value.length >= requiredLength) + : false + ; + }, + not: function(value, notValue) { + return (value != notValue); + }, + maxLength: function(value, maxLength) { + return (value !== undefined) + ? (value.length <= maxLength) + : false + ; + }, + match: function(value, matchingField) { + // use either id or name of field + var + $form = $(this), + matchingValue + ; + if($form.find('#' + matchingField).size() > 0) { + matchingValue = $form.find('#' + matchingField).val(); + } + else if($form.find('[name=' + matchingField +']').size() > 0) { + matchingValue = $form.find('[name=' + matchingField + ']').val(); + } + else if( $form.find('[data-validate="'+ matchingField +'"]').size() > 0 ) { + matchingValue = $form.find('[data-validate="'+ matchingField +'"]').val(); + } + return (matchingValue !== undefined) + ? ( value.toString() == matchingValue.toString() ) + : false + ; + }, + url: function(value) { + var + urlRegExp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ + ; + return urlRegExp.test(value); + } + } + +}; + +})( jQuery, window , document ); diff --git a/node/src/documents/modules/form.html b/node/src/documents/modules/form.html new file mode 100755 index 000000000..49886b850 --- /dev/null +++ b/node/src/documents/modules/form.html @@ -0,0 +1,253 @@ +--- +layout : 'default' +css : 'form' + +title : 'Validate Form' +type : 'UI Module' +--- + + + + +
+
+

Form Validation

+

Form validation checks user input data against a set of criteria before passing along the data to the server.

+
+
+
+ +
+ +
+ +

Usage

+ +
+

Basic Validation

+

Form validation requires passing in a validation object with the rules required to validate your form.

+
If no validation object is specified then the form will validate against the default validation set up for the plugin.
+
+

Let's go ahead and get you signed up.

+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
Submit
+
+
+ +
+

Validation w/ Message

+

Forms that contain a ui message error block will automatically be filled in with form validation information.

+
The template for error messages can be modified by adjusting settings.template.error
+
+ $('.ui.form') + .form() + ; +
+
+

Let's go ahead and get you signed up.

+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
Submit
+
+
+
+ +
+

Custom Validation

+

Custom form validation requires passing in a validation object with the rules required to validate your form.

+
+ A validation object includes a list of form elements, and rules to validate each against. Fields are matched by either the id tag, name tag, or data-validate metadata matching the identifier provided in the settings object. To pass parameters to a rule, use bracket notation +
+
+ $('.ui.form') + .form({ + dog: { + identifier: 'dog', + rules: [ + { + type: 'empty', + prompt: 'You must have a dog to add' + }, + { + type: 'is[fluffy dog]', + prompt: 'I only want you to add fluffy dogs!' + }, + { + type: 'not[mean]', + prompt: 'Why would you add a mean dog to the list?' + } + ] + } + }) + ; +
+
+

Let's go ahead and get you signed up.

+
+ + +
+
Add Dog
+
+
+
+ + + +

Settings

+ +

Defaults

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Form Settings
keyboardShortcutstrueAdds keyboard shortcuts for enter and escape keys to submit form and blur fields respectively
onclickEvent used to trigger validation. Can be either submit or change
inlineErrorfalseAdds prompt text from template on validation error
animationDuration150Fade in speed for inline prompt
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Callbacks
onValidNoneCallback on each valid field
onInvalidNoneCallback on each invalid field
onSuccessNoneCallback if a form is all valid
onFailureNoneCallback if any form field is invalid
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
General Settings
moduleNameFormName used in debug logs
debugFalseProvides standard debug output to console
performanceTrueProvides standard debug output to console
verboseFalseProvides ancillary debug output to console
namespaceformEvent namespace. Makes sure module teardown does not effect other events attached to an element.
errors +
+ errors : { + action : 'You called a form action that was not defined', + method : 'The method you called is not defined.' + } +
+
+ +
+ + + \ No newline at end of file diff --git a/node/src/files/components/semantic/modules/form.js b/node/src/files/components/semantic/modules/form.js new file mode 100644 index 000000000..68e0fa814 --- /dev/null +++ b/node/src/files/components/semantic/modules/form.js @@ -0,0 +1,536 @@ +/* ****************************** + Form Validation Components + Author: Jack Lukic + Notes: First Commit April 08, 2012 + + Refactored May 28, 2013 + + Allows you to validate forms based on a form validation object + Form validation objects are bound by either data-validate="" metadata, or form id or name tags + +****************************** */ + +;(function ( $, window, document, undefined ) { + +$.fn.form = function(fields, parameters) { + var + $allModules = $(this), + $document = $(document), + + settings = $.extend(true, {}, $.fn.form.settings, parameters), + + eventNamespace = '.' + settings.namespace, + moduleNamespace = 'module-' + settings.namespace, + + selector = $allModules.selector || '', + time = new Date().getTime(), + performance = [], + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1), + invokedResponse + ; + $allModules + .each(function() { + var + $module = $(this), + $group = $(this).find(settings.selector.group), + $field = $(this).find(settings.selector.field), + $errorPrompt = $(this).find(settings.selector.prompt), + + formErrors = [], + + element = this, + instance = $module.data('module-' + settings.namespace), + + namespace = settings.namespace, + metadata = settings.metadata, + className = settings.className, + errors = settings.errors, + module + ; + + module = { + + initialize: function() { + module.verbose('Initializing form validation'); + if(fields !== undefined || !$.isEmptyObject(fields) ) { + // attach event handler + if(settings.on == 'submit') { + $module + .on('submit.' + namespace, module.validate.form) + ; + } + } + else { + module.error(errors.noFields, $module); + } + }, + + destroy: function() { + $module + .off(namespace) + ; + }, + + refresh: function() { + $field = $module.find(settings.selector.field); + }, + + field: { + find: function(identifier) { + module.refresh(); + if( $field.filter('#' + identifier).size() > 0 ) { + return $field.filter('#' + identifier); + } + else if( $field.filter('[name="' + identifier +'"]').size() > 0 ) { + return $field.filter('[name="' + identifier +'"]'); + } + else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').size() > 0 ) { + return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]'); + } + return $(''); + }, + add: { + error: function(field, errors) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt), + promptExists = ($errorPrompt.size() !== 0) + ; + $errorGroup + .addClass(className.error) + ; + if(settings.inlineError) { + // create message container on first invalid validation attempt + if(!promptExists) { + $errorPrompt = $('
') + .addClass(className.prompt) + .insertBefore($field) + ; + } + // add prompt message + $errorPrompt + .html(errors[0]) + .fadeIn(settings.animateSpeed) + ; + } + } + }, + remove: { + error: function(field) { + var + $field = module.field.find(field.identifier), + $errorGroup = $field.closest($group), + $errorPrompt = $group.find($errorPrompt) + ; + $errorGroup + .removeClass(className.error) + ; + if(settings.inlineError) { + $errorPrompt.hide(); + } + } + } + }, + + validate: { + + form: function(event) { + var + allValid = true + ; + // reset errors + formErrors = []; + $.each(fields, function(fieldName, field){ + // form is invalid after first bad field, but keep checking + if( !( module.validate.field(field) ) ) { + allValid = false; + } + }); + // Evaluate form callbacks + return (allValid) + ? $.proxy(settings.onSuccess, this)(event) + : $.proxy(settings.onFailure, this)(formErrors) + ; + }, + + // takes a validation object and returns whether field passes validation + field: function(field) { + var + $field = module.field.find(field.identifier), + fieldValid = true, + fieldErrors = [] + ; + if(field.rules !== undefined) { + // iterate over all validation types for a certain field + $.each(field.rules, function(index, rule) { + if( !( module.validate.rule(field, rule) ) ) { + module.debug('Field is invalid', field.identifier, rule.type); + fieldErrors.push(rule.prompt); + fieldValid = false; + } + }); + } + if(fieldValid) { + module.field.remove.error(field, fieldErrors); + settings.onValid($field); + } + else { + formErrors = formErrors.concat(fieldErrors); + module.field.add.error(field, fieldErrors); + $.proxy(settings.onInvalid, $field)(fieldErrors); + return false; + } + return true; + }, + + // takes validation rule and returns whether field passes rule + rule: function(field, validation) { + var + $field = module.field.find(field.identifier), + type = validation.type, + value = $field.val(), + + bracketRegExp = /\[(.*?)\]/i, + bracket = bracketRegExp.exec(type), + isValid = true, + ancillary, + functionType + ; + // if bracket notation is used, pass in extra parameters + if(bracket !== undefined && bracket != null) { + ancillary = bracket[1]; + functionType = type.replace(bracket[0], ''); + isValid = $.proxy(settings.rules[functionType], $module)(value, ancillary); + } + // normal notation + else { + isValid = (type == 'checked') + ? $field.filter(':checked').size() > 0 + : settings.rules[type](value) + ; + } + return isValid; + } + }, + + setting: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, settings, name); + } + else { + settings[name] = value; + } + } + else { + return settings[name]; + } + }, + internal: function(name, value) { + if(value !== undefined) { + if( $.isPlainObject(name) ) { + $.extend(true, module, name); + } + else { + module[name] = value; + } + } + else { + return module[name]; + } + }, + debug: function() { + if(settings.debug) { + module.performance.log(arguments[0]); + module.debug = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + } + }, + verbose: function() { + if(settings.verbose && settings.debug) { + module.performance.log(arguments[0]); + module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':'); + } + }, + error: function() { + module.error = Function.prototype.bind.call(console.log, console, settings.moduleName + ':'); + }, + performance: { + log: function(message) { + var + currentTime, + executionTime, + previousTime + ; + if(settings.performance) { + currentTime = new Date().getTime(); + previousTime = time || currentTime, + executionTime = currentTime - previousTime; + time = currentTime; + performance.push({ + 'Element' : element, + 'Name' : message, + 'Execution Time' : executionTime + }); + clearTimeout(module.performance.timer); + module.performance.timer = setTimeout(module.performance.display, 100); + } + }, + display: function() { + var + title = settings.moduleName, + caption = settings.moduleName + ': ' + selector + '(' + $allModules.size() + ' elements)', + totalExecutionTime = 0 + ; + if(selector) { + title += 'Performance (' + selector + ')'; + } + if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { + console.groupCollapsed(title); + if(console.table) { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + console.table(performance); + } + else { + $.each(performance, function(index, data) { + totalExecutionTime += data['Execution Time']; + }); + } + console.log('Total Execution Time:', totalExecutionTime +'ms'); + console.groupEnd(); + performance = []; + time = false; + } + } + }, + invoke: function(query, passedArguments, context) { + var + maxDepth, + found + ; + passedArguments = passedArguments || queryArguments; + context = element || context; + if(typeof query == 'string' && instance !== undefined) { + query = query.split('.'); + maxDepth = query.length - 1; + $.each(query, function(depth, value) { + if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) { + instance = instance[value]; + return true; + } + else if( instance[value] !== undefined ) { + found = instance[value]; + return true; + } + module.error(errors.method); + return false; + }); + } + if ( $.isFunction( found ) ) { + module.verbose('Executing invoked function', found); + return found.apply(context, passedArguments); + } + return found || false; + } + }; + + if(methodInvoked) { + if(instance === undefined) { + module.initialize(); + } + invokedResponse = module.invoke(query); + } + else { + if(instance !== undefined) { + module.destroy(); + } + module.initialize(); + } + }) + ; + return (invokedResponse) + ? invokedResponse + : this + ; +}; + +$.fn.form.settings = { + + // module info + moduleName : 'Validate Form Module', + debug : true, + verbose : false, + namespace : 'validate', + + animateSpeed : 150, + inlineError : false, + + on: 'submit', + + onValid : function() {}, + onInvalid : function() {}, + onSuccess : function() { return true; }, + onFailure : function() { return false; }, + + metadata : { + validate: 'validate' + }, + + // errors + errors: { + method : 'The method you called is not defined.', + noFields : 'No validation object specified.' + }, + + + selector : { + group : '.field', + prompt : '.prompt', + field : 'input, textarea, select' + }, + + className : { + error : 'error', + prompt : 'prompt' + }, + + defaults: { + firstName: { + identifier : 'first-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your first name' + } + ] + }, + lastName: { + identifier : 'last-name', + rules: [ + { + type : 'empty', + prompt : 'Please enter your last name' + } + ] + }, + username: { + identifier : 'username', + rules: [ + { + type : 'email', + prompt : 'Please enter a username' + } + ] + }, + email: { + identifier : 'email', + rules: [ + { + type : 'empty', + prompt : 'Please enter your email' + }, + { + type : 'email', + prompt : 'Please enter a valid email' + } + ] + }, + password: { + identifier : 'password', + rules: [ + { + type : 'empty', + prompt : 'Please enter a password' + }, + { + type : 'length[6]', + prompt : 'Your password must be at least 6 characters' + } + ] + }, + passwordConfirm: { + identifier : 'password-confirm', + rules: [ + { + type : 'empty', + prompt : 'Please confirm your password' + }, + { + identifier : 'password-confirm', + type : 'match[password]', + prompt : 'Please verify password matches' + } + ] + }, + terms: { + identifier : 'terms', + rules: [ + { + type : 'checked', + prompt : 'You must agree to the terms and conditions' + } + ] + } + }, + + rules: { + empty: function(value) { + return !(value === undefined || '' === value); + }, + email: function(value){ + var + emailRegExp = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?") + ; + return emailRegExp.test(value); + }, + length: function(value, requiredLength) { + return (value !== undefined) + ? (value.length >= requiredLength) + : false + ; + }, + not: function(value, notValue) { + return (value != notValue); + }, + maxLength: function(value, maxLength) { + return (value !== undefined) + ? (value.length <= maxLength) + : false + ; + }, + match: function(value, matchingField) { + // use either id or name of field + var + $form = $(this), + matchingValue + ; + if($form.find('#' + matchingField).size() > 0) { + matchingValue = $form.find('#' + matchingField).val(); + } + else if($form.find('[name=' + matchingField +']').size() > 0) { + matchingValue = $form.find('[name=' + matchingField + ']').val(); + } + else if( $form.find('[data-validate="'+ matchingField +'"]').size() > 0 ) { + matchingValue = $form.find('[data-validate="'+ matchingField +'"]').val(); + } + return (matchingValue !== undefined) + ? ( value.toString() == matchingValue.toString() ) + : false + ; + }, + url: function(value) { + var + urlRegExp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/ + ; + return urlRegExp.test(value); + } + } + +}; + +})( jQuery, window , document ); diff --git a/node/src/files/javascript/form.js b/node/src/files/javascript/form.js new file mode 100755 index 000000000..175957a40 --- /dev/null +++ b/node/src/files/javascript/form.js @@ -0,0 +1,29 @@ +semantic.validateForm = {}; + +// ready event +semantic.validateForm.ready = function() { + + // selector cache + var + $checkbox = $('.ui.checkbox'), + // alias + handler + ; + + // event handlers + handler = { + + }; + + $checkbox + .checkbox() + ; + + +}; + + +// attach ready event +$(document) + .ready(semantic.validateForm.ready) +; \ No newline at end of file diff --git a/node/src/files/javascript/validate-form.js b/node/src/files/javascript/validate-form.js new file mode 100755 index 000000000..1ba83058e --- /dev/null +++ b/node/src/files/javascript/validate-form.js @@ -0,0 +1,56 @@ +semantic.validateForm = {}; + +// ready event +semantic.validateForm.ready = function() { + + // selector cache + var + $dogForm = $('.dog.example .ui.form'), + $form = $('.ui.form').not($dogForm), + $checkbox = $('.ui.checkbox'), + // alias + handler + ; + + // event handlers + handler = { + + }; + + $checkbox + .checkbox() + ; + + $dogForm + .form({ + dog: { + identifier: 'dog', + rules: [ + { + type: 'empty', + prompt: 'You must have a dog to add' + }, + { + type: 'is[fluffy dog]', + prompt: 'I only want you to add fluffy dogs!' + }, + { + type: 'not[mean]', + prompt: 'Why would you add a mean dog to the list?' + } + ] + } + }) + ; + + $form + .form() + ; + +}; + + +// attach ready event +$(document) + .ready(semantic.validateForm.ready) +; \ No newline at end of file