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.