27bba46671a41be72dc7330e586fbf8f547a1f13
[ptitvelo/web/www.git] / www / prive / javascript / ajaxCallback.js
1 jQuery.spip=jQuery.spip || {};
2 jQuery.spip.log = function(){
3 if (jQuery.spip.debug && window.console && window.console.log)
4 window.console.log.apply(this,arguments);
5 }
6 // A plugin that wraps all ajax calls introducing a fixed callback function on ajax complete
7 if(!jQuery.spip.load_handlers) {
8 jQuery.spip.load_handlers = new Array();
9
10 /**
11 * OnAjaxLoad allow to
12 * add a function to the list of those
13 * to be executed on ajax load complete
14 *
15 * most of time function f is applied on the loaded data
16 * if not known, the whole document is targetted
17 *
18 * @param function f
19 */
20 function onAjaxLoad(f) {
21 jQuery.spip.load_handlers.push(f);
22 };
23
24 /**
25 * Call the functions that have been added to onAjaxLoad
26 * @param root
27 */
28 jQuery.spip.triggerAjaxLoad = function (root) {
29 jQuery.spip.log('triggerAjaxLoad');
30 jQuery.spip.log(root);
31 for ( var i = 0; i < jQuery.spip.load_handlers.length; i++ )
32 jQuery.spip.load_handlers[i].apply( root );
33 };
34
35 jQuery.spip.intercepted={};
36
37 // intercept jQuery.fn.load
38 jQuery.spip.intercepted.load = jQuery.fn.load;
39 jQuery.fn.load = function( url, params, callback ) {
40
41 callback = callback || function(){};
42
43 // If the second parameter was provided
44 if ( params ) {
45 // If it's a function
46 if ( params.constructor == Function ) {
47 // We assume that it's the callback
48 callback = params;
49 params = null;
50 }
51 }
52 var callback2 = function() {jQuery.spip.log('jQuery.load');jQuery.spip.triggerAjaxLoad(this);callback.apply(this,arguments);};
53 return jQuery.spip.intercepted.load.apply(this,[url, params, callback2]);
54 };
55
56 // intercept jQuery.fn.ajaxSubmit
57 jQuery.spip.intercepted.ajaxSubmit = jQuery.fn.ajaxSubmit;
58 jQuery.fn.ajaxSubmit = function(options){
59 // find the first parent that will not be removed by formulaire_dyn_ajax
60 // or take the whole document
61 options = options || {};
62 if (typeof options.onAjaxLoad=="undefined" || options.onAjaxLoad!=false) {
63 var me=jQuery(this).parents('div.ajax');
64 if (me.length)
65 me=me.parent();
66 else
67 me = document;
68 if (typeof options=='function')
69 options = { success: options };
70 var callback = options.success || function(){};
71 options.success = function(){callback.apply(this,arguments);jQuery.spip.log('jQuery.ajaxSubmit');jQuery.spip.triggerAjaxLoad(me);}
72 }
73 return jQuery.spip.intercepted.ajaxSubmit.apply(this,[options]);
74 }
75
76 // intercept jQuery.ajax
77 jQuery.spip.intercepted.ajax = jQuery.ajax;
78 jQuery.ajax = function(type) {
79 var s = jQuery.extend(true, {}, jQuery.ajaxSettings, type);
80 var callbackContext = s.context || s;
81 if (jQuery.ajax.caller==jQuery.spip.intercepted.load || jQuery.ajax.caller==jQuery.spip.intercepted.ajaxSubmit)
82 return jQuery.spip.intercepted.ajax(type);
83 var orig_complete = s.complete || function() {};
84 type.complete = function(res,status) {
85 // Do not fire OnAjaxLoad if the dataType is not html
86 var dataType = type.dataType;
87 var ct = (res && (typeof res.getResponseHeader == 'function'))
88 ? res.getResponseHeader("content-type"): '';
89 var xml = !dataType && ct && ct.indexOf("xml") >= 0;
90 orig_complete.call( callbackContext, res, status);
91 if(!dataType && !xml || dataType == "html") {
92 jQuery.spip.log('jQuery.ajax');
93 if (typeof s.onAjaxLoad=="undefined" || s.onAjaxLoad!=false)
94 jQuery.spip.triggerAjaxLoad(s.ajaxTarget?s.ajaxTarget:document);
95 }
96 };
97 return jQuery.spip.intercepted.ajax(type);
98 };
99
100 }
101
102 /**
103 * if not fully visible, scroll the page to position
104 * target block at the top of page
105 * if force = true, allways scroll
106 *
107 * @param bool force
108 */
109 jQuery.fn.positionner = function(force, setfocus) {
110 var offset = jQuery(this).offset();
111 var hauteur = parseInt(jQuery(this).css('height'));
112 var scrolltop = self['pageYOffset'] ||
113 jQuery.boxModel && document.documentElement[ 'scrollTop' ] ||
114 document.body[ 'scrollTop' ];
115 var h = jQuery(window).height();
116 var scroll=0;
117
118 if (force || (offset && offset['top'] - 5 <= scrolltop))
119 scroll = offset['top'] - 5;
120 else if (offset && offset['top'] + hauteur - h + 5 > scrolltop)
121 scroll = Math.min(offset['top'] - 5, offset['top'] + hauteur - h + 15);
122 if (scroll)
123 jQuery('html,body')
124 .animate({scrollTop: scroll}, 300);
125
126 // positionner le curseur dans la premiere zone de saisie
127 if (setfocus!==false)
128 jQuery(jQuery('*', this).filter('input[type=text],textarea')[0]).focus();
129 return this; // don't break the chain
130 }
131
132 // deux fonctions pour rendre l'ajax compatible Jaws
133 jQuery.spip.virtualbuffer_id='spip_virtualbufferupdate';
134 jQuery.spip.initReaderBuffer = function(){
135 if (jQuery('#'+jQuery.spip.virtualbuffer_id).length) return;
136 jQuery('body').append('<p style="float:left;width:0;height:0;position:absolute;left:-5000;top:-5000;"><input type="hidden" name="'+jQuery.spip.virtualbuffer_id+'" id="'+jQuery.spip.virtualbuffer_id+'" value="0" /></p>');
137 }
138 jQuery.spip.updateReaderBuffer = function(){
139 var i = jQuery('#'+jQuery.spip.virtualbuffer_id);
140 if (!i.length) return;
141 // incrementons l'input hidden, ce qui a pour effet de forcer le rafraichissement du
142 // buffer du lecteur d'ecran (au moins dans Jaws)
143 i.attr('value',parseInt(i.attr('value'))+1);
144 }
145
146 jQuery.fn.formulaire_setARIA = function(){
147 if (!this.closest('.ariaformprop').length){
148 // eviter une double execution du js au moment de sa reinsertion dans le DOM par wrap()
149 // cf http://bugs.jquery.com/ticket/7447
150 this.find('script').remove();
151 this.wrap('<div class="ariaformprop" aria-live="assertive" aria-atomic="true"></div>');
152 }
153 return this;
154 }
155 /**
156 * rechargement ajax d'un formulaire dynamique implemente par formulaires/xxx.html
157 * @param target
158 */
159 jQuery.fn.formulaire_dyn_ajax = function(target) {
160 if (this.length)
161 jQuery.spip.initReaderBuffer();
162 return this.each(function() {
163 var scrollwhensubmit = !jQuery(this).is('.noscroll');
164 var cible = target || this;
165 jQuery(cible).formulaire_setARIA();
166 jQuery('form:not(.noajax):not(.bouton_action_post)', this).each(function(){
167 var leform = this;
168 var leclk,leclk_x,leclk_y;
169 jQuery(this).prepend("<input type='hidden' name='var_ajax' value='form' />")
170 .ajaxForm({
171 beforeSubmit: function(){
172 // memoriser le bouton clique, en cas de repost non ajax
173 leclk = leform.clk;
174 if (leclk) {
175 var n = leclk.name;
176 if (n && !leclk.disabled && leclk.type == "image") {
177 leclk_x = leform.clk_x;
178 leclk_y = leform.clk_y;
179 }
180 }
181 jQuery(cible).wrap('<div />');
182 cible = jQuery(cible).parent();
183 jQuery(cible).closest('.ariaformprop').animateLoading();
184 if (scrollwhensubmit)
185 jQuery(cible).positionner(false,false);
186 },
187 success: function(c){
188 if (c=='noajax'){
189 // le serveur ne veut pas traiter ce formulaire en ajax
190 // on resubmit sans ajax
191 jQuery("input[name=var_ajax]",leform).remove();
192 // si on a memorise le nom et la valeur du bouton clique
193 // les reinjecter dans le dom sous forme de input hidden
194 // pour que le serveur les recoive
195 if (leclk){
196 var n = leclk.name;
197 if (n && !leclk.disabled) {
198 jQuery(leform).prepend("<input type='hidden' name='"+n+"' value='"+leclk.value+"' />");
199 if (leclk.type == "image") {
200 jQuery(leform).prepend("<input type='hidden' name='"+n+".x' value='"+leform.clk_x+"' />");
201 jQuery(leform).prepend("<input type='hidden' name='"+n+".y' value='"+leform.clk_y+"' />");
202 }
203 }
204 }
205 jQuery(leform).ajaxFormUnbind().submit();
206 }
207 else {
208 // commencons par vider le cache des urls, si jamais un js au retour
209 // essaye tout de suite de suivre un lien en cache
210 // dans le doute sur la validite du cache il vaut mieux l'invalider
211 var preloaded = jQuery.spip.preloaded_urls;
212 jQuery.spip.preloaded_urls = {};
213 jQuery(cible).html(c);
214 var a = jQuery('a:first',cible).eq(0);
215 var d = jQuery('div.ajax',cible);
216 if (!d.length){
217 // si pas .ajax dans le form, remettre la classe sur le div que l'on a insere
218 jQuery(cible).addClass('ajax');
219 if (!scrollwhensubmit)
220 jQuery(cible).addClass('noscroll');
221 }
222 else {
223 // sinon nettoyer les br ajaxie
224 d.siblings('br.bugajaxie').remove();
225 // desemboiter d'un niveau pour manger le div que l'on a insere
226 cible = jQuery(":first",cible);
227 cible.unwrap();
228 }
229 // chercher une ancre en debut de html pour positionner la page
230 if (a.length
231 && a.is('a[name=ajax_ancre]')
232 && jQuery(a.attr('href'),cible).length){
233 a = a.attr('href');
234 if (jQuery(a,cible).length)
235 setTimeout(function(){
236 jQuery(a,cible).positionner(false);
237 //a = a.split('#');
238 //window.location.hash = a[1];
239 },10);
240 jQuery(cible).closest('.ariaformprop').endLoading(true);
241 }
242 else{
243 //jQuery(cible).positionner(false);
244 if (a.length && a.is('a[name=ajax_redirect]')){
245 a = a.get(0).href;
246 setTimeout(function(){
247 var cur = window.location.href.split('#');
248 document.location.replace(a);
249 // regarder si c'est juste un changement d'ancre : dans ce cas il faut reload
250 // (le faire systematiquement provoque des bugs)
251 if (cur[0]==a.split('#')[0]){
252 window.location.reload();
253 }
254 },10);
255 // ne pas arreter l'etat loading, puisqu'on redirige !
256 // mais le relancer car l'image loading a pu disparaitre
257 jQuery(cible).closest('.ariaformprop').animateLoading();
258 }
259 else {
260 jQuery(cible).closest('.ariaformprop').endLoading(true);
261 }
262 }
263 // si jamais le formulaire n'a pas un retour OK, retablissons le cache
264 // car a priori on a pas fait d'operation en base de donnee
265 if (!jQuery('.reponse_formulaire_ok',cible).length)
266 jQuery.spip.preloaded_urls = preloaded;
267 // mettre a jour le buffer du navigateur pour aider jaws et autres readers
268 // a supprimer ?
269 jQuery.spip.updateReaderBuffer();
270 }
271 },
272 iframe: jQuery.browser.msie
273 })
274 // previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
275 // mais le marquer comme ayant l'ajax au cas ou on reinjecte du contenu ajax dedans
276 .addClass('noajax hasajax')
277 ;
278 });
279 });
280 }
281
282 jQuery.fn.formulaire_verifier = function(callback, champ){
283 var erreurs = {'message_erreur':'form non ajax'};
284 var me=this;
285 // si on est aussi en train de submit pour de vrai, abandonner
286 if (jQuery(me).closest('.ariaformprop').attr('aria-busy')!='true') {
287 if (jQuery(me).is('form.hasajax')){
288 jQuery(me).ajaxSubmit({
289 dataType:"json",
290 data:{formulaire_action_verifier_json:true},
291 success:function(errs){
292 var args = [errs, champ]
293 // si on est aussi en train de submit pour de vrai, abandonner
294 if (jQuery(me).closest('.ariaformprop').attr('aria-busy')!='true')
295 callback.apply(me,args);
296 }
297 });
298 }
299 else
300 callback.apply(me,[erreurs, champ]);
301 }
302 return this;
303 }
304
305 jQuery.fn.formulaire_activer_verif_auto = function(callback){
306 callback = callback || formulaire_actualiser_erreurs;
307 var me = jQuery(this).closest('.ariaformprop');
308 var check = function(){
309 var name=jQuery(this).attr('name');
310 // declencher apres 50ms pour ne pas double submit sur sequence saisie+submit
311 setTimeout(function(){me.find('form').formulaire_verifier(callback,name);},50);
312 }
313 var activer = function(){
314 if (me.find('form').attr('data-verifjson')!='on'){
315 me
316 .find('form')
317 .attr('data-verifjson','on')
318 .find('input,select,textarea')
319 .bind('change',check);
320 }
321 }
322 jQuery(activer);
323 onAjaxLoad(function(){setTimeout(activer,150);});
324 }
325
326 function formulaire_actualiser_erreurs(erreurs){
327 var parent = jQuery(this).closest('.formulaire_spip');
328 if (!parent.length) return;
329 // d'abord effacer tous les messages d'erreurs
330 parent.find('.reponse_formulaire,.erreur_message').fadeOut().remove();
331 parent.find('.erreur').removeClass('erreur');
332 // ensuite afficher les nouveaux messages d'erreur
333 if (erreurs['message_ok'])
334 parent.find('form').before('<p class="reponse_formulaire reponse_formulaire_ok">'+erreurs['message_ok']+'</p>');
335 if (erreurs['message_erreur'])
336 parent.find('form').before('<p class="reponse_formulaire reponse_formulaire_erreur">'+erreurs['message_erreur']+'</p>');
337 for (var k in erreurs){
338 var saisie = parent.find('.editer_'+k);
339 if (saisie.length) {
340 saisie.addClass('erreur');
341 saisie.find('label').after('<span class="erreur_message">'+erreurs[k]+'</span>');
342 }
343 }
344 }
345
346
347 // permettre d'utiliser onclick='return confirm('etes vous sur?');' sur un lien ajax
348 var ajax_confirm=true;
349 var ajax_confirm_date=0;
350 var spip_confirm = window.confirm;
351 function _confirm(message){
352 ajax_confirm = spip_confirm(message);
353 if (!ajax_confirm) {
354 var d = new Date();
355 ajax_confirm_date = d.getTime();
356 }
357 return ajax_confirm;
358 }
359 window.confirm = _confirm;
360
361 /**
362 * rechargement ajax d'une noisette implementee par {ajax}
363 * selecteur personalise, sera defini par defaut a '.pagination a,a.ajax'
364 */
365 var ajaxbloc_selecteur;
366
367 /**
368 * mise en cache des url. Il suffit de vider cete variable pour vider le cache
369 */
370 jQuery.spip.preloaded_urls = {};
371
372 /**
373 * Afficher dans la page
374 * le html d'un bloc ajax charge
375 * @param object blocfrag
376 * @param string c
377 * @param string href
378 * @param bool history
379 */
380 jQuery.spip.on_ajax_loaded = function(blocfrag,c,href,history) {
381 history = history || (history==null);
382 if (typeof href == undefined || href==null)
383 history = false;
384 if (history)
385 jQuery.spip.setHistoryState(blocfrag);
386
387 jQuery(blocfrag)
388 .html(c)
389 .endLoading();
390 if (typeof href != undefined)
391 jQuery(blocfrag).attr('data-url',href);
392 if (history) {
393 jQuery.spip.pushHistoryState(href);
394 jQuery.spip.setHistoryState(blocfrag);
395 }
396
397 var a = jQuery('a:first',jQuery(blocfrag)).eq(0);
398 if (a.length
399 && a.is('a[name=ajax_ancre]')
400 && jQuery(a.attr('href'),blocfrag).length){
401 a = a.attr('href');
402 jQuery(a,blocfrag).positionner(false);
403 }
404 jQuery.spip.log('on_ajax_loaded');
405 jQuery.spip.triggerAjaxLoad(blocfrag);
406 // si le fragment ajax est dans un form ajax,
407 // il faut remettre a jour les evenements attaches
408 // car le fragment peut comporter des submit ou button
409 a = jQuery(blocfrag).parents('form.hasajax')
410 if (a.length)
411 a.eq(0).removeClass('noajax').parents('div.ajax').formulaire_dyn_ajax();
412 jQuery.spip.updateReaderBuffer();
413 }
414
415 jQuery.spip.stateId=0;
416 jQuery.spip.setHistoryState = function(blocfrag){
417 if (!window.history.replaceState) return;
418 // attribuer un id au bloc si il n'en a pas
419 if (!blocfrag.attr('id')){
420 while (jQuery('#ghsid'+jQuery.spip.stateId).length)
421 jQuery.spip.stateId++;
422 blocfrag.attr('id','ghsid'+jQuery.spip.stateId);
423 }
424 var href= blocfrag.attr('data-url') || blocfrag.attr('data-origin');
425 href = jQuery("<"+"a href='"+href+"'></a>").get(0).href;
426 var state={
427 id:blocfrag.attr('id'),
428 href: href
429 };
430 // on remplace la variable qui decrit l'etat courant
431 // initialement vide
432 // -> elle servira a revenir dans l'etat courant
433 window.history.replaceState(state,window.document.title, window.document.location);
434 }
435
436 jQuery.spip.pushHistoryState = function(href, title){
437 if (!window.history.pushState)
438 return false;
439 window.history.pushState({}, title, href);
440 }
441
442 window.onpopstate = function(popState){
443 if (popState.state && popState.state.id){
444 var blocfrag=jQuery('#'+popState.state.id);
445 if (blocfrag.length && popState.state.href) {
446 jQuery.spip.ajaxClick(blocfrag,popState.state.href,{history:false});
447 return true;
448 }
449 }
450 }
451
452 /**
453 * Charger un bloc ajax represente par l'objet jQuery blocajax qui le pointe
454 * avec la requete ajax url, qui represente le lien href
455 * @param object blocfrag
456 * bloc cible
457 * @param string url
458 * url pour la requete ajax
459 * @param string href
460 * url du lien clique
461 * @param object options
462 * bool force : pour forcer la requete sans utiliser le cache
463 * function callback : callback au retour du chargement
464 * bool history : prendre en charge l'histrisation dans l'url
465 */
466 jQuery.spip.loadAjax = function(blocfrag,url, href, options){
467 var force = options.force || false;
468 jQuery(blocfrag).animateLoading();
469 if (jQuery.spip.preloaded_urls[url] && !force) {
470 // si on est deja en train de charger ce fragment, revenir plus tard
471 if (jQuery.spip.preloaded_urls[url]=="<!--loading-->"){
472 setTimeout(function(){jQuery.spip.loadAjax(blocfrag,url,href,options);},100);
473 return;
474 }
475 jQuery.spip.on_ajax_loaded(blocfrag,jQuery.spip.preloaded_urls[url],href,options.history);
476 } else {
477 var d = new Date();
478 jQuery.spip.preloaded_urls[url] = "<!--loading-->";
479 jQuery.ajax({
480 url: parametre_url(url,'var_t',d.getTime()),
481 onAjaxLoad:false,
482 success: function(c){
483 jQuery.spip.on_ajax_loaded(blocfrag,c,href,options.history);
484 jQuery.spip.preloaded_urls[url] = c;
485 if (options.callback && typeof options.callback == "function")
486 options.callback.apply(blocfrag);
487 },
488 error: function(){
489 jQuery.spip.preloaded_urls[url]='';
490 }
491 });
492 }
493 }
494
495 /**
496 * Calculer l'url ajax a partir de l'url du lien
497 * et de la variable d'environnement du bloc ajax
498 * passe aussi l'ancre eventuelle sous forme d'une variable
499 * pour que le serveur puisse la prendre en compte
500 * et la propager jusqu'a la reponse
501 * sous la forme d'un lien cache
502 *
503 * @param string href
504 * @param string ajax_env
505 */
506 jQuery.spip.makeAjaxUrl = function(href,ajax_env){
507 var url = href.split('#');
508 url[0] = parametre_url(url[0],'var_ajax',1);
509 url[0] = parametre_url(url[0],'var_ajax_env',ajax_env);
510 if (url[1])
511 url[0] = parametre_url(url[0],'var_ajax_ancre',url[1]);
512 return url[0];
513 }
514
515 /**
516 * fonction appelee sur l'evenement ajaxReload d'un bloc ajax
517 * que l'on declenche quand on veut forcer sa mise a jour
518 *
519 * @param object blocfrag
520 * @param object options
521 * callback : fonction appelee apres le rechargement
522 * args : arguments passes a l'url rechargee (permet une modif du contexte)
523 * history : bool to specify if navigation history is modified by reload or not (false if not provided)
524 */
525 jQuery.spip.ajaxReload = function(blocfrag, options){
526 var ajax_env = blocfrag.attr('data-ajax-env');
527 if (!ajax_env || ajax_env==undefined) return;
528 var href = blocfrag.attr('data-url') || blocfrag.attr('data-origin');
529 if (href && typeof href != undefined){
530 options == options || {};
531 var callback=options.callback || null;
532 var history=options.history || false;
533 var args = options.args || {};
534 for (var key in args)
535 href = parametre_url(href,key,args[key]==undefined?'':args[key],'&',args[key]==undefined?false:true);
536 var url = jQuery.spip.makeAjaxUrl(href,ajax_env);
537 // recharger sans historisation dans l'url
538 jQuery.spip.loadAjax(blocfrag, url, href, {force:true, callback:callback, history:history});
539 return true;
540 }
541 }
542
543 /**
544 * fonction appelee sur l'evenement click d'un lien ajax
545 *
546 * @param object blocfrag
547 * objet jQuery qui cible le bloc ajax contenant
548 * @param string href
549 * url du lien a suivre
550 * @param object options
551 * force : pour interdire l'utilisation du cache
552 * history : pour interdire la mise en historique
553 */
554 jQuery.spip.ajaxClick = function(blocfrag, href, options){
555 var ajax_env = blocfrag.attr('data-ajax-env');
556 if (!ajax_env || ajax_env==undefined) return;
557 if (!ajax_confirm) {
558 // on rearme pour le prochain clic
559 ajax_confirm=true;
560 var d = new Date();
561 // seule une annulation par confirm() dans les 2 secondes precedentes est prise en compte
562 if ((d.getTime()-ajax_confirm_date)<=2)
563 return false;
564 }
565 var url = jQuery.spip.makeAjaxUrl(href,ajax_env);
566 jQuery.spip.loadAjax(blocfrag, url, href, options);
567 return false;
568 }
569
570 /**
571 * Implementer le comportemant des liens ajax
572 * et boutons post ajax qui se comportent
573 * comme un lien ajax
574 */
575 jQuery.fn.ajaxbloc = function() {
576 // hack accessibilite vieille version de JAWS
577 // a supprimer ?
578 if (this.length)
579 jQuery.spip.initReaderBuffer();
580 if (ajaxbloc_selecteur==undefined)
581 ajaxbloc_selecteur = '.pagination a,a.ajax';
582
583 return this.each(function() {
584 // traiter les enfants d'abord :
585 // un lien ajax provoque le rechargement
586 // du plus petit bloc ajax le contenant
587 jQuery('div.ajaxbloc',this).ajaxbloc();
588 var blocfrag = jQuery(this);
589
590 var ajax_env = blocfrag.attr('data-ajax-env');
591 if (!ajax_env || ajax_env==undefined) return;
592
593 blocfrag.not('.bind-ajaxReload').bind('ajaxReload',function(event, options){
594 if (jQuery.spip.ajaxReload(blocfrag,options))
595 // don't trig reload of parent blocks
596 event.stopPropagation();
597 }).addClass('bind-ajaxReload');
598
599 jQuery(ajaxbloc_selecteur,this).not('.noajax,.bind-ajax')
600 .click(function(){return jQuery.spip.ajaxClick(blocfrag,this.href,{force:jQuery(this).is('.nocache'),history:!(jQuery(this).is('.nohistory')||jQuery(this).closest('.box_modalbox').length)});})
601 .addClass('bind-ajax')
602 .filter('.preload').each(function(){
603 var href = this.href;
604 var url = jQuery.spip.makeAjaxUrl(href,ajax_env);
605 if (!jQuery.spip.preloaded_urls[url]) {
606 jQuery.spip.preloaded_urls[url] = '<!--loading-->';
607 jQuery.ajax({url:url,onAjaxLoad:false,success:function(r){jQuery.spip.preloaded_urls[url]=r;},error:function(){jQuery.spip.preloaded_urls[url]='';}});
608 }
609 }); // previent qu'on ajax pas deux fois le meme lien
610
611 // ajaxer les boutons actions qui sont techniquement des form minimaux
612 // mais se comportent comme des liens
613 jQuery('form.bouton_action_post.ajax', this).not('.noajax,.bind-ajax').each(function(){
614 var leform = this;
615 var url = jQuery(this).attr('action').split('#');
616 jQuery(this)
617 .prepend("<input type='hidden' name='var_ajax' value='1' /><input type='hidden' name='var_ajax_env' value='"+(ajax_env)+"' />"+(url[1]?"<input type='hidden' name='var_ajax_ancre' value='"+url[1]+"' />":""))
618 .ajaxForm({
619 beforeSubmit: function(){
620 jQuery(blocfrag).animateLoading().positionner(false);
621 },
622 onAjaxLoad:false,
623 success: function(c){
624 jQuery.spip.on_ajax_loaded(blocfrag,c);
625 jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
626 },
627 iframe: jQuery.browser.msie
628 })
629 .addClass('bind-ajax') // previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
630 ;
631 });
632 });
633 };
634
635 /**
636 * Suivre un lien en simulant le click sur le lien
637 * Si le lien est ajax, on se contente de declencher l'evenement click()
638 * Si le lien est non ajax, on finit en remplacant l'url de la page
639 */
640 jQuery.fn.followLink = function(){
641 $(this).click();
642 if (!$(this).is('.bind-ajax'))
643 window.location.href = $(this).get(0).href;
644 return this;
645 }
646 /**
647 * Recharger un bloc ajax pour le mettre a jour
648 * ajaxid est l'id passe en argument de INCLURE{ajax=ajaxid}
649 * options permet de definir une callbackk ou de passer des arguments a l'url
650 * au rechargement
651 * ajaxReload peut s'utiliser en passant un id :
652 * ajaxReload('xx');
653 * ou sur un objet jQuery
654 * jQuery(this).ajaxReload();
655 * Dans ce dernier cas, le plus petit conteneur ajax est recharge
656 *
657 * @param string ajaxid
658 * @param object options
659 * callback : callback after reloading
660 * args : {arg:value,...} to pass tu the url
661 * history : bool to specify if navigation history is modified by reload or not (false if not provided)
662 */
663 function ajaxReload(ajaxid, options){
664 jQuery('div.ajaxbloc.ajax-id-'+ajaxid).ajaxReload(options);
665 }
666
667 /**
668 * Variante jQuery de ajaxReload pour la syntaxe
669 * jQuery(..).ajaxReload();
670 * cf doc ci-dessus
671 * @param options
672 */
673 jQuery.fn.ajaxReload = function(options){
674 options = options||{};
675 // just trigg the event, as it will bubble up the DOM
676 jQuery(this).trigger('ajaxReload', [options]);
677 return this; // don't break the chain
678 }
679
680 /**
681 * animation du bloc cible pour faire patienter
682 *
683 */
684 jQuery.fn.animateLoading = function() {
685 this.attr('aria-busy','true').addClass('loading').children().css('opacity', 0.5);
686 if (typeof ajax_image_searching != 'undefined'){
687 var i = (this).find('.image_loading');
688 if (i.length) i.eq(0).html(ajax_image_searching);
689 else this.prepend('<span class="image_loading">'+ajax_image_searching+'</span>');
690 }
691 return this; // don't break the chain
692 }
693 // compatibilite avec ancien nommage
694 jQuery.fn.animeajax = jQuery.fn.animateLoading;
695
696 /**
697 * Fin de l'animation
698 * l'argument permet de forcer le raz du contenu si il est inchange
699 * @param hard
700 */
701 jQuery.fn.endLoading = function(hard) {
702 hard = hard || false;
703 this.attr('aria-busy','false').removeClass('loading');
704 if (hard){
705 this.children().css('opacity', '');
706 this.find('.image_loading').html('');
707 }
708 return this; // don't break the chain
709 }
710
711 /**
712 * animation d'un item que l'on supprime :
713 * ajout de la classe remove avec un background tire de cette classe
714 * puis fading vers opacity 0
715 * quand l'element est masque, on retire les classes et css inline
716 *
717 * @param function callback
718 *
719 */
720 jQuery.fn.animateRemove = function(callback){
721 if (this.length){
722 var color = $("<div class='remove'></div>").css('background-color');
723 $(this).addClass('remove').css({backgroundColor: color}).animate({opacity: "0.0"}, 'fast',function(){
724 $(this).removeClass('remove').css({backgroundColor: ''});
725 if (callback)
726 callback.apply(this);
727 });
728 }
729 return this; // don't break the chain
730 }
731
732 /**
733 * animation d'un item que l'on ajoute :
734 * ajout de la classe append
735 * fading vers opacity 1 avec background herite de la classe append,
736 * puis suppression progressive du background pour revenir a la valeur heritee
737 *
738 * @param function callback
739 */
740 jQuery.fn.animateAppend = function(callback){
741 if (this.length){
742 var me=this;
743 // recuperer la couleur portee par la classe append (permet une personalisation)
744 var color = $("<div class='append'></div>").css('background-color');
745 var origin = $(this).css('background-color') || '#ffffff';
746 // pis aller
747 if (origin=='transparent') origin='#ffffff';
748 var sel=$(this);
749 // if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
750 if (sel.is('tr'))
751 sel.add('>td',sel);
752 sel.css('opacity','0.0').addClass('append').css({backgroundColor: color}).animate({opacity: "1.0"}, 1000,function(){
753 sel.animate({backgroundColor: origin}, 3000,function(){
754 sel.removeClass('append').css({backgroundColor: ''});
755 if (callback)
756 callback.apply(me);
757 });
758 });
759 }
760 return this; // don't break the chain
761 }
762
763 /**
764 * Equivalent js de parametre_url php de spip
765 *
766 * Exemples :
767 * parametre_url(url,suite,18) (ajout)
768 * parametre_url(url,suite,'') (supprime)
769 * parametre_url(url,suite) (lit la valeur suite)
770 * parametre_url(url,suite[],1) (tableau valeurs multiples)
771 * @param url
772 * url
773 * @param c
774 * champ
775 * @param v
776 * valeur
777 * @param sep
778 * separateur '&' par defaut
779 * @param force_vide
780 * si true et v='' insere &k= dans l'url au lieu de supprimer le k (false par defaut)
781 * permet de vider une valeur dans une requete ajax (dans un reload)
782 */
783 function parametre_url(url,c,v,sep,force_vide){
784 // Si l'URL n'est pas une chaine, on ne peut pas travailler dessus et on quitte
785 if (typeof(url) == 'undefined'){
786 url = '';
787 }
788
789 var p;
790 // lever l'#ancre
791 var ancre='';
792 var a='./';
793 var args=[];
794 p = url.indexOf('#');
795 if (p!=-1) {
796 ancre=url.substring(p);
797 url = url.substring(0,p);
798 }
799
800 // eclater
801 p=url.indexOf('?');
802 if (p!==-1){
803 // recuperer la base
804 if (p>0) a=url.substring(0,p);
805 args = url.substring(p+1).split('&');
806 }
807 else
808 a=url;
809 var regexp = new RegExp('^(' + c.replace('[]','\[\]') + '\[?\]?)(=.*)?$');
810 var ajouts = [];
811 var u = (typeof(v)!=='object')?encodeURIComponent(v):v;
812 var na = [];
813 // lire les variables et agir
814 for(var n=0;n<args.length;n++){
815 var val = args[n];
816 try {
817 val = decodeURIComponent(val);
818 } catch(e) {}
819 var r=val.match(regexp);
820 if (r && r.length){
821 if (v==null){
822 return (r.length>2)?r[2].substring(1):'';
823 }
824 // suppression
825 else if (!v.length) {
826 }
827 // Ajout. Pour une variable, remplacer au meme endroit,
828 // pour un tableau ce sera fait dans la prochaine boucle
829 else if (r[1].substring(-2) != '[]') {
830 na.push(r[1]+'='+u);
831 ajouts.push(r[1]);
832 }
833 else na.push(args[n]);
834 }
835 else
836 na.push(args[n]);
837 }
838
839 if (v==null) return v; // rien de trouve
840 // traiter les parametres pas encore trouves
841 if (v || v.length || force_vide) {
842 ajouts = "="+ajouts.join("=")+"=";
843 var all=c.split('|');
844 for (n=0;n<all.length;n++){
845 if (ajouts.search("="+all[n]+"=")==-1){
846 if (typeof(v)!=='object'){
847 na.push(all[n] +'='+ u);
848 }
849 else {
850 var id = ((all[n].substring(-2)=='[]')?all[n]:all[n]+"[]");
851 for(p=0;p<v.length;p++)
852 na.push(id +'='+ encodeURIComponent(v[p]));
853 }
854 }
855 }
856 }
857
858 // recomposer l'adresse
859 if (na.length){
860 if (!sep) sep='&';
861 a = a+"?"+na.join(sep);
862 }
863
864 return a + ancre;
865 }
866
867
868
869 // Ajaxer les formulaires qui le demandent, au demarrage
870 if (!window.var_zajax_content)
871 window.var_zajax_content = 'contenu';
872 jQuery(function() {
873 jQuery('form:not(.bouton_action_post)').parents('div.ajax')
874 .formulaire_dyn_ajax();
875 jQuery('div.ajaxbloc').ajaxbloc();
876 jQuery("input[placeholder]:text").placeholderLabel();
877 jQuery('a.popin').click(function(){if (jQuery.modalbox) jQuery.modalbox(parametre_url(this.href,"var_zajax",jQuery(this).attr('data-var_zajax')?jQuery(this).attr('data-var_zajax'):var_zajax_content));return false;});
878 });
879
880 // ... et a chaque fois que le DOM change
881 onAjaxLoad(function() {
882 if (jQuery){
883 jQuery('form:not(.bouton_action_post)', this).parents('div.ajax')
884 .formulaire_dyn_ajax();
885 if (jQuery(this).is('div.ajaxbloc'))
886 jQuery(this).ajaxbloc();
887 else if (jQuery(this).closest('div.ajaxbloc').length)
888 jQuery(this).closest('div.ajaxbloc').ajaxbloc();
889 else
890 jQuery('div.ajaxbloc', this).ajaxbloc();
891 jQuery("input[placeholder]:text",this).placeholderLabel();
892 jQuery('a.popin',this).click(function(){if (jQuery.modalbox) jQuery.modalbox(parametre_url(this.href,"var_zajax",jQuery(this).attr('data-var_zajax')?jQuery(this).attr('data-var_zajax'):var_zajax_content));return false;});
893 }
894 });
895