MediaWiki:Timeless.js: Difference between revisions

From Exuvia Wiki
No edit summary
No edit summary
 
Line 6: Line 6:
     * ============================================================
     * ============================================================
     *
     *
     * The names here must match the names in MediaWiki:Sidebar.
     * A string creates a normal page link.
     *
     *
     * To add another dropdown, simply add another entry here.
     * An object creates a second-level dropdown:
    *
    * 'Continents': [
    *    'Alorea',
    *    'Another Continent'
    * ]
    *
    * This can be nested as deeply as desired.
     */
     */


     var menus = {
     var menus = {
        'Locations': [
            'Continents',
            'Kingdoms',
            'Towns'
        ],


         'Religions': [
        'Locations': {
            'The Valor',
 
            'The Brumal'
            'Continents': [
         ],
                'Alorea',
                'Another Continent'
            ],
 
            'Kingdoms': [
                'Koble',
                'Yamen',
                'Zagis',
                'Tekk',
                'Frossik'
            ],
 
            'Towns': [
                'Town A',
                'Town B'
            ]
        },
 
 
         'Religions': {
 
            'Kippelian Pantheon': [
                'The Valor',
                'The Brumal'
            ],
 
            'Other Religions': [
                'Religion A',
                'Religion B'
            ]
         },
 


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


         'World Building': [
            'Kippelian Empire': [
            'History',
                'High Lord Kip',
             'Magic',
                'Queen Melena'
             'War'
            ],
         ]
 
            'Other People': [
                'Person A',
                'Person B'
            ]
        },
 
 
         'World Building': {
 
            'History': [
                'War of Unification',
                'History of Kippel'
            ],
 
             'Magic': [
                'Magic',
                'Necromancy'
            ],
 
             'War': [
                'War of Unification',
                'Thalassic War'
            ]
         }
     };
     };


Line 56: Line 110:


     var links = sidebar.getElementsByTagName( 'a' );
     var links = sidebar.getElementsByTagName( 'a' );
    var sidebarLinks = Array.prototype.slice.call( links );




     /*
     /*
     * Convert the HTMLCollection into a normal array.
     * ============================================================
    * CREATE A DROPDOWN
    * ============================================================
    *
    * This function creates a dropdown from an object.
    *
    * It can call itself to create another dropdown inside it.
     */
     */


     var sidebarLinks = Array.prototype.slice.call( links );
     function createDropdown( menuData, parentLink ) {
 
        var dropdown = document.createElement( 'ul' );
 
        dropdown.className = 'exuvia-dropdown-menu exuvia-dropdown-level-2';
 
        dropdown.style.display = 'none';
 
 
        Object.keys( menuData ).forEach( function ( name ) {
 
            var item = document.createElement( 'li' );
 
 
            /*
            * ====================================================
            * SECOND-LEVEL DROPDOWN
            * ====================================================
            *
            * If the value is an array, it is a normal list of
            * pages.
            *
            * If the value is an object, it contains another
            * dropdown.
            */
 
            if ( Array.isArray( menuData[ name ] ) ) {
 
                /*
                * Normal page group
                */
 
                var link = document.createElement( 'a' );
 
                link.href = mw.util.getUrl( name );
 
                link.textContent = name;
 
                item.appendChild( link );
 
 
                /*
                * If this is being used as a dropdown title,
                * it can be turned into a submenu later.
                */
 
            } else {
 
                /*
                * =================================================
                * CREATE SECOND-LEVEL TITLE
                * =================================================
                */
 
                var link = document.createElement( 'a' );
 
                link.href = '#';
 
                link.textContent = name;
 
                link.className = 'exuvia-dropdown-title';
 
 
                /*
                * Arrow
                */
 
                var arrow = document.createElement( 'span' );
 
                arrow.className = 'exuvia-dropdown-arrow';
 
                arrow.textContent = ' ▼';
 
                link.appendChild( arrow );
 
 
                /*
                * Create the next level recursively.
                */
 
                var submenu = createDropdown(
                    menuData[ name ],
                    link
                );
 
 
                /*
                * Add submenu to this item.
                */
 
                item.appendChild( link );
 
                item.appendChild( submenu );
 
 
                /*
                * =================================================
                * OPEN / CLOSE SUBMENU
                * =================================================
                */
 
                link.addEventListener( 'click', function ( event ) {
 
                    event.preventDefault();
 
                    if ( submenu.style.display === 'none' ) {
 
                        submenu.style.display = 'block';
 
                        arrow.textContent = ' ▲';
 
                    } else {
 
                        submenu.style.display = 'none';
 
                        arrow.textContent = ' ▼';
 
                    }
 
                });
 
            }
 
 
            dropdown.appendChild( item );
 
        });
 
 
        return dropdown;
    }




     /*
     /*
     * ============================================================
     * ============================================================
     * PROCESS EACH DROPDOWN
     * PROCESS TOP-LEVEL MENUS
     * ============================================================
     * ============================================================
     */
     */
Line 77: Line 269:


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


Line 85: Line 277:


             if ( text === menuName ) {
             if ( text === menuName ) {
                 mainLink = link;
                 mainLink = link;
                 return true;
                 return true;
             }
             }
Line 93: Line 287:
         });
         });


        /*
        * If the link wasn't found, don't do anything.
        */


         if ( !mainLink ) {
         if ( !mainLink ) {
Line 107: Line 297:
         * FIND THE SIDEBAR ITEM
         * FIND THE SIDEBAR ITEM
         * ========================================================
         * ========================================================
        *
        * Walk upward until we find the list item containing
        * the link.
         */
         */


Line 121: Line 308:
         /*
         /*
         * ========================================================
         * ========================================================
         * CREATE THE DROPDOWN
         * CREATE TOP-LEVEL DROPDOWN
         * ========================================================
         * ========================================================
         */
         */
Line 127: Line 314:
         var dropdown = document.createElement( 'ul' );
         var dropdown = document.createElement( 'ul' );


         dropdown.className = 'exuvia-dropdown-menu';
         dropdown.className = 'exuvia-dropdown-menu exuvia-dropdown-level-1';
 
        dropdown.style.display = 'none';




         /*
         /*
         * ========================================================
         * ========================================================
         * CREATE THE CHILD LINKS
         * CREATE FIRST-LEVEL ITEMS
         * ========================================================
         * ========================================================
         */
         */


         menus[ menuName ].forEach( function ( pageName ) {
         Object.keys( menus[ menuName ] ).forEach( function ( name ) {


             var item = document.createElement( 'li' );
             var item = document.createElement( 'li' );
            /*
            * Every entry in the top-level menu is treated as
            * a submenu title.
            */


             var link = document.createElement( 'a' );
             var link = document.createElement( 'a' );


             link.href = mw.util.getUrl( pageName );
             link.href = '#';


             link.textContent = pageName;
             link.textContent = name;
 
            link.className = 'exuvia-dropdown-title';
 
 
            /*
            * Arrow
            */
 
            var arrow = document.createElement( 'span' );
 
            arrow.className = 'exuvia-dropdown-arrow';
 
            arrow.textContent = ' ▼';
 
            link.appendChild( arrow );
 
 
            /*
            * ====================================================
            * CREATE SECOND LEVEL
            * ====================================================
            */
 
            var submenuData = menus[ menuName ][ name ];
 
            var submenu = document.createElement( 'ul' );
 
            submenu.className =
                'exuvia-dropdown-menu exuvia-dropdown-level-2';
 
            submenu.style.display = 'none';
 
 
            /*
            * Add the actual pages.
            */
 
            submenuData.forEach( function ( pageName ) {
 
                var pageItem = document.createElement( 'li' );
 
                var pageLink = document.createElement( 'a' );
 
                pageLink.href = mw.util.getUrl( pageName );
 
                pageLink.textContent = pageName;
 
                pageItem.appendChild( pageLink );
 
                submenu.appendChild( pageItem );
 
            });
 
 
            /*
            * Add submenu.
            */


             item.appendChild( link );
             item.appendChild( link );
            item.appendChild( submenu );


             dropdown.appendChild( item );
             dropdown.appendChild( item );
            /*
            * ====================================================
            * OPEN / CLOSE SECOND LEVEL
            * ====================================================
            */
            link.addEventListener( 'click', function ( event ) {
                event.preventDefault();
                if ( submenu.style.display === 'none' ) {
                    submenu.style.display = 'block';
                    arrow.textContent = ' ▲';
                } else {
                    submenu.style.display = 'none';
                    arrow.textContent = ' ▼';
                }
            });


         });
         });
Line 155: Line 435:
         /*
         /*
         * ========================================================
         * ========================================================
         * ADD THE DROPDOWN TO THE SIDEBAR
         * ADD DROPDOWN TO SIDEBAR
         * ========================================================
         * ========================================================
         */
         */
Line 164: Line 444:
         /*
         /*
         * ========================================================
         * ========================================================
         * HIDE IT INITIALLY
         * TOP-LEVEL ARROW
         * ========================================================
         * ========================================================
         */
         */


         dropdown.style.display = 'none';
         var arrow = document.createElement( 'span' );


        arrow.className = 'exuvia-dropdown-arrow';


         /*
         arrow.textContent = ' ▼';
        * ========================================================
        * ADD THE ARROW
        * ========================================================
        */


var arrow = document.createElement( 'span' );
        mainLink.appendChild( arrow );


arrow.className = 'exuvia-dropdown-arrow';
arrow.textContent = ' ▼';
mainLink.appendChild( arrow );


        /*
        * Mark as dropdown title.
        */


/*
        mainLink.classList.add( 'exuvia-dropdown-title' );
* Mark this link as a dropdown title.
*
* This gives the CSS a reliable way to distinguish:
*
*    Locations
*
* from:
*
*    Continents
*    Kingdoms
*    Towns
*/


mainLink.classList.add( 'exuvia-dropdown-title' );


         /*
         /*
         * ========================================================
         * ========================================================
         * MAKE THE TITLE A BUTTON
         * OPEN / CLOSE TOP LEVEL
         * ========================================================
         * ========================================================
        *
        * Clicking the title does NOT open a page.
         */
         */


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


             event.preventDefault();
             event.preventDefault();

Latest revision as of 23:35, 26 August 2026

$( function () {

    /*
     * ============================================================
     * DROPDOWN MENU CONTENT
     * ============================================================
     *
     * A string creates a normal page link.
     *
     * An object creates a second-level dropdown:
     *
     * 'Continents': [
     *     'Alorea',
     *     'Another Continent'
     * ]
     *
     * This can be nested as deeply as desired.
     */

    var menus = {

        'Locations': {

            'Continents': [
                'Alorea',
                'Another Continent'
            ],

            'Kingdoms': [
                'Koble',
                'Yamen',
                'Zagis',
                'Tekk',
                'Frossik'
            ],

            'Towns': [
                'Town A',
                'Town B'
            ]
        },


        'Religions': {

            'Kippelian Pantheon': [
                'The Valor',
                'The Brumal'
            ],

            'Other Religions': [
                'Religion A',
                'Religion B'
            ]
        },


        'People': {

            'Kippelian Empire': [
                'High Lord Kip',
                'Queen Melena'
            ],

            'Other People': [
                'Person A',
                'Person B'
            ]
        },


        'World Building': {

            'History': [
                'War of Unification',
                'History of Kippel'
            ],

            'Magic': [
                'Magic',
                'Necromancy'
            ],

            'War': [
                'War of Unification',
                'Thalassic War'
            ]
        }
    };


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

    var sidebar = document.getElementById( 'mw-site-navigation' );

    if ( !sidebar ) {
        return;
    }


    /*
     * ============================================================
     * FIND ALL LINKS IN THE SIDEBAR
     * ============================================================
     */

    var links = sidebar.getElementsByTagName( 'a' );

    var sidebarLinks = Array.prototype.slice.call( links );


    /*
     * ============================================================
     * CREATE A DROPDOWN
     * ============================================================
     *
     * This function creates a dropdown from an object.
     *
     * It can call itself to create another dropdown inside it.
     */

    function createDropdown( menuData, parentLink ) {

        var dropdown = document.createElement( 'ul' );

        dropdown.className = 'exuvia-dropdown-menu exuvia-dropdown-level-2';

        dropdown.style.display = 'none';


        Object.keys( menuData ).forEach( function ( name ) {

            var item = document.createElement( 'li' );


            /*
             * ====================================================
             * SECOND-LEVEL DROPDOWN
             * ====================================================
             *
             * If the value is an array, it is a normal list of
             * pages.
             *
             * If the value is an object, it contains another
             * dropdown.
             */

            if ( Array.isArray( menuData[ name ] ) ) {

                /*
                 * Normal page group
                 */

                var link = document.createElement( 'a' );

                link.href = mw.util.getUrl( name );

                link.textContent = name;

                item.appendChild( link );


                /*
                 * If this is being used as a dropdown title,
                 * it can be turned into a submenu later.
                 */

            } else {

                /*
                 * =================================================
                 * CREATE SECOND-LEVEL TITLE
                 * =================================================
                 */

                var link = document.createElement( 'a' );

                link.href = '#';

                link.textContent = name;

                link.className = 'exuvia-dropdown-title';


                /*
                 * Arrow
                 */

                var arrow = document.createElement( 'span' );

                arrow.className = 'exuvia-dropdown-arrow';

                arrow.textContent = ' ▼';

                link.appendChild( arrow );


                /*
                 * Create the next level recursively.
                 */

                var submenu = createDropdown(
                    menuData[ name ],
                    link
                );


                /*
                 * Add submenu to this item.
                 */

                item.appendChild( link );

                item.appendChild( submenu );


                /*
                 * =================================================
                 * OPEN / CLOSE SUBMENU
                 * =================================================
                 */

                link.addEventListener( 'click', function ( event ) {

                    event.preventDefault();

                    if ( submenu.style.display === 'none' ) {

                        submenu.style.display = 'block';

                        arrow.textContent = ' ▲';

                    } else {

                        submenu.style.display = 'none';

                        arrow.textContent = ' ▼';

                    }

                });

            }


            dropdown.appendChild( item );

        });


        return dropdown;
    }


    /*
     * ============================================================
     * PROCESS TOP-LEVEL MENUS
     * ============================================================
     */

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

        var mainLink = null;


        /*
         * Find the sidebar link matching the menu name.
         */

        sidebarLinks.some( function ( link ) {

            var text = link.textContent.trim();

            if ( text === menuName ) {

                mainLink = link;

                return true;
            }

            return false;

        });


        if ( !mainLink ) {
            return;
        }


        /*
         * ========================================================
         * FIND THE SIDEBAR ITEM
         * ========================================================
         */

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

        if ( !parent ) {
            return;
        }


        /*
         * ========================================================
         * CREATE TOP-LEVEL DROPDOWN
         * ========================================================
         */

        var dropdown = document.createElement( 'ul' );

        dropdown.className = 'exuvia-dropdown-menu exuvia-dropdown-level-1';

        dropdown.style.display = 'none';


        /*
         * ========================================================
         * CREATE FIRST-LEVEL ITEMS
         * ========================================================
         */

        Object.keys( menus[ menuName ] ).forEach( function ( name ) {

            var item = document.createElement( 'li' );

            /*
             * Every entry in the top-level menu is treated as
             * a submenu title.
             */

            var link = document.createElement( 'a' );

            link.href = '#';

            link.textContent = name;

            link.className = 'exuvia-dropdown-title';


            /*
             * Arrow
             */

            var arrow = document.createElement( 'span' );

            arrow.className = 'exuvia-dropdown-arrow';

            arrow.textContent = ' ▼';

            link.appendChild( arrow );


            /*
             * ====================================================
             * CREATE SECOND LEVEL
             * ====================================================
             */

            var submenuData = menus[ menuName ][ name ];

            var submenu = document.createElement( 'ul' );

            submenu.className =
                'exuvia-dropdown-menu exuvia-dropdown-level-2';

            submenu.style.display = 'none';


            /*
             * Add the actual pages.
             */

            submenuData.forEach( function ( pageName ) {

                var pageItem = document.createElement( 'li' );

                var pageLink = document.createElement( 'a' );

                pageLink.href = mw.util.getUrl( pageName );

                pageLink.textContent = pageName;

                pageItem.appendChild( pageLink );

                submenu.appendChild( pageItem );

            });


            /*
             * Add submenu.
             */

            item.appendChild( link );

            item.appendChild( submenu );

            dropdown.appendChild( item );


            /*
             * ====================================================
             * OPEN / CLOSE SECOND LEVEL
             * ====================================================
             */

            link.addEventListener( 'click', function ( event ) {

                event.preventDefault();

                if ( submenu.style.display === 'none' ) {

                    submenu.style.display = 'block';

                    arrow.textContent = ' ▲';

                } else {

                    submenu.style.display = 'none';

                    arrow.textContent = ' ▼';

                }

            });

        });


        /*
         * ========================================================
         * ADD DROPDOWN TO SIDEBAR
         * ========================================================
         */

        parent.appendChild( dropdown );


        /*
         * ========================================================
         * TOP-LEVEL ARROW
         * ========================================================
         */

        var arrow = document.createElement( 'span' );

        arrow.className = 'exuvia-dropdown-arrow';

        arrow.textContent = ' ▼';

        mainLink.appendChild( arrow );


        /*
         * Mark as dropdown title.
         */

        mainLink.classList.add( 'exuvia-dropdown-title' );


        /*
         * ========================================================
         * OPEN / CLOSE TOP LEVEL
         * ========================================================
         */

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

            event.preventDefault();

            if ( dropdown.style.display === 'none' ) {

                dropdown.style.display = 'block';

                arrow.textContent = ' ▲';

            } else {

                dropdown.style.display = 'none';

                arrow.textContent = ' ▼';

            }

        });

    });

});