PageSourceSearch

https://archidev.org/prive/javascript/ajaxCallback.js?1788435097

js archidev.org collected 2026-10-02 11:47:21 UTC 39,055 bytes, 1,178 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
7/**
8 * Test si on est dans l'admin de SPIP
9 *
10 * @return bool
11 *   Retourne true si on est dans l'admin, false sinon
12 */
13jQuery.spip.test_espace_prive = function () {
14	if (typeof spipConfig.core.test_espace_prive != undefined && spipConfig.core.test_espace_prive) {
15		return true;
16	}
17
18	return false;
19}
20
21// A plugin that wraps all ajax calls introducing a fixed callback function on ajax complete
22if(!jQuery.spip.load_handlers) {
23	jQuery.spip.load_handlers = new Array();
24
25	/**
26	 * OnAjaxLoad allow to
27	 * add a function to the list of those
28	 * to be executed on ajax load complete
29	 *
30	 * most of time function f is applied on the loaded data
31	 * if not known, the whole document is targetted
32	 *
33	 * @param function f
34	 */
35	function onAjaxLoad(f) {
36		jQuery.spip.load_handlers.push(f);
37	};
38
39	/**
40	 * Call the functions that have been added to onAjaxLoad
41	 * @param root
42	 */
43	jQuery.spip.triggerAjaxLoad = function (root) {
44		jQuery.spip.log('triggerAjaxLoad');
45		jQuery.spip.log(root);
46		for ( var i = 0; i < jQuery.spip.load_handlers.length; i++ )
47			jQuery.spip.load_handlers[i].apply( root );
48	};
49
50	jQuery.spip.intercepted={};
51
52	// intercept jQuery.fn.load
53	jQuery.spip.intercepted.load = jQuery.fn.load;
54	jQuery.fn.load = function( url, params, callback ) {
55		if ( typeof url !== "string") {
56			return jQuery.spip.intercepted.load.apply( this, arguments );
57		}
58
59		callback = callback || function(){};
60
61		// If the second parameter was provided
62		if ( params ) {
63			// If it's a function
64			if ( params.constructor == Function ) {
65				// We assume that it's the callback
66				callback = params;
67				params = null;
68			}
69		}
70		params = jQuery.extend(params, {triggerAjaxLoad:false}); // prevent $.ajax to triggerAjaxLoad
71		var callback2 = function() {jQuery.spip.log('jQuery.load');jQuery.spip.triggerAjaxLoad(this);callback.apply(this,arguments);};
72		return jQuery.spip.intercepted.load.apply(this,[url, params, callback2]);
73	};
74
75	// intercept jQuery.fn.ajaxSubmit
76	jQuery.spip.intercepted.ajaxSubmit = jQuery.fn.ajaxSubmit;
77	jQuery.fn.ajaxSubmit = function(options){
78		// find the first parent that will not be removed by formulaire_dyn_ajax
79		// or take the whole document
80		options = options || {};
81		if (typeof options.onAjaxLoad=="undefined" || options.onAjaxLoad!=false) {
82			var me=jQuery(this).parents('div.ajax');
83			if (me.length)
84				me=me.parent();
85			else
86				me = document;
87			if (typeof options=='function')
88					options = { success: options };
89			var callback = options.success || function(){};
90			options.success = function(){callback.apply(this,arguments);jQuery.spip.log('jQuery.ajaxSubmit');jQuery.spip.triggerAjaxLoad(me);}
91		}
92		return jQuery.spip.intercepted.ajaxSubmit.apply(this,[options]);
93	}
94
95	// intercept jQuery.ajax
96	jQuery.spip.intercepted.ajax = jQuery.ajax;
97	jQuery.ajax = function(url, settings) {
98		if (typeof settings == 'undefined') {
99			settings = {};
100			if (typeof url == 'object') {
101				settings = url;
102				url = null;
103			}
104		}
105		if (typeof url == 'string') {
106			settings['url'] = url;
107		}
108		// if triggerAjaxLoad is prevented, finish without faking callback
109		if (settings.data && settings.data['triggerAjaxLoad'] === false) {
110			settings.data['triggerAjaxLoad'] = null;
111			return jQuery.spip.intercepted.ajax(settings);
112		}
113		var s = jQuery.extend(true, {}, jQuery.ajaxSettings, settings);
114		var callbackContext = s.context || s;
115		try {
116			if (jQuery.ajax.caller==jQuery.spip.intercepted.load || jQuery.ajax.caller==jQuery.spip.intercepted.ajaxSubmit)
117				return jQuery.spip.intercepted.ajax(settings);
118		}
119		catch (err){}
120		var orig_complete = s.complete || function() {};
121		settings.complete = function(res,status) {
122			// Do not fire OnAjaxLoad if the dataType is not html
123			var dataType = settings.dataType;
124			var ct = (res && (typeof res.getResponseHeader == 'function'))
125				? res.getResponseHeader("content-type"): '';
126			var xml = !dataType && ct && ct.indexOf("xml") >= 0;
127			orig_complete.call( callbackContext, res, status);
128			if((!dataType && !xml) || dataType == "html") {
129				jQuery.spip.log('jQuery.ajax');
130				if (typeof s.onAjaxLoad=="undefined" || s.onAjaxLoad!=false)
131					jQuery.spip.triggerAjaxLoad(s.ajaxTarget?s.ajaxTarget:document);
132			}
133		};
134		return jQuery.spip.intercepted.ajax(settings);
135	};
136
137}
138
139/* jQuery.browser */
140jQuery.uaMatch = function( ua ) {
141	ua = ua.toLowerCase();
142
143	var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
144		/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
145		/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
146		/(msie) ([\w.]+)/.exec( ua ) ||
147		ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
148		[];
149
150	return {
151		browser: match[ 1 ] || "",
152		version: match[ 2 ] || "0"
153	};
154};
155
156// Don't clobber any existing jQuery.browser in case it's different
157if ( !jQuery.browser ) {
158	matched = jQuery.uaMatch( navigator.userAgent );
159	browser = {};
160
161	if ( matched.browser ) {
162		browser[ matched.browser ] = true;
163		browser.version = matched.version;
164	}
165
166	// Chrome is Webkit, but Webkit is also Safari.
167	if ( browser.chrome ) {
168		browser.webkit = true;
169	} else if ( browser.webkit ) {
170		browser.safari = true;
171	}
172
173	jQuery.browser = browser;
174}
175
176// jQuery.getScript cache par defaut
177jQuery.getScript = function(url,callback){
178	return $.ajax({
179		url: url,
180		dataType: "script",
181		success: callback,
182		cache: true
183	});
184}
185
186/**
187 * if not fully visible, scroll the page to position
188 * target block at the top of page
189 * if force = true, always scroll
190 *
191 * @param bool force
192 */
193jQuery.fn.positionner = function(force, setfocus) {
194	if (!this.length) {
195		return this;
196	}
197	var offset = jQuery(this).offset();
198	var hauteur = parseInt(jQuery(this).css('height'));
199	var marge = jQuery.spip.positionner_marge || 5;
200	var scrolltop = self['pageYOffset'] ||
201		jQuery.boxModel && document.documentElement[ 'scrollTop' ] ||
202		document.body[ 'scrollTop' ];
203	var h = jQuery(window).height();
204	var scroll=0;
205
206	if (force || (offset && offset['top'] - marge <= scrolltop)) {
207		scroll = offset['top'] - marge;
208	}
209	else if (offset && offset['top'] + hauteur - h + marge > scrolltop) {
210		scroll = Math.min(offset['top'] - marge - 15, offset['top'] + hauteur - h + 40);
211	}
212
213	if (scroll)
214		jQuery('html,body')
215		.animate({scrollTop: scroll}, 300);
216
217	// positionner le curseur dans la premiere zone de saisie
218	if (setfocus!==false)
219		jQuery(jQuery('*', this).filter('input[type=text],textarea')[0]).focus();
220	return this; // don't break the chain
221}
222
223// deux fonctions pour rendre l'ajax compatible Jaws
224jQuery.spip.virtualbuffer_id='spip_virtualbufferupdate';
225jQuery.spip.initReaderBuffer = function(){
226	if (jQuery('#'+jQuery.spip.virtualbuffer_id).length) return;
227	jQuery('body').append('<div 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"></div>');
228}
229jQuery.spip.updateReaderBuffer = function(){
230	var i = jQuery('#'+jQuery.spip.virtualbuffer_id);
231	if (!i.length) return;
232	// incrementons l'input hidden, ce qui a pour effet de forcer le rafraichissement du
233	// buffer du lecteur d'ecran (au moins dans Jaws)
234	i.val(parseInt(i.val())+1);
235}
236
237jQuery.fn.formulaire_setContainer = function(){
238	if (!this.closest('.ajax-form-container').length){
239		// eviter une double execution du js au moment de sa reinsertion dans le DOM par wrap()
240		// cf http://bugs.jquery.com/ticket/7447
241		this.find('script').remove();
242		var aria = this.data('aria');
243		var $container = jQuery('<div class="ajax-form-container"></div>');
244		if (aria && typeof aria === 'object') {
245			for (var i in aria) {
246				$container = $container.attr(i, aria[i]);
247			}
248		}
249		else {
250			aria = false;
251		}
252		this.wrap($container);
253		if (aria) {
254			// dans un formulaire, le screen reader relit tout a chaque saisie d'un caractere si on est en aria-live
255			jQuery('form',this).not('[aria-live]').attr('aria-live','off');
256		}
257	}
258	return this;
259}
260/**
261 * rechargement ajax d'un formulaire dynamique implemente par formulaires/xxx.html
262 * @param target
263 */
264jQuery.fn.formulaire_dyn_ajax = function(target) {
265	if (this.length)
266		jQuery.spip.initReaderBuffer();
267	return this.each(function() {
268		var scrollwhensubmit = !jQuery(this).is('.noscroll');
269		var cible = target || this;
270		jQuery(cible).formulaire_setContainer();
271		jQuery('form:not(.noajax):not(.bouton_action_post)', this).each(function(){
272		var leform = this;
273		var leclk,leclk_x,leclk_y;
274		var onError = function(xhr, status, error, $form){
275			jQuery(leform).ajaxFormUnbind().find('input[name="var_ajax"]').remove();
276			var msg = "Erreur";
277			if (typeof(error_on_ajaxform)!=="undefined") msg = error_on_ajaxform;
278			jQuery(leform).prepend("<p class='error ajax-error none'>"+msg+"</p>").find('.ajax-error').show('fast');
279			jQuery(cible).closest('.ajax-form-container').endLoading(true);
280		}
281		jQuery(this).prepend("<input type='hidden' name='var_ajax' value='form'>")
282		.ajaxForm({
283			beforeSubmit: function(){
284				// memoriser le bouton clique, en cas de repost non ajax
285				leclk = leform.clk;
286				var scrollwhensubmit_button = true;
287				if (leclk) {
288					scrollwhensubmit_button = !jQuery(leclk).is('.noscroll');
289					var n = leclk.name;
290					if (n && !leclk.disabled && leclk.type === "image") {
291						leclk_x = leform.clk_x;
292						leclk_y = leform.clk_y;
293					}
294				}
295				jQuery(cible).wrap('<div />');
296				cible = jQuery(cible).parent();
297				jQuery(cible).closest('.ajax-form-container').animateLoading();
298				if (scrollwhensubmit && scrollwhensubmit_button) {
299					jQuery(cible).positionner(false,false);
300				}
301			},
302			error: onError,
303			success: function(c, status, xhr , $form){
304				if (c.match(/^\s*noajax\s*$/)){
305					// le serveur ne veut pas traiter ce formulaire en ajax
306					// on resubmit sans ajax
307					jQuery("input[name=var_ajax]",leform).remove();
308					// si on a memorise le nom et la valeur du bouton clique
309					// les reinjecter dans le dom sous forme de input hidden
310					// pour que le serveur les recoive
311					if (leclk){
312						var n = leclk.name;
313						if (n && !leclk.disabled) {
314							jQuery(leform).prepend("<input type='hidden' name='"+n+"' value='"+leclk.value+"'>");
315							if (leclk.type === "image") {
316								jQuery(leform).prepend("<input type='hidden' name='"+n+".x' value='"+leform.clk_x+"'>");
317								jQuery(leform).prepend("<input type='hidden' name='"+n+".y' value='"+leform.clk_y+"'>");
318							}
319						}
320					}
321					jQuery(leform).ajaxFormUnbind().closest('.formulaire_spip').addClass('resubmit-noajax');
322					try {
323						leform.submit();
324					} catch (err) {
325						// just in case form has element with name/id of 'submit'
326						var submitFn = document.createElement('form').submit;
327						submitFn.apply(leform);
328					}
329				}
330				else {
331					if (!c.length || c.indexOf("ajax-form-is-ok")==-1)
332						return onError.apply(this,[status, xhr , $form]);
333					// commencons par vider le cache des urls, si jamais un js au retour
334					// essaye tout de suite de suivre un lien en cache
335					// dans le doute sur la validite du cache il vaut mieux l'invalider
336					var preloaded = jQuery.spip.preloaded_urls;
337					jQuery.spip.preloaded_urls = {};
338					jQuery(cible).html(c);
339					var a = jQuery('a:first',cible).eq(0);
340					var d = jQuery('div.ajax',cible);
341					if (!d.length){
342						// si pas .ajax dans le form, remettre la classe sur le div que l'on a insere
343						jQuery(cible).addClass('ajax');
344						if (!scrollwhensubmit)
345							jQuery(cible).addClass('noscroll');
346					}
347					else {
348						// sinon nettoyer les br ajaxie
349						d.siblings('br.bugajaxie').remove();
350						// desemboiter d'un niveau pour manger le div que l'on a insere
351						cible = jQuery(":first",cible);
352						cible.unwrap();
353					}
354					// chercher une ancre en debut de html pour positionner la page
355					if (a.length
356					  && a.is('a[name=ajax_ancre]')
357					  && jQuery(a.attr('href'),cible).length){
358						a = a.attr('href');
359						if (jQuery(a,cible).length)
360							setTimeout(function(){
361							jQuery(a,cible).positionner(false);
362							//a = a.split('#');
363							//window.location.hash = a[1];
364							},10);
365						jQuery(cible).closest('.ajax-form-container').endLoading(true);
366					}
367					else{
368						//jQuery(cible).positionner(false);
369						if (a.length && a.is('a[name=ajax_redirect]')){
370							a = a.get(0).href;
371							setTimeout(function(){
372								var cur = window.location.href.split('#');
373								document.location.replace(a);
374								// regarder si c'est juste un changement d'ancre : dans ce cas il faut reload
375								// (le faire systematiquement provoque des bugs)
376								if (cur[0]==a.split('#')[0]){
377									window.location.reload();
378								}
379							},10);
380							// ne pas arreter l'etat loading, puisqu'on redirige !
381							// mais le relancer car l'image loading a pu disparaitre
382							jQuery(cible).closest('.ajax-form-container').animateLoading();
383						}
384						else {
385							jQuery(cible).closest('.ajax-form-container').endLoading(true);
386						}
387					}
388					// si jamais le formulaire n'a pas un retour OK, retablissons le cache
389					// car a priori on a pas fait d'operation en base de donnee
390					if (!jQuery('.reponse_formulaire_ok',cible).length)
391						jQuery.spip.preloaded_urls = preloaded;
392					// mettre a jour le buffer du navigateur pour aider jaws et autres readers
393					// a supprimer ?
394					jQuery.spip.updateReaderBuffer();
395				}
396			}/*,
397			iframe: jQuery.browser.msie*/
398		})
399		// previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
400		// mais le marquer comme ayant l'ajax au cas ou on reinjecte du contenu ajax dedans
401		.addClass('noajax hasajax');
402		});
403  });
404}
405
406jQuery.fn.formulaire_verifier = function(callback, champ){
407	var erreurs = {'message_erreur':'form non ajax'};
408	var me=this;
409	// si on est aussi en train de submit pour de vrai, abandonner
410	if (jQuery(me).closest('.ajax-form-container').attr('aria-busy')!='true') {
411		if (jQuery(me).is('form.hasajax')){
412			jQuery(me).ajaxSubmit({
413				dataType:"json",
414				data:{formulaire_action_verifier_json:true},
415				success:function(errs){
416					var args = [errs, champ]
417					// si on est aussi en train de submit pour de vrai, abandonner
418					if (jQuery(me).closest('.ajax-form-container').attr('aria-busy')!='true')
419						callback.apply(me,args);
420				}
421			});
422		}
423		else
424			callback.apply(me,[erreurs, champ]);
425	}
426	return this;
427}
428
429jQuery.fn.formulaire_activer_verif_auto = function(callback){
430	callback = callback || formulaire_actualiser_erreurs;
431	var me = jQuery(this).closest('.ajax-form-container');
432	var check = function(){
433		var name=jQuery(this).attr('name');
434		// declencher apres 50ms pour ne pas double submit sur sequence saisie+submit
435		setTimeout(function(){me.find('form').formulaire_verifier(callback,name);},50);
436	}
437	var activer = function(){
438		if (me.find('form').attr('data-verifjson')!='on'){
439			me
440				.find('form')
441				.attr('data-verifjson','on')
442				.find('input,select,textarea')
443				.on('change', check);
444		}
445	}
446	jQuery(activer);
447	onAjaxLoad(function(){setTimeout(activer,150);});
448}
449
450function formulaire_actualiser_erreurs(erreurs){
451	var parent = jQuery(this).closest('.formulaire_spip');
452	if (!parent.length) return;
453	// d'abord effacer tous les messages d'erreurs
454	parent.find('.reponse_formulaire,.erreur_message').fadeOut().remove();
455	parent.find('.erreur').removeClass('erreur');
456	// ensuite afficher les nouveaux messages d'erreur
457	if (erreurs['message_ok'])
458		parent.find('form').before('<p class="reponse_formulaire reponse_formulaire_ok">'+erreurs['message_ok']+'</p>');
459	if (erreurs['message_erreur'])
460		parent.find('form').before('<p class="reponse_formulaire reponse_formulaire_erreur">'+erreurs['message_erreur']+'</p>');
461	for (var k in erreurs){
462		var saisie = parent.find('.editer_'+k);
463		if (saisie.length) {
464			saisie.addClass('erreur');
465			saisie.find('label').after('<span class="erreur_message">'+erreurs[k]+'</span>');
466		}
467	}
468}
469
470
471// permettre d'utiliser onclick='return confirm('etes vous sur?');' sur un lien ajax
472var ajax_confirm=true;
473var ajax_confirm_date=0;
474var spip_confirm = window.confirm;
475function _confirm(message){
476	ajax_confirm = spip_confirm(message);
477	if (!ajax_confirm) {
478		var d = new Date();
479		ajax_confirm_date = d.getTime();
480	}
481	return ajax_confirm;
482}
483window.confirm = _confirm;
484
485/**
486 * rechargement ajax d'une noisette implementee par {ajax}
487 * selecteur personalise, sera defini par defaut a '.pagination a,a.ajax'
488 */
489var ajaxbloc_selecteur;
490
491/**
492 * mise en cache des url. Il suffit de vider cete variable pour vider le cache
493 */
494jQuery.spip.preloaded_urls = {};
495
496/**
497 * Afficher dans la page
498 * le html d'un bloc ajax charge
499 * @param object blocfrag
500 * @param string c
501 * @param string href
502 * @param bool history
503 */
504jQuery.spip.on_ajax_loaded = function(blocfrag,c,href,history) {
505	history = history || (history==null);
506	if (typeof href == undefined || href==null)
507		history = false;
508	if (history)
509		jQuery.spip.setHistoryState(blocfrag);
510
511	if (jQuery(blocfrag).attr('data-loaded-callback')){
512		var callback = eval(jQuery(blocfrag).attr('data-loaded-callback'));
513		callback.call(blocfrag, c, href, history);
514	}
515	else {
516		jQuery(blocfrag)
517		.html(c)
518		.endLoading();
519	}
520
521	if (typeof href != undefined)
522		jQuery(blocfrag).attr('data-url',href);
523	if (history) {
524		var href_history = href;
525		if (href_history.indexOf('var_nullify') !== -1) {
526			href_history = parametre_url(href_history, 'var_nullify', '');
527		}
528		jQuery.spip.pushHistoryState(href_history);
529		jQuery.spip.setHistoryState(blocfrag);
530	}
531
532	var a = jQuery('a:first',jQuery(blocfrag)).eq(0);
533	if (a.length
534		&& a.is('a[name=ajax_ancre]')
535		&& jQuery(a.attr('href'),blocfrag).length){
536		a = a.attr('href');
537		jQuery(a,blocfrag).positionner(false);
538	}
539	jQuery.spip.log('on_ajax_loaded');
540	jQuery.spip.triggerAjaxLoad(blocfrag);
541	// si le fragment ajax est dans un form ajax,
542	// il faut remettre a jour les evenements attaches
543	// car le fragment peut comporter des submit ou button
544	a = jQuery(blocfrag).parents('form.hasajax')
545	if (a.length)
546		a.eq(0).removeClass('noajax').parents('div.ajax').formulaire_dyn_ajax();
547	jQuery.spip.updateReaderBuffer();
548}
549
550jQuery.spip.on_ajax_failed = function(blocfrag,statusCode,href,history) {
551	// marquer le bloc invalide
552	jQuery(blocfrag).addClass('invalid');
553	// si c'est une erreur 400 on a perdu la signature ajax
554	jQuery.spip.log("Echec AJAX statusCode " + statusCode)
555	history = history || (history==null);
556	// quelle que soit l'erreur, on redirige si c'était la nouvelle URL principale de la page
557	if (history) {
558		if (jQuery.spip.debug) {
559			jQuery.spip.log("On redirige sur sur " + href)
560		}
561		else {
562			window.location.href = href;
563		}
564	}
565}
566
567jQuery.spip.stateId=0;
568jQuery.spip.setHistoryState = function(blocfrag){
569	if (!window.history.replaceState) return;
570	// attribuer un id au bloc si il n'en a pas
571	if (!blocfrag.attr('id')){
572		while (jQuery('#ghsid'+jQuery.spip.stateId).length)
573			jQuery.spip.stateId++;
574		blocfrag.attr('id','ghsid'+jQuery.spip.stateId);
575	}
576	var href= blocfrag.attr('data-url') || blocfrag.attr('data-origin');
577	href = jQuery("<"+"a href='"+href+"'></a>").get(0).href;
578	var state={
579		id:blocfrag.attr('id'),
580		href: href
581	};
582	var ajaxid = blocfrag.attr('class').match(/\bajax-id-[\w-]+\b/);
583	if (ajaxid && ajaxid.length)
584		state["ajaxid"] = ajaxid[0];
585	// on remplace la variable qui decrit l'etat courant
586	// initialement vide
587	// -> elle servira a revenir dans l'etat courant
588	window.history.replaceState(state,window.document.title, window.document.location);
589}
590
591jQuery.spip.pushHistoryState = function(href, title){
592	if (!window.history.pushState)
593		return false;
594	window.history.pushState({}, title, href);
595}
596
597window.onpopstate = function(popState){
598	if (popState.state && popState.state.href){
599		var blocfrag=false;
600		if (popState.state.id){
601			blocfrag=jQuery('#'+popState.state.id);
602		}
603		if ((!blocfrag || !blocfrag.length) && popState.state.ajaxid){
604			blocfrag=jQuery('.ajaxbloc.'+popState.state.ajaxid);
605		}
606		if (blocfrag && blocfrag.length==1) {
607			jQuery.spip.ajaxClick(blocfrag,popState.state.href,{history:false});
608			return true;
609		}
610		// si on revient apres avoir rompu la chaine ajax, on a pu perdre l'id #ghsidxx ajoute en JS
611		// dans ce cas on redirige hors ajax
612		else {
613			window.location.href = popState.state.href;
614		}
615	}
616}
617
618/**
619 * Charger un bloc ajax represente par l'objet jQuery blocajax qui le pointe
620 * avec la requete ajax url, qui represente le lien href
621 * @param object blocfrag
622 *   bloc cible
623 * @param string url
624 *   url pour la requete ajax
625 * @param string href
626 *   url du lien clique
627 * @param object options
628 *   bool force : pour forcer la requete sans utiliser le cache
629 *   function callback : callback au retour du chargement
630 *   bool history : prendre en charge l'histrisation dans l'url
631 */
632jQuery.spip.loadAjax = function(blocfrag,url, href, options){
633	var force = options.force || false;
634	if (jQuery(blocfrag).attr('data-loading-callback')){
635		var callback = eval(jQuery(blocfrag).attr('data-loading-callback'));
636		callback.call(blocfrag,url,href,options);
637	}
638	else {
639		jQuery(blocfrag).animateLoading();
640	}
641	if (jQuery.spip.preloaded_urls[url] && !force) {
642		// si on est deja en train de charger ce fragment, revenir plus tard
643		if (jQuery.spip.preloaded_urls[url]=="<!--loading-->"){
644			setTimeout(function(){jQuery.spip.loadAjax(blocfrag,url,href,options);},100);
645			return;
646		}
647		jQuery.spip.on_ajax_loaded(blocfrag,jQuery.spip.preloaded_urls[url],href,options.history);
648	} else {
649		var d = new Date();
650		jQuery.spip.preloaded_urls[url] = "<!--loading-->";
651		jQuery.ajax({
652			url: parametre_url(url,'var_t',d.getTime()),
653			onAjaxLoad:false,
654			success: function(c){
655				jQuery.spip.on_ajax_loaded(blocfrag,c,href,options.history);
656				jQuery.spip.preloaded_urls[url] = c;
657				if (options.callback && typeof options.callback == "function")
658					options.callback.apply(blocfrag);
659			},
660			error: function(e){
661				jQuery.spip.preloaded_urls[url]='';
662				jQuery.spip.on_ajax_failed(blocfrag,e.status,href,options.history);
663			}
664		});
665	}
666}
667
668/**
669 * Calculer l'url ajax a partir de l'url du lien
670 * et de la variable d'environnement du bloc ajax
671 * passe aussi l'ancre eventuelle sous forme d'une variable
672 * pour que le serveur puisse la prendre en compte
673 * et la propager jusqu'a la reponse
674 * sous la forme d'un lien cache
675 *
676 * @param string href
677 * @param string ajax_env
678 */
679jQuery.spip.makeAjaxUrl = function(href,ajax_env,origin){
680	var url = href.split('#');
681	url[0] = parametre_url(url[0],'var_ajax',1);
682	url[0] = parametre_url(url[0],'var_ajax_env',ajax_env);
683
684	// les arguments de origin qui ne sont pas dans href doivent etre explicitement annules dans url
685	if (origin){
686		if (origin.indexOf('var_nullify') !== -1) {
687			origin = parametre_url(origin, 'var_nullify', '');
688		}
689		var p=origin.indexOf('?');
690		var nullify = [];
691		if (p!==-1){
692			// recuperer la base
693			var args = origin.substring(p+1).split('&');
694			var val;
695			var arg;
696			for(var n=0;n<args.length;n++){
697				arg = args[n].split('=');
698				arg = decodeURIComponent(arg[0]);
699				p = arg.indexOf('[');
700				if (p!==-1)
701					arg = arg.substring(0,p);
702				val = parametre_url(href,arg);
703				if ((typeof val=="undefined" || val==null) && nullify.indexOf(arg) === -1) {
704					nullify.push(arg);
705				}
706			}
707			if (nullify.length) {
708				url[0] = url[0] + '&' + 'var_nullify=' + encodeURIComponent(nullify.join('|'));
709			}
710		}
711	}
712
713	if (url[1])
714		url[0] = parametre_url(url[0],'var_ajax_ancre',url[1]);
715	return url[0];
716}
717
718/**
719 * fonction appelee sur l'evenement ajaxReload d'un bloc ajax
720 * que l'on declenche quand on veut forcer sa mise a jour
721 *
722 * @param object blocfrag
723 * @param object options
724 *   callback : fonction appelee apres le rechargement
725 *   href : url to load instead of origin url
726 *   args : arguments passes a l'url rechargee (permet une modif du contexte)
727 *   history : bool to specify if navigation history is modified by reload or not (false if not provided)
728 */
729jQuery.spip.ajaxReload = function(blocfrag, options){
730	var ajax_env = blocfrag.attr('data-ajax-env');
731	if (!ajax_env || ajax_env==undefined) return;
732	var href = options.href || blocfrag.attr('data-url') || blocfrag.attr('data-origin');
733	if (href && typeof href != undefined){
734		if (href.indexOf('var_nullify') !== -1) {
735			href = parametre_url(href, 'var_nullify', '');
736		}
737		options = options || {};
738		var callback=options.callback || null;
739		var history=options.history || false;
740		var args = options.args || {};
741		for (var key in args) {
742			href = parametre_url(href,key,args[key]==undefined?'':args[key],'&',args[key]==undefined?fal
742se:true);
743		}
744		var url = jQuery.spip.makeAjaxUrl(href,ajax_env,blocfrag.attr('data-origin'));
745		// recharger sans historisation dans l'url
746		jQuery.spip.loadAjax(blocfrag, url, href, {force:true, callback:callback, history:history});
747		return true;
748	}
749}
750
751/**
752 * fonction appelee sur l'evenement click d'un lien ajax
753 *
754 * @param object blocfrag
755 *   objet jQuery qui cible le bloc ajax contenant
756 * @param string href
757 *   url du lien a suivre
758 * @param object options
759 *   force : pour interdire l'utilisation du cache
760 *   history : pour interdire la mise en historique
761 */
762jQuery.spip.ajaxClick = function(blocfrag, href, options){
763	var ajax_env = blocfrag.attr('data-ajax-env');
764	if (!ajax_env || ajax_env==undefined) return;
765	if (!ajax_confirm) {
766		// on rearme pour le prochain clic
767		ajax_confirm=true;
768		var d = new Date();
769		// seule une annulation par confirm() dans les 2 secondes precedentes est prise en compte
770		if ((d.getTime()-ajax_confirm_date)<=2)
771			return false;
772	}
773	var url = jQuery.spip.makeAjaxUrl(href,ajax_env,blocfrag.attr('data-origin'));
774	jQuery.spip.loadAjax(blocfrag, url, href, options);
775	return false;
776}
777
778/**
779 * Implementer le comportemant des liens ajax
780 * et boutons post ajax qui se comportent
781 * comme un lien ajax
782 */
783jQuery.fn.ajaxbloc = function() {
784	// hack accessibilite vieille version de JAWS
785	// a supprimer ?
786	if (this.length)
787		jQuery.spip.initReaderBuffer();
788	if (ajaxbloc_selecteur==undefined)
789		ajaxbloc_selecteur = '.pagination a,a.ajax';
790
791	return this.each(function() {
792		// traiter les enfants d'abord :
793		// un lien ajax provoque le rechargement
794		// du plus petit bloc ajax le contenant
795		jQuery('div.ajaxbloc',this).ajaxbloc();
796		var blocfrag = jQuery(this);
797
798		var ajax_env = blocfrag.attr('data-ajax-env');
799		if (!ajax_env || ajax_env==undefined) return;
800
801		blocfrag.not('.bind-ajaxReload').on('ajaxReload', function(event, options){
802			if (jQuery.spip.ajaxReload(blocfrag,options))
803				// don't trig reload of parent blocks
804				event.stopPropagation();
805		}).addClass('bind-ajaxReload');
806
807		// "No aria is better than bad aria"
808		// blocfrag.attr('aria-live','polite').attr('aria-atomic','true')
809		// dans un formulaire, le screen reader relit tout a chaque saisie d'un caractere si on est en aria-live
810		// mettre un aria-live="off" sur les forms inclus dans ce bloc aria-live="polite"
811		// jQuery('form',this).not('[aria-live]').attr('aria-live','off');
812
813		jQuery(ajaxbloc_selecteur,this).not('.noajax,.bind-ajax')
814			.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)});})
815			.addClass('bind-ajax')
816			.filter('.preload').each(function(){
817				var href = this.href;
818				var url = jQuery.spip.makeAjaxUrl(href,ajax_env,blocfrag.attr('data-origin'));
819				if (!jQuery.spip.preloaded_urls[url]) {
820					jQuery.spip.preloaded_urls[url] = '<!--loading-->';
821					jQuery.ajax({url:url,onAjaxLoad:false,success:function(r){jQuery.spip.preloaded_urls[url]=r;},error:function(){jQuery.spip.preloaded_urls[url]='';}});
822				}
823			}); // previent qu'on ajax pas deux fois le meme lien
824
825		// ajaxer les boutons actions qui sont techniquement des form minimaux
826		// mais se comportent comme des liens
827		jQuery('form.bouton_action_post.ajax', this).not('.noajax,.bind-ajax').each(function(){
828			var leform = this;
829			var url = jQuery(this).attr('action').split('#');
830			var scrollwhensubmit = (!jQuery(this).is('.noscroll') && !jQuery('.submit',this).is('.noscroll'));
831			jQuery(this)
832			.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]+"'>":""))
833			.ajaxForm({
834				beforeSubmit: function(){
835					jQuery(blocfrag).animateLoading();
836					if (scrollwhensubmit) {
837						jQuery(blocfrag).positionner(false);
838					}
839				},
840				onAjaxLoad:false,
841				success: function(c){
842					jQuery.spip.on_ajax_loaded(blocfrag,c);
843					jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
844				},
845				error: function(e){
846					jQuery.spip.preloaded_urls = {}; // on vide le cache des urls car on a fait une action en bdd
847					var href = parametre_url(url, 'redirect');
848					if (!href) {
849						href = window.location.href;
850					}
851					// si c'est une erreur 400 c'est un fragment ajax invalide, il faut rediriger vers href
852					jQuery.spip.on_ajax_failed(blocfrag,e.status,href,e.status === 400);
853				}/*,
854				iframe: jQuery.browser.msie*/
855			})
856			.addClass('bind-ajax'); // previent qu'on n'ajaxera pas deux fois le meme formulaire en cas de ajaxload
857		});
858  });
859};
860
861/**
862 * Suivre un lien en simulant le click sur le lien
863 * Si le lien est ajax, on se contente de declencher l'evenement click()
864 * Si le lien est non ajax, on finit en remplacant l'url de la page
865 */
866jQuery.fn.followLink = function(){
867	$(this).click();
868	if (!$(this).is('.bind-ajax'))
869		window.location.href = $(this).get(0).href;
870	return this;
871}
872/**
873 * Recharger un bloc ajax pour le mettre a jour
874 * ajaxid est l'id passe en argument de INCLURE{ajax=ajaxid}
875 * options permet de definir une callbackk ou de passer des arguments a l'url
876 * au rechargement
877 * ajaxReload peut s'utiliser en passant un id :
878 * ajaxReload('xx');
879 * ou sur un objet jQuery
880 * jQuery(this).ajaxReload();
881 * Dans ce dernier cas, le plus petit conteneur ajax est recharge
882 *
883 * @param string ajaxid
884 * @param object options
885 *   callback : callback after reloading
886 *   href : url to load instead of origin url
887 *   args : {arg:value,...} to pass tu the url
888 *   history : bool to specify if navigation history is modified by reload or not (false if not provided)
889 */
890function ajaxReload(ajaxid, options){
891	jQuery('div.ajaxbloc.ajax-id-'+ajaxid).ajaxReload(options);
892}
893
894/**
895 * Variante jQuery de ajaxReload pour la syntaxe
896 * jQuery(..).ajaxReload();
897 * cf doc ci-dessus
898 * @param options
899 */
900jQuery.fn.ajaxReload = function(options){
901	options = options||{};
902	// just trigg the event, as it will bubble up the DOM
903	jQuery(this).trigger('ajaxReload', [options]);
904	return this; // don't break the chain
905}
906
907/**
908 * animation du bloc cible pour faire patienter
909 *
910 */
911jQuery.fn.animateLoading = function() {
912	this.attr('aria-busy','true').addClass('loading').children().css('opacity', 0.5);
913	if (typeof ajax_image_searching != 'undefined'){
914		var i = (this).find('.image_loading');
915		if (i.length) i.eq(0).html(ajax_image_searching);
916		else this.prepend('<span class="image_loading">'+ajax_image_searching+'</span>');
917	}
918	return this; // don't break the chain
919}
920// compatibilite avec ancien nommage
921jQuery.fn.animeajax = jQuery.fn.animateLoading;
922
923/**
924 * Fin de l'animation
925 * l'argument permet de forcer le raz du contenu si il est inchange
926 * @param hard
927 */
928jQuery.fn.endLoading = function(hard) {
929	hard = hard || false;
930	this.attr('aria-busy','false').removeClass('loading');
931	if (hard){
932		this.children().css('opacity', '');
933		this.find('.image_loading').html('');
934	}
935	return this; // don't break the chain
936}
937
938/**
939 * animation d'un item que l'on supprime :
940 * ajout de la classe remove avec un background tire de cette classe
941 * puis fading vers opacity 0
942 * quand l'element est masque, on retire les classes et css inline
943 *
944 * @param function callback
945 *
946 */
947jQuery.fn.animateRemove = function(callback){
948	if (this.length){
949		var me=this;
950		var color = $("<div class='remove'></div>").css('background-color');
951		var sel=$(this);
952		// if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
953		if (sel.is('tr'))
954			sel = sel.add('>td',sel);
955		sel.addClass('remove').css({backgroundColor: color}).animate({opacity: "0.0"}, 'fast', function(){
956			sel.removeClass('remove').css({backgroundColor: ''});
957			if (callback)
958				callback.apply(me);
959		});
960	}
961	return this; // don't break the chain
962}
963
964
965/**
966 * animation d'un item que l'on ajoute :
967 * ajout de la classe append
968 * fading vers opacity 1 avec background herite de la classe append,
969 * puis suppression progressive du background pour revenir a la valeur heritee
970 *
971 * @param function callback
972 */
973jQuery.fn.animateAppend = function(callback){
974	if (this.length){
975		var me=this;
976		// recuperer la couleur portee par la classe append (permet une personalisation)
977		var color = $("<div class='append'></div>").css('background-color');
978		var origin = $(this).css('background-color') || '#ffffff';
979		// pis aller
980		if (origin=='transparent') origin='#ffffff';
981		var sel=$(this);
982		// if target is a tr, include td childrens cause background color on tr doesn't works in a lot of browsers
983		if (sel.is('tr'))
984			sel = sel.add('>td',sel);
985		sel.css('opacity','0.0').addClass('append').css({backgroundColor: color}).animate({opacity: "1.0"}, 1000,function(){
986			sel.animate({backgroundColor: origin}, 3000,function(){
987				sel.removeClass('append').css({backgroundColor: ''});
988				if (callback)
989					callback.apply(me);
990			});
991		});
992	}
993	return this; // don't break the chain
994}
995
996/**
997 * Equivalent js de parametre_url php de spip
998 *
999 * Exemples :
1000 * parametre_url(url,suite,18) (ajout)
1001 * parametre_url(url,suite,'') (supprime)
1002 * parametre_url(url,suite) (lit la valeur suite)
1003 * parametre_url(url,suite[],1) (tableau valeurs multiples)
1004 * @param url
1005 *   url
1006 * @param c
1007 *   champ
1008 * @param v
1009 *   valeur
1010 * @param sep
1011 *  separateur '&' par defaut
1012 * @param force_vide
1013 *  si true et v='' insere &k= dans l'url au lieu de supprimer le k (false par defaut)
1014 *  permet de vider une valeur dans une requete ajax (dans un reload)
1015 */
1016function parametre_url(url,c,v,sep,force_vide){
1017	// Si l'URL n'est pas une chaine, on ne peut pas travailler dessus et on quitte
1018	if (typeof(url) == 'undefined'){
1019		url = '';
1020	}
1021
1022	var p;
1023	// lever l'#ancre
1024	var ancre='';
1025	var a='./';
1026	var args=[];
1027	p = url.indexOf('#');
1028	if (p!=-1) {
1029		ancre=url.substring(p);
1030		url = url.substring(0,p);
1031	}
1032
1033	// eclater
1034	p=url.indexOf('?');
1035	if (p!==-1){
1036		// recuperer la base
1037		if (p>0) a=url.substring(0,p);
1038		args = url.substring(p+1).split('&');
1039	}
1040	else
1041		a=url;
1042	var regexp = new RegExp('^(' + c.replace('[]','\\[\\]') + '\\[?\\]?)(=.*)?$');
1043	var ajouts = [];
1044	var u = (typeof(v)!=='object')?encodeURIComponent(v):v;
1045	var na = [];
1046	var v_read = null;
1047	// lire les variables et agir
1048	for(var n=0;n<args.length;n++){
1049		var val = args[n];
1050		try {
1051			val = decodeURIComponent(val);
1052		} catch(e) {}
1053		var r=val.match(regexp);
1054		if (r && r.length){
1055			if (v==null){
1056				// c'est un tableau, on memorise les valeurs
1057				if (r[1].substr(-2) == '[]') {
1058					if (!v_read) v_read = [];
1059					v_read.push((r.length>2 && typeof r[2]!=='undefined')?r[2].substring(1):'');
1060				}
1061				// c'est un scalaire, on retourne direct
1062				else {
1063					return (r.length>2 && typeof r[2]!=='undefined')?r[2].substring(1):'';
1064				}
1065			}
1066			// suppression
1067			else if (!v.length) {
1068			}
1069			// Ajout. Pour une variable, remplacer au meme endroit,
1070			// pour un tableau ce sera fait dans la prochaine boucle
1071			else if (r[1].substr(-2) != '[]') {
1072				na.push(r[1]+'='+u);
1073				ajouts.push(r[1]);
1074			}
1075			/* Pour les tableaux ont laisse tomber les valeurs de départ, on
1076			remplira à l'étape suivante */
1077			// else na.push(args[n]);
1078		}
1079		else
1080			na.push(args[n]);
1081	}
1082
1083	if (v==null) return v_read; // rien de trouve ou un tableau
1084	// traiter les parametres pas encore trouves
1085	if (v || v.length || force_vide) {
1086		ajouts = "="+ajouts.join("=")+"=";
1087		var all=c.split('|');
1088		for (n=0;n<all.length;n++){
1089			if (ajouts.search("="+all[n]+"=")==-1){
1090				if (typeof(v)!=='object'){
1091				  na.push(all[n] +'='+ u);
1092				}
1093				else {
1094					var id = ((all[n].substring(-2)=='[]')?all[n]:all[n]+"[]");
1095					for(p=0;p<v.length;p++)
1096						na.push(id +'='+ encodeURIComponent(v[p]));
1097				}
1098			}
1099		}
1100	}
1101
1102	// recomposer l'adresse
1103	if (na.length){
1104		if (!sep) sep='&';
1105			a = a+"?"+na.join(sep);
1106	}
1107
1108	return a + ancre;
1109}
1110
1111function spip_logo_survol_hover() {
1112	var me = jQuery(this);
1113	if (me.attr('data-src-hover')) {
1114		me.attr('data-src-original', me.attr('src'));
1115		me.attr('src', me.attr('data-src-hover'));
1116	}
1117}
1118
1119function spip_logo_survol_out() {
1120	var me = jQuery(this);
1121	if (me.attr('data-src-original')) {
1122		me.attr('src', me.attr('data-src-original'));
1123	}
1124}
1125
1126function disableClickAfterFormSubmit(){
1127	if (jQuery(this).is('.processing-submitted-form')) {
1128		return false;
1129	}
1130	jQuery(this)
1131		.addClass('processing-submitted-form')
1132		.find('button[type="submit"]')
1133		.attr('disabled','disabled')
1134		.addClass('disabled')
1135}
1136
1137function puce_enable_survol() {
1138	jQuery('span.puce_objet_popup a',this).not('.puce-survol-enabled').click(function(){
1139		selec_statut(jQuery(this).attr('data-puce-id'), jQuery(this).attr('data-puce-type'), jQuery(this).attr('data-puce-decal'), jQuery('img',this).attr('src'), jQuery(this).attr('data-puce-action'));
1140		return false;
1141	}).addClass('puce-survol-enabled');
1142	jQuery('span.puce_objet',this).not('.puce-survol-enabled').mouseover(function(){
1143		if (!this.puce_loaded) {
1144			this.puce_loaded = true; prepare_selec_statut(this, jQuery(this).attr('data-puce-nom'), jQuery(this).attr('data-puce-type'), jQuery(this).attr('data-puce-id'), jQuery(this).attr('data-puce-action'));
1145		}
1146	}).addClass('puce-survol-enabled');
1147}
1148
1149// Ajaxer les formulaires qui le demandent, au demarrage
1150if (!window.var_zajax_content)
1151	window.var_zajax_content = 'contenu';
1152jQuery(function() {
1153	jQuery('form:not(.bouton_action_post)').parents('div.ajax')
1154	.formulaire_dyn_ajax();
1155	jQuery('div.ajaxbloc').ajaxbloc();
1156	jQuery("input[placeholder]:text").placeholderLabel();
1157	jQuery('.spip_logo_survol').hover(spip_logo_survol_hover, spip_logo_survol_out);
1158	puce_enable_survol.apply(this);
1159
1160	jQuery('body').on('submit','form.bouton_action_post', disableClickAfterFormSubmit);
1161});
1162
1163// ... et a chaque fois que le DOM change
1164onAjaxLoad(function() {
1165	if (jQuery){
1166		jQuery('form:not(.bouton_action_post)', this).parents('div.ajax')
1167			.formulaire_dyn_ajax();
1168		if (jQuery(this).is('div.ajaxbloc'))
1169			jQuery(this).ajaxbloc();
1170		else if (jQuery(this).closest('div.ajaxbloc').length)
1171			jQuery(this).closest('div.ajaxbloc').ajaxbloc();
1172		else
1173			jQuery('div.ajaxbloc', this).ajaxbloc();
1174		jQuery("input[placeholder]:text",this).placeholderLabel();
1175		jQuery('.spip_logo_survol',this).hover(spip_logo_survol_hover, spip_logo_survol_out);
1176		puce_enable_survol.apply(this);
1177	}
1178});

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.