PageSourceSearch

https://jean-charles-hachet.com/prive/javascript/ajaxCallback.js?1618426014

js jean-charles-hachet.com collected 2026-10-03 01:01:11 UTC 35,316 bytes, 1,054 lines download raw bytes

1jQuery.spip=jQuery.spip || {};
2jQuery.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
7if(!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		if ( typeof url !== "string") {
41			return jQuery.spip.intercepted.load.apply( this, arguments );
42		}
43
44		callback = callback || function(){};
45
46		// If the second parameter was provided
47		if ( params ) {
48			// If it's a function
49			if ( params.constructor == Function ) {
50				// We assume that it's the callback
51				callback = params;
52				params = null;
53			}
54		}
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]);
58	};
59
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');
68			if (me.length)
69				me=me.parent();
70			else
71				me = document;
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);}
76		}
77		return jQuery.spip.intercepted.ajaxSubmit.apply(this,[options]);
78	}
79
80	// intercept jQuery.ajax
81	jQuery.spip.intercepted.ajax = jQuery.ajax;
82	jQuery.ajax = function(url, settings) {
83		if (typeof settings == 'undefined') {
84			settings = {};
85			if (typeof url == 'object') {
86				settings = url;
87				url = null;
88			}
89		}
90		if (typeof url == 'string') {
91			settings['url'] = url;
92		}
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);
97		}
98		var s = jQuery.extend(true, {}, jQuery.ajaxSettings, settings);
99		var callbackContext = s.context || s;
100		try {
101			if (jQuery.ajax.caller==jQuery.spip.intercepted.load || jQuery.ajax.caller==jQuery.spip.intercepted.ajaxSubmit)
102				return jQuery.spip.intercepted.ajax(settings);
103		}
104		catch (err){}
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);
117			}
118		};
119		return jQuery.spip.intercepted.ajax(settings);
120	};
121
122}
123
124/* jQuery.browser */
125jQuery.uaMatch = function( ua ) {
126	ua = ua.toLowerCase();
127
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 ) ||
133		[];
134
135	return {
136		browser: match[ 1 ] || "",
137		version: match[ 2 ] || "0"
138	};
139};
140
141// Don't clobber any existing jQuery.browser in case it's different
142if ( !jQuery.browser ) {
143	matched = jQuery.uaMatch( navigator.userAgent );
144	browser = {};
145
146	if ( matched.browser ) {
147		browser[ matched.browser ] = true;
148		browser.version = matched.version;
149	}
150
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;
156	}
157
158	jQuery.browser = browser;
159}
160
161// jQuery.getScript cache par defaut
162jQuery.getScript = function(url,callback){
163	return $.ajax({
164		url: url,
165		dataType: "script",
166		success: callback,
167		cache: true
168	});
169}
170
171/**
172 * if not fully visible, scroll the page to position
173 * target block at the top of page
174 * if force = true, allways scroll
175 *
176 * @param bool force
177 */
178jQuery.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();
185	var scroll=0;
186
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);
191	if (scroll)
192		jQuery('html,body')
193		.animate({scrollTop: scroll}, 300);
194
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
199}
200
201// deux fonctions pour rendre l'ajax compatible Jaws
202jQuery.spip.virtualbuffer_id='spip_virtualbufferupdate';
203jQuery.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>');
206}
207jQuery.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);
213}
214
215jQuery.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');
223	}
224	return this;
225}
226/**
227 * rechargement ajax d'un formulaire dynamique implemente par formulaires/xxx.html
228 * @param target
229 */
230jQuery.fn.formulaire_dyn_ajax = function(target) {
231	if (this.length)
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(){
238		var leform = this;
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();
242			var msg = "Erreur";
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);
246		}
247		jQuery(this).prepend("<input type='hidden' name='var_ajax' value='form' />")
248		.ajaxForm({
249			beforeSubmit: function(){
250				// memoriser le bouton clique, en cas de repost non ajax
251				leclk = leform.clk;
252				var scrollwhensubmit_button = true;
253				if (leclk) {
254					scrollwhensubmit_button = !jQuery(leclk).is('.noscroll');
255					var n = leclk.name;
256					if (n && !leclk.disabled && leclk.type == "image") {
257						leclk_x = leform.clk_x;
258						leclk_y = leform.clk_y;
259					}
260				}
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);
266				}
267			},
268			error: onError,
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
277					if (leclk){
278						var n = leclk.name;
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+"' />");
284							}
285						}
286					}
287					jQuery(leform).ajaxFormUnbind().submit();
288				}
289				else {
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);
300					if (!d.length){
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');
305					}
306					else {
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);
311						cible.unwrap();
312					}
313					// chercher une ancre en debut de html pour positionner la page
314					if (a.length
315					  && a.is('a[name=ajax_ancre]')
316					  && jQuery(a.attr('href'),cible).length){
317						a = a.attr('href');
318						if (jQuery(a,cible).length)
319							setTimeout(function(){
320							jQuery(a,cible).positionner(false);
321							//a = a.split('#');
322							//window.location.hash = a[1];
323							},10);
324						jQuery(cible).closest('.ariaformprop').endLoading(true);
325					}
326					else{
327						//jQuery(cible).positionner(false);
328						if (a.length && a.is('a[name=ajax_redirect]')){
329							a = a.get(0).href;
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();
337								}
338							},10);
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();
342						}
343						else {
344							jQuery(cible).closest('.ariaformprop').endLoading(true);
345						}
346					}
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
352					// a supprimer ?
353					jQuery.spip.updateReaderBuffer();
354				}
355			}/*,
356			iframe: jQuery.browser.msie*/
357		})
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');
361		});
362  });
363}
364
365jQuery.fn.formulaire_verifier = function(callback, champ){
366	var erreurs = {'message_erreur':'form non ajax'};
367	var me=this;
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({
372				dataType:"json",
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);
379				}
380			});
381		}
382		else
383			callback.apply(me,[erreurs, champ]);
384	}
385	return this;
386}
387
388jQuery.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);
395	}
396	var activer = function(){
397		if (me.find('form').attr('data-verifjson')!='on'){
398			me
399				.find('form')
400				.attr('data-verifjson','on')
401				.find('input,select,textarea')
402				.on('change', check);
403		}
404	}
405	jQuery(activer);
406	onAjaxLoad(function(){setTimeout(activer,150);});
407}
408
409function 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);
422		if (saisie.length) {
423			saisie.addClass('erreur');
424			saisie.find('label').after('<span class="erreur_message">'+erreurs[k]+'</span>');
425		}
426	}
427}
428
429
430// permettre d'utiliser onclick='return confirm('etes vous sur?');' sur un lien ajax
431var ajax_confirm=true;
432var ajax_confirm_date=0;
433var spip_confirm = window.confirm;
434function _confirm(message){
435	ajax_confirm = spip_confirm(message);
436	if (!ajax_confirm) {
437		var d = new Date();
438		ajax_confirm_date = d.getTime();
439	}
440	return ajax_confirm;
441}
442window.confirm = _confirm;
443
444/**
445 * rechargement ajax d'une noisette implementee par {ajax}
446 * selecteur personalise, sera defini par defaut a '.pagination a,a.ajax'
447 */
448var ajaxbloc_selecteur;
449
450/**
451 * mise en cache des url. Il suffit de vider cete variable pour vider le cache
452 */
453jQuery.spip.preloaded_urls = {};
454
455/**
456 * Afficher dans la page
457 * le html d'un bloc ajax charge
458 * @param object blocfrag
459 * @param string c
460 * @param string href
461 * @param bool history
462 */
463jQuery.spip.on_ajax_loaded = function(blocfrag,c,href,history) {
464	history = history || (history==null);
465	if (typeof href == undefined || href==null)
466		history = false;
467	if (history)
468		jQuery.spip.setHistoryState(blocfrag);
469
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);
473	}
474	else {
475		jQuery(blocfrag)
476		.html(c)
477		.endLoading();
478	}
479
480	if (typeof href != undefined)
481		jQuery(blocfrag).attr('data-url',href);
482	if (history) {
483		jQuery.spip.pushHistoryState(href);
484		jQuery.spip.setHistoryState(blocfrag);
485	}
486
487	var a = jQuery('a:first',jQuery(blocfrag)).eq(0);
488	if (a.length
489		&& a.is('a[name=ajax_ancre]')
490		&& jQuery(a.attr('href'),blocfrag).length){
491		a = a.attr('href');
492		jQuery(a,blocfrag).positionner(false);
493	}
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')
500	if (a.length)
501		a.eq(0).removeClass('noajax').parents('div.ajax').formulaire_dyn_ajax();
502	jQuery.spip.updateReaderBuffer();
503}
504
505jQuery.spip.stateId=0;
506jQuery.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);
513	}
514	var href= blocfrag.attr('data-url') || blocfrag.attr('data-origin');
515	href = jQuery("<"+"a href='"+href+"'></a>").get(0).href;
516	var state={
517		id:blocfrag.attr('id'),
518		href: href
519	};
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
524	// initialement vide
525	// -> elle servira a revenir dans l'etat courant
526	window.history.replaceState(state,window.document.title, window.document.location);
527}
528
529jQuery.spip.pushHistoryState = function(href, title){
530	if (!window.history.pushState)
531		return false;
532	window.history.pushState({}, title, href);
533}
534
535window.onpopstate = function(popState){
536	if (popState.state && popState.state.href){
537		var blocfrag=false;
538		if (popState.state.id){
539			blocfrag=jQuery('#'+popState.state.id);
540		}
541		if ((!blocfrag || !blocfrag.length) && popState.state.ajaxid){
542			blocfrag=jQuery('.ajaxbloc.'+popState.state.ajaxid);
543		}
544		if (blocfrag && blocfrag.length==1) {
545			jQuery.spip.ajaxClick(blocfrag,popState.state.href,{history:false});
546			return true;
547		}
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
550		else {
551			window.location.href = popState.state.href;
552		}
553	}
554}
555
556/**
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
560 *   bloc cible
561 * @param string url
562 *   url pour la requete ajax
563 * @param string href
564 *   url du lien clique
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
569 */
570jQuery.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);
575	}
576	else {
577		jQuery(blocfrag).animateLoading();
578	}
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);
583			return;
584		}
585		jQuery.spip.on_ajax_loaded(blocfrag,jQuery.spip.preloaded_urls[url],href,options.history);
586	} else {
587		var d = new Date();
588		jQuery.spip.preloaded_urls[url] = "<!--loading-->";
589		jQuery.ajax({
590			url: parametre_url(url,'var_t',d.getTime()),
591			onAjaxLoad:false,
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);
597			},
598			error: function(){
599				jQuery.spip.preloaded_urls[url]='';
600			}
601		});
602	}
603}
604
605/**
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
612 *
613 * @param string href
614 * @param string ajax_env
615 */
616jQuery.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);
620
621	// les arguments de origin qui ne sont pas dans href doivent etre explicitement fournis vides dans url
622	if (origin){
623		var p=origin.indexOf('?');
624		if (p!==-1){
625			// recuperer la base
626			var args = origin.substring(p+1).split('&');
627			var val;
628			var arg;
629			for(var n=0;n<args.length;n++){
630				arg = args[n].split('=');
631				arg = arg[0];
632				p = arg.indexOf('[');
633				if (p!==-1)
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 + '=';
638			}
639		}
640	}
641
642	if (url[1])
643		url[0] = parametre_url(url[0],'var_ajax_ancre',url[1]);
644	return url[0];
645}
646
647/**
648 * fonction appelee sur l'evenement ajaxReload d'un bloc ajax
649 * que l'on declenche quand on veut forcer sa mise a jour
650 *
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)
657 */
658jQuery.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});
672		return true;
673	}
674}
675
676/**
677 * fonction appelee sur l'evenement click d'un lien ajax
678 *
679 * @param object blocfrag
680 *   objet jQuery qui cible le bloc ajax contenant
681 * @param string href
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
686 */
687jQuery.spip.ajaxClick = function(blocfrag, href, options){
688	var ajax_env = blocfrag.attr('data-ajax-env');
689	if (!ajax_env || ajax_env==undefined) return;
690	if (!ajax_confirm) {
691		// on rearme pour le prochain clic
692		ajax_confirm=true;
693		var d = new Date();
694		// seule une annulation par confirm() dans les 2 secondes precedentes est prise en compte
695		if ((d.getTime()-ajax_confirm_date)<=2)
696			return false;
697	}
698	var url = jQuery.spip.makeAjaxUrl(href,ajax_env,blocfrag.attr('data-origin'));
699	jQuery.spip.loadAjax(blocfrag, url, href, options);
700	return false;
701}
702
703/**
704 * Implementer le comportemant des liens ajax
705 * et boutons post ajax qui se comportent
706 * comme un lien ajax
707 */
708jQuery.fn.ajaxbloc = function() {
709	// hack accessibilite vieille version de JAWS
710	// a supprimer ?
711	if (this.length)
712		jQuery.spip.initReaderBuffer();
713	if (ajaxbloc_selecteur==undefined)
714		ajaxbloc_selecteur = '.pagination a,a.ajax';
715
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);
722
723		var ajax_env = blocfrag.attr('data-ajax-env');
724		if (!ajax_env || ajax_env==undefined) return;
725
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');
732
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');
736
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]='';}});
746				}
747			}); // previent qu'on ajax pas deux fois le meme lien
748
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(){
752			var leform = this;
753			var url = jQuery(this).attr('action').split('#');
754			var scrollwhensubmit = (!jQuery(this).is('.noscroll') && !jQuery('.submit',this).is('.noscroll'));
755			jQuery(this)
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]+"' />":""))
757			.ajaxForm({
758				beforeSubmit: function(){
759					jQuery(blocfrag).animateLoading();
760					if (scrollwhensubmit) {
761						jQuery(blocfrag).positionner(false);
762					}
763				},
764				onAjaxLoad: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
768				}/*,
769				iframe: jQuery.browser.msie*/
770			})
771			.addClass('bind-ajax'); // previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
772		});
773  });
774};
775
776/**
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
780 */
781jQuery.fn.followLink = function(){
782	$(this).click();
783	if (!$(this).is('.bind-ajax'))
784		window.location.href = $(this).get(0).href;
785	return this;
786}
787/**
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
791 * au rechargement
792 * ajaxReload peut s'utiliser en passant un id :
793 * ajaxReload('xx');
794 * ou sur un objet jQuery
795 * jQuery(this).ajaxReload();
796 * Dans ce dernier cas, le plus petit conteneur ajax est recharge
797 *
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)
804 */
805function ajaxReload(ajaxid, options){
806	jQuery('div.ajaxbloc.ajax-id-'+ajaxid).ajaxReload(options);
807}
808
809/**
810 * Variante jQuery de ajaxReload pour la syntaxe
811 * jQuery(..).ajaxReload();
812 * cf doc ci-dessus
813 * @param options
814 */
815jQuery.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
820}
821
822/**
823 * animation du bloc cible pour faire patienter
824 *
825 */
826jQuery.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>');
832	}
833	return this; // don't break the chain
834}
835// compatibilite avec ancien nommage
836jQuery.fn.animeajax = jQuery.fn.animateLoading;
837
838/**
839 * Fin de l'animation
840 * l'argument permet de forcer le raz du contenu si il est inchange
841 * @param hard
842 */
843jQuery.fn.endLoading = function(hard) {
844	hard = hard || false;
845	this.attr('aria-busy','false').removeClass('loading');
846	if (hard){
847		this.children().css('opacity', '');
848		this.find('.image_loading').html('');
849	}
850	return this; // don't break the chain
851}
852
853/**
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
858 *
859 * @param function callback
860 *
861 */
862jQuery.fn.animateRemove = function(callback){
863	if (this.length){
864		var me=this;
865		var color = $("<div class='remove'></div>").css('background-color');
866		var sel=$(this);
867		// if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
868		if (sel.is('tr'))
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: ''});
872			if (callback)
873				callback.apply(me);
874		});
875	}
876	return this; // don't break the chain
877}
878
879
880/**
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
885 *
886 * @param function callback
887 */
888jQuery.fn.animateAppend = function(callback){
889	if (this.length){
890		var me=this;
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';
894		// pis aller
895		if (origin=='transparent') origin='#ffffff';
896		var sel=$(this);
897		// if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
898		if (sel.is('tr'))
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: ''});
903				if (callback)
904					callback.apply(me);
905			});
906		});
907	}
908	return this; // don't break the chain
909}
910
911/**
912 * Equivalent js de parametre_url php de spip
913 *
914 * Exemples :
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)
919 * @param url
920 *   url
921 * @param c
922 *   champ
923 * @param v
924 *   valeur
925 * @param sep
926 *  separateur '&' par defaut
927 * @param force_vide
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)
930 */
931function 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'){
934		url = '';
935	}
936
937	var p;
938	// lever l'#ancre
939	var ancre='';
940	var a='./';
941	var args=[];
942	p = url.indexOf('#');
943	if (p!=-1) {
944		ancre=url.substring(p);
945		url = url.substring(0,p);
946	}
947
948	// eclater
949	p=url.indexOf('?');
950	if (p!==-1){
951		// recuperer la base
952		if (p>0) a=url.substring(0,p);
953		args = url.substring(p+1).split('&');
954	}
955	else
956		a=url;
957	var regexp = new RegExp('^(' + c.replace('[]','\\[\\]') + '\\[?\\]?)(=.*)?$');
958	var ajouts = [];
959	var u = (typeof(v)!=='object')?encodeURIComponent(v):v;
960	var na = [];
961	var v_read = null;
962	// lire les variables et agir
963	for(var n=0;n<args.length;n++){
964		var val = args[n];
965		try {
966			val = decodeURIComponent(val);
967		} catch(e) {}
968		var r=val.match(regexp);
969		if (r && r.length){
970			if (v==null){
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):'');
975				}
976				// c'est un scalaire, on retourne direct
977				else {
978					return (r.length>2 && typeof r[2]!=='undefined')?r[2].substring(1):'';
979				}
980			}
981			// suppression
982			else if (!v.length) {
983			}
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) != '[]') {
987				na.push(r[1]+'='+u);
988				ajouts.push(r[1]);
989			}
990			/* Pour les tableaux ont laisse tomber les valeurs de départ, on
991			remplira à l'étape suivante */
992			// else na.push(args[n]);
993		}
994		else
995			na.push(args[n]);
996	}
997
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);
1007				}
1008				else {
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]));
1012				}
1013			}
1014		}
1015	}
1016
1017	// recomposer l'adresse
1018	if (na.length){
1019		if (!sep) sep='&';
1020			a = a+"?"+na.join(sep);
1021	}
1022
1023	return a + ancre;
1024}
1025
1026
1027
1028// Ajaxer les formulaires qui le demandent, au demarrage
1029if (!window.var_zajax_content)
1030	window.var_zajax_content = 'contenu';
1031jQuery(function() {
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;});
1037});
1038
1039// ... et a chaque fois que le DOM change
1040onAjaxLoad(function() {
1041	if (jQuery){
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();
1048		else
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;});
1052	}
1053});
1054

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.