/**
* @author davidt@eolas.fr
* @version v0.1
* Controle de formulaires HTML5
* contrôles effectués :
* - isNotNullContainer : test qu'au moins un des inputs de type checkbox|radio est cochée
* - required : si le navigateur ne le prend pas en charge, test que le champs n'est pas vide
* - email : si le navigateur ne le prend pas en charge, test que le champs est une adresse email valide
* - number : si le navigateur ne le prend pas en charge, test que le champs est une valeur numérique valide
* - date : si le navigateur ne le prend pas en charge, test que le champs est une date valide
* - url : si le navigateur ne le prend pas en charge, test que le champs est une url valide
* L'attribut placeholder est géré si le navigateur ne le prend pas en charge
* L'attribut autofocus est géré si le navigateur ne le prend pas en charge
*
* Evènements lancés :
* - preformcheck : événement lancé avant les vérifications
* - postformcheck : événement lancé après les vérifications - le deuxième paramètre du handler est un objet contenant l'état des tests et en cas d'échec, le nom du test qui à échoué (testPassed et test)
*/
;if (typeof(window.CMS) == 'undefined') {
window.CMS = {};
}
/** Check from https://gist.github.com/bminer/3559343 for update **/
/* x is the element
type is the type you want to change it to.
jQuery is required and assumed to be the "$" variable */
function changeType(x, type) {
if(x.prop('type') == type) {
return x; //That was easy.
}
try {
return x.prop('type', type); //Stupid IE security will not allow this
} catch(e) {
//Try re-creating the element (yep... this sucks)
//jQuery has no html() method for the element, so we have to put into a div first
var html = $("
").append(x.clone()).html();
var regex = /type=(\")?([^\"\s]+)(\")?/; //matches type=text or type="text"
//If no match, we add the type attribute to the end; otherwise, we replace
var tmp = $(html.match(regex) == null ?
html.replace(">", ' type="' + type + '">') :
html.replace(regex, 'type="' + type + '"') );
//Copy data from old element
tmp.data('type', x.data('type') );
var events = x.data('events');
var cb = function(events) {
return function() {
//Bind all prior events
for(i in events)
{
var y = events[i];
for(j in y)
tmp.on(i, y[j].handler);
}
}
}(events);
x.replaceWith(tmp);
setTimeout(cb, 10); //Wait a bit to call function
return tmp;
}
}
window.CMS.html5Form = (function($, undefined) {
"use strict";
var html5Form = {
//Configuration
config: {
defaultLang: 'fr',
dateFormat: {
fr: /[0-9]{2}\/[0-9]{2}\/[0-9]{4}/
},
urlFormat: /^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?$/,
errorMsg: {
fr: {
email: 'Veuillez saisir un email valide',
number: 'Veuillez saisir une valeur numérique',
required: 'Veuillez compléter ce champ',
date: 'Veuillez saisir une date valide (JJ/MM/AAAA)',
url: 'Veuillez saisir une url valide',
isNotNullContainer: 'Veuillez cocher au moins une case'
}
}
},
init: function() {
//Prise en charge rétro compatibilité :
//Remplacement des anciennes classes isNotNull, isEmail, isInt, isDate et isFloat
$('label.isNotNull, label.isEmail, label.isInt, label.isDate, label.isFloat').each(function(){
if($(this).hasClass('isNotNull') && $(this).attr('for') != '') {
$('#' + $(this).attr('for')).attr('required', true);
}
if(Modernizr.inputtypes.email && $(this).hasClass('isEmail') && $(this).attr('for') != ''){
//$('#' + $(this).attr('for')).attr('type', 'email');
changeType($('#' + $(this).attr('for')), 'email');
} else if(Modernizr.inputtypes.date && $(this).hasClass('isDate') && $(this).attr('for') != ''){
//$('#' + $(this).attr('for')).attr('type', 'date');
changeType($('#' + $(this).attr('for')), 'date');
} else if(Modernizr.inputtypes.number && ($(this).hasClass('isInt') || $(this).hasClass('isFloat')) && $(this).attr('for') != ''){
//$('#' + $(this).attr('for')).attr('type', 'number');
changeType($('#' + $(this).attr('for')), 'number');
}
});
if(!Modernizr.input.placeholder) {
//Si pas de prise en charge de placeholder
html5Form._polyfills.placeholder.run();
}
if(!Modernizr.input.autofocus) {
//Si pas de prise en charge de autofocus
html5Form._polyfills.autofocus.run();
}
$('form').each(function() {
//Affectation des événements au submit des formulaires
$(this).submit(function(e) {
e.shouldPreventDefault = false;
$(this).trigger('preformcheck', e);
var oParams = { test: '', testPassed: true };
//Cette fonctionalité est perso, le fait de mettre un required sur un checkbox
//veut simplement dire qu'il faut qu'elle soit cochée,
//ici on verifie qu'au moins une case est cochée
html5Form._polyfills.isNotNullContainer.run(this, e);
if(e.shouldPreventDefault){
oParams.test = 'isNotNullContainer';
oParams.testPassed = false;
}
//Si pas de prise en charge de required
if(!e.shouldPreventDefault && !Modernizr.input.required) {
html5Form._polyfills.required.run(this, e);
if(e.shouldPreventDefault){
oParams.test = 'required';
oParams.testPassed = false;
}
}
//Si pas de prise en charge de email
if(!e.shouldPreventDefault && !Modernizr.inputtypes.email) {
html5Form._polyfills.types.email.run(this, e);
if(e.shouldPreventDefault){
oParams.test = 'email';
oParams.testPassed = false;
}
}
//Si pas de prise en charge de number
if(!e.shouldPreventDefault && !Modernizr.inputtypes.number) {
html5Form._polyfills.types.number.run(this, e);
if(e.shouldPreventDefault){
oParams.test = 'number';
oParams.testPassed = false;
}
}
//Si pas de prise en charge de date
if(!e.shouldPreventDefault && !Modernizr.inputtypes.date) {
html5Form._polyfills.types.date.run(this, e);
if(e.shouldPreventDefault){
oParams.test = 'date';
oParams.testPassed = false;
}
}
//Si pas de prise en charge de url
if(!e.shouldPreventDefault && !Modernizr.inputtypes.url) {
html5Form._polyfills.types.url.run(this, e);
if(e.shouldPreventDefault){
oParams.test = 'url';
oParams.testPassed = false;
}
}
oParams.oSubmitEvent = e;
$(this).trigger('postformcheck', oParams);
if(e.shouldPreventDefault){
e.preventDefault();
}
});
});
//Suppression de la fonction init pour gagner de la place en mémoire
//(inutile dans la plupart des cas mais ne fait pas de mal)
delete html5Form.init;
},
/**
* Fonctions de remplacement
* chaque fonctionalité remplacée contient une méthode run à laquelle on passe
* l'objet formulaire ainsi que l'objet événement qui sera arreté en cas d'echec de la validation.
**/
_polyfills: {
types: {
email: {
emailFormat: /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})+$/i,
run: function(oForm, e) {
var $cEmail = $('input[type="email"]', oForm).filter(function(){
return ($(this).val() != '' && !html5Form._polyfills.types.email.emailFormat.test($(this).val()));
});
if($cEmail.length>0) {
alert(html5Form.config.errorMsg[html5Form.config.defaultLang].email);
$cEmail.addClass('html5Form_error').first().focus();
e.shouldPreventDefault = true;
return false;
}
return true;
}
},
number: {
numberFormat: /^[0-9]+(\.[0-9]+)?$/i,
run: function(oForm, e) {
var $cNumber = $('input[type="number"]', oForm).filter(function(){
return $(this).val() != '' && !html5Form._polyfills.types.number.numberFormat.test($(this).val());
});
if($cNumber.length>0) {
alert(html5Form.config.errorMsg[html5Form.config.defaultLang].number);
$cNumber.addClass('html5Form_error').first().focus();
e.shouldPreventDefault = true;
return false;
}
return true;
}
},
date: {
run: function(oForm, e) {
var $cDate = $('input[type="date"]', oForm).filter(function(){
return ($(this).val() != '' && !html5Form.config.dateFormat[html5Form.config.defaultLang].test($(this).val()));
});
if($cDate.length>0) {
alert(html5Form.config.errorMsg[html5Form.config.defaultLang].date);
$cDate.addClass('html5Form_error').first().focus();
e.shouldPreventDefault = true;
return false;
}
return true;
}
},
url: {
run: function(oForm, e){
var $cUrl = $('input[type="url"]', oForm).filter(function(){
return ($(this).val() != '' && !html5Form.config.urlFormat.test($(this).val()));
});
if($cUrl.length>0) {
alert(html5Form.config.errorMsg[html5Form.config.defaultLang].url);
$cUrl.addClass('html5Form_error').first().focus();
e.shouldPreventDefault = true;
return false;
}
$cUrl.removeClass('html5Form_error');
return true;
}
}
},
autofocus: {
run: function() {
$('input[autofocus]').focus();
}
},
placeholder: {
className: 'placeholder',
run: function() {
$('form').has('input[placeholder]').on('submit', function() {
$('input[placeholder]').each(function() {
if($(this).val() == $(this).attr('placeholder')) {
$(this).val('');
$(this).removeClass('placeholder');
}
});
});
$('*[placeholder]')
.each(function() {
$(this)
.addClass(html5Form._polyfills.placeholder.className)
.focus(function() {
if($(this).val() == $(this).attr('placeholder')) {
$(this).val('');
$(this).removeClass('placeholder');
}
})
.blur(function() {
if($(this).val()=='' || $(this).val() == $(this).attr('placeholder')) {
$(this).val($(this).attr('placeholder'));
$(this).addClass('placeholder');
}
});
if ($(this).val() == '') {
$(this).val($(this).attr('placeholder'));
}
});
}
},
required: {
className: 'required',
run: function(oForm, e) {
//Il faut bien utiliser la bonne syntaxe pour une compatibilité max : "" sans valeur
var $cField = $('input[required=""],select[required=""],textarea[required=""]', oForm).filter(function(){
return ($(this).val() == '' || ($(this).attr('placeholder') && $(this).val() == $(this).attr('placeholder')));
});
if($cField.length > 0) {
alert(html5Form.config.errorMsg[html5Form.config.defaultLang].required);
$cField.addClass('html5Form_error').first().focus();
e.shouldPreventDefault = true;
return false;
} else {
$cField.removeClass('html5Form_error');
}
return true;
}
},
isNotNullContainer: {
run: function(oForm, e){
if($('.isNotNullContainer', oForm).length == 0) {
return true;
}
var $cField = $('.isNotNullContainer', oForm).has('input[type="checkbox"]:checked,input[type="radio"]:checked');
if($cField.length < $('.isNotNullContainer', oForm).length) {
alert(html5Form.config.errorMsg[html5Form.config.defaultLang].isNotNullContainer);
$('input[type="checkbox"],input[type="radio"]', $('.isNotNullContainer', oForm).filter(function(){
return $(this).has('input[type="checkbox"]:checked,input[type="radio"]:checked').length==0;
})).addClass('html5Form_error').first().focus();
e.shouldPreventDefault = true;
return false;
} else {
$('.isNotNullContainer input', oForm).removeClass('html5Form_error');
}
return true;
}
}
}
};
//Simulation méthode et propriétés publiques
//Tout ce qui n'est pas init et config est privé
var publicStuff = { init: html5Form.init, config: html5Form.config };
$(document).ready(function(){
html5Form.init();
/*
$('form').bind('preformcheck', function(e, oSubmitEvent) {
alert('preformcheck start');
oSubmitEvent.shouldPreventDefault = true;
alert('preformcheck end');
});
$('form').bind('postformcheck', function(e, oParam) {
var str = 'postformcheck';
if(oParam.testPassed) {
str += ' - all tests passed' ;
//Tout est ok mais j'ai envie de l'areter quand même
oParam.oSubmitEvent.shouldPreventDefault = true;
} else {
str += ' test failed on ' + oParam.test;
//Je force la soumission et j'en assume les conséquences!!
oParam.oSubmitEvent.shouldPreventDefault = false;
}
alert(str);
});*/
});
return publicStuff;
})(jQuery, undefined);