// LiveValidation 1.2 (standalone version)
// Copyright (c) 2007 Alec Hill (www.livevalidation.com)
// LiveValidation is licensed under the terms of the MIT License
var LiveValidation = function(element, optionsObj){
this.initialize(element, optionsObj);
}
LiveValidation.TEXTAREA = 1;
LiveValidation.TEXT = 2;
LiveValidation.PASSWORD = 3;
LiveValidation.CHECKBOX = 4;
LiveValidation.SELECT = 5;
LiveValidation.massValidate = function(validations){
var returnValue = true;
for(var i = 0, len = validations.length; i < len; ++i ){
var valid = validations[i].validate();
if(returnValue) returnValue = valid;
}
return returnValue;
}
LiveValidation.prototype = {
validClass: 'LV_valid',
invalidClass: 'LV_invalid',
messageClass: 'LV_validation_message',
validFieldClass: 'LV_valid_field',
invalidFieldClass: 'LV_invalid_field',
initialize: function(element, optionsObj){
var self = this;
if(!element) throw new Error("LiveValidation::initialize - Aucune référence d'éléments fourni!");
this.element = element.nodeName ? element : document.getElementById(element);
if(!this.element) throw new Error("LiveValidation::initialize - Aucun élément avec la référence '" + element + "' n'existe!");
this.validations = [];
this.elementType = this.getElementType();
this.form = this.element.form;
var options = optionsObj || {};
this.validMessage = options.validMessage || '';
this.insertAfterWhatNode = options.insertAfterWhatNode || this.element;
this.onValid = options.onValid || function(){ this.insertMessage(this.createMessageSpan()); this.addFieldClass(); };
this.onInvalid = options.onInvalid || function(){ this.insertMessage(this.createMessageSpan()); this.addFieldClass(); };
this.onlyOnBlur = options.onlyOnBlur || false;
this.wait = options.wait || 0;
this.onlyOnSubmit = options.onlyOnSubmit || false;
if(this.form){
this.formObj = LiveValidationForm.getInstance(this.form);
this.formObj.addField(this);
}
this.element.onfocus = function(e){ self.doOnFocus(); }
if(!this.onlyOnSubmit){
switch(this.elementType){
case LiveValidation.CHECKBOX:
this.element.onclick = function(e){ self.validate(); }
case LiveValidation.SELECT:
this.element.onchange = function(e){ self.validate(); }
break;
default:
if(!this.onlyOnBlur) this.element.onkeyup = function(e){ self.deferValidation(); }
this.element.onblur = function(e){ self.doOnBlur(); }
}
}
},
add: function(validationFunction, validationParamsObj){
this.validations.push( {type: validationFunction, params: validationParamsObj || {} } );
return this;
},
deferValidation: function(e){
if(this.wait >= 300) this.removeMessageAndFieldClass();
var self = this;
if(this.timeout) clearTimeout(self.timeout);
this.timeout = setTimeout( function(){ self.validate() }, self.wait);
},
doOnBlur: function(e){
this.focused = false;
this.validate(e);
},
doOnFocus: function(e){
this.focused = true;
this.removeMessageAndFieldClass()
},
getElementType: function(){
switch(true){
case (this.element.nodeName == 'TEXTAREA'):
return LiveValidation.TEXTAREA;
case (this.element.nodeName == 'INPUT' && this.element.type == 'text'):
return LiveValidation.TEXT;
case (this.element.nodeName == 'INPUT' && this.element.type == 'password'):
return LiveValidation.PASSWORD;
case (this.element.nodeName == 'INPUT' && this.element.type == 'checkbox'):
return LiveValidation.CHECKBOX;
case (this.element.nodeName == 'SELECT'):
return LiveValidation.SELECT;
case (this.element.nodeName == 'INPUT'):
throw new Error('LiveValidation::getElementType - Impossible de se servir de LiveValidation sur ' + this.element.type + ' input!');
default:
throw new Error('LiveValidation::getElementType - Le type de formulaire requis doit être input, select, ou textarea!');
}
},
doValidations: function(){
this.validationFailed = false;
for(var i = 0, len = this.validations.length; i < len; ++i){
var validation = this.validations[i];
switch(validation.type){
case Validate.Presence:
case Validate.Confirmation:
case Validate.Acceptance:
this.displayMessageWhenEmpty = true;
this.validationFailed = !this.validateElement(validation.type, validation.params);
break;
default:
this.validationFailed = !this.validateElement(validation.type, validation.params);
break;
}
if(this.validationFailed) return false;
}
this.message = this.validMessage;
return true;
},
validateElement: function(validationFunction, validationParamsObj){
var value = (this.elementType == LiveValidation.SELECT) ? this.element.options[this.element.selectedIndex].value : this.element.value;
if(validationFunction == Validate.Acceptance){
if(this.elementType != LiveValidation.CHECKBOX) throw new Error('LiveValidation::validateElement - Element à valider doit être une checkbox!');
value = this.element.checked;
}
var isValid = true;
try{
validationFunction(value, validationParamsObj);
} catch(error) {
if(error instanceof Validate.Error){
if( value !== '' || (value === '' && this.displayMessageWhenEmpty) ){
this.validationFailed = true;
this.message = error.message;
isValid = false;
}
}else{
throw error;
}
}finally{
return isValid;
}
},
validate: function(){
var isValid = this.doValidations();
if(isValid){
this.onValid();
return true;
}else{
this.onInvalid();
return false;
}
},
createMessageSpan: function(){
var span = document.createElement('span');
var textNode = document.createTextNode(this.message);
span.appendChild(textNode);
return span;
},
insertMessage: function(elementToInsert){
this.removeMessage();
if( (this.displayMessageWhenEmpty && (this.elementType == LiveValidation.CHECKBOX || this.element.value == ''))
|| this.element.value != '' ){
var className = this.validationFailed ? this.invalidClass : this.validClass;
elementToInsert.className += ' ' + this.messageClass + ' ' + className;
if(this.insertAfterWhatNode.nextSibling){
this.insertAfterWhatNode.parentNode.insertBefore(elementToInsert, this.insertAfterWhatNode.nextSibling);
}else{
this.insertAfterWhatNode.parentNode.appendChild(elementToInsert);
}
}
},
addFieldClass: function(){
this.removeFieldClass();
if(!this.validationFailed){
if(this.displayMessageWhenEmpty || this.element.value != ''){
if(this.element.className.indexOf(this.validFieldClass) == -1) this.element.className += ' ' + this.validFieldClass;
}
}else{
if(this.element.className.indexOf(this.invalidFieldClass) == -1) this.element.className += ' ' + this.invalidFieldClass;
}
},
removeMessage: function(){
var nextEl;
var el = this.insertAfterWhatNode;
while(el.nextSibling){
if(el.nextSibling.nodeType === 1){
nextEl = el.nextSibling;
break;
}
el = el.nextSibling;
}
if(nextEl && nextEl.className.indexOf(this.messageClass) != -1) this.insertAfterWhatNode.parentNode.removeChild(nextEl);
},
removeFieldClass: function(){
if(this.element.className.indexOf(this.invalidFieldClass) != -1) this.element.className = this.element.className.split(this.invalidFieldClass).join('');
if(this.element.className.indexOf(this.validFieldClass) != -1) this.element.className = this.element.className.split(this.validFieldClass).join(' ');
},
removeMessageAndFieldClass: function(){
this.removeMessage();
this.removeFieldClass();
}
}
var LiveValidationForm = function(element){
this.initialize(element);
}
LiveValidationForm.getInstance = function(element){
if(!element.id) element.id = 'formId_' + new Date().valueOf();
if(!window['LiveValidationForm_' + element.id]) window['LiveValidationForm_' + element.id] = new LiveValidationForm(element);
return window['LiveValidationForm_' + element.id];
}
LiveValidationForm.prototype = {
initialize: function(element){
this.element = element;
this.fields = [];
var self = this;
this.element.onsubmit = function(){
return LiveValidation.massValidate(self.fields);
}
},
addField: function(newField){
this.fields.push(newField);
}
}
var Validate = {
/**
*	validates that the field has been filled in
*
*	@var value {mixed} - value to be checked
*	@var paramsObj {Object} - parameters for this particular validation, see below for details
*
*	paramsObj properties:
*	failureMessage {String} - the message to show when the field fails validation
*	(DEFAULT: "Can't be empty!")
*/
Presence: function(value, paramsObj){
var paramsObj = paramsObj || {};
var message = paramsObj.failureMessage || "Ne peut être vide !";
if(value === '' || value === null || value === undefined){
Validate.fail(message);
}
return true;
},
Numericality: function(value, paramsObj){
var suppliedValue = value;
var value = Number(value);
var paramsObj = paramsObj || {};
var minimum = ((paramsObj.minimum) || (paramsObj.minimum == 0)) ? paramsObj.minimum : null;;
var maximum = ((paramsObj.maximum) || (paramsObj.maximum == 0)) ? paramsObj.maximum : null;
var is = ((paramsObj.is) || (paramsObj.is == 0)) ? paramsObj.is : null;
var notANumberMessage = paramsObj.notANumberMessage || "Il faut un nombre!";
var notAnIntegerMessage = paramsObj.notAnIntegerMessage || "Il faut un entier!";
var wrongNumberMessage = paramsObj.wrongNumberMessage || "Doit être " + is + "!";
var tooLowMessage = paramsObj.tooLowMessage || "Doit être supérieur ou égal à " + minimum + "!";
var tooHighMessage = paramsObj.tooHighMessage || "Doit être inférieur ou égal à " + maximum + "!";
if (!isFinite(value)) Validate.fail(notANumberMessage);
if (paramsObj.onlyInteger && (/\.0+$|\.$/.test(String(suppliedValue)) || value != parseInt(value)) ) Validate.fail(notAnIntegerMessage);
switch(true){
case (is !== null):
if( value != Number(is) ) Validate.fail(wrongNumberMessage);
break;
case (minimum !== null && maximum !== null):
Validate.Numericality(value, {tooLowMessage: tooLowMessage, minimum: minimum});
Validate.Numericality(value, {tooHighMessage: tooHighMessage, maximum: maximum});
break;
case (minimum !== null):
if( value < Number(minimum) ) Validate.fail(tooLowMessage);
break;
case (maximum !== null):
if( value > Number(maximum) ) Validate.fail(tooHighMessage);
break;
}
return true;
},
Format: function(value, paramsObj){
var value = String(value);
var paramsObj = paramsObj || {};
var message = paramsObj.failureMessage || "Incorrect!";
var pattern = paramsObj.pattern || /./;
if(!pattern.test(value) /* && value != ''*/ ){
Validate.fail(message);
}
return true;
},
Email: function(value, paramsObj){
var paramsObj = paramsObj || {};
var message = paramsObj.failureMessage || "Ceci n'est pas une adresse email correcte!";
Validate.Format(value, { failureMessage: message, pattern: /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i } );
return true;
},
Length: function(value, paramsObj){
var value = String(value);
var paramsObj = paramsObj || {};
var minimum = ((paramsObj.minimum) || (paramsObj.minimum == 0)) ? paramsObj.minimum : null;
var maximum = ((paramsObj.maximum) || (paramsObj.maximum == 0)) ? paramsObj.maximum : null;
var is = ((paramsObj.is) || (paramsObj.is == 0)) ? paramsObj.is : null;
var wrongLengthMessage = paramsObj.wrongLengthMessage || "Ceci doit faire " + is + " caractères de long!";
var tooShortMessage = paramsObj.tooShortMessage || "Ceci ne doit pas faire moins de " + minimum + " caractères de long!";
var tooLongMessage = paramsObj.tooLongMessage || "Ceci ne doit pas faire plus de " + maximum + " caractères de long!";
switch(true){
case (is !== null):
if( value.length != Number(is) ) Validate.fail(wrongLengthMessage);
break;
case (minimum !== null && maximum !== null):
Validate.Length(value, {tooShortMessage: tooShortMessage, minimum: minimum});
Validate.Length(value, {tooLongMessage: tooLongMessage, maximum: maximum});
break;
case (minimum !== null):
if( value.length < Number(minimum) ) Validate.fail(tooShortMessage);
break;
case (maximum !== null):
if( value.length > Number(maximum) ) Validate.fail(tooLongMessage);
break;
default:
throw new Error("Validate::Length - La longueur à comparer doit être fournie!");
}
return true;
},
Inclusion: function(value, paramsObj){
var paramsObj = paramsObj || {};
var message = paramsObj.failureMessage || "Doit faire partie de la liste !";
if(paramsObj.allowNull && value == null) return true;
if(!paramsObj.allowNull && value == null) Validate.fail(message)
var list = paramsObj.within || [];
var found = false;
for(var i = 0, length = list.length; i < length; ++i){
if(list[i] == value) found = true;
if(paramsObj.partialMatch){
if(value.indexOf(list[i]) != -1) found = true;
}
}
if( (!paramsObj.exclusion && !found) || (paramsObj.exclusion && found) ) Validate.fail(message);
return true;
},
Exclusion: function(value, paramsObj){
var paramsObj = paramsObj || {};
paramsObj.failureMessage = paramsObj.failureMessage || "Ne doit pas faire partie de la liste!";
paramsObj.exclusion = true;
Validate.Inclusion(value, paramsObj);
return true;
},
Confirmation: function(value, paramsObj){
if(!paramsObj.match) throw new Error("Validate::Confirmation - Erreur de validation : La référence de l'élément à tester doit être fourni!");
var paramsObj = paramsObj || {};
var message = paramsObj.failureMessage || "Ne correspond pas à la valeur attendue !";
var match = paramsObj.match.nodeName ? paramsObj.match : document.getElementById(paramsObj.match);
if(!match) throw new Error("Validate::Confirmation - Pas de référence correspondant à '" + paramsObj.match + "'!");
if(value != match.value){
Validate.fail(message);
}
return true;
},
Acceptance: function(value, paramsObj){
var paramsObj = paramsObj || {};
var message = paramsObj.failureMessage || "Doit être accepté !";
if(!value){
Validate.fail(message);
}
return true;
},
now: function(validationFunction, value, validationParamsObj){
if(!validationFunction) throw new Error("Validate::now - La fonction de validation doit être fournie!");
var isValid = true;
try{
validationFunction(value, validationParamsObj || {});
} catch(error) {
if(error instanceof Validate.Error){
isValid = false;
}else{
throw error;
}
}finally{
return isValid
}
},
fail: function(errorMessage){
throw new Validate.Error(errorMessage);
},
Error: function(errorMessage){
this.message = errorMessage;
this.name = 'ValidationError';
}
}
