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 () { | |||
/* | |||
* ============================================================ | |||
* 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 = | var sidebar = document.getElementById( 'mw-site-navigation' ); | ||
if ( !sidebar | if ( !sidebar ) { | ||
return; | return; | ||
} | } | ||
| Line 73: | Line 104: | ||
/* | /* | ||
=========================================================================== | * ============================================================ | ||
* 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 | |||
* ======================================================== | |||
*/ | |||
if ( ! | var parent = mainLink.closest( 'li' ); | ||
if ( !parent ) { | |||
return; | return; | ||
} | } | ||
| Line 101: | Line 307: | ||
/* | /* | ||
* ======================================================== | |||
* 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. | parent.appendChild( dropdown ); | ||
/* | /* | ||
* ======================================================== | |||
* TOP-LEVEL ARROW | |||
* ======================================================== | |||
*/ | |||
dropdown. | 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(); | event.preventDefault(); | ||
dropdown. | if ( dropdown.style.display === 'none' ) { | ||
dropdown.style.display = 'block'; | |||
arrow.textContent = ' ▲'; | |||
} else { | |||
dropdown.style.display = 'none'; | |||
arrow.textContent = ' ▼'; | |||
} | |||
}); | |||
}); | }); | ||
}); | }); | ||
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 = ' ▼';
}
});
});
});