/**
* Uni-Form jQuery Plugin
*
* Provides form actions for use with the Uni-Form markup style
* This version adds additional support for client side validation
*
* Author: Ilija Studen for the purposes of Uni-Form
*
* Modified by Aris Karageorgos to use the parents function
*
* Modified by Toni Karlheinz to support input fields' text
* coloring and removal of their initial values on focus
*
* Modified by Jason Brumwell for optimization, addition
* of valid and invalid states and default data attribues
*
* Modified by LearningStation to add support for client
* side validation routines. The validation routines based on an
* open source library of unknown authorship.
*
* @see http://sprawsm.com/uni-form/
* @license MIT http://www.opensource.org/licenses/mit-license.php
*/
jQuery.fn.uniform = function(settings) {
/**
* prevent_submit : enable with either true or class on form of "preventSubmit"
* ask_on_leave : enable with either true or class on form of "askOnLeave"
*/
settings = jQuery.extend({
prevent_submit : false,
ask_on_leave : false,
valid_class : 'valid',
invalid_class : 'invalid',
error_class : 'error',
focused_class : 'focused',
holder_class : 'ctrlHolder',
field_selector : 'input, textarea, select',
default_value_color: "#AFAFAF"
}, settings);
/**
* Internationalized language strings for validation messages
*
* @var Object
*/
var i18n_en = {
required : '%s is required',
minlength : '%s should be at least %d characters long',
min : '%s should be greater than or equal to %d',
maxlength : '%s should not be longer than %d characters',
max : '%s should be less than or equal to %d',
same_as : '%s is expected to be same as %s',
email : '%s is not a valid email address',
url : '%s is not a valid URL',
number : '%s needs to be a number',
integer : '%s needs to be a whole number',
alpha : '%s should contain only letters (without special characters or numbers)',
alphanum : '%s should contain only numbers and letters (without special characters)',
phrase : '%s should contain only alphabetic characters, numbers, spaces, and the following: . , - _ () * # :',
phone : '%s should be a phone number',
date : '%s should be a date (mm/dd/yyyy)',
callback : 'Failed to validate %s field. Validator function (%s) is not defined!',
on_leave : 'Are you sure you want to leave this page without saving this form?'
};
/**
* Supported validators
*
* @var Object
*/
var validators = {
/**
* Get the value for a validator that takes parameters
*
* @param string name
* @param string all classes on element
*
* @return mixed || null
*/
get_val : function(name, classes, default_value) {
var value = default_value;
classes = classes.split(' ');
for(var i = 0; i < classes.length; i++) {
if(classes[i] == name) {
if((classes[i + 1] != 'undefined') && ('val-' === classes[i + 1].substr(0,4))) {
value = parseInt(classes[i + 1].substr(4),10);
return value;
}
}
}
return value;
},
/**
* Check if value of specific field is present, whitespace will be counted as empty
*
* @param jQuery field
* @param string caption
*/
required : function(field, caption) {
if(jQuery.trim(field.val()) == '') {
return i18n('required', caption);
} else {
return true;
}
},
/**
* Validate is value of given field is shorter than supported
*
* @param jQuery field
* @param sting caption
*/
validateMinLength : function(field, caption) {
var min_length = this.get_val('validateMinLength', field.attr('class'), 0);
if((min_length > 0) && (field.val().length < min_length)) {
return i18n('minlength', caption, min_length);
} else {
return true;
}
},
/**
* Validate is if value is lesser than min
*
* @param jQuery field
* @param sting caption
*/
validateMin : function(field, caption) {
var min_val = this.get_val('validateMin', field.attr('class'), 0);
if((parseInt(field.val(),10) < min_val)) {
return i18n('min', caption, min_val);
} else {
return true;
}
},
/**
* Validate if field value is longer than allowed
*
* @param jQuery field
* @param string caption
*/
validateMaxLength : function(field, caption) {
var max_length = this.get_val('validateMaxLength', field.attr('class'), 0);
if((max_length > 0) && (field.val().length > max_length)) {
return i18n('maxlength', caption, max_length);
} else {
return true;
}
},
/**
* Validate is if value is lesser than min
*
* @param jQuery field
* @param sting caption
*/
validateMax : function(field, caption) {
var max_val = this.get_val('validateMax', field.attr('class'), 0);
if((parseInt(field.val(),10) > max_val)) {
return i18n('max', caption, max_val);
} else {
return true;
}
},
/**
* Make sure that field has same value as the value of target field
*
* @param jQuery field
* @param string caption
*/
validateSameAs : function(field, caption) {
var classes = field.attr('class').split(' ');
var target_field_name = '';
for(var i = 0; i < classes.length; i++) {
if(classes[i] == 'validateSameAs') {
if(classes[i + 1] != 'undefined') {
target_field_name = classes[i + 1];
break;
}
}
}
if(target_field_name) {
var target_field = jQuery('#' + target_field_name);
if(target_field.length > 0) {
//var target_field_caption = field_caption(field);
var target_field_caption = field_caption(target_field);
if(target_field.val() != field.val()) {
return i18n('same_as', caption, target_field_caption);
}
}
}
return true;
},
/**
* Validate if provided value is valid email address
*
* @param jQuery field
* @param string caption
*/
validateEmail : function(field, caption) {
if(field.val().match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)) {
return true;
} else {
return i18n('email', caption)
}
},
/**
* Validate if provided value is valid URL
*
* @param jQuery field
* @param string caption
*/
validateUrl : function(field, caption) {
if(field.val().match(/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i)) {
return true;
} else {
return i18n('url', caption);
}
},
/**
* Number is only valid value (integers and floats)
*
* @param jQuery field
* @param string caption
*/
validateNumber : function(field, caption) {
if(field.val().match(/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/) || field.val() == '') {
return true;
} else {
return i18n('number', caption);
}
},
/**
* Whole numbers are allowed
*
* @param jQuery field
* @param string caption
*/
validateInteger : function(field, caption) {
if(field.val().match(/(^-?\d\d*$)/) || field.val() == '') {
return true;
} else {
return i18n('integer', caption);
}
},
/**
* Letters only
*
* @param jQuery field
* @param string caption
*/
validateAlpha : function(field, caption) {
if(field.val().match(/^[a-zA-Z]+$/)) {
return true;
} else {
return i18n('alpha', caption);
}
},
/**
* Letters and numbers
*
* @param jQuery field
* @param string caption
*/
validateAlphaNum : function(field, caption) {
if(field.val().match(/\W/)) {
return i18n('alphanum', caption);
} else {
return true;
}
},
/**
* Simple phrases
*
* @param jQuery field
* @param string caption
*/
validatePhrase : function(field, caption) {
if((field.val() == '') || field.val().match(/^[\w\d\.\-_\(\)\*'# :,]+$/i)) {
return true;
} else {
return i18n('phrase', caption);
}
},
/**
* Phone number
*
* @param jQuery field
* @param string caption
*/
validatePhone : function(field, caption) {
if(field.val().match('/^1?-?(\d{3})?-?(\d{2})?\d-?(\d{4})$/')) {
return true;
} else {
return i18n('phone', caption);
}
},
/**
* Phone number
*
* @param jQuery field
* @param string caption
*/
validateDate : function(field, caption) {
if(field.val().match('(1[0-9]|[1-9])/([1-3][0-9]|[1-9])/((19|20)[0-9][0-9]|[0-9][0-9])')) {
return true;
} else {
return i18n('date', caption);
}
},
/**
* Callback validator
*
* Lets you define your own validators. Usage:
*
*
*
* This will result in UniForm searching for window.my_callback funciton and
* executing it with field and caption arguments. Sample implementation:
*
* window.my_callback = function(field, caption) {
* if(field.val() == '34') {
* return true;
* } else {
* return caption + ' value should be "34"';
* }
* }
*
* @param jQuery field
* @param caption
*/
validateCallback : function(field, caption) {
var classes = field.attr('class').split(' ');
var callback_function = '';
for(var i = 0; i < classes.length; i++) {
if(classes[i] == 'validateCallback') {
if(classes[i + 1] != 'undefined') {
callback_function = classes[i + 1];
break;
}
}
}
if(window[callback_function] != 'undefined' && (typeof window[callback_function] == 'function')) {
return window[callback_function](field, caption);
}
return i18n('callback', caption, callback_function);
}
};
/**
* Simple replacement for i18n + sprintf
*
* @param string language for for the local i18n object
* @param mixed substitution vars
*
* @return internationalized string
*/
var i18n = function(lang_key) {
var lang_string = i18n_en[lang_key];
var bits = lang_string.split('%');
var out = bits[0];
var re = /^([ds])(.*)$/;
for (var i=1; i