4 * Copyright (c) 2006-2010 Renato Formato (rformato@gmail.com)
5 * Licensed under the GPL License:
6 * http://www.gnu.org/licenses/gpl.html
8 * Modif Yffic mars 2010
9 * - Correction bug : Fonctionnement incoherent si plusieurs menu dans la meme page (ex : portfolio dans page de
10 * presentation d'un article)
11 * - On ne rajoute pas le menu s'il existe deja (cas d'un retour Ajax)
12 * - On ne rajoute pas le menu dans forms d'upload (par ex vignette d'un doc)
16 var multilang_containers
={}, //menu containers
17 multilang_forms_fields
={};
20 (?:\[([a-z_]+)\]|^[\s\n]*)
31 * Initialisation de différentes variables :
34 var multilang_match_multi
= /(?:\[([a-z_]+)\]|^[\s\n]*)((?:.|\n|\s)*?)(?=\[[a-z_]+\]|$)/ig;
35 var multilang_jq_root
, //root of the search (jQuery object)
37 multilang_fields_selector
,
38 multilang_fields_selector_opt
,
39 multilang_menu_selector
,
41 multilang_forms_toadd
,
42 multilang_forms
, //forms to be processed (jQuery object)
43 multilang_menu_lang
, //template of the menu (jQuery object)
44 multilang_forms_selector
, //selector of the forms to be processed (string)
45 multilang_init
= false;
48 * options is a hash having the following values:
49 * - fields (mandatory): a jQuery selector to set the fields that have to be internationalized.
50 * - page (optional): a string to be searched in the current url. if found the plugin is applied.
51 * - root (optional): the root element of all processing. Default value is 'document'. To speed up search
52 * - forms (optional): a jQuery selector to set the forms that have to be internationalized. Default value is 'form'.
53 * - main_menu (optional): a jQuery selector to set the container for the main menu to control all the selected forms.
54 * - form_menu (optional): a jQuery selector to set the container for the form menus.
56 function multilang_init_lang(options
) {
57 var init_done
= options
.init_done
|| multilang_init
;
58 //Detect if we're on the right page and if multilinguism is activated. If not return.
59 if((options
.page
&& window
.location
.search
.indexOf(options
.page
)==-1) || multilang_avail_langs
.length
<=1) return;
61 //set the root element of all processing
63 var root
= options
.root
|| document
;
64 multilang_jq_root
= $(root
).add($(options
.root_opt
).parent());
65 multilang_root_opt
= options
.root_opt
;
68 * set the main menu element
69 * Plus utilisé pour l'instant
71 multilang_containers
= options
.main_menu
? $(options
.main_menu
,multilang_jq_root
) : $([]);
73 multilang_forms_toadd
= $([]);
76 * On crée le modèle du menu de langue
77 * C'est ce modèle qui est cloné au début de chaque formulaire
79 multilang_menu_lang
= $("<div class='langues'></div>");
80 $.each(multilang_avail_langs
,function() {
81 var title
= 'multilang_lang.title_lien_multi_'+this;
82 multilang_menu_lang
.append($("<a class='change_lang "+this+"' title='"+eval(title
)+"'></a>").html("["+this+"]"));
84 multilang_menu_lang
.append($("<a class='recover_lang' href='#'></a>").html("["+multilang_lang
.lien_desactiver
+"]"));
87 multilang_fields_selector
= options
.fields
;
88 multilang_fields_selector_opt
= options
.fields_opt
;
90 //store all the internationalized forms
91 multilang_forms_selector
= options
.forms
|| "form";
94 multilang_forms_toadd
= $(multilang_forms_selector
,multilang_jq_root
).not($(multilang_forms
));
96 multilang_forms
= $(multilang_forms_selector
,multilang_jq_root
);
98 multilang_forms_toadd
= multilang_forms
;
100 //create menu lang for the global form
101 if(multilang_containers
.size())
102 multilang_make_menu_lang(multilang_containers
);
103 multilang_menu_selector
= options
.form_menu
;
105 multilang_init
= true;
107 // Modif Yffic : On va pas plus loin s'il n'y a pas de form
108 if(multilang_forms_toadd
.size()) multilang_init_multi();
113 * Initialisation des champs multi sur les formulaires
118 function multilang_init_multi(options
) {
119 var target
= options
? options
.target
: null;
121 //Update the list of form if this is an update
123 //Verify the target is really a form to be internationalized (in case of an ajax request fired by onAjaxLoad)
124 if(target
==document
) return;
125 init_forms
= $(target
).find('form').in_set($(multilang_forms_selector
,multilang_jq_root
));
126 if(!init_forms
.length
) return;
127 multilang_forms
.add(init_forms
.each(multilang_attach_submit
).get());
129 //attach multi processing to submit event
130 init_forms
= multilang_forms_toadd
;
131 multilang_forms_toadd
.each(multilang_attach_submit
);
134 multilang_forms_fields
= {};
135 multilang_forms_fields
["undefined"] = $(multilang_fields_selector
,multilang_forms
);
136 //init the value of the field to current lang
137 //add a container for the language menu inside the form
138 init_forms
.each(function() {
140 * Je ne sais pas à quoi cela sert particulièrement, désactivé pour l'instant
142 //$(this).find('input[type=submit],button').click(function(){
143 //multilang_multi_submit.apply($(this).parents('form').get(0));
144 //$(this).parents('form').submit();
148 this.form_lang
= multilang_def_lang
;
149 var container
= multilang_menu_selector
? $(multilang_menu_selector
,this) : $(this);
150 // Pas de rajout s'il y en deja un
151 if(!container
.find('.menu_multilang').size())
152 container
.prepend("<div class='menu_multilang'></div>");
156 * Initialisation de chaque input ou textarea
157 * On vérifie si on est dans un formulaire optionnel (dans ce cas on ne prend que
158 * les éléments qui on la class optionnelle) sinon on prend tous les champs qui
161 $(multilang_fields_selector
,init_forms
).each(function(){
163 if(me
.closest(multilang_root_opt
).length
){
164 if(me
.is(multilang_fields_selector_opt
))
165 multilang_init_field(this,this.form
.form_lang
);
167 multilang_init_field(this,this.form
.form_lang
);
170 //create menu for each form. The menu is just before the form
171 $("div.menu_multilang",init_forms
).empty().each(function() {
172 //store all form containers to allow menu lang update on each container
173 //when it is triggered by global menu
174 multilang_containers
.add(this);
175 multilang_make_menu_lang($(this),$(this).parents("form"));
180 * Création du menu de langue
181 * Liste les langues disponibles et ajoute un lien pour désactiver multilang
187 function multilang_make_menu_lang(container
,target
) {
188 target
= target
|| multilang_forms
;
189 $(multilang_menu_lang
).clone().find("a").click(function() {
190 if($(this).is('.change_lang') && !$(this).is('.on')){
191 $(this).parents('form > .menu_multilang').find('a.on').removeClass('on');
192 $(this).parents('form > .menu_multilang').find('.multilang_message').detach();
193 $(this).parents('form').find('li.editer_titre_numero,div.editer_titre_numero').show();
194 $(this).addClass('on');
195 multilang_change_lang(this,container
,target
);
196 }else if(!$(this).is('.on') && $(this).is('.recover_lang')){
197 $(this).parents('form > .menu_multilang').find('a.on').removeClass('on');
198 $(this).parents('form > .menu_multilang').append('<div class="multilang_message"><p>'+multilang_lang
.champs_readonly
+'<\/p><\/div>');
199 $(this).parents('form').find('li.editer_titre_numero,div.editer_titre_numero').hide();
200 $(this).addClass('on');
201 multilang_multi_recover(this,container
,target
,'submit');
204 }).end().appendTo(container
);
205 $(target
).find('.menu_multilang .langues a').eq(0).addClass('on');
207 var target_id
= multilang_init_target_id(target
);
208 multilang_forms_fields
[target_id
].each(function(){
209 multilang_save_lang(this,this.form
.form_lang
);
211 // Maj du menu de langues
212 multilang_mark_empty_langs(container
,target
);
216 * Initialise target_id
218 * @param target Le formulaire
221 function multilang_init_target_id(target
){
222 var target_id
= target
!= multilang_forms
? jQuery
.data(target
[0]) : "undefined";
223 multilang_forms_fields
[target_id
] = $(multilang_fields_selector
,target
);
228 * Affiche le contenu complet du champ
229 * Utilisé lors de la désactivation de multilang et de la validation des formulaires
231 * @param el Le lien de désactivation
232 * @param container Le container du formulaire
233 * @param target Le formulaire
236 function multilang_multi_recover(el
,container
,target
,event
){
237 if(target
[0].isfull
){
240 if(event
== 'submit'){
242 var target_id
= multilang_init_target_id(target
);
243 target
[0].isfull
= true;
244 multilang_forms_fields
[target_id
].each(function(){
245 if(!this.totreat
) return ;
246 //save data before submit
247 multilang_save_lang(this,this.form
.form_lang
);
248 //build the string value
249 multilang_field_set_background(this,lang
);
250 if(container
&& target
){
251 multilang_mark_empty_langs(container
,target
);
253 var def_value
= this.field_lang
[multilang_def_lang
];
255 this.value
= (def_value
==undefined?"":def_value
);
257 var value
="",count
=0;
258 $.each(this.field_lang
,function(name
){
259 if((name
!= 'full') && (this.length
> 0)){
260 //save default lang value and other lang values if different from the default one
261 if(name
== multilang_def_lang
){
262 value
= "["+name
+"]"+this+value
;
264 }else if(this!=def_value
) {
265 value
+= "["+name
+"]"+this;
270 this.value
= (count
> 1 ? "<multi>"+value
+"</multi>":value
.replace(/^\[[a
-z_
]+\]/,''));
272 // Add the title number to the final value
273 if(multilang_is_title(this) && ($('#'+this.id
+'_numero').val() != ''))
274 this.value
= $('#'+this.id
+'_numero').val().replace(/\.|\s+/,'') + ". " + this.value
;
281 * Défini si un id de champ correspond a un champ "numerotable"
283 * @param id chaine correspondant a l'id du champ
285 function multilang_is_title(el
) {
286 return (el
.id
=='titre' || el
.id
=='champ_titre' || (el
.id
=='nom_site' && ($(el
).parents('#configurer-accueil,.formulaire_configurer_identite,.formulaire_editer_auteur').size() < 1)) || el
.id
.match(/^titre_document[0-9]+/)!=null || el
.name
.match(/^content_[a-z0-9_]+_titre/)!=null || el
.name
.match(/^content_[a-z0-9_-]+nom_/)!=null)
290 * Initialisation du script sur un champ
292 * Récupère les données suivantes
293 * - Le contenu de l'élément du champ
294 * - Le booléen (true/false) multi (est ce un champs déjà multi)
295 * - Les différentes chaines de langue dans un objet :
296 * {fr="texte fr",en="texte en",full="<multi>[fr]texte fr[en]texte en</multi>"}
297 * Si le champ est déjà initialisé, fait un simple return
299 * @param el Le champ a initialiser
300 * @param lang La langue
303 function multilang_init_field(el
,lang
,force
) {
304 if(el
.field_lang
&& !force
) return;
307 // On enlève les espaces, retours à la ligne et tabulations de début et de fin de chaine
308 el
.value
.replace(/(?:^\s+|\s+$)/g, "");
310 // Modif Yffic : ne pas considerer comme multi les champs qui contiennent du texte
311 // en dehors des multi sauf un numero (\d+\.\s+)
312 var m
= el
.value
.match(/(\d+\.\s+)?<multi>((?:.|\n|\s)*?)<\/multi>(.|\n*)/);
314 el
.field_pre_lang
= ""; //this is the 01. part of the string, the will be put outside the <multi>
315 el
.titre_el
= $("#titre_"+el
.id
);
317 // Init the elements to treat
319 if( m
.index
|| (m
[3]!=undefined && m
[3]!="")){
320 $(el
).addClass('multi_lang_broken');
326 el
.field_pre_lang
= m
[1] || "";
327 // Suppress point and spaces
328 el
.field_pre_lang
= el
.field_pre_lang
.replace(/\.|\s+/,'') ;
330 multilang_match_multi
.lastIndex
=0;
331 el
.field_lang
['full'] = el
.value
;
332 while((langs
=multilang_match_multi
.exec(m
[2]))!=null) {
333 var text
= langs
[2].match(/^(\d+\.\s+)((?:.|\n|\s)*)/), value
;
334 // Suppression du numero uniquement pour les titres
335 if(multilang_is_title(el
) && text
!=null) {
337 // Suppress point and spaces
338 el
.field_pre_lang
= text
[1].replace(/\.|\s+/,'') || "";
342 el
.field_lang
[langs
[1]||multilang_def_lang
] = value
;
349 // Suppression du numero uniquement pour les titres
350 if(multilang_is_title(el
)) {
351 var n
= el
.value
.match(/(\d+\.\s+)?(.*)/);
352 el
.field_pre_lang
= n
[1] || "";
353 el
.field_pre_lang
= el
.field_pre_lang
.replace(/\.|\s+/,'') ;
354 el
.field_lang
[multilang_def_lang
] = n
[2];
356 el
.field_lang
[multilang_def_lang
] = el
.value
;
359 // Put the current lang string only in the field
360 multilang_set_lang(el
,lang
);
363 * Si le champ est un titre, on ajoute un champ facultatif "numéro" au formulaire permettant
364 * de traiter le cas où l'on utilise les numéros pour trier les objets
365 * Ajout d'Yffic le 30/03/2010
367 if(!force
&& multilang_is_title(el
)){
368 numid
=el
.id
+'_numero';
370 * Cas des crayons qui n'ont pas toujours de formalisme en ul > li
372 if(el
.name
.match(/^content_[a-z0-9_]+_titre/)){
373 if($(el
).parent().is('li'))
375 .before('<li class="editer_'+numid
+'"><label for="titre_numero">'+multilang_lang
.numero
+'</label><input id="'+numid
+'" name="titre_numero" type="text" value="'+el
.field_pre_lang
+'" size="4" class="text nomulti" /></li>');
378 .before('<div class="editer_titre_numero"><label for="titre_numero">'+multilang_lang
.numero
+'</label><input id="'+numid
+'" name="titre_numero" type="text" value="'+el
.field_pre_lang
+'" size="4" class="text nomulti" /><br /><br /></div>');
381 .before('<li class="editer_'+numid
+'"><label for="titre_numero">'+multilang_lang
.numero
+'</label><input id="'+numid
+'" name="titre_numero" type="text" value="'+el
.field_pre_lang
+'" size="4" class="text nomulti" /></li>');
382 $('#'+numid
).totreat
= false;
387 * Action au click sur une langue du menu de langue
389 * @param el Le lien cliqué sur le menu
390 * @param container Le conteneur du formulaire
391 * @param target Le formulaire lui même
394 function multilang_change_lang(el
,container
,target
) {
396 var target_id
= multilang_init_target_id(target
);
397 var lang
= el
.innerHTML
;
399 lang
= lang
.slice(1,-1);
401 if(target
[0].isfull
){
402 // Maj du menu de langues avant multilang_init_field
403 multilang_forms_fields
[target_id
].each(function(){
405 if(me
.parents(multilang_root_opt
).size()>0){
406 if(me
.is(multilang_fields_selector_opt
))
407 multilang_init_field(this,lang
,true);
409 multilang_init_field(this,lang
,true);
411 target
[0].isfull
= false;
413 //store the fields inputs for later use (usefull for select)
414 //save the current values
415 multilang_forms_fields
[target_id
].each(function(){
416 multilang_save_lang(this,this.form
.form_lang
);
418 // Maj du menu de langues apres multilang_save_lang
421 //change current lang
422 target
.each(function(){this.form_lang
= lang
});
424 //reinit fields to current lang
425 multilang_forms_fields
[target_id
].each(function(){
426 multilang_set_lang(this,lang
);
429 multilang_mark_empty_langs(container
,target
);
433 * Marquer dans le menu des langues, celles pour lesquelles
434 * au moins un champ multi du formulaire n'est pas renseigne
436 * @param container Le conteneur du formulaire
439 function multilang_mark_empty_langs(container
,target
) {
440 var langs_empty
= [];
441 var target_id
= multilang_init_target_id(target
);
443 multilang_forms_fields
[target_id
].each(function(){
444 var field_langs
= [];
445 // Mise sous forme de tableau
446 if(typeof(this.field_lang
) != 'undefined'){
447 $.each(this.field_lang
,function(name
,value
){
449 field_langs
.push(name
);
452 // Trouver les elements non communs entre le tableau des langues availables et pour chaque champ,
453 // celui des langues renseignees, si ce champ est multi
454 // Si la langue d'origine n'est pas remplie (champ texte par exemple, on ne considère donc pas empty)
456 // Comparaison des tableaux
457 $.each(multilang_avail_langs
,function(i
,name
){
458 if ((jQuery
.inArray(name
, field_langs
) == -1) && (jQuery
.inArray(name
, langs_empty
) == -1) && (jQuery
.inArray(multilang_def_lang
, field_langs
) != -1))
459 langs_empty
.push(name
);
462 // Comparaison des tableaux
463 $.each(multilang_avail_langs
,function(i
,name
){
464 if ((jQuery
.inArray(name
, field_langs
) == -1) && (jQuery
.inArray(name
, langs_empty
) == -1) && (jQuery
.inArray(multilang_def_lang
, field_langs
) != -1))
465 langs_empty
.push(name
);
470 // On indique dans le menu de langue, celles qui ont au moins un champ non renseigne
472 $.each(multilang_avail_langs
,function(i
,name
){
473 if((jQuery
.inArray(name
, langs_empty
) == -1)){
474 var title
= 'multilang_lang.title_lien_multi_'+name
;
475 container
.find('a[class~='+name
+']').removeClass('empty').attr('title',eval(title
));
477 var title
= 'multilang_lang.title_lien_multi_sans_'+name
;
478 container
.find('a[class~='+name
+']').addClass('empty').attr('title',eval(title
));
485 * Action au changement de la langue
486 * Lorsque l'on clique sur une le menu de langue
487 * On affiche pour le champ "el" son contenu dans la langue "lang"
489 * @param el Un champ du formulaire (input ou textarea)
490 * @param lang La langue correspondante souhaitée
493 function multilang_set_lang(el
,lang
) {
495 if(!el
.totreat
) return;
497 //if current lang is not setted use default lang value
498 if(el
.field_lang
[lang
]==undefined) {
499 el
.field_lang
[lang
] = el
.field_lang
[multilang_def_lang
];
502 el
.value
= (el
.field_lang
[lang
] == undefined ? "" : el
.field_lang
[lang
]);
504 el
.titre_el
.html(el
.value
);
506 multilang_field_set_background(el
,lang
);
510 * Change la class multi_lang_* d'un champ pour indiquer la présence ou non de multis
511 * - multi_lang_(lang) si une langue particulière est disponible
512 * - multi_lang_no_multi si pas de multis pour le champ
518 function multilang_field_set_background(el
,lang
) {
521 $(el
).removeAttr('readonly').removeClass('multilang_readonly');
522 if(typeof($(el
).attr('class')) != 'undefined'){
523 $($(el
).attr('class').split(' ')).each(function(){
524 var m
= this.match(/^multi_lang_*/);
526 $(el
).removeClass(m
.input
).addClass('multi_lang_'+lang
);
529 $(el
).addClass('multi_lang_'+(el
.multi
?lang
:'no_multi'));
532 if(typeof($(el
).attr('class')) != 'undefined'){
533 $($(el
).attr('class').split(' ')).each(function(){
534 var m
= this.match(/^multi_lang_*/);
536 $(el
).removeClass(m
.input
);
539 $(el
).css({"background":"url("+multilang_dir_plugin
+"/images/multi_forbidden.png) no-repeat right top"});
542 $(el
).attr('readonly','readonly').addClass('multilang_readonly');
543 if(typeof($(el
).attr('class')) != 'undefined'){
544 $($(el
).attr('class').split(' ')).each(function(){
545 var m
= this.match(/^multi_lang_*/);
547 $(el
).removeClass(m
.input
);
554 * Garde en mémoire dans l'array de langues du champs la valeur de la langue
557 * @param el Le champ du formulaire concerné
558 * @param lang La langue actuelle
561 function multilang_save_lang(el
,lang
) {
563 if(!el
.totreat
) return ;
565 // Suppression du numero uniquement pour les titres
566 if(multilang_is_title(el
)) {
567 var m
= el
.value
.match(/^(\d+\.\s+)((?:.|\n|\s)*)/);
569 // Suppress point and spaces
570 el
.field_pre_lang
= m
[1].replace(/\.|\s+/,'');
575 //if the lang value is equal to the def lang do nothing
576 //else save value but if the field is not empty, delete lang value
577 if(el
.field_lang
[multilang_def_lang
]!= el
.value
) {
579 delete el
.field_lang
[lang
];
583 el
.field_lang
[lang
] = el
.value
;
585 el
.field_lang
[lang
] = el
.field_lang
[multilang_def_lang
];
586 $.each(el
.field_lang
,function(index
, value
){
587 if((index
!= multilang_def_lang
) && (value
== el
.field_lang
[multilang_def_lang
])){
588 delete el
.field_lang
[index
];
594 //This func receives the form that is going to be submitted
595 function multilang_multi_submit(params
) {
596 if(multilang_avail_langs
.length
<=1) return;
598 //remove the current form from the list of forms
599 multilang_forms
.not(this);
600 //remove the current menu lang container from the list
601 multilang_containers
.not("div.menu_multilang",$(this));
602 //build the input values
603 multilang_multi_recover('','',form
,'submit');
604 //save back the params
605 if(params
) $.extend(params
,$(form
).formToArray(false));
609 * On attache nos évènements pour la validation du formulaire
610 * - sur le submit pour tous les formulaires
611 * - sur l'évènement 'form-pre-serialize' d'ajaxForms au cas où nous sommes dans
616 function multilang_attach_submit() {
617 if($(this).parents('.ajax').size() && $(this).find('input[name=var_ajax]')){
618 $(this).bind('form-pre-serialize',multilang_multi_submit
);
619 }else if($(this).is('.formulaire_crayon')){
620 cQuery(this).bind('form-pre-serialize',function(){multilang_multi_submit
.apply(this);});
622 var oldsubmit
= this.onsubmit
;
624 if(oldsubmit
&& oldsubmit
!= ""){
625 $(this).submit(function(){multilang_multi_submit
.apply(this);return oldsubmit
.apply(this);});
627 else if(oldsubmit
!= "")
628 $(this).submit(multilang_multi_submit
);
634 in_set: function(set) {
635 var elements
= this.get();
636 var result
= $.grep(set,function(i
){
638 $.each(elements
,function(){
639 if(this==i
) found
=true;
643 return jQuery(result
);