MediaWiki:Timeless.js: Difference between revisions

From Exuvia Wiki
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
/*
$( function () {
===============================================================================
EXUVIA WIKI SIDEBAR DROPDOWNS
===============================================================================


The sidebar contains:
    /*
    * ============================================================
    * 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.
    */


     Locations
     var menus = {
    Religions
    People
    World Building


JavaScript turns selected entries into expandable menus.
        'Locations': {


The top-level entries DO NOT need to be real wiki pages.
            'Continents': [
                'Alorea',
                'Another Continent'
            ],


===============================================================================
            'Kingdoms': [
*/
                'Koble',
                'Yamen',
                'Zagis',
                'Tekk',
                'Frossik'
            ],


$( function () {
            'Towns': [
                'Town A',
                'Town B'
            ]
        },
 
 
        'Religions': {
 
            'Kippelian Pantheon': [
                'The Valor',
                'The Brumal'
            ],


    /*
            'Other Religions': [
    ===========================================================================
                'Religion A',
    DROPDOWN MENUS
                'Religion B'
    ===========================================================================
            ]
        },


    The name on the left must exactly match the text in MediaWiki:Sidebar.


    The names inside [ ] are the wiki pages that appear when the menu opens.
        'People': {


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


    var menus = {
            'Other People': [
                'Person A',
                'Person B'
            ]
        },


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


         'Religions': [
         'World Building': {
            'The Valor',
            'The Brumal'
        ],


        'People': [
            'History': [
            'High Lord Kip',
                'War of Unification',
            'Queen Melena'
                'History of Kippel'
        ],
            ],


        'World Building': [
            'Magic': [
            'History',
                'Magic',
            'Magic',
                'Necromancy'
             'War'
             ],
        ]


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




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


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


     if ( !sidebar.length ) {
     if ( !sidebar ) {
         return;
         return;
     }
     }
Line 73: Line 104:


     /*
     /*
     ===========================================================================
    * ============================================================
     FIND EVERY SIDEBAR LINK
    * 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
    * ============================================================
    */


     sidebar.find( 'a' ).each( function () {
     Object.keys( menus ).forEach( function ( menuName ) {
 
        var mainLink = null;


        var link = $( this );


         /*
         /*
         Get only the visible text.
        * Find the sidebar link matching the menu name.
        */
 
         sidebarLinks.some( function ( link ) {
 
            var text = link.textContent.trim();
 
            if ( text === menuName ) {
 
                mainLink = link;
 
                return true;
            }


        trim() removes extra spaces.
            return false;
        */


         var name = $.trim( link.clone().children().remove().end().text() );
         });
 
 
        if ( !mainLink ) {
            return;
        }




         /*
         /*
        Check whether this sidebar item is one of our dropdowns.
        * ========================================================
        */
        * FIND THE SIDEBAR ITEM
        * ========================================================
        */


         if ( !Object.prototype.hasOwnProperty.call( menus, name ) ) {
        var parent = mainLink.closest( 'li' );
 
         if ( !parent ) {
             return;
             return;
         }
         }
Line 101: Line 307:


         /*
         /*
        =======================================================================
        * ========================================================
        FIND THE CONTAINER
        * CREATE TOP-LEVEL DROPDOWN
        =======================================================================
        * ========================================================
         */
        */
 
        var dropdown = document.createElement( 'ul' );
 
         dropdown.className = 'exuvia-dropdown-menu exuvia-dropdown-level-1';


         var parent = link.closest( 'li' );
         dropdown.style.display = 'none';




         /*
         /*
        =======================================================================
        * ========================================================
        CREATE THE DROPDOWN
        * 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';


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


            link.appendChild( arrow );


        /*
        =======================================================================
        CREATE EACH LINK
        =======================================================================
        */


        menus[ name ].forEach( function ( page ) {
            /*
            * ====================================================
            * 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 = ' ▲';


            var childLink = $( '<a>' )
                 } else {
                 .attr( 'href', mw.util.getUrl( page ) )
                .text( page );


            var childItem = $( '<li>' )
                    submenu.style.display = 'none';
                .append( childLink );


            dropdown.append( childItem );
                    arrow.textContent = ' ▼';


         } );
                }
 
            });
 
         });




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


         parent.append( dropdown );
         parent.appendChild( dropdown );




         /*
         /*
        Start closed.
        * ========================================================
        */
        * TOP-LEVEL ARROW
        * ========================================================
        */


         dropdown.hide();
         var arrow = document.createElement( 'span' );
 
        arrow.className = 'exuvia-dropdown-arrow';
 
        arrow.textContent = ' ▼';
 
        mainLink.appendChild( arrow );




         /*
         /*
        =======================================================================
        * Mark as dropdown title.
        MAKE THE TITLE A DROPDOWN BUTTON
        */
        =======================================================================
 
         */
         mainLink.classList.add( 'exuvia-dropdown-title' );


         link.on( 'click', function ( event ) {
 
         /*
        * ========================================================
        * OPEN / CLOSE TOP LEVEL
        * ========================================================
        */
 
        mainLink.addEventListener( 'click', function ( event ) {


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


             dropdown.stop( true, true ).slideToggle( 150 );
             if ( dropdown.style.display === 'none' ) {
 
                dropdown.style.display = 'block';
 
                arrow.textContent = ' ▲';
 
            } else {


        });
                dropdown.style.display = 'none';


                arrow.textContent = ' ▼';


        /*
            }
        =======================================================================
        ADD ARROW
        =======================================================================
        */


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


     });
     });


});
});

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 = ' ▼';

            }

        });

    });

});