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.