2011-10-16 12:06:00 +00:00
|
|
|
/*
|
|
|
|
* Inline Form Validation Engine 2.2, jQuery plugin
|
|
|
|
*
|
|
|
|
* Copyright(c) 2010, Cedric Dugas
|
|
|
|
* http://www.position-absolute.com
|
|
|
|
*
|
|
|
|
* 2.0 Rewrite by Olivier Refalo
|
|
|
|
* http://www.crionics.com
|
|
|
|
*
|
|
|
|
* Form validation engine allowing custom regex rules to be added.
|
|
|
|
* Licensed under the MIT License
|
|
|
|
*/
|
|
|
|
(function($) {
|
|
|
|
|
|
|
|
var methods = {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Kind of the constructor, called before any action
|
|
|
|
* @param {Map} user options
|
|
|
|
*/
|
|
|
|
init: function(options) {
|
|
|
|
var form = this;
|
|
|
|
if (!form.data('jqv') || form.data('jqv') == null ) {
|
|
|
|
methods._saveOptions(form, options);
|
|
|
|
|
|
|
|
// bind all formError elements to close on click
|
|
|
|
$(".formError").live("click", function() {
|
|
|
|
$(this).fadeOut(150, function() {
|
|
|
|
|
|
|
|
// remove prompt once invisible
|
|
|
|
$(this).remove();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Attachs jQuery.validationEngine to form.submit and field.blur events
|
|
|
|
* Takes an optional params: a list of options
|
|
|
|
* ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});
|
|
|
|
*/
|
|
|
|
attach: function(userOptions) {
|
|
|
|
|
|
|
|
var form = this;
|
|
|
|
var options;
|
|
|
|
|
|
|
|
if(userOptions)
|
|
|
|
options = methods._saveOptions(form, userOptions);
|
|
|
|
else
|
|
|
|
options = form.data('jqv');
|
|
|
|
|
|
|
|
var validateAttribute = (form.find("[data-validation-engine*=validate]")) ? "data-validation-engine" : "class";
|
|
|
|
|
|
|
|
if (!options.binded) {
|
|
|
|
if (options.bindMethod == "bind"){
|
|
|
|
|
|
|
|
// bind fields
|
|
|
|
form.find("[class*=validate]").not("[type=checkbox]").not("[type=radio]").not(".datepicker").bind(options.validationEventTrigger, methods._onFieldEvent);
|
|
|
|
form.find("[class*=validate][type=checkbox],[class*=validate][type=radio]").bind("click", methods._onFieldEvent);
|
|
|
|
|
|
|
|
form.find("[class*=validate][class*=datepicker]").bind(options.validationEventTrigger,{"delay": 300}, methods._onFieldEvent);
|
|
|
|
|
|
|
|
// bind form.submit
|
2011-12-01 18:55:54 +00:00
|
|
|
//form.bind("submit", methods._onSubmitEvent);
|
2011-10-16 12:06:00 +00:00
|
|
|
} else if (options.bindMethod == "live") {
|
|
|
|
// bind fields with LIVE (for persistant state)
|
|
|
|
form.find("[class*=validate]").not("[type=checkbox]").not(".datepicker").live(options.validationEventTrigger, methods._onFieldEvent);
|
|
|
|
form.find("[class*=validate][type=checkbox]").live("click", methods._onFieldEvent);
|
|
|
|
|
|
|
|
form.find("[class*=validate][class*=datepicker]").live(options.validationEventTrigger,{"delay": 300}, methods._onFieldEvent);
|
|
|
|
|
|
|
|
// bind form.submit
|
2011-12-01 18:55:54 +00:00
|
|
|
//form.live("submit", methods._onSubmitEvent);
|
2011-10-16 12:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
options.binded = true;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Unregisters any bindings that may point to jQuery.validaitonEngine
|
|
|
|
*/
|
|
|
|
detach: function() {
|
|
|
|
var form = this;
|
|
|
|
var options = form.data('jqv');
|
|
|
|
if (options.binded) {
|
|
|
|
|
|
|
|
// unbind fields
|
|
|
|
form.find("[class*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent);
|
|
|
|
form.find("[class*=validate][type=checkbox],[class*=validate][type=radio]").unbind("click", methods._onFieldEvent);
|
|
|
|
|
|
|
|
// unbind form.submit
|
|
|
|
form.unbind("submit", methods.onAjaxFormComplete);
|
|
|
|
|
|
|
|
|
|
|
|
// unbind live fields (kill)
|
|
|
|
form.find("[class*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent);
|
|
|
|
form.find("[class*=validate][type=checkbox]").die("click", methods._onFieldEvent);
|
|
|
|
// unbind form.submit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
form.die("submit", methods.onAjaxFormComplete);
|
|
|
|
|
|
|
|
form.removeData('jqv');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validates the form fields, shows prompts accordingly.
|
|
|
|
* Note: There is no ajax form validation with this method, only field ajax validation are evaluated
|
|
|
|
*
|
|
|
|
* @return true if the form validates, false if it fails
|
|
|
|
*/
|
|
|
|
validate: function() {
|
|
|
|
return methods._validateFields(this);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validates one field, shows prompt accordingly.
|
|
|
|
* Note: There is no ajax form validation with this method, only field ajax validation are evaluated
|
|
|
|
*
|
|
|
|
* @return true if the form validates, false if it fails
|
|
|
|
*/
|
|
|
|
validateField: function(el) {
|
|
|
|
var options = $(this).data('jqv');
|
|
|
|
return methods._validateField($(el), options);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validates the form fields, shows prompts accordingly.
|
|
|
|
* Note: this methods performs fields and form ajax validations(if setup)
|
|
|
|
*
|
|
|
|
* @return true if the form validates, false if it fails, undefined if ajax is used for form validation
|
|
|
|
*/
|
|
|
|
validateform: function() {
|
|
|
|
return methods._onSubmitEvent.call(this);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Redraw prompts position, useful when you change the DOM state when validating
|
|
|
|
*/
|
|
|
|
updatePromptsPosition: function() {
|
|
|
|
var form = this.closest('form');
|
|
|
|
var options = form.data('jqv');
|
|
|
|
// No option, take default one
|
|
|
|
form.find('[class*=validate]').not(':hidden').not(":disabled").each(function(){
|
|
|
|
var field = $(this);
|
|
|
|
|
|
|
|
var prompt = methods._getPrompt(field);
|
|
|
|
var promptText = $(prompt).find(".formErrorContent").html();
|
|
|
|
|
|
|
|
if(prompt) methods._updatePrompt(field, $(prompt), promptText, undefined, false, options);
|
|
|
|
})
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Displays a prompt on a element.
|
|
|
|
* Note that the element needs an id!
|
|
|
|
*
|
|
|
|
* @param {String} promptText html text to display type
|
|
|
|
* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
|
|
|
|
* @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight
|
|
|
|
*/
|
|
|
|
showPrompt: function(promptText, type, promptPosition, showArrow) {
|
|
|
|
|
|
|
|
var form = this.closest('form');
|
|
|
|
var options = form.data('jqv');
|
|
|
|
// No option, take default one
|
|
|
|
if(!options) options = methods._saveOptions(this, options);
|
|
|
|
if(promptPosition)
|
|
|
|
options.promptPosition=promptPosition;
|
|
|
|
options.showArrow = showArrow==true;
|
|
|
|
|
|
|
|
methods._showPrompt(this, promptText, type, false, options);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Closes all error prompts on the page
|
|
|
|
*/
|
|
|
|
hidePrompt: function() {
|
|
|
|
var promptClass = "."+ methods._getClassName($(this).attr("id")) + "formError";
|
|
|
|
$(promptClass).fadeTo("fast", 0.3, function() {
|
|
|
|
$(this).remove();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Closes form error prompts, CAN be invidual
|
|
|
|
*/
|
|
|
|
hide: function() {
|
|
|
|
var closingtag;
|
|
|
|
if($(this).is("form")){
|
|
|
|
closingtag = "parentForm"+$(this).attr('id');
|
|
|
|
}else{
|
|
|
|
closingtag = $(this).attr('id') +"formError";
|
|
|
|
}
|
|
|
|
$('.'+closingtag).fadeTo("fast", 0.3, function() {
|
|
|
|
$(this).remove();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Closes all error prompts on the page
|
|
|
|
*/
|
|
|
|
hideAll: function() {
|
|
|
|
$('.formError').fadeTo("fast", 0.3, function() {
|
|
|
|
$(this).remove();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Typically called when user exists a field using tab or a mouse click, triggers a field
|
|
|
|
* validation
|
|
|
|
*/
|
|
|
|
_onFieldEvent: function(event) {
|
|
|
|
var field = $(this);
|
|
|
|
var form = field.closest('form');
|
|
|
|
var options = form.data('jqv');
|
|
|
|
// validate the current field
|
|
|
|
window.setTimeout(function() {
|
|
|
|
methods._validateField(field, options);
|
|
|
|
}, (event.data) ? event.data.delay : 0);
|
|
|
|
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Called when the form is submited, shows prompts accordingly
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* form
|
|
|
|
* @return false if form submission needs to be cancelled
|
|
|
|
*/
|
|
|
|
_onSubmitEvent: function() {
|
|
|
|
var form = $(this);
|
|
|
|
var options = form.data('jqv');
|
|
|
|
|
|
|
|
// validate each field (- skip field ajax validation, no necessary since we will perform an ajax form validation)
|
|
|
|
var r=methods._validateFields(form, true);
|
|
|
|
|
|
|
|
if (r && options.ajaxFormValidation) {
|
|
|
|
methods._validateFormWithAjax(form, options);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(options.onValidationComplete) {
|
|
|
|
options.onValidationComplete(form, r);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return true if the ajax field validations passed so far
|
|
|
|
* @param {Object} options
|
|
|
|
* @return true, is all ajax validation passed so far (remember ajax is async)
|
|
|
|
*/
|
|
|
|
_checkAjaxStatus: function(options) {
|
|
|
|
var status = true;
|
|
|
|
$.each(options.ajaxValidCache, function(key, value) {
|
|
|
|
if (!value) {
|
|
|
|
status = false;
|
|
|
|
// break the each
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return status;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validates form fields, shows prompts accordingly
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* form
|
|
|
|
* @param {skipAjaxFieldValidation}
|
|
|
|
* boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked
|
|
|
|
*
|
|
|
|
* @return true if form is valid, false if not, undefined if ajax form validation is done
|
|
|
|
*/
|
|
|
|
_validateFields: function(form, skipAjaxValidation) {
|
|
|
|
var options = form.data('jqv');
|
|
|
|
|
|
|
|
// this variable is set to true if an error is found
|
|
|
|
var errorFound = false;
|
|
|
|
|
|
|
|
// Trigger hook, start validation
|
|
|
|
form.trigger("jqv.form.validating");
|
|
|
|
// first, evaluate status of non ajax fields
|
|
|
|
form.find('[class*=validate]').not(':hidden').not(":disabled").each( function() {
|
|
|
|
var field = $(this);
|
|
|
|
errorFound |= methods._validateField(field, options, skipAjaxValidation);
|
|
|
|
});
|
|
|
|
// second, check to see if all ajax calls completed ok
|
|
|
|
// errorFound |= !methods._checkAjaxStatus(options);
|
|
|
|
|
|
|
|
// thrird, check status and scroll the container accordingly
|
|
|
|
form.trigger("jqv.form.result", [errorFound]);
|
|
|
|
|
|
|
|
if (errorFound) {
|
|
|
|
|
|
|
|
if (options.scroll) {
|
|
|
|
|
|
|
|
// get the position of the first error, there should be at least one, no need to check this
|
|
|
|
//var destination = form.find(".formError:not('.greenPopup'):first").offset().top;
|
|
|
|
|
|
|
|
// look for the visually top prompt
|
|
|
|
var destination = Number.MAX_VALUE;
|
|
|
|
var fixleft = 0;
|
|
|
|
var lst = $(".formError:not('.greenPopup')");
|
|
|
|
|
|
|
|
for (var i = 0; i < lst.length; i++) {
|
|
|
|
var d = $(lst[i]).offset().top;
|
|
|
|
if (d < destination){
|
|
|
|
destination = d;
|
|
|
|
fixleft = $(lst[i]).offset().left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.isOverflown)
|
|
|
|
$("html:not(:animated),body:not(:animated)").animate({
|
|
|
|
scrollTop: destination,
|
|
|
|
scrollLeft: fixleft
|
|
|
|
}, 1100);
|
|
|
|
else {
|
|
|
|
var overflowDIV = $(options.overflownDIV);
|
|
|
|
var scrollContainerScroll = overflowDIV.scrollTop();
|
|
|
|
var scrollContainerPos = -parseInt(overflowDIV.offset().top);
|
|
|
|
|
|
|
|
destination += scrollContainerScroll + scrollContainerPos - 5;
|
|
|
|
var scrollContainer = $(options.overflownDIV + ":not(:animated)");
|
|
|
|
|
|
|
|
scrollContainer.animate({
|
|
|
|
scrollTop: destination
|
|
|
|
}, 1100);
|
|
|
|
|
|
|
|
$("html:not(:animated),body:not(:animated)").animate({
|
|
|
|
scrollTop: overflowDIV.offset().top,
|
|
|
|
scrollLeft: fixleft
|
|
|
|
}, 1100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* This method is called to perform an ajax form validation.
|
|
|
|
* During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true
|
|
|
|
*
|
|
|
|
* @param {jqObject} form
|
|
|
|
* @param {Map} options
|
|
|
|
*/
|
|
|
|
_validateFormWithAjax: function(form, options) {
|
|
|
|
|
|
|
|
var data = form.serialize();
|
|
|
|
var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action");
|
|
|
|
$.ajax({
|
|
|
|
type: "GET",
|
|
|
|
url: url,
|
|
|
|
cache: false,
|
|
|
|
dataType: "json",
|
|
|
|
data: data,
|
|
|
|
form: form,
|
|
|
|
methods: methods,
|
|
|
|
options: options,
|
|
|
|
beforeSend: function() {
|
|
|
|
return options.onBeforeAjaxFormValidation(form, options);
|
|
|
|
},
|
|
|
|
error: function(data, transport) {
|
|
|
|
methods._ajaxError(data, transport);
|
|
|
|
},
|
|
|
|
success: function(json) {
|
|
|
|
|
|
|
|
if (json !== true) {
|
|
|
|
|
|
|
|
// getting to this case doesn't necessary means that the form is invalid
|
|
|
|
// the server may return green or closing prompt actions
|
|
|
|
// this flag helps figuring it out
|
|
|
|
var errorInForm=false;
|
|
|
|
for (var i = 0; i < json.length; i++) {
|
|
|
|
var value = json[i];
|
|
|
|
|
|
|
|
var errorFieldId = value[0];
|
|
|
|
var errorField = $($("#" + errorFieldId)[0]);
|
|
|
|
|
|
|
|
// make sure we found the element
|
|
|
|
if (errorField.length == 1) {
|
|
|
|
|
|
|
|
// promptText or selector
|
|
|
|
var msg = value[2];
|
|
|
|
// if the field is valid
|
|
|
|
if (value[1] == true) {
|
|
|
|
|
|
|
|
if (msg == "" || !msg){
|
|
|
|
// if for some reason, status==true and error="", just close the prompt
|
|
|
|
methods._closePrompt(errorField);
|
|
|
|
} else {
|
|
|
|
// the field is valid, but we are displaying a green prompt
|
|
|
|
if (options.allrules[msg]) {
|
|
|
|
var txt = options.allrules[msg].alertTextOk;
|
|
|
|
if (txt)
|
|
|
|
msg = txt;
|
|
|
|
}
|
|
|
|
methods._showPrompt(errorField, msg, "pass", false, options, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// the field is invalid, show the red error prompt
|
|
|
|
errorInForm|=true;
|
|
|
|
if (options.allrules[msg]) {
|
|
|
|
var txt = options.allrules[msg].alertText;
|
|
|
|
if (txt)
|
|
|
|
msg = txt;
|
|
|
|
}
|
|
|
|
methods._showPrompt(errorField, msg, "", false, options, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
options.onAjaxFormComplete(!errorInForm, form, json, options);
|
|
|
|
} else
|
|
|
|
options.onAjaxFormComplete(true, form, "", options);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validates field, shows prompts accordingly
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* field
|
|
|
|
* @param {Array[String]}
|
|
|
|
* field's validation rules
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return true if field is valid
|
|
|
|
*/
|
|
|
|
_validateField: function(field, options, skipAjaxValidation) {
|
|
|
|
if (!field.attr("id"))
|
|
|
|
$.error("jQueryValidate: an ID attribute is required for this field: " + field.attr("name") + " class:" +
|
|
|
|
field.attr("class"));
|
|
|
|
|
|
|
|
var rulesParsing = field.attr('class');
|
|
|
|
var getRules = /validate\[(.*)\]/.exec(rulesParsing);
|
|
|
|
if (!getRules)
|
|
|
|
return false;
|
|
|
|
var str = getRules[1];
|
|
|
|
var rules = str.split(/\[|,|\]/);
|
|
|
|
|
|
|
|
// true if we ran the ajax validation, tells the logic to stop messing with prompts
|
|
|
|
var isAjaxValidator = false;
|
|
|
|
var fieldName = field.attr("name");
|
|
|
|
var promptText = "";
|
|
|
|
var required = false;
|
|
|
|
options.isError = false;
|
|
|
|
options.showArrow = true;
|
|
|
|
|
|
|
|
for (var i = 0; i < rules.length; i++) {
|
|
|
|
|
|
|
|
var errorMsg = undefined;
|
|
|
|
switch (rules[i]) {
|
|
|
|
|
|
|
|
case "required":
|
|
|
|
required = true;
|
|
|
|
errorMsg = methods._required(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "custom":
|
|
|
|
errorMsg = methods._customRegex(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "groupRequired":
|
|
|
|
// Check is its the first of group, if not, reload validation with first field
|
|
|
|
// AND continue normal validation on present field
|
|
|
|
var classGroup = "[class*=" +rules[i + 1] +"]";
|
|
|
|
var firstOfGroup = field.closest("form").find(classGroup).eq(0);
|
|
|
|
if(firstOfGroup[0] != field[0]){
|
|
|
|
methods._validateField(firstOfGroup, options, skipAjaxValidation)
|
|
|
|
options.showArrow = true;
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
errorMsg = methods._groupRequired(field, rules, i, options);
|
|
|
|
if(errorMsg) required = true;
|
|
|
|
options.showArrow = false;
|
|
|
|
break;
|
|
|
|
case "ajax":
|
|
|
|
// ajax has its own prompts handling technique
|
|
|
|
if(!skipAjaxValidation){
|
|
|
|
methods._ajax(field, rules, i, options);
|
|
|
|
isAjaxValidator = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "minSize":
|
|
|
|
errorMsg = methods._minSize(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "maxSize":
|
|
|
|
errorMsg = methods._maxSize(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "min":
|
|
|
|
errorMsg = methods._min(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "max":
|
|
|
|
errorMsg = methods._max(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "past":
|
|
|
|
errorMsg = methods._past(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "future":
|
|
|
|
errorMsg = methods._future(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "dateRange":
|
|
|
|
var classGroup = "[class*=" + rules[i + 1] + "]";
|
|
|
|
var firstOfGroup = field.closest("form").find(classGroup).eq(0);
|
|
|
|
var secondOfGroup = field.closest("form").find(classGroup).eq(1);
|
|
|
|
/*
|
|
|
|
if (firstOfGroup[0] != field[0]) {
|
|
|
|
methods._validateField(firstOfGroup, options, skipAjaxValidation)
|
|
|
|
options.showArrow = true;
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
//if one entry out of the pair has value then proceed to run through validation
|
|
|
|
if (firstOfGroup[0].value || secondOfGroup[0].value) {
|
|
|
|
errorMsg = methods._dateRange(firstOfGroup, secondOfGroup, rules, i, options);
|
|
|
|
}
|
|
|
|
if (errorMsg) required = true;
|
|
|
|
options.showArrow = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "dateTimeRange":
|
|
|
|
var classGroup = "[class*=" + rules[i + 1] + "]";
|
|
|
|
var firstOfGroup = field.closest("form").find(classGroup).eq(0);
|
|
|
|
var secondOfGroup = field.closest("form").find(classGroup).eq(1);
|
|
|
|
/*
|
|
|
|
if (firstOfGroup[0] != field[0]) {
|
|
|
|
methods._validateField(firstOfGroup, options, skipAjaxValidation)
|
|
|
|
options.showArrow = true;
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
//if one entry out of the pair has value then proceed to run through validation
|
|
|
|
if (firstOfGroup[0].value || secondOfGroup[0].value) {
|
|
|
|
errorMsg = methods._dateTimeRange(firstOfGroup, secondOfGroup, rules, i, options);
|
|
|
|
}
|
|
|
|
if (errorMsg) required = true;
|
|
|
|
options.showArrow = false;
|
|
|
|
break;
|
|
|
|
case "maxCheckbox":
|
|
|
|
errorMsg = methods._maxCheckbox(field, rules, i, options);
|
|
|
|
field = $($("input[name='" + fieldName + "']"));
|
|
|
|
break;
|
|
|
|
case "minCheckbox":
|
|
|
|
errorMsg = methods._minCheckbox(field, rules, i, options);
|
|
|
|
field = $($("input[name='" + fieldName + "']"));
|
|
|
|
break;
|
|
|
|
case "equals":
|
|
|
|
errorMsg = methods._equals(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
case "funcCall":
|
|
|
|
errorMsg = methods._funcCall(field, rules, i, options);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
//$.error("jQueryValidator rule not found"+rules[i]);
|
|
|
|
}
|
|
|
|
if (errorMsg !== undefined) {
|
|
|
|
promptText += errorMsg + "<br/>";
|
|
|
|
options.isError = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// If the rules required is not added, an empty field is not validated
|
|
|
|
if(!required){
|
|
|
|
if(field.val() == "") options.isError = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hack for radio/checkbox group button, the validation go into the
|
|
|
|
// first radio/checkbox of the group
|
|
|
|
var fieldType = field.attr("type");
|
|
|
|
|
|
|
|
if ((fieldType == "radio" || fieldType == "checkbox") && $("input[name='" + fieldName + "']").size() > 1) {
|
|
|
|
field = $($("input[name='" + fieldName + "'][type!=hidden]:first"));
|
|
|
|
options.showArrow = false;
|
|
|
|
}
|
|
|
|
if (fieldType == "text" && $("input[name='" + fieldName + "']").size() > 1) {
|
|
|
|
field = $($("input[name='" + fieldName + "'][type!=hidden]:first"));
|
|
|
|
options.showArrow = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.isError){
|
|
|
|
|
|
|
|
methods._showPrompt(field, promptText, "", false, options);
|
|
|
|
}else{
|
|
|
|
if (!isAjaxValidator) methods._closePrompt(field);
|
|
|
|
}
|
|
|
|
field.trigger("jqv.field.result", [field, options.isError, promptText]);
|
|
|
|
return options.isError;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Required validation
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_required: function(field, rules, i, options) {
|
|
|
|
switch (field.attr("type")) {
|
|
|
|
case "text":
|
|
|
|
case "password":
|
|
|
|
case "textarea":
|
|
|
|
case "file":
|
|
|
|
default:
|
|
|
|
if (!field.val())
|
|
|
|
return options.allrules[rules[i]].alertText;
|
|
|
|
break;
|
|
|
|
case "radio":
|
|
|
|
case "checkbox":
|
|
|
|
var name = field.attr("name");
|
|
|
|
if ($("input[name='" + name + "']:checked").size() == 0) {
|
|
|
|
if ($("input[name='" + name + "']").size() == 1)
|
|
|
|
return options.allrules[rules[i]].alertTextCheckboxe;
|
|
|
|
else
|
|
|
|
return options.allrules[rules[i]].alertTextCheckboxMultiple;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
// required for <select>
|
|
|
|
case "select-one":
|
|
|
|
// added by paul@kinetek.net for select boxes, Thank you
|
|
|
|
if (!field.val())
|
|
|
|
return options.allrules[rules[i]].alertText;
|
|
|
|
break;
|
|
|
|
case "select-multiple":
|
|
|
|
// added by paul@kinetek.net for select boxes, Thank you
|
|
|
|
if (!field.find("option:selected").val())
|
|
|
|
return options.allrules[rules[i]].alertText;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validate that 1 from the group field is required
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_groupRequired: function(field, rules, i, options) {
|
|
|
|
var classGroup = "[class*=" +rules[i + 1] +"]";
|
|
|
|
var isValid = false;
|
|
|
|
// Check all fields from the group
|
|
|
|
field.closest("form").find(classGroup).each(function(){
|
|
|
|
if(!methods._required($(this), rules, i, options)){
|
|
|
|
isValid = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if(!isValid) return options.allrules[rules[i]].alertText;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validate Regex rules
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_customRegex: function(field, rules, i, options) {
|
|
|
|
var customRule = rules[i + 1];
|
|
|
|
var rule = options.allrules[customRule];
|
|
|
|
if(!rule) {
|
|
|
|
alert("jqv:custom rule not found "+customRule);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var ex=rule.regex;
|
|
|
|
if(!ex) {
|
|
|
|
alert("jqv:custom regex not found "+customRule);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var pattern = new RegExp(ex);
|
|
|
|
|
|
|
|
if (!pattern.test(field.val()))
|
|
|
|
return options.allrules[customRule].alertText;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Validate custom function outside of the engine scope
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_funcCall: function(field, rules, i, options) {
|
|
|
|
var functionName = rules[i + 1];
|
|
|
|
var fn = window[functionName];
|
|
|
|
if (typeof(fn) == 'function')
|
|
|
|
return fn(field, rules, i, options);
|
|
|
|
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Field match
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_equals: function(field, rules, i, options) {
|
|
|
|
var equalsField = rules[i + 1];
|
|
|
|
|
|
|
|
if (field.val() != $("#" + equalsField).val())
|
|
|
|
return options.allrules.equals.alertText;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Check the maximum size (in characters)
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_maxSize: function(field, rules, i, options) {
|
|
|
|
var max = rules[i + 1];
|
|
|
|
var len = field.val().length;
|
|
|
|
|
|
|
|
if (len > max) {
|
|
|
|
var rule = options.allrules.maxSize;
|
|
|
|
return rule.alertText + max + rule.alertText2;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Check the minimum size (in characters)
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_minSize: function(field, rules, i, options) {
|
|
|
|
var min = rules[i + 1];
|
|
|
|
var len = field.val().length;
|
|
|
|
|
|
|
|
if (len < min) {
|
|
|
|
var rule = options.allrules.minSize;
|
|
|
|
return rule.alertText + min + rule.alertText2;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Check number minimum value
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_min: function(field, rules, i, options) {
|
|
|
|
var min = parseFloat(rules[i + 1]);
|
|
|
|
var len = parseFloat(field.val());
|
|
|
|
|
|
|
|
if (len < min) {
|
|
|
|
var rule = options.allrules.min;
|
|
|
|
if (rule.alertText2) return rule.alertText + min + rule.alertText2;
|
|
|
|
return rule.alertText + min;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Check number maximum value
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_max: function(field, rules, i, options) {
|
|
|
|
var max = parseFloat(rules[i + 1]);
|
|
|
|
var len = parseFloat(field.val());
|
|
|
|
|
|
|
|
if (len >max ) {
|
|
|
|
var rule = options.allrules.max;
|
|
|
|
if (rule.alertText2) return rule.alertText + max + rule.alertText2;
|
|
|
|
//orefalo: to review, also do the translations
|
|
|
|
return rule.alertText + max;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Checks date is in the past
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_past: function(field, rules, i, options) {
|
|
|
|
|
|
|
|
var p=rules[i + 1];
|
|
|
|
var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p);
|
|
|
|
var vdate = methods._parseDate(field.val());
|
|
|
|
|
|
|
|
if (vdate < pdate ) {
|
|
|
|
var rule = options.allrules.past;
|
|
|
|
if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
|
|
|
|
return rule.alertText + methods._dateToString(pdate);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Checks date is in the future
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_future: function(field, rules, i, options) {
|
|
|
|
|
|
|
|
var p=rules[i + 1];
|
|
|
|
var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p);
|
|
|
|
var vdate = methods._parseDate(field.val());
|
|
|
|
|
|
|
|
if (vdate > pdate ) {
|
|
|
|
var rule = options.allrules.future;
|
|
|
|
if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
|
|
|
|
return rule.alertText + methods._dateToString(pdate);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Checks if valid date
|
|
|
|
*
|
|
|
|
* @param {string} date string
|
|
|
|
* @return a bool based on determination of valid date
|
|
|
|
*/
|
|
|
|
_isDate: function (value) {
|
|
|
|
var dateRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/);
|
|
|
|
if (dateRegEx.test(value)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Checks if valid date time
|
|
|
|
*
|
|
|
|
* @param {string} date string
|
|
|
|
* @return a bool based on determination of valid date time
|
|
|
|
*/
|
|
|
|
_isDateTime: function (value){
|
|
|
|
var dateTimeRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/);
|
|
|
|
if (dateTimeRegEx.test(value)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
//Checks if the start date is before the end date
|
|
|
|
//returns true if end is later than start
|
|
|
|
_dateCompare: function (start, end) {
|
|
|
|
return (new Date(start.toString()) < new Date(end.toString()));
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Checks date range
|
|
|
|
*
|
|
|
|
* @param {jqObject} first field name
|
|
|
|
* @param {jqObject} second field name
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_dateRange: function (first, second, rules, i, options) {
|
|
|
|
//are not both populated
|
|
|
|
if ((!first[0].value && second[0].value) || (first[0].value && !second[0].value)) {
|
|
|
|
return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
|
|
|
|
}
|
|
|
|
|
|
|
|
//are not both dates
|
|
|
|
if (!methods._isDate(first[0].value) || !methods._isDate(second[0].value)) {
|
|
|
|
return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
|
|
|
|
}
|
|
|
|
|
|
|
|
//are both dates but range is off
|
|
|
|
if (!methods._dateCompare(first[0].value, second[0].value)) {
|
|
|
|
return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks date time range
|
|
|
|
*
|
|
|
|
* @param {jqObject} first field name
|
|
|
|
* @param {jqObject} second field name
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_dateTimeRange: function (first, second, rules, i, options) {
|
|
|
|
//are not both populated
|
|
|
|
if ((!first[0].value && second[0].value) || (first[0].value && !second[0].value)) {
|
|
|
|
return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
|
|
|
|
}
|
|
|
|
//are not both dates
|
|
|
|
if (!methods._isDateTime(first[0].value) || !methods._isDateTime(second[0].value)) {
|
|
|
|
return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
|
|
|
|
}
|
|
|
|
//are both dates but range is off
|
|
|
|
if (!methods._dateCompare(first[0].value, second[0].value)) {
|
|
|
|
return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Max number of checkbox selected
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_maxCheckbox: function(field, rules, i, options) {
|
|
|
|
|
|
|
|
var nbCheck = rules[i + 1];
|
|
|
|
var groupname = field.attr("name");
|
|
|
|
var groupSize = $("input[name='" + groupname + "']:checked").size();
|
|
|
|
if (groupSize > nbCheck) {
|
|
|
|
options.showArrow = false;
|
|
|
|
if (options.allrules.maxCheckbox.alertText2) return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2;
|
|
|
|
return options.allrules.maxCheckbox.alertText;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Min number of checkbox selected
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return an error string if validation failed
|
|
|
|
*/
|
|
|
|
_minCheckbox: function(field, rules, i, options) {
|
|
|
|
|
|
|
|
var nbCheck = rules[i + 1];
|
|
|
|
var groupname = field.attr("name");
|
|
|
|
var groupSize = $("input[name='" + groupname + "']:checked").size();
|
|
|
|
if (groupSize < nbCheck) {
|
|
|
|
options.showArrow = false;
|
|
|
|
return options.allrules.minCheckbox.alertText + " " + nbCheck + " " +
|
|
|
|
options.allrules.minCheckbox.alertText2;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Ajax field validation
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {Array[String]} rules
|
|
|
|
* @param {int} i rules index
|
|
|
|
* @param {Map}
|
|
|
|
* user options
|
|
|
|
* @return nothing! the ajax validator handles the prompts itself
|
|
|
|
*/
|
|
|
|
_ajax: function(field, rules, i, options) {
|
|
|
|
|
|
|
|
|
|
|
|
var errorSelector = rules[i + 1];
|
|
|
|
var rule = options.allrules[errorSelector];
|
|
|
|
var extraData = rule.extraData;
|
|
|
|
var extraDataDynamic = rule.extraDataDynamic;
|
|
|
|
|
|
|
|
if (!extraData)
|
|
|
|
extraData = "";
|
|
|
|
|
|
|
|
if (extraDataDynamic) {
|
|
|
|
var tmpData = [];
|
|
|
|
var domIds = String(extraDataDynamic).split(",");
|
|
|
|
for (var i = 0; i < domIds.length; i++) {
|
|
|
|
var id = domIds[i];
|
|
|
|
if ($(id).length) {
|
|
|
|
var inputValue = field.closest("form").find(id).val();
|
|
|
|
var keyValue = id.replace('#', '') + '=' + escape(inputValue);
|
|
|
|
tmpData.push(keyValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
extraDataDynamic = tmpData.join("&");
|
|
|
|
} else {
|
|
|
|
extraDataDynamic = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.isError) {
|
|
|
|
$.ajax({
|
|
|
|
type: "GET",
|
|
|
|
url: rule.url,
|
|
|
|
cache: false,
|
|
|
|
dataType: "json",
|
|
|
|
data: "fieldId=" + field.attr("id") + "&fieldValue=" + field.val() + "&extraData=" + extraData + "&" + extraDataDynamic,
|
|
|
|
field: field,
|
|
|
|
rule: rule,
|
|
|
|
methods: methods,
|
|
|
|
options: options,
|
|
|
|
beforeSend: function() {
|
|
|
|
// build the loading prompt
|
|
|
|
var loadingText = rule.alertTextLoad;
|
|
|
|
if (loadingText)
|
|
|
|
methods._showPrompt(field, loadingText, "load", true, options);
|
|
|
|
},
|
|
|
|
error: function(data, transport) {
|
|
|
|
methods._ajaxError(data, transport);
|
|
|
|
},
|
|
|
|
success: function(json) {
|
|
|
|
|
|
|
|
// asynchronously called on success, data is the json answer from the server
|
|
|
|
var errorFieldId = json[0];
|
|
|
|
var errorField = $($("#" + errorFieldId)[0]);
|
|
|
|
// make sure we found the element
|
|
|
|
if (errorField.length == 1) {
|
|
|
|
var status = json[1];
|
|
|
|
// read the optional msg from the server
|
|
|
|
var msg = json[2];
|
|
|
|
if (!status) {
|
|
|
|
// Houston we got a problem - display an red prompt
|
|
|
|
options.ajaxValidCache[errorFieldId] = false;
|
|
|
|
options.isError = true;
|
|
|
|
|
|
|
|
// resolve the msg prompt
|
|
|
|
if(msg) {
|
|
|
|
if (options.allrules[msg]) {
|
|
|
|
var txt = options.allrules[msg].alertText;
|
|
|
|
if (txt)
|
|
|
|
msg = txt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg = rule.alertText;
|
|
|
|
|
|
|
|
methods._showPrompt(errorField, msg, "", true, options);
|
|
|
|
} else {
|
|
|
|
if (options.ajaxValidCache[errorFieldId] !== undefined)
|
|
|
|
options.ajaxValidCache[errorFieldId] = true;
|
|
|
|
|
|
|
|
// resolves the msg prompt
|
|
|
|
if(msg) {
|
|
|
|
if (options.allrules[msg]) {
|
|
|
|
var txt = options.allrules[msg].alertTextOk;
|
|
|
|
if (txt)
|
|
|
|
msg = txt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg = rule.alertTextOk;
|
|
|
|
|
|
|
|
// see if we should display a green prompt
|
|
|
|
if (msg)
|
|
|
|
methods._showPrompt(errorField, msg, "pass", true, options);
|
|
|
|
else
|
|
|
|
methods._closePrompt(errorField);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Common method to handle ajax errors
|
|
|
|
*
|
|
|
|
* @param {Object} data
|
|
|
|
* @param {Object} transport
|
|
|
|
*/
|
|
|
|
_ajaxError: function(data, transport) {
|
|
|
|
if(data.status == 0 && transport == null)
|
|
|
|
alert("The page is not served from a server! ajax call failed");
|
|
|
|
else if(typeof console != "undefined")
|
|
|
|
console.log("Ajax error: " + data.status + " " + transport);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* date -> string
|
|
|
|
*
|
|
|
|
* @param {Object} date
|
|
|
|
*/
|
|
|
|
_dateToString: function(date) {
|
|
|
|
|
|
|
|
return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Parses an ISO date
|
|
|
|
* @param {String} d
|
|
|
|
*/
|
|
|
|
_parseDate: function(d) {
|
|
|
|
|
|
|
|
var dateParts = d.split("-");
|
|
|
|
if(dateParts==d)
|
|
|
|
dateParts = d.split("/");
|
|
|
|
return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Builds or updates a prompt with the given information
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {String} promptText html text to display type
|
|
|
|
* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
|
|
|
|
* @param {boolean} ajaxed - use to mark fields than being validated with ajax
|
|
|
|
* @param {Map} options user options
|
|
|
|
*/
|
|
|
|
_showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) {
|
|
|
|
var prompt = methods._getPrompt(field);
|
|
|
|
// The ajax submit errors are not see has an error in the form,
|
|
|
|
// When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time
|
|
|
|
// Because no error was found befor submitting
|
|
|
|
if(ajaxform) prompt = false;
|
|
|
|
if (prompt)
|
|
|
|
methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);
|
|
|
|
else
|
|
|
|
methods._buildPrompt(field, promptText, type, ajaxed, options);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Builds and shades a prompt for the given field.
|
|
|
|
*
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {String} promptText html text to display type
|
|
|
|
* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
|
|
|
|
* @param {boolean} ajaxed - use to mark fields than being validated with ajax
|
|
|
|
* @param {Map} options user options
|
|
|
|
*/
|
|
|
|
_buildPrompt: function(field, promptText, type, ajaxed, options) {
|
|
|
|
|
|
|
|
// create the prompt
|
|
|
|
var prompt = $('<div>');
|
|
|
|
prompt.addClass(methods._getClassName(field.attr("id")) + "formError");
|
|
|
|
// add a class name to identify the parent form of the prompt
|
|
|
|
if(field.is(":input")) prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id")));
|
|
|
|
prompt.addClass("formError");
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case "pass":
|
|
|
|
prompt.addClass("greenPopup");
|
|
|
|
break;
|
|
|
|
case "load":
|
|
|
|
prompt.addClass("blackPopup");
|
|
|
|
}
|
|
|
|
if (ajaxed)
|
|
|
|
prompt.addClass("ajaxed");
|
|
|
|
|
|
|
|
// create the prompt content
|
|
|
|
var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);
|
|
|
|
// create the css arrow pointing at the field
|
|
|
|
// note that there is no triangle on max-checkbox and radio
|
|
|
|
if (options.showArrow) {
|
|
|
|
var arrow = $('<div>').addClass("formErrorArrow");
|
|
|
|
|
|
|
|
switch (options.promptPosition) {
|
|
|
|
case "bottomLeft":
|
|
|
|
case "bottomRight":
|
|
|
|
prompt.find(".formErrorContent").before(arrow);
|
|
|
|
arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');
|
|
|
|
break;
|
|
|
|
case "topLeft":
|
|
|
|
case "topRight":
|
|
|
|
arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>');
|
|
|
|
prompt.append(arrow);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Cedric: Needed if a container is in position:relative
|
|
|
|
// insert prompt in the form or in the overflown container?
|
|
|
|
if (options.isOverflown)
|
|
|
|
field.before(prompt);
|
|
|
|
else
|
|
|
|
$("body").append(prompt);
|
|
|
|
|
|
|
|
var pos = methods._calculatePosition(field, prompt, options);
|
|
|
|
prompt.css({
|
|
|
|
"top": pos.callerTopPosition,
|
|
|
|
"left": pos.callerleftPosition,
|
|
|
|
"marginTop": pos.marginTopSize,
|
|
|
|
"opacity": 0
|
|
|
|
});
|
|
|
|
|
|
|
|
return prompt.animate({
|
|
|
|
"opacity": 0.87
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Updates the prompt text field - the field for which the prompt
|
|
|
|
* @param {jqObject} field
|
|
|
|
* @param {String} promptText html text to display type
|
|
|
|
* @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
|
|
|
|
* @param {boolean} ajaxed - use to mark fields than being validated with ajax
|
|
|
|
* @param {Map} options user options
|
|
|
|
*/
|
|
|
|
_updatePrompt: function(field, prompt, promptText, type, ajaxed, options) {
|
|
|
|
|
|
|
|
if (prompt) {
|
|
|
|
if (type == "pass")
|
|
|
|
prompt.addClass("greenPopup");
|
|
|
|
else
|
|
|
|
prompt.removeClass("greenPopup");
|
|
|
|
|
|
|
|
if (type == "load")
|
|
|
|
prompt.addClass("blackPopup");
|
|
|
|
else
|
|
|
|
prompt.removeClass("blackPopup");
|
|
|
|
|
|
|
|
if (ajaxed)
|
|
|
|
prompt.addClass("ajaxed");
|
|
|
|
else
|
|
|
|
prompt.removeClass("ajaxed");
|
|
|
|
|
|
|
|
prompt.find(".formErrorContent").html(promptText);
|
|
|
|
|
|
|
|
var pos = methods._calculatePosition(field, prompt, options);
|
|
|
|
prompt.animate({
|
|
|
|
"top": pos.callerTopPosition,
|
|
|
|
"left": pos.callerleftPosition,
|
|
|
|
"marginTop": pos.marginTopSize
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Closes the prompt associated with the given field
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* field
|
|
|
|
*/
|
|
|
|
_closePrompt: function(field) {
|
|
|
|
|
|
|
|
var prompt = methods._getPrompt(field);
|
|
|
|
if (prompt)
|
|
|
|
prompt.fadeTo("fast", 0, function() {
|
|
|
|
prompt.remove();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
closePrompt: function(field) {
|
|
|
|
return methods._closePrompt(field);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Returns the error prompt matching the field if any
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* field
|
|
|
|
* @return undefined or the error prompt (jqObject)
|
|
|
|
*/
|
|
|
|
_getPrompt: function(field) {
|
|
|
|
var className = field.attr("id").replace(":","_") + "formError";
|
|
|
|
var match = $("." + methods._escapeExpression(className))[0];
|
|
|
|
if (match)
|
|
|
|
return $(match);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Returns the escapade classname
|
|
|
|
*
|
|
|
|
* @param {selector}
|
|
|
|
* className
|
|
|
|
*/
|
|
|
|
_escapeExpression: function (selector) {
|
|
|
|
return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1");
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Calculates prompt position
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* field
|
|
|
|
* @param {jqObject}
|
|
|
|
* the prompt
|
|
|
|
* @param {Map}
|
|
|
|
* options
|
|
|
|
* @return positions
|
|
|
|
*/
|
|
|
|
_calculatePosition: function (field, promptElmt, options) {
|
|
|
|
|
|
|
|
var promptTopPosition, promptleftPosition, marginTopSize;
|
|
|
|
var fieldWidth = field.width();
|
|
|
|
var promptHeight = promptElmt.height();
|
|
|
|
|
|
|
|
var overflow = options.isOverflown;
|
|
|
|
if (overflow) {
|
|
|
|
// is the form contained in an overflown container?
|
|
|
|
promptTopPosition = promptleftPosition = 0;
|
|
|
|
// compensation for the arrow
|
|
|
|
marginTopSize = -promptHeight;
|
|
|
|
} else {
|
|
|
|
var offset = field.offset();
|
|
|
|
promptTopPosition = offset.top;
|
|
|
|
promptleftPosition = offset.left;
|
|
|
|
marginTopSize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (options.promptPosition) {
|
|
|
|
|
|
|
|
default:
|
|
|
|
case "topRight":
|
|
|
|
if (overflow)
|
|
|
|
// Is the form contained in an overflown container?
|
|
|
|
promptleftPosition += fieldWidth - 30;
|
|
|
|
else {
|
|
|
|
promptleftPosition += fieldWidth - 30;
|
|
|
|
promptTopPosition += -promptHeight -2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "topLeft":
|
|
|
|
promptTopPosition += -promptHeight - 10;
|
|
|
|
break;
|
|
|
|
case "centerRight":
|
|
|
|
promptleftPosition += fieldWidth + 13;
|
|
|
|
break;
|
|
|
|
case "bottomLeft":
|
|
|
|
promptTopPosition = promptTopPosition + field.height() + 15;
|
|
|
|
break;
|
|
|
|
case "bottomRight":
|
|
|
|
promptleftPosition += fieldWidth - 30;
|
|
|
|
promptTopPosition += field.height() + 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
"callerTopPosition": promptTopPosition + "px",
|
|
|
|
"callerleftPosition": promptleftPosition + "px",
|
|
|
|
"marginTopSize": marginTopSize + "px"
|
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Saves the user options and variables in the form.data
|
|
|
|
*
|
|
|
|
* @param {jqObject}
|
|
|
|
* form - the form where the user option should be saved
|
|
|
|
* @param {Map}
|
|
|
|
* options - the user options
|
|
|
|
* @return the user options (extended from the defaults)
|
|
|
|
*/
|
|
|
|
_saveOptions: function(form, options) {
|
|
|
|
|
|
|
|
// is there a language localisation ?
|
|
|
|
if ($.validationEngineLanguage)
|
|
|
|
var allRules = $.validationEngineLanguage.allRules;
|
|
|
|
else
|
|
|
|
$.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");
|
|
|
|
// --- Internals DO NOT TOUCH or OVERLOAD ---
|
|
|
|
// validation rules and i18
|
|
|
|
$.validationEngine.defaults.allrules = allRules;
|
|
|
|
|
|
|
|
var userOptions = $.extend({},$.validationEngine.defaults, options);
|
|
|
|
|
|
|
|
form.data('jqv', userOptions);
|
|
|
|
return userOptions;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes forbidden characters from class name
|
|
|
|
* @param {String} className
|
|
|
|
*/
|
|
|
|
_getClassName: function(className) {
|
|
|
|
return className.replace(":","_").replace(".","_");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Plugin entry point.
|
|
|
|
* You may pass an action as a parameter or a list of options.
|
|
|
|
* if none, the init and attach methods are being called.
|
|
|
|
* Remember: if you pass options, the attached method is NOT called automatically
|
|
|
|
*
|
|
|
|
* @param {String}
|
|
|
|
* method (optional) action
|
|
|
|
*/
|
|
|
|
$.fn.validationEngine = function(method) {
|
|
|
|
|
|
|
|
var form = $(this);
|
|
|
|
if(!form[0]) return false; // stop here if the form does not exist
|
|
|
|
|
|
|
|
if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) {
|
|
|
|
|
|
|
|
// make sure init is called once
|
|
|
|
if(method != "showPrompt" && method != "hidePrompt" && method != "hide" && method != "hideAll")
|
|
|
|
methods.init.apply(form);
|
|
|
|
|
|
|
|
return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));
|
|
|
|
} else if (typeof method == 'object' || !method) {
|
|
|
|
// default constructor with or without arguments
|
|
|
|
|
|
|
|
methods.init.apply(form, arguments);
|
|
|
|
return methods.attach.apply(form);
|
|
|
|
} else {
|
|
|
|
$.error('Method ' + method + ' does not exist in jQuery.validationEngine');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// LEAK GLOBAL OPTIONS
|
|
|
|
$.validationEngine= {defaults:{
|
|
|
|
|
|
|
|
// Name of the event triggering field validation
|
|
|
|
validationEventTrigger: "blur",
|
|
|
|
// Automatically scroll viewport to the first error
|
|
|
|
scroll: true,
|
|
|
|
// Opening box position, possible locations are: topLeft,
|
|
|
|
// topRight, bottomLeft, centerRight, bottomRight
|
|
|
|
promptPosition: "topRight",
|
|
|
|
bindMethod:"bind",
|
|
|
|
// internal, automatically set to true when it parse a _ajax rule
|
|
|
|
inlineAjax: false,
|
|
|
|
// if set to true, the form data is sent asynchronously via ajax to the form.action url (get)
|
|
|
|
ajaxFormValidation: false,
|
|
|
|
// Ajax form validation callback method: boolean onComplete(form, status, errors, options)
|
|
|
|
// retuns false if the form.submit event needs to be canceled.
|
|
|
|
ajaxFormValidationURL: false,
|
|
|
|
// The url to send the submit ajax validation (default to action)
|
|
|
|
onAjaxFormComplete: $.noop,
|
|
|
|
// called right before the ajax call, may return false to cancel
|
|
|
|
onBeforeAjaxFormValidation: $.noop,
|
|
|
|
// Stops form from submitting and execute function assiciated with it
|
|
|
|
onValidationComplete: false,
|
|
|
|
|
|
|
|
// Used when the form is displayed within a scrolling DIV
|
|
|
|
isOverflown: false,
|
|
|
|
overflownDIV: "",
|
|
|
|
|
|
|
|
// true when form and fields are binded
|
|
|
|
binded: false,
|
|
|
|
// set to true, when the prompt arrow needs to be displayed
|
|
|
|
showArrow: true,
|
|
|
|
// did one of the validation fail ? kept global to stop further ajax validations
|
|
|
|
isError: false,
|
|
|
|
// Caches field validation status, typically only bad status are created.
|
|
|
|
// the array is used during ajax form validation to detect issues early and prevent an expensive submit
|
|
|
|
ajaxValidCache: {}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
})(jQuery);
|