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