MediaWiki:Timeless.js: Difference between revisions

From Exuvia Wiki
Created page with "/* =============================================================================== EXUVIA WIKI - SIDEBAR DROPDOWN MENUS =============================================================================== This script converts sidebar entries into expandable dropdown menus. The sidebar is structured like this: ** Locations *** Continents *** Kingdoms *** Towns ** Religions *** The Valor *** The Brumal The script automatically detects this struc..."
 
No edit summary
Line 1: Line 1:
/*
/*
===============================================================================
===============================================================================
EXUVIA WIKI - SIDEBAR DROPDOWN MENUS
EXUVIA WIKI SIDEBAR DROPDOWNS
===============================================================================
===============================================================================


This script converts sidebar entries into expandable dropdown menus.
The sidebar contains the top-level navigation:


The sidebar is structured like this:
    Locations
    Religions
    People
    World Building


    ** Locations
The JavaScript turns those entries into expandable menus.
    *** Continents
    *** Kingdoms
    *** Towns


    ** Religions
Each dropdown's contents are defined HERE.
    *** The Valor
    *** The Brumal


The script automatically detects this structure.
To add another dropdown later, add another entry to the "menus" object.


You do NOT need to add anything to this JavaScript when creating another
===============================================================================
dropdown.
*/
 
$( function () {


For example, adding this to MediaWiki:Sidebar:
    /*
    ===========================================================================
    DROPDOWN CONTENT
    ===========================================================================


     ** Organizations
     Each key must exactly match the text of a sidebar entry.
    *** The Theurgic Knights
    *** ZIMS
    *** YCCC


will automatically create:
    The value is an array containing the pages that should appear underneath
    that entry.


     Organizations
     Example:
        The Theurgic Knights
        ZIMS
        YCCC


        Locations: [
            'Continents',
            'Kingdoms',
            'Towns'
        ]


===============================================================================
    creates:
*/


        Locations ▼
            Continents
            Kingdoms
            Towns


/*
    ===========================================================================
===============================================================================
    */
1. WAIT FOR THE PAGE TO FINISH LOADING
===============================================================================


MediaWiki may load this script before the sidebar has finished being created.
    var menus = {


$( function () { ... } );
        Locations: [
            'Continents',
            'Kingdoms',
            'Towns'
        ]


waits until the page is ready before running the code.
        /*
        Add future dropdowns here.


===============================================================================
        Example:
*/


$( function () {
        Religions: [
            'The Valor',
            'The Brumal'
        ],


        People: [
            'High Lord Kip',
            'Queen Melena'
        ],


    /*
        'World Building': [
    ===========================================================================
            'History',
    2. FIND THE TIMeless SIDEBAR
            'Magic',
    ===========================================================================
            'War'
        ]
        */


     #mw-site-navigation
     };


    is the main navigation area used by Timeless.


    /*
    ===========================================================================
    FIND THE TIMELESS SIDEBAR
     ===========================================================================
     ===========================================================================
     */
     */


     var sidebar = $( '#mw-site-navigation' );
     var sidebar = $( '#mw-site-navigation' );
    /*
    If the sidebar cannot be found, stop.
    This prevents JavaScript errors.
    ===========================================================================
    */


     if ( !sidebar.length ) {
     if ( !sidebar.length ) {
Line 88: Line 98:
     /*
     /*
     ===========================================================================
     ===========================================================================
     3. FIND SIDEBAR SECTIONS
     PROCESS EACH DROPDOWN
    ===========================================================================
 
    Timeless puts groups of sidebar links inside "portal" elements.
 
    We examine every portal separately.
 
     ===========================================================================
     ===========================================================================
     */
     */


     sidebar.find( '.portal' ).each( function () {
     Object.keys( menus ).forEach( function ( menuName ) {
 
        var portal = $( this );
 


         /*
         /*
         =======================================================================
         Find the sidebar link whose visible text matches the menu name.
        4. FIND THE SIDEBAR LIST
        =======================================================================
 
        Sidebar links are normally contained inside a <ul>.
 
        ===========================================================================
         */
         */


         var list = portal.find( 'ul' ).first();
         var mainLink = sidebar.find( 'a' ).filter( function () {
            return $.trim( $( this ).text() ) === menuName;
        } ).first();




         /*
         /*
         If there isn't a list, there is nothing to modify.
         If the sidebar entry doesn't exist, skip it.
 
        ===========================================================================
         */
         */


         if ( !list.length ) {
         if ( !mainLink.length ) {
             return;
             return;
         }
         }
Line 128: Line 123:


         /*
         /*
         =======================================================================
         Find the <li> containing the sidebar link.
        5. LOOK AT EVERY SIDEBAR ITEM
         */
         =======================================================================


         Each sidebar entry is normally an <li>.
         var parent = mainLink.closest( 'li' );


        We examine each one to determine whether it should become a dropdown.


         ===========================================================================
         /*
        Create the dropdown list.
         */
         */


         list.children( 'li' ).each( function () {
         var dropdown = $( '<ul>' )
            .addClass( 'exuvia-dropdown-menu' );


            var item = $( this );


        /*
        Add each page to the dropdown.
        */


            /*
        menus[ menuName ].forEach( function ( pageName ) {
            ===================================================================
            6. LOOK FOR CHILD ITEMS
            ===================================================================


             A normal sidebar entry looks like:
             var link = $( '<a>' )
                .attr( 'href', mw.util.getUrl( pageName ) )
                .text( pageName );


                <li>
            var item = $( '<li>' )
                    <a>Locations</a>
                 .append( link );
                 </li>


             A dropdown entry needs another list underneath it:
             dropdown.append( item );


                <li>
        } );
                    <a>Locations</a>


                    <ul>
                        <li>
                            <a>Continents</a>
                        </li>
                    </ul>
                </li>


            If the <li> contains another <ul>, it has children.
        /*
        Add the dropdown underneath the main navigation item.
        */


            ===================================================================
        parent.append( dropdown );
            */


            var childMenu = item.children( 'ul' );


        /*
        Hide the dropdown when the page first loads.
        */


            /*
        dropdown.hide();
            ===================================================================
            7. IGNORE NORMAL LINKS
            ===================================================================


            If there isn't a child menu, this is just a normal sidebar link.


            For example:
        /*
        Make the main navigation item behave like a button.


                ** About
        Clicking it opens or closes the dropdown instead of opening a page.
                ** Contact
        */


            Those remain normal links.
        mainLink.on( 'click', function ( event ) {


             ===================================================================
             event.preventDefault();
            */


             if ( !childMenu.length ) {
             dropdown.stop( true, true ).slideToggle( 150 );
                return;
            }


        } );


            /*
            ===================================================================
            8. FIND THE TOP-LEVEL LINK
            ===================================================================


            This is the link that currently says something like:
        /*
 
        Add an arrow so users know that this item expands.
                Locations
        */
 
            We are going to turn this into a button.
 
            ===========================================================================
            */
 
            var mainLink = item.children( 'a' );
 
 
            /*
            ===================================================================
            9. SAFETY CHECK
            ===================================================================
 
            If no link exists, there is nothing to turn into a dropdown button.
 
            ===================================================================
            */
 
            if ( !mainLink.length ) {
                return;
            }
 
 
            /*
            ===================================================================
            10. PREVENT THE MAIN LINK FROM NAVIGATING
            ===================================================================
 
            The user specifically wants:
 
                Clicking Locations = open/close menu
 
            NOT:
 
                Clicking Locations = go to a Locations page
 
            preventDefault() prevents the browser from following the link.
 
            ===================================================================
            */
 
            mainLink.on( 'click', function ( event ) {
 
                event.preventDefault();
 
 
                /*
                ===============================================================
                11. OPEN OR CLOSE THE DROPDOWN
                ===============================================================
 
                slideToggle() does exactly what is wanted:
 
                    closed → open
 
                    open → closed
 
                150 means the animation lasts approximately 150 milliseconds.
 
                ===============================================================
                */
 
                childMenu.stop( true, true ).slideToggle( 150 );
 
 
                /*
                ===============================================================
                12. ACCESSIBILITY INFORMATION
                ===============================================================
 
                aria-expanded tells screen readers whether the menu is open.
 
                ===============================================================
                */
 
                var isOpen = childMenu.is( ':visible' );
 
                mainLink.attr(
                    'aria-expanded',
                    isOpen ? 'true' : 'false'
                );
 
            });
 
 
            /*
            ===================================================================
            13. MARK THE LINK AS A DROPDOWN
            ===================================================================
 
            aria-haspopup tells accessibility software that this element
            controls another menu.
 
            ===================================================================
            */
 
            mainLink.attr( 'aria-haspopup', 'true' );
 
            mainLink.attr( 'aria-expanded', 'false' );
 
 
            /*
            ===================================================================
            14. ADD A DROPDOWN ARROW
            ===================================================================
 
            This adds a small visual arrow after the title.
 
                Locations ▼
 
            The arrow itself does not affect navigation.
 
            ===================================================================
            */
 
            mainLink.append(
                $( '<span>' )
                    .addClass( 'exuvia-dropdown-arrow' )
                    .text( ' ▼' )
            );
 
 
            /*
            ===================================================================
            15. HIDE THE CHILDREN WHEN THE PAGE LOADS
            ===================================================================
 
            Dropdowns start closed.
 
            The user can open them by clicking the title.
 
            ===================================================================
            */
 
            childMenu.hide();
 
 
            /*
            ===================================================================
            16. GIVE THE DROPDOWN A CLASS
            ===================================================================
 
            This lets the CSS identify these menus.
 
            ===================================================================
            */
 
            childMenu.addClass( 'exuvia-dropdown-menu' );
 
 
            /*
            ===================================================================
            17. MARK THE PARENT ITEM
            ===================================================================
 
            This gives the parent <li> a class.
 
            It can be useful for CSS later.
 
            ===================================================================
            */
 
            item.addClass( 'exuvia-dropdown-parent' );


         });
         mainLink.append(
            $( '<span>' )
                .addClass( 'exuvia-dropdown-arrow' )
                .text( ' ▼' )
        );


     });
     } );


} );
} );

Revision as of 01:50, 26 August 2026

/*
===============================================================================
EXUVIA WIKI SIDEBAR DROPDOWNS
===============================================================================

The sidebar contains the top-level navigation:

    Locations
    Religions
    People
    World Building

The JavaScript turns those entries into expandable menus.

Each dropdown's contents are defined HERE.

To add another dropdown later, add another entry to the "menus" object.

===============================================================================
*/

$( function () {

    /*
    ===========================================================================
    DROPDOWN CONTENT
    ===========================================================================

    Each key must exactly match the text of a sidebar entry.

    The value is an array containing the pages that should appear underneath
    that entry.

    Example:

        Locations: [
            'Continents',
            'Kingdoms',
            'Towns'
        ]

    creates:

        Locations ▼
            Continents
            Kingdoms
            Towns

    ===========================================================================
    */

    var menus = {

        Locations: [
            'Continents',
            'Kingdoms',
            'Towns'
        ]

        /*
        Add future dropdowns here.

        Example:

        Religions: [
            'The Valor',
            'The Brumal'
        ],

        People: [
            'High Lord Kip',
            'Queen Melena'
        ],

        'World Building': [
            'History',
            'Magic',
            'War'
        ]
        */

    };


    /*
    ===========================================================================
    FIND THE TIMELESS SIDEBAR
    ===========================================================================
    */

    var sidebar = $( '#mw-site-navigation' );

    if ( !sidebar.length ) {
        return;
    }


    /*
    ===========================================================================
    PROCESS EACH DROPDOWN
    ===========================================================================
    */

    Object.keys( menus ).forEach( function ( menuName ) {

        /*
        Find the sidebar link whose visible text matches the menu name.
        */

        var mainLink = sidebar.find( 'a' ).filter( function () {
            return $.trim( $( this ).text() ) === menuName;
        } ).first();


        /*
        If the sidebar entry doesn't exist, skip it.
        */

        if ( !mainLink.length ) {
            return;
        }


        /*
        Find the <li> containing the sidebar link.
        */

        var parent = mainLink.closest( 'li' );


        /*
        Create the dropdown list.
        */

        var dropdown = $( '<ul>' )
            .addClass( 'exuvia-dropdown-menu' );


        /*
        Add each page to the dropdown.
        */

        menus[ menuName ].forEach( function ( pageName ) {

            var link = $( '<a>' )
                .attr( 'href', mw.util.getUrl( pageName ) )
                .text( pageName );

            var item = $( '<li>' )
                .append( link );

            dropdown.append( item );

        } );


        /*
        Add the dropdown underneath the main navigation item.
        */

        parent.append( dropdown );


        /*
        Hide the dropdown when the page first loads.
        */

        dropdown.hide();


        /*
        Make the main navigation item behave like a button.

        Clicking it opens or closes the dropdown instead of opening a page.
        */

        mainLink.on( 'click', function ( event ) {

            event.preventDefault();

            dropdown.stop( true, true ).slideToggle( 150 );

        } );


        /*
        Add an arrow so users know that this item expands.
        */

        mainLink.append(
            $( '<span>' )
                .addClass( 'exuvia-dropdown-arrow' )
                .text( ' ▼' )
        );

    } );

} );