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
);
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();
12 * add a function to the list of those
13 * to be executed on ajax load complete
15 * most of time function f is applied on the loaded data
16 * if not known, the whole document is targetted
20 function onAjaxLoad(f
) {
21 jQuery
.spip
.load_handlers
.push(f
);
25 * Call the functions that have been added to onAjaxLoad
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
);
35 jQuery
.spip
.intercepted
={};
37 // intercept jQuery.fn.load
38 jQuery
.spip
.intercepted
.load
= jQuery
.fn
.load
;
39 jQuery
.fn
.load = function( url
, params
, callback
) {
40 if ( typeof url
!== "string") {
41 return jQuery
.spip
.intercepted
.load
.apply( this, arguments
);
44 callback
= callback
|| function(){};
46 // If the second parameter was provided
49 if ( params
.constructor == Function
) {
50 // We assume that it's the callback
55 params
= jQuery
.extend(params
, {triggerAjaxLoad
:false}); // prevent $.ajax to triggerAjaxLoad
56 var callback2 = function() {jQuery
.spip
.log('jQuery.load');jQuery
.spip
.triggerAjaxLoad(this);callback
.apply(this,arguments
);};
57 return jQuery
.spip
.intercepted
.load
.apply(this,[url
, params
, callback2
]);
60 // intercept jQuery.fn.ajaxSubmit
61 jQuery
.spip
.intercepted
.ajaxSubmit
= jQuery
.fn
.ajaxSubmit
;
62 jQuery
.fn
.ajaxSubmit = function(options
){
63 // find the first parent that will not be removed by formulaire_dyn_ajax
64 // or take the whole document
65 options
= options
|| {};
66 if (typeof options
.onAjaxLoad
=="undefined" || options
.onAjaxLoad
!=false) {
67 var me
=jQuery(this).parents('div.ajax');
72 if (typeof options
=='function')
73 options
= { success
: options
};
74 var callback
= options
.success
|| function(){};
75 options
.success = function(){callback
.apply(this,arguments
);jQuery
.spip
.log('jQuery.ajaxSubmit');jQuery
.spip
.triggerAjaxLoad(me
);}
77 return jQuery
.spip
.intercepted
.ajaxSubmit
.apply(this,[options
]);
80 // intercept jQuery.ajax
81 jQuery
.spip
.intercepted
.ajax
= jQuery
.ajax
;
82 jQuery
.ajax = function(url
, settings
) {
83 if (typeof settings
== 'undefined') {
85 if (typeof url
== 'object') {
90 if (typeof url
== 'string') {
91 settings
['url'] = url
;
93 // if triggerAjaxLoad is prevented, finish without faking callback
94 if (settings
.data
&& settings
.data
['triggerAjaxLoad'] === false) {
95 settings
.data
['triggerAjaxLoad'] = null;
96 return jQuery
.spip
.intercepted
.ajax(settings
);
98 var s
= jQuery
.extend(true, {}, jQuery
.ajaxSettings
, settings
);
99 var callbackContext
= s
.context
|| s
;
101 if (jQuery
.ajax
.caller
==jQuery
.spip
.intercepted
.load
|| jQuery
.ajax
.caller
==jQuery
.spip
.intercepted
.ajaxSubmit
)
102 return jQuery
.spip
.intercepted
.ajax(settings
);
105 var orig_complete
= s
.complete
|| function() {};
106 settings
.complete = function(res
,status
) {
107 // Do not fire OnAjaxLoad if the dataType is not html
108 var dataType
= settings
.dataType
;
109 var ct
= (res
&& (typeof res
.getResponseHeader
== 'function'))
110 ? res
.getResponseHeader("content-type"): '';
111 var xml
= !dataType
&& ct
&& ct
.indexOf("xml") >= 0;
112 orig_complete
.call( callbackContext
, res
, status
);
113 if((!dataType
&& !xml
) || dataType
== "html") {
114 jQuery
.spip
.log('jQuery.ajax');
115 if (typeof s
.onAjaxLoad
=="undefined" || s
.onAjaxLoad
!=false)
116 jQuery
.spip
.triggerAjaxLoad(s
.ajaxTarget
?s
.ajaxTarget
:document
);
119 return jQuery
.spip
.intercepted
.ajax(settings
);
125 jQuery
.uaMatch = function( ua
) {
126 ua
= ua
.toLowerCase();
128 var match
= /(chrome)[ \/]([\w.]+)/.exec( ua
) ||
129 /(webkit)[ \/]([\w.]+)/.exec( ua
) ||
130 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua
) ||
131 /(msie) ([\w.]+)/.exec( ua
) ||
132 ua
.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua
) ||
136 browser
: match
[ 1 ] || "",
137 version
: match
[ 2 ] || "0"
141 // Don't clobber any existing jQuery.browser in case it's different
142 if ( !jQuery
.browser
) {
143 matched
= jQuery
.uaMatch( navigator
.userAgent
);
146 if ( matched
.browser
) {
147 browser
[ matched
.browser
] = true;
148 browser
.version
= matched
.version
;
151 // Chrome is Webkit, but Webkit is also Safari.
152 if ( browser
.chrome
) {
153 browser
.webkit
= true;
154 } else if ( browser
.webkit
) {
155 browser
.safari
= true;
158 jQuery
.browser
= browser
;
161 // jQuery.getScript cache par defaut
162 jQuery
.getScript = function(url
,callback
){
172 * if not fully visible, scroll the page to position
173 * target block at the top of page
174 * if force = true, allways scroll
178 jQuery
.fn
.positionner = function(force
, setfocus
) {
179 var offset
= jQuery(this).offset();
180 var hauteur
= parseInt(jQuery(this).css('height'));
181 var scrolltop
= self
['pageYOffset'] ||
182 jQuery
.boxModel
&& document
.documentElement
[ 'scrollTop' ] ||
183 document
.body
[ 'scrollTop' ];
184 var h
= jQuery(window
).height();
187 if (force
|| (offset
&& offset
['top'] - 5 <= scrolltop
))
188 scroll
= offset
['top'] - 5;
189 else if (offset
&& offset
['top'] + hauteur
- h
+ 5 > scrolltop
)
190 scroll
= Math
.min(offset
['top'] - 5, offset
['top'] + hauteur
- h
+ 15);
193 .animate({scrollTop
: scroll
}, 300);
195 // positionner le curseur dans la premiere zone de saisie
196 if (setfocus
!==false)
197 jQuery(jQuery('*', this).filter('input[type=text],textarea')[0]).focus();
198 return this; // don't break the chain
201 // deux fonctions pour rendre l'ajax compatible Jaws
202 jQuery
.spip
.virtualbuffer_id
='spip_virtualbufferupdate';
203 jQuery
.spip
.initReaderBuffer = function(){
204 if (jQuery('#'+jQuery
.spip
.virtualbuffer_id
).length
) return;
205 jQuery('body').append('<p style="float:left;width:0;height:0;position:absolute;left:-5000px;top:-5000px;"><input type="hidden" name="'+jQuery
.spip
.virtualbuffer_id
+'" id="'+jQuery
.spip
.virtualbuffer_id
+'" value="0" /></p>');
207 jQuery
.spip
.updateReaderBuffer = function(){
208 var i
= jQuery('#'+jQuery
.spip
.virtualbuffer_id
);
209 if (!i
.length
) return;
210 // incrementons l'input hidden, ce qui a pour effet de forcer le rafraichissement du
211 // buffer du lecteur d'ecran (au moins dans Jaws)
212 i
.val(parseInt(i
.val())+1);
215 jQuery
.fn
.formulaire_setARIA = function(){
216 if (!this.closest('.ariaformprop').length
){
217 // eviter une double execution du js au moment de sa reinsertion dans le DOM par wrap()
218 // cf http://bugs.jquery.com/ticket/7447
219 this.find('script').remove();
220 this.wrap('<div class="ariaformprop" aria-live="polite" aria-atomic="true" aria-relevant="additions"></div>');
221 // dans un formulaire, le screen reader relit tout a chaque saisie d'un caractere si on est en aria-live
222 jQuery('form',this).not('[aria-live]').attr('aria-live','off');
227 * rechargement ajax d'un formulaire dynamique implemente par formulaires/xxx.html
230 jQuery
.fn
.formulaire_dyn_ajax = function(target
) {
232 jQuery
.spip
.initReaderBuffer();
233 return this.each(function() {
234 var scrollwhensubmit
= !jQuery(this).is('.noscroll');
235 var cible
= target
|| this;
236 jQuery(cible
).formulaire_setARIA();
237 jQuery('form:not(.noajax):not(.bouton_action_post)', this).each(function(){
239 var leclk
,leclk_x
,leclk_y
;
240 var onError = function(xhr
, status
, error
, $form
){
241 jQuery(leform
).ajaxFormUnbind().find('input[name="var_ajax"]').remove();
243 if (typeof(error_on_ajaxform
)!=="undefined") msg
= error_on_ajaxform
;
244 jQuery(leform
).prepend("<p class='error ajax-error none'>"+msg
+"</p>").find('.ajax-error').show('fast');
245 jQuery(cible
).closest('.ariaformprop').endLoading(true);
247 jQuery(this).prepend("<input type='hidden' name='var_ajax' value='form' />")
249 beforeSubmit: function(){
250 // memoriser le bouton clique, en cas de repost non ajax
252 var scrollwhensubmit_button
= true;
254 scrollwhensubmit_button
= !jQuery(leclk
).is('.noscroll');
256 if (n
&& !leclk
.disabled
&& leclk
.type
== "image") {
257 leclk_x
= leform
.clk_x
;
258 leclk_y
= leform
.clk_y
;
261 jQuery(cible
).wrap('<div />');
262 cible
= jQuery(cible
).parent();
263 jQuery(cible
).closest('.ariaformprop').animateLoading();
264 if (scrollwhensubmit
&& scrollwhensubmit_button
) {
265 jQuery(cible
).positionner(false,false);
269 success: function(c
, status
, xhr
, $form
){
270 if (c
.match(/^\s*noajax\s*$/)){
271 // le serveur ne veut pas traiter ce formulaire en ajax
272 // on resubmit sans ajax
273 jQuery("input[name=var_ajax]",leform
).remove();
274 // si on a memorise le nom et la valeur du bouton clique
275 // les reinjecter dans le dom sous forme de input hidden
276 // pour que le serveur les recoive
279 if (n
&& !leclk
.disabled
) {
280 jQuery(leform
).prepend("<input type='hidden' name='"+n
+"' value='"+leclk
.value
+"' />");
281 if (leclk
.type
== "image") {
282 jQuery(leform
).prepend("<input type='hidden' name='"+n
+".x' value='"+leform
.clk_x
+"' />");
283 jQuery(leform
).prepend("<input type='hidden' name='"+n
+".y' value='"+leform
.clk_y
+"' />");
287 jQuery(leform
).ajaxFormUnbind().submit();
290 if (!c
.length
|| c
.indexOf("ajax-form-is-ok")==-1)
291 return onError
.apply(this,[status
, xhr
, $form
]);
292 // commencons par vider le cache des urls, si jamais un js au retour
293 // essaye tout de suite de suivre un lien en cache
294 // dans le doute sur la validite du cache il vaut mieux l'invalider
295 var preloaded
= jQuery
.spip
.preloaded_urls
;
296 jQuery
.spip
.preloaded_urls
= {};
297 jQuery(cible
).html(c
);
298 var a
= jQuery('a:first',cible
).eq(0);
299 var d
= jQuery('div.ajax',cible
);
301 // si pas .ajax dans le form, remettre la classe sur le div que l'on a insere
302 jQuery(cible
).addClass('ajax');
303 if (!scrollwhensubmit
)
304 jQuery(cible
).addClass('noscroll');
307 // sinon nettoyer les br ajaxie
308 d
.siblings('br.bugajaxie').remove();
309 // desemboiter d'un niveau pour manger le div que l'on a insere
310 cible
= jQuery(":first",cible
);
313 // chercher une ancre en debut de html pour positionner la page
315 && a
.is('a[name=ajax_ancre]')
316 && jQuery(a
.attr('href'),cible
).length
){
318 if (jQuery(a
,cible
).length
)
319 setTimeout(function(){
320 jQuery(a
,cible
).positionner(false);
322 //window.location.hash = a[1];
324 jQuery(cible
).closest('.ariaformprop').endLoading(true);
327 //jQuery(cible).positionner(false);
328 if (a
.length
&& a
.is('a[name=ajax_redirect]')){
330 setTimeout(function(){
331 var cur
= window
.location
.href
.split('#');
332 document
.location
.replace(a
);
333 // regarder si c'est juste un changement d'ancre : dans ce cas il faut reload
334 // (le faire systematiquement provoque des bugs)
335 if (cur
[0]==a
.split('#')[0]){
336 window
.location
.reload();
339 // ne pas arreter l'etat loading, puisqu'on redirige !
340 // mais le relancer car l'image loading a pu disparaitre
341 jQuery(cible
).closest('.ariaformprop').animateLoading();
344 jQuery(cible
).closest('.ariaformprop').endLoading(true);
347 // si jamais le formulaire n'a pas un retour OK, retablissons le cache
348 // car a priori on a pas fait d'operation en base de donnee
349 if (!jQuery('.reponse_formulaire_ok',cible
).length
)
350 jQuery
.spip
.preloaded_urls
= preloaded
;
351 // mettre a jour le buffer du navigateur pour aider jaws et autres readers
353 jQuery
.spip
.updateReaderBuffer();
356 iframe: jQuery.browser.msie*/
358 // previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
359 // mais le marquer comme ayant l'ajax au cas ou on reinjecte du contenu ajax dedans
360 .addClass('noajax hasajax');
365 jQuery
.fn
.formulaire_verifier = function(callback
, champ
){
366 var erreurs
= {'message_erreur':'form non ajax'};
368 // si on est aussi en train de submit pour de vrai, abandonner
369 if (jQuery(me
).closest('.ariaformprop').attr('aria-busy')!='true') {
370 if (jQuery(me
).is('form.hasajax')){
371 jQuery(me
).ajaxSubmit({
373 data
:{formulaire_action_verifier_json
:true},
374 success:function(errs
){
375 var args
= [errs
, champ
]
376 // si on est aussi en train de submit pour de vrai, abandonner
377 if (jQuery(me
).closest('.ariaformprop').attr('aria-busy')!='true')
378 callback
.apply(me
,args
);
383 callback
.apply(me
,[erreurs
, champ
]);
388 jQuery
.fn
.formulaire_activer_verif_auto = function(callback
){
389 callback
= callback
|| formulaire_actualiser_erreurs
;
390 var me
= jQuery(this).closest('.ariaformprop');
391 var check = function(){
392 var name
=jQuery(this).attr('name');
393 // declencher apres 50ms pour ne pas double submit sur sequence saisie+submit
394 setTimeout(function(){me
.find('form').formulaire_verifier(callback
,name
);},50);
396 var activer = function(){
397 if (me
.find('form').attr('data-verifjson')!='on'){
400 .attr('data-verifjson','on')
401 .find('input,select,textarea')
402 .on('change', check
);
406 onAjaxLoad(function(){setTimeout(activer
,150);});
409 function formulaire_actualiser_erreurs(erreurs
){
410 var parent
= jQuery(this).closest('.formulaire_spip');
411 if (!parent
.length
) return;
412 // d'abord effacer tous les messages d'erreurs
413 parent
.find('.reponse_formulaire,.erreur_message').fadeOut().remove();
414 parent
.find('.erreur').removeClass('erreur');
415 // ensuite afficher les nouveaux messages d'erreur
416 if (erreurs
['message_ok'])
417 parent
.find('form').before('<p class="reponse_formulaire reponse_formulaire_ok">'+erreurs
['message_ok']+'</p>');
418 if (erreurs
['message_erreur'])
419 parent
.find('form').before('<p class="reponse_formulaire reponse_formulaire_erreur">'+erreurs
['message_erreur']+'</p>');
420 for (var k
in erreurs
){
421 var saisie
= parent
.find('.editer_'+k
);
423 saisie
.addClass('erreur');
424 saisie
.find('label').after('<span class="erreur_message">'+erreurs
[k
]+'</span>');
430 // permettre d'utiliser onclick='return confirm('etes vous sur?');' sur un lien ajax
431 var ajax_confirm
=true;
432 var ajax_confirm_date
=0;
433 var spip_confirm
= window
.confirm
;
434 function _confirm(message
){
435 ajax_confirm
= spip_confirm(message
);
438 ajax_confirm_date
= d
.getTime();
442 window
.confirm
= _confirm
;
445 * rechargement ajax d'une noisette implementee par {ajax}
446 * selecteur personalise, sera defini par defaut a '.pagination a,a.ajax'
448 var ajaxbloc_selecteur
;
451 * mise en cache des url. Il suffit de vider cete variable pour vider le cache
453 jQuery
.spip
.preloaded_urls
= {};
456 * Afficher dans la page
457 * le html d'un bloc ajax charge
458 * @param object blocfrag
461 * @param bool history
463 jQuery
.spip
.on_ajax_loaded = function(blocfrag
,c
,href
,history
) {
464 history
= history
|| (history
==null);
465 if (typeof href
== undefined || href
==null)
468 jQuery
.spip
.setHistoryState(blocfrag
);
470 if (jQuery(blocfrag
).attr('data-loaded-callback')){
471 var callback
= eval(jQuery(blocfrag
).attr('data-loaded-callback'));
472 callback
.call(blocfrag
, c
, href
, history
);
480 if (typeof href
!= undefined)
481 jQuery(blocfrag
).attr('data-url',href
);
483 jQuery
.spip
.pushHistoryState(href
);
484 jQuery
.spip
.setHistoryState(blocfrag
);
487 var a
= jQuery('a:first',jQuery(blocfrag
)).eq(0);
489 && a
.is('a[name=ajax_ancre]')
490 && jQuery(a
.attr('href'),blocfrag
).length
){
492 jQuery(a
,blocfrag
).positionner(false);
494 jQuery
.spip
.log('on_ajax_loaded');
495 jQuery
.spip
.triggerAjaxLoad(blocfrag
);
496 // si le fragment ajax est dans un form ajax,
497 // il faut remettre a jour les evenements attaches
498 // car le fragment peut comporter des submit ou button
499 a
= jQuery(blocfrag
).parents('form.hasajax')
501 a
.eq(0).removeClass('noajax').parents('div.ajax').formulaire_dyn_ajax();
502 jQuery
.spip
.updateReaderBuffer();
505 jQuery
.spip
.stateId
=0;
506 jQuery
.spip
.setHistoryState = function(blocfrag
){
507 if (!window
.history
.replaceState
) return;
508 // attribuer un id au bloc si il n'en a pas
509 if (!blocfrag
.attr('id')){
510 while (jQuery('#ghsid'+jQuery
.spip
.stateId
).length
)
511 jQuery
.spip
.stateId
++;
512 blocfrag
.attr('id','ghsid'+jQuery
.spip
.stateId
);
514 var href
= blocfrag
.attr('data-url') || blocfrag
.attr('data-origin');
515 href
= jQuery("<"+"a href='"+href
+"'></a>").get(0).href
;
517 id
:blocfrag
.attr('id'),
520 var ajaxid
= blocfrag
.attr('class').match(/\bajax-id-[\w-]+\b/);
521 if (ajaxid
&& ajaxid
.length
)
522 state
["ajaxid"] = ajaxid
[0];
523 // on remplace la variable qui decrit l'etat courant
525 // -> elle servira a revenir dans l'etat courant
526 window
.history
.replaceState(state
,window
.document
.title
, window
.document
.location
);
529 jQuery
.spip
.pushHistoryState = function(href
, title
){
530 if (!window
.history
.pushState
)
532 window
.history
.pushState({}, title
, href
);
535 window
.onpopstate = function(popState
){
536 if (popState
.state
&& popState
.state
.href
){
538 if (popState
.state
.id
){
539 blocfrag
=jQuery('#'+popState
.state
.id
);
541 if ((!blocfrag
|| !blocfrag
.length
) && popState
.state
.ajaxid
){
542 blocfrag
=jQuery('.ajaxbloc.'+popState
.state
.ajaxid
);
544 if (blocfrag
&& blocfrag
.length
==1) {
545 jQuery
.spip
.ajaxClick(blocfrag
,popState
.state
.href
,{history
:false});
548 // si on revient apres avoir rompu la chaine ajax, on a pu perdre l'id #ghsidxx ajoute en JS
549 // dans ce cas on redirige hors ajax
551 window
.location
.href
= popState
.state
.href
;
557 * Charger un bloc ajax represente par l'objet jQuery blocajax qui le pointe
558 * avec la requete ajax url, qui represente le lien href
559 * @param object blocfrag
562 * url pour la requete ajax
565 * @param object options
566 * bool force : pour forcer la requete sans utiliser le cache
567 * function callback : callback au retour du chargement
568 * bool history : prendre en charge l'histrisation dans l'url
570 jQuery
.spip
.loadAjax = function(blocfrag
,url
, href
, options
){
571 var force
= options
.force
|| false;
572 if (jQuery(blocfrag
).attr('data-loading-callback')){
573 var callback
= eval(jQuery(blocfrag
).attr('data-loading-callback'));
574 callback
.call(blocfrag
,url
,href
,options
);
577 jQuery(blocfrag
).animateLoading();
579 if (jQuery
.spip
.preloaded_urls
[url
] && !force
) {
580 // si on est deja en train de charger ce fragment, revenir plus tard
581 if (jQuery
.spip
.preloaded_urls
[url
]=="<!--loading-->"){
582 setTimeout(function(){jQuery
.spip
.loadAjax(blocfrag
,url
,href
,options
);},100);
585 jQuery
.spip
.on_ajax_loaded(blocfrag
,jQuery
.spip
.preloaded_urls
[url
],href
,options
.history
);
588 jQuery
.spip
.preloaded_urls
[url
] = "<!--loading-->";
590 url
: parametre_url(url
,'var_t',d
.getTime()),
592 success: function(c
){
593 jQuery
.spip
.on_ajax_loaded(blocfrag
,c
,href
,options
.history
);
594 jQuery
.spip
.preloaded_urls
[url
] = c
;
595 if (options
.callback
&& typeof options
.callback
== "function")
596 options
.callback
.apply(blocfrag
);
599 jQuery
.spip
.preloaded_urls
[url
]='';
606 * Calculer l'url ajax a partir de l'url du lien
607 * et de la variable d'environnement du bloc ajax
608 * passe aussi l'ancre eventuelle sous forme d'une variable
609 * pour que le serveur puisse la prendre en compte
610 * et la propager jusqu'a la reponse
611 * sous la forme d'un lien cache
614 * @param string ajax_env
616 jQuery
.spip
.makeAjaxUrl = function(href
,ajax_env
,origin
){
617 var url
= href
.split('#');
618 url
[0] = parametre_url(url
[0],'var_ajax',1);
619 url
[0] = parametre_url(url
[0],'var_ajax_env',ajax_env
);
621 // les arguments de origin qui ne sont pas dans href doivent etre explicitement fournis vides dans url
623 var p
=origin
.indexOf('?');
626 var args
= origin
.substring(p
+1).split('&');
629 for(var n
=0;n
<args
.length
;n
++){
630 arg
= args
[n
].split('=');
632 p
= arg
.indexOf('[');
634 arg
= arg
.substring(0,p
);
635 val
= parametre_url(href
,arg
);
636 if (typeof val
=="undefined" || val
==null)
637 url
[0] = url
[0] + '&' + arg
+ '=';
643 url
[0] = parametre_url(url
[0],'var_ajax_ancre',url
[1]);
648 * fonction appelee sur l'evenement ajaxReload d'un bloc ajax
649 * que l'on declenche quand on veut forcer sa mise a jour
651 * @param object blocfrag
652 * @param object options
653 * callback : fonction appelee apres le rechargement
654 * href : url to load instead of origin url
655 * args : arguments passes a l'url rechargee (permet une modif du contexte)
656 * history : bool to specify if navigation history is modified by reload or not (false if not provided)
658 jQuery
.spip
.ajaxReload = function(blocfrag
, options
){
659 var ajax_env
= blocfrag
.attr('data-ajax-env');
660 if (!ajax_env
|| ajax_env
==undefined) return;
661 var href
= options
.href
|| blocfrag
.attr('data-url') || blocfrag
.attr('data-origin');
662 if (href
&& typeof href
!= undefined){
663 options
= options
|| {};
664 var callback
=options
.callback
|| null;
665 var history
=options
.history
|| false;
666 var args
= options
.args
|| {};
667 for (var key
in args
)
668 href
= parametre_url(href
,key
,args
[key
]==undefined?'':args
[key
],'&',args
[key
]==undefined?false:true);
669 var url
= jQuery
.spip
.makeAjaxUrl(href
,ajax_env
,blocfrag
.attr('data-origin'));
670 // recharger sans historisation dans l'url
671 jQuery
.spip
.loadAjax(blocfrag
, url
, href
, {force
:true, callback
:callback
, history
:history
});
677 * fonction appelee sur l'evenement click d'un lien ajax
679 * @param object blocfrag
680 * objet jQuery qui cible le bloc ajax contenant
682 * url du lien a suivre
683 * @param object options
684 * force : pour interdire l'utilisation du cache
685 * history : pour interdire la mise en historique
687 jQuery
.spip
.ajaxClick = function(blocfrag
, href
, options
){
688 var ajax_env
= blocfrag
.attr('data-ajax-env');
689 if (!ajax_env
|| ajax_env
==undefined) return;
691 // on rearme pour le prochain clic
694 // seule une annulation par confirm() dans les 2 secondes precedentes est prise en compte
695 if ((d
.getTime()-ajax_confirm_date
)<=2)
698 var url
= jQuery
.spip
.makeAjaxUrl(href
,ajax_env
,blocfrag
.attr('data-origin'));
699 jQuery
.spip
.loadAjax(blocfrag
, url
, href
, options
);
704 * Implementer le comportemant des liens ajax
705 * et boutons post ajax qui se comportent
708 jQuery
.fn
.ajaxbloc = function() {
709 // hack accessibilite vieille version de JAWS
712 jQuery
.spip
.initReaderBuffer();
713 if (ajaxbloc_selecteur
==undefined)
714 ajaxbloc_selecteur
= '.pagination a,a.ajax';
716 return this.each(function() {
717 // traiter les enfants d'abord :
718 // un lien ajax provoque le rechargement
719 // du plus petit bloc ajax le contenant
720 jQuery('div.ajaxbloc',this).ajaxbloc();
721 var blocfrag
= jQuery(this);
723 var ajax_env
= blocfrag
.attr('data-ajax-env');
724 if (!ajax_env
|| ajax_env
==undefined) return;
726 blocfrag
.not('.bind-ajaxReload').on('ajaxReload', function(event
, options
){
727 if (jQuery
.spip
.ajaxReload(blocfrag
,options
))
728 // don't trig reload of parent blocks
729 event
.stopPropagation();
730 }).addClass('bind-ajaxReload')
731 .attr('aria-live','polite').attr('aria-atomic','true');
733 // dans un formulaire, le screen reader relit tout a chaque saisie d'un caractere si on est en aria-live
734 // mettre un aria-live="off" sur les forms inclus dans ce bloc aria-live="polite"
735 jQuery('form',this).not('[aria-live]').attr('aria-live','off');
737 jQuery(ajaxbloc_selecteur
,this).not('.noajax,.bind-ajax')
738 .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
)});})
739 .addClass('bind-ajax')
740 .filter('.preload').each(function(){
741 var href
= this.href
;
742 var url
= jQuery
.spip
.makeAjaxUrl(href
,ajax_env
,blocfrag
.attr('data-origin'));
743 if (!jQuery
.spip
.preloaded_urls
[url
]) {
744 jQuery
.spip
.preloaded_urls
[url
] = '<!--loading-->';
745 jQuery
.ajax({url
:url
,onAjaxLoad
:false,success:function(r
){jQuery
.spip
.preloaded_urls
[url
]=r
;},error:function(){jQuery
.spip
.preloaded_urls
[url
]='';}});
747 }); // previent qu'on ajax pas deux fois le meme lien
749 // ajaxer les boutons actions qui sont techniquement des form minimaux
750 // mais se comportent comme des liens
751 jQuery('form.bouton_action_post.ajax', this).not('.noajax,.bind-ajax').each(function(){
753 var url
= jQuery(this).attr('action').split('#');
754 var scrollwhensubmit
= (!jQuery(this).is('.noscroll') && !jQuery('.submit',this).is('.noscroll'));
756 .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]+"' />":""))
758 beforeSubmit: function(){
759 jQuery(blocfrag
).animateLoading();
760 if (scrollwhensubmit
) {
761 jQuery(blocfrag
).positionner(false);
765 success: function(c
){
766 jQuery
.spip
.on_ajax_loaded(blocfrag
,c
);
767 jQuery
.spip
.preloaded_urls
= {}; // on vide le cache des urls car on a fait une action en bdd
769 iframe: jQuery.browser.msie*/
771 .addClass('bind-ajax'); // previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
777 * Suivre un lien en simulant le click sur le lien
778 * Si le lien est ajax, on se contente de declencher l'evenement click()
779 * Si le lien est non ajax, on finit en remplacant l'url de la page
781 jQuery
.fn
.followLink = function(){
783 if (!$(this).is('.bind-ajax'))
784 window
.location
.href
= $(this).get(0).href
;
788 * Recharger un bloc ajax pour le mettre a jour
789 * ajaxid est l'id passe en argument de INCLURE{ajax=ajaxid}
790 * options permet de definir une callbackk ou de passer des arguments a l'url
792 * ajaxReload peut s'utiliser en passant un id :
794 * ou sur un objet jQuery
795 * jQuery(this).ajaxReload();
796 * Dans ce dernier cas, le plus petit conteneur ajax est recharge
798 * @param string ajaxid
799 * @param object options
800 * callback : callback after reloading
801 * href : url to load instead of origin url
802 * args : {arg:value,...} to pass tu the url
803 * history : bool to specify if navigation history is modified by reload or not (false if not provided)
805 function ajaxReload(ajaxid
, options
){
806 jQuery('div.ajaxbloc.ajax-id-'+ajaxid
).ajaxReload(options
);
810 * Variante jQuery de ajaxReload pour la syntaxe
811 * jQuery(..).ajaxReload();
815 jQuery
.fn
.ajaxReload = function(options
){
816 options
= options
||{};
817 // just trigg the event, as it will bubble up the DOM
818 jQuery(this).trigger('ajaxReload', [options
]);
819 return this; // don't break the chain
823 * animation du bloc cible pour faire patienter
826 jQuery
.fn
.animateLoading = function() {
827 this.attr('aria-busy','true').addClass('loading').children().css('opacity', 0.5);
828 if (typeof ajax_image_searching
!= 'undefined'){
829 var i
= (this).find('.image_loading');
830 if (i
.length
) i
.eq(0).html(ajax_image_searching
);
831 else this.prepend('<span class="image_loading">'+ajax_image_searching
+'</span>');
833 return this; // don't break the chain
835 // compatibilite avec ancien nommage
836 jQuery
.fn
.animeajax
= jQuery
.fn
.animateLoading
;
840 * l'argument permet de forcer le raz du contenu si il est inchange
843 jQuery
.fn
.endLoading = function(hard
) {
844 hard
= hard
|| false;
845 this.attr('aria-busy','false').removeClass('loading');
847 this.children().css('opacity', '');
848 this.find('.image_loading').html('');
850 return this; // don't break the chain
854 * animation d'un item que l'on supprime :
855 * ajout de la classe remove avec un background tire de cette classe
856 * puis fading vers opacity 0
857 * quand l'element est masque, on retire les classes et css inline
859 * @param function callback
862 jQuery
.fn
.animateRemove = function(callback
){
865 var color
= $("<div class='remove'></div>").css('background-color');
867 // if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
869 sel
= sel
.add('>td',sel
);
870 sel
.addClass('remove').css({backgroundColor
: color
}).animate({opacity
: "0.0"}, 'fast', function(){
871 sel
.removeClass('remove').css({backgroundColor
: ''});
876 return this; // don't break the chain
881 * animation d'un item que l'on ajoute :
882 * ajout de la classe append
883 * fading vers opacity 1 avec background herite de la classe append,
884 * puis suppression progressive du background pour revenir a la valeur heritee
886 * @param function callback
888 jQuery
.fn
.animateAppend = function(callback
){
891 // recuperer la couleur portee par la classe append (permet une personalisation)
892 var color
= $("<div class='append'></div>").css('background-color');
893 var origin
= $(this).css('background-color') || '#ffffff';
895 if (origin
=='transparent') origin
='#ffffff';
897 // if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
899 sel
= sel
.add('>td',sel
);
900 sel
.css('opacity','0.0').addClass('append').css({backgroundColor
: color
}).animate({opacity
: "1.0"}, 1000,function(){
901 sel
.animate({backgroundColor
: origin
}, 3000,function(){
902 sel
.removeClass('append').css({backgroundColor
: ''});
908 return this; // don't break the chain
912 * Equivalent js de parametre_url php de spip
915 * parametre_url(url,suite,18) (ajout)
916 * parametre_url(url,suite,'') (supprime)
917 * parametre_url(url,suite) (lit la valeur suite)
918 * parametre_url(url,suite[],1) (tableau valeurs multiples)
926 * separateur '&' par defaut
928 * si true et v='' insere &k= dans l'url au lieu de supprimer le k (false par defaut)
929 * permet de vider une valeur dans une requete ajax (dans un reload)
931 function parametre_url(url
,c
,v
,sep
,force_vide
){
932 // Si l'URL n'est pas une chaine, on ne peut pas travailler dessus et on quitte
933 if (typeof(url
) == 'undefined'){
942 p
= url
.indexOf('#');
944 ancre
=url
.substring(p
);
945 url
= url
.substring(0,p
);
952 if (p
>0) a
=url
.substring(0,p
);
953 args
= url
.substring(p
+1).split('&');
957 var regexp
= new RegExp('^(' + c
.replace('[]','\\[\\]') + '\\[?\\]?)(=.*)?$');
959 var u
= (typeof(v
)!=='object')?encodeURIComponent(v
):v
;
962 // lire les variables et agir
963 for(var n
=0;n
<args
.length
;n
++){
966 val
= decodeURIComponent(val
);
968 var r
=val
.match(regexp
);
971 // c'est un tableau, on memorise les valeurs
972 if (r
[1].substr(-2) == '[]') {
973 if (!v_read
) v_read
= [];
974 v_read
.push((r
.length
>2 && typeof r
[2]!=='undefined')?r
[2].substring(1):'');
976 // c'est un scalaire, on retourne direct
978 return (r
.length
>2 && typeof r
[2]!=='undefined')?r
[2].substring(1):'';
982 else if (!v
.length
) {
984 // Ajout. Pour une variable, remplacer au meme endroit,
985 // pour un tableau ce sera fait dans la prochaine boucle
986 else if (r
[1].substr(-2) != '[]') {
990 /* Pour les tableaux ont laisse tomber les valeurs de départ, on
991 remplira à l'étape suivante */
992 // else na.push(args[n]);
998 if (v
==null) return v_read
; // rien de trouve ou un tableau
999 // traiter les parametres pas encore trouves
1000 if (v
|| v
.length
|| force_vide
) {
1001 ajouts
= "="+ajouts
.join("=")+"=";
1002 var all
=c
.split('|');
1003 for (n
=0;n
<all
.length
;n
++){
1004 if (ajouts
.search("="+all
[n
]+"=")==-1){
1005 if (typeof(v
)!=='object'){
1006 na
.push(all
[n
] +'='+ u
);
1009 var id
= ((all
[n
].substring(-2)=='[]')?all
[n
]:all
[n
]+"[]");
1010 for(p
=0;p
<v
.length
;p
++)
1011 na
.push(id
+'='+ encodeURIComponent(v
[p
]));
1017 // recomposer l'adresse
1020 a
= a
+"?"+na
.join(sep
);
1028 // Ajaxer les formulaires qui le demandent, au demarrage
1029 if (!window
.var_zajax_content
)
1030 window
.var_zajax_content
= 'contenu';
1032 jQuery('form:not(.bouton_action_post)').parents('div.ajax')
1033 .formulaire_dyn_ajax();
1034 jQuery('div.ajaxbloc').ajaxbloc();
1035 jQuery("input[placeholder]:text").placeholderLabel();
1036 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;});
1039 // ... et a chaque fois que le DOM change
1040 onAjaxLoad(function() {
1042 jQuery('form:not(.bouton_action_post)', this).parents('div.ajax')
1043 .formulaire_dyn_ajax();
1044 if (jQuery(this).is('div.ajaxbloc'))
1045 jQuery(this).ajaxbloc();
1046 else if (jQuery(this).closest('div.ajaxbloc').length
)
1047 jQuery(this).closest('div.ajaxbloc').ajaxbloc();
1049 jQuery('div.ajaxbloc', this).ajaxbloc();
1050 jQuery("input[placeholder]:text",this).placeholderLabel();
1051 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;});