Basculer le menu
Changer de menu des préférences
Basculer le menu personnel
Non connecté(e)
Votre adresse IP sera visible au public si vous faites des modifications.

« MediaWiki:Gadget-explorer.js » : différence entre les versions

Page de l’interface de MediaWiki
mAucun résumé des modifications
mAucun résumé des modifications
 
(9 versions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
/**
/**
  * MediaWiki:Gadget-explorer.js
  * MediaWiki:Gadget-explorer.js
  * Explorateur de wiki — étape 3 : fetch et injection du shell.
  * Explorateur de wiki — étape 5 : chargement à la demande des chunks.
  *
  *
  * Au premier clic sur le déclencheur, fetch le HTML rendu de Modèle:Explorer
  * Au clic sur une rubrique, charge le sous-template correspondant et
  * via l'API MediaWiki et l'injecte dans le panneau. Les ouvertures suivantes
  * l'injecte dans le pane. Déclenche mw.hook('wikipage.content') pour
  * réutilisent le contenu déjà chargé.
  * que CategoryTree initialise ses arbres dans le contenu fraîchement
* injecté. Comportement accordéon : une seule rubrique active à la fois.
  */
  */
( function () {
( function () {
Ligne 31 : Ligne 32 :
         btn.setAttribute( 'aria-controls', ROOT_ID );
         btn.setAttribute( 'aria-controls', ROOT_ID );
         btn.setAttribute( 'aria-label', 'Ouvrir l\'explorateur' );
         btn.setAttribute( 'aria-label', 'Ouvrir l\'explorateur' );
         btn.textContent = '';
         btn.innerHTML = '<img src="/images/e/ef/Navigator-tree.png">';
         return btn;
         return btn;
     }
     }
Ligne 69 : Ligne 70 :
             shellLoading = false;
             shellLoading = false;
             delete root.dataset.loading;
             delete root.dataset.loading;
        } );
    }
    // --- Chunk loading ------------------------------------------------------
function loadChunk( menuItem ) {
    var chunkId = menuItem.dataset.chunk;
    var content = menuItem.querySelector( '.explorer-chunk-content' );
    if ( !content ) {
        return;
    }
    var state = content.dataset.state;
    if ( state === 'loaded' || state === 'loading' ) {
        return;
    }
    content.dataset.state = 'loading';
    var pageTitle = SHELL_PAGE + '/' + chunkId;
    var api = new mw.Api();
    // 1. Purger pour invalider le parser cache.
    api.postWithToken( 'csrf', {
        action: 'purge',
        titles: pageTitle,
        formatversion: 2
    } ).then( function () {
        // 2. Parser frais.
        return api.get( {
            action: 'parse',
            page: pageTitle,
            prop: 'text',
            disablelimitreport: 1,
            disabletoc: 1,
            formatversion: 2
        } );
    } ).then( function ( data ) {
        content.innerHTML = data.parse.text;
        content.dataset.state = 'loaded';
        mw.hook( 'wikipage.content' ).fire( $( content ) );
    } ).catch( function ( code, info ) {
        mw.log.error( '[explorer] failed to load chunk', chunkId, code, info );
        content.dataset.state = 'error';
        content.innerHTML = '<div class="explorer-error">Contenu indisponible.</div>';
    } );
}
    // --- Rubric activation (accordion) -------------------------------------
    function activateRubric( menuItem, root ) {
        // Désactiver les autres rubriques.
        var others = root.querySelectorAll( '.explorer-menu-item[data-active]' );
        Array.prototype.forEach.call( others, function ( el ) {
            if ( el !== menuItem ) {
                el.removeAttribute( 'data-active' );
            }
        } );
        // Toggle sur la rubrique cliquée.
        if ( menuItem.hasAttribute( 'data-active' ) ) {
            menuItem.removeAttribute( 'data-active' );
        } else {
            menuItem.setAttribute( 'data-active', '' );
            loadChunk( menuItem );
        }
    }
    // --- Event handlers -----------------------------------------------------
    function attachRubricHandler( root ) {
        root.addEventListener( 'click', function ( e ) {
            var label = e.target.closest( '.explorer-menu-label' );
            if ( !label ) {
                return;
            }
            var menuItem = label.closest( '.explorer-menu-item[data-chunk]' );
            if ( !menuItem ) {
                return;
            }
            activateRubric( menuItem, root );
        } );
    }
    function attachDismissHandlers( trigger, root ) {
        root.addEventListener( 'click', function ( e ) {
            if ( !e.target.closest( '.explorer-menu' ) ) {
                close( trigger, root );
            }
        } );
        document.addEventListener( 'keydown', function ( e ) {
            if ( e.key === 'Escape' && root.dataset.state === 'open' ) {
                close( trigger, root );
            }
         } );
         } );
     }
     }
Ligne 91 : Ligne 185 :
             open( trigger, root );
             open( trigger, root );
         }
         }
    }
   
    function attachDismissHandlers( trigger, root ) {
    root.addEventListener( 'click', function ( e ) {
        // Clic en dehors du contenu (donc dans le backdrop) → fermer.
        if ( !e.target.closest( '.explorer-menu' ) ) {
            close( trigger, root );
        }
    } );
    document.addEventListener( 'keydown', function ( e ) {
        if ( e.key === 'Escape' && root.dataset.state === 'open' ) {
            close( trigger, root );
        }
    } );
     }
     }


Ligne 121 : Ligne 200 :


         slot.appendChild( trigger );
         slot.appendChild( trigger );
        $(document.body).addClass('explorer-available');
         document.body.appendChild( root );
         document.body.appendChild( root );


Ligne 126 : Ligne 206 :
             toggle( trigger, root );
             toggle( trigger, root );
         } );
         } );
 
attachDismissHandlers( trigger, root );
        attachDismissHandlers( trigger, root );
        attachRubricHandler( root );
     }
     }



Dernière version du 6 juin 2026 à 14:07

/**
 * MediaWiki:Gadget-explorer.js
 * Explorateur de wiki — étape 5 : chargement à la demande des chunks.
 *
 * Au clic sur une rubrique, charge le sous-template correspondant et
 * l'injecte dans le pane. Déclenche mw.hook('wikipage.content') pour
 * que CategoryTree initialise ses arbres dans le contenu fraîchement
 * injecté. Comportement accordéon : une seule rubrique active à la fois.
 */
( function () {
    'use strict';

    // --- Configuration ------------------------------------------------------

    var HEADER_SLOT_SELECTOR = '.citizen-header__start';
    var TRIGGER_CLASS = 'explorer-trigger';
    var ROOT_ID = 'explorer-root';
    var SHELL_PAGE = 'Modèle:Explorer';

    // --- Internal state -----------------------------------------------------

    var shellLoaded = false;
    var shellLoading = false;

    // --- DOM construction ---------------------------------------------------

    function createTrigger() {
        var btn = document.createElement( 'button' );
        btn.type = 'button';
        btn.className = TRIGGER_CLASS;
        btn.setAttribute( 'aria-expanded', 'false' );
        btn.setAttribute( 'aria-controls', ROOT_ID );
        btn.setAttribute( 'aria-label', 'Ouvrir l\'explorateur' );
        btn.innerHTML = '<img src="/images/e/ef/Navigator-tree.png">';
        return btn;
    }

    function createRoot() {
        var root = document.createElement( 'div' );
        root.id = ROOT_ID;
        root.className = 'explorer-root';
        root.dataset.state = 'closed';
        return root;
    }

    // --- Shell loading ------------------------------------------------------

    function loadShell( root ) {
        if ( shellLoaded || shellLoading ) {
            return;
        }
        shellLoading = true;
        root.dataset.loading = 'true';

        var api = new mw.Api();
        api.get( {
            action: 'parse',
            page: SHELL_PAGE,
            prop: 'text',
            disablelimitreport: 1,
            disabletoc: 1,
            formatversion: 2
        } ).then( function ( data ) {
            root.innerHTML = data.parse.text;
            shellLoaded = true;
        } ).catch( function ( code, info ) {
            mw.log.error( '[explorer] failed to load shell', code, info );
            root.innerHTML = '<div class="explorer-error">Impossible de charger l\'explorateur.</div>';
        } ).always( function () {
            shellLoading = false;
            delete root.dataset.loading;
        } );
    }

    // --- Chunk loading ------------------------------------------------------

	function loadChunk( menuItem ) {
	    var chunkId = menuItem.dataset.chunk;
	    var content = menuItem.querySelector( '.explorer-chunk-content' );
	    if ( !content ) {
	        return;
	    }
	    var state = content.dataset.state;
	    if ( state === 'loaded' || state === 'loading' ) {
	        return;
	    }
	    content.dataset.state = 'loading';
	
	    var pageTitle = SHELL_PAGE + '/' + chunkId;
	    var api = new mw.Api();
	
	    // 1. Purger pour invalider le parser cache.
	    api.postWithToken( 'csrf', {
	        action: 'purge',
	        titles: pageTitle,
	        formatversion: 2
	    } ).then( function () {
	        // 2. Parser frais.
	        return api.get( {
	            action: 'parse',
	            page: pageTitle,
	            prop: 'text',
	            disablelimitreport: 1,
	            disabletoc: 1,
	            formatversion: 2
	        } );
	    } ).then( function ( data ) {
	        content.innerHTML = data.parse.text;
	        content.dataset.state = 'loaded';
	        mw.hook( 'wikipage.content' ).fire( $( content ) );
	    } ).catch( function ( code, info ) {
	        mw.log.error( '[explorer] failed to load chunk', chunkId, code, info );
	        content.dataset.state = 'error';
	        content.innerHTML = '<div class="explorer-error">Contenu indisponible.</div>';
	    } );
	}

    // --- Rubric activation (accordion) -------------------------------------

    function activateRubric( menuItem, root ) {
        // Désactiver les autres rubriques.
        var others = root.querySelectorAll( '.explorer-menu-item[data-active]' );
        Array.prototype.forEach.call( others, function ( el ) {
            if ( el !== menuItem ) {
                el.removeAttribute( 'data-active' );
            }
        } );

        // Toggle sur la rubrique cliquée.
        if ( menuItem.hasAttribute( 'data-active' ) ) {
            menuItem.removeAttribute( 'data-active' );
        } else {
            menuItem.setAttribute( 'data-active', '' );
            loadChunk( menuItem );
        }
    }

    // --- Event handlers -----------------------------------------------------

    function attachRubricHandler( root ) {
        root.addEventListener( 'click', function ( e ) {
            var label = e.target.closest( '.explorer-menu-label' );
            if ( !label ) {
                return;
            }
            var menuItem = label.closest( '.explorer-menu-item[data-chunk]' );
            if ( !menuItem ) {
                return;
            }
            activateRubric( menuItem, root );
        } );
    }

    function attachDismissHandlers( trigger, root ) {
        root.addEventListener( 'click', function ( e ) {
            if ( !e.target.closest( '.explorer-menu' ) ) {
                close( trigger, root );
            }
        } );

        document.addEventListener( 'keydown', function ( e ) {
            if ( e.key === 'Escape' && root.dataset.state === 'open' ) {
                close( trigger, root );
            }
        } );
    }

    // --- State management ---------------------------------------------------

    function open( trigger, root ) {
        root.dataset.state = 'open';
        trigger.setAttribute( 'aria-expanded', 'true' );
        loadShell( root );
    }

    function close( trigger, root ) {
        root.dataset.state = 'closed';
        trigger.setAttribute( 'aria-expanded', 'false' );
    }

    function toggle( trigger, root ) {
        if ( root.dataset.state === 'open' ) {
            close( trigger, root );
        } else {
            open( trigger, root );
        }
    }

    // --- Bootstrap ----------------------------------------------------------

    function init() {
        var slot = document.querySelector( HEADER_SLOT_SELECTOR );
        if ( !slot ) {
            mw.log.warn( '[explorer] header slot not found: ' + HEADER_SLOT_SELECTOR );
            return;
        }

        var trigger = createTrigger();
        var root = createRoot();

        slot.appendChild( trigger );
        $(document.body).addClass('explorer-available');
        document.body.appendChild( root );

        trigger.addEventListener( 'click', function () {
            toggle( trigger, root );
        } );

        attachDismissHandlers( trigger, root );
        attachRubricHandler( root );
    }

    if ( document.readyState === 'loading' ) {
        document.addEventListener( 'DOMContentLoaded', init );
    } else {
        init();
    }

}() );
Les témoins (''cookies'') nous aident à fournir nos services. En utilisant nos services, vous acceptez notre utilisation de témoins.