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 checks user input data against a set of criteria before passing along the data to the server.
+
+
+
+
+
+
+
+
+
+
+
+
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.
+
+
+
+
+
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()
+ ;
+
+
+
+
+
+
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?'
+ }
+ ]
+ }
+ })
+ ;
+
+
+
+
+
+
+
Settings
+
+
+
+
+ Form Settings
+
+
+
+ keyboardShortcuts
+ true
+ Adds keyboard shortcuts for enter and escape keys to submit form and blur fields respectively
+
+
+ on
+ click
+ Event used to trigger validation. Can be either submit or change
+
+
+ inlineError
+ false
+ Adds prompt text from template on validation error
+
+
+ animationDuration
+ 150
+ Fade in speed for inline prompt
+
+
+
+
+
+
+ Callbacks
+
+
+
+ onValid
+ None
+ Callback on each valid field
+
+
+ onInvalid
+ None
+ Callback on each invalid field
+
+
+ onSuccess
+ None
+ Callback if a form is all valid
+
+
+ onFailure
+ None
+ Callback if any form field is invalid
+
+
+
+
+
+
+ General Settings
+
+
+
+ moduleName
+ Form
+ Name used in debug logs
+
+
+ debug
+ False
+ Provides standard debug output to console
+
+
+ performance
+ True
+ Provides standard debug output to console
+
+
+ verbose
+ False
+ Provides ancillary debug output to console
+
+
+ namespace
+ form
+ Event 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.'
+ }
+
+
+
+
+
+
+
+