MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
Blanked the page Tags: Blanking Manual revert Reverted |
No edit summary Tags: Manual revert Reverted |
||
| Line 1: | Line 1: | ||
( function () { | |||
'use strict'; | |||
function ensureThemeStylesLoaded() { | |||
try { | |||
if ( !window.mw || !mw.loader || !mw.config ) { | |||
return; | |||
} | |||
const skin = mw.config.get( 'skin' ) || 'vector'; | |||
const moduleName = 'themeloader.skins.' + skin + '.default'; | |||
if ( typeof mw.loader.getState === 'function' ) { | |||
const state = mw.loader.getState( moduleName ); | |||
if ( state === null ) { | |||
return; | |||
} | |||
if ( state === 'ready' || state === 'loading' ) { | |||
return; | |||
} | |||
} | |||
mw.loader.load( moduleName ); | |||
} catch ( e ) { | |||
// Ignore error | |||
} | |||
} | |||
function getSavedTheme() { | |||
try { | |||
return localStorage.getItem( 'mw-theme' ) || 'default'; | |||
} catch ( e ) { | |||
return 'default'; | |||
} | |||
} | |||
// Define available themes matching christmas.css roots | |||
const themes = [ | |||
{ name: 'Pink', id: 'default' }, | |||
{ name: 'Dark', id: 'dark-neutral' }, | |||
{ name: 'Christmas', id: 'christmas' }, | |||
{ name: 'Power Light', id: 'power-light' }, | |||
{ name: 'Magic Light', id: 'magic-light' }, | |||
{ name: 'Sense Light', id: 'sense-light' }, | |||
{ name: 'Charm Light', id: 'charm-light' }, | |||
{ name: 'Power Dark', id: 'power-dark' }, | |||
{ name: 'Charm Dark', id: 'charm-dark' }, | |||
{ name: 'Magic Dark', id: 'dark-lightBlue' }, | |||
{ name: 'Sense Dark', id: 'dark-purple' }, | |||
]; | |||
// Function to apply theme | |||
function applyTheme( themeId ) { | |||
ensureThemeStylesLoaded(); | |||
try { | |||
localStorage.setItem( 'mw-theme', themeId ); | |||
} catch ( e ) { | |||
// Ignore error | |||
} | |||
if ( themeId === 'default' ) { | |||
document.documentElement.removeAttribute( 'data-theme' ); | |||
} else { | |||
document.documentElement.setAttribute( 'data-theme', themeId ); | |||
} | |||
} | |||
// Initialize theme immediately | |||
ensureThemeStylesLoaded(); | |||
applyTheme( getSavedTheme() ); | |||
// Wait for DOM | |||
const domReady = function ( callback ) { | |||
if ( document.readyState === 'loading' ) { | |||
document.addEventListener( 'DOMContentLoaded', callback ); | |||
} else { | |||
setTimeout( callback, 0 ); | |||
} | |||
}; | |||
domReady( function () { | |||
// Prevent duplicate injection | |||
if ( document.getElementById( 'mw-theme-floating' ) ) { | |||
return; | |||
} | |||
// Create Floating Container | |||
// ID matches CSS: #mw-theme-floating | |||
const container = document.createElement( 'div' ); | |||
container.id = 'mw-theme-floating'; | |||
// Create Inner Wrapper | |||
// Class matches CSS: .themeMenu | |||
const themeMenuDiv = document.createElement( 'div' ); | |||
themeMenuDiv.className = 'themeMenu'; | |||
// Create Toggle Button | |||
// Class matches CSS: .themeMenu-toggle | |||
const btn = document.createElement( 'button' ); | |||
btn.className = 'themeMenu-toggle'; | |||
btn.textContent = 'Appearence'; | |||
btn.title = 'Change appearence'; | |||
btn.type = 'button'; | |||
// Create Dropdown List | |||
// Class matches CSS: .themeMenu-dropdown | |||
const dropdown = document.createElement( 'ul' ); | |||
dropdown.className = 'themeMenu-dropdown'; | |||
// Populate Items | |||
themes.forEach( function ( theme ) { | |||
// Item Wrapper | |||
// CSS doesn't strictly require this wrapper for floating, | |||
// but theme-menu.css might use .themeMenu-itemWrap | |||
const itemWrap = document.createElement( 'li' ); | |||
itemWrap.className = 'themeMenu-itemWrap'; | |||
const themeLink = document.createElement( 'a' ); | |||
themeLink.className = 'themeMenu-item'; | |||
themeLink.href = '#'; | |||
themeLink.textContent = theme.name; | |||
themeLink.dataset.themeId = theme.id; | |||
// Highlight current | |||
const currentTheme = getSavedTheme(); | |||
if ( theme.id === currentTheme ) { | |||
themeLink.classList.add( 'is-current' ); | |||
} | |||
themeLink.addEventListener( 'click', function ( e ) { | |||
e.preventDefault(); | |||
ensureThemeStylesLoaded(); | |||
applyTheme( theme.id ); | |||
// Update highlighting | |||
dropdown.querySelectorAll( '.themeMenu-item' ).forEach( function ( link ) { | |||
link.classList.remove( 'is-current' ); | |||
} ); | |||
themeLink.classList.add( 'is-current' ); | |||
// Close menu | |||
themeMenuDiv.classList.remove( 'is-open' ); | |||
} ); | |||
itemWrap.appendChild( themeLink ); | |||
dropdown.appendChild( itemWrap ); | |||
} ); | |||
// Toggle Logic | |||
// CSS uses .themeMenu.is-open .themeMenu-dropdown { display: block } | |||
btn.addEventListener( 'click', function ( e ) { | |||
e.preventDefault(); | |||
e.stopPropagation(); | |||
themeMenuDiv.classList.toggle( 'is-open' ); | |||
} ); | |||
// Click Outside Logic | |||
document.addEventListener( 'click', function ( e ) { | |||
if ( !themeMenuDiv.contains( e.target ) ) { | |||
themeMenuDiv.classList.remove( 'is-open' ); | |||
} | |||
} ); | |||
// Assemble | |||
themeMenuDiv.appendChild( btn ); | |||
themeMenuDiv.appendChild( dropdown ); | |||
container.appendChild( themeMenuDiv ); | |||
// Inject into Body | |||
document.body.appendChild( container ); | |||
} ); | |||
}() ); | |||
Revision as of 18:00, 2 January 2026
( function () {
'use strict';
function ensureThemeStylesLoaded() {
try {
if ( !window.mw || !mw.loader || !mw.config ) {
return;
}
const skin = mw.config.get( 'skin' ) || 'vector';
const moduleName = 'themeloader.skins.' + skin + '.default';
if ( typeof mw.loader.getState === 'function' ) {
const state = mw.loader.getState( moduleName );
if ( state === null ) {
return;
}
if ( state === 'ready' || state === 'loading' ) {
return;
}
}
mw.loader.load( moduleName );
} catch ( e ) {
// Ignore error
}
}
function getSavedTheme() {
try {
return localStorage.getItem( 'mw-theme' ) || 'default';
} catch ( e ) {
return 'default';
}
}
// Define available themes matching christmas.css roots
const themes = [
{ name: 'Pink', id: 'default' },
{ name: 'Dark', id: 'dark-neutral' },
{ name: 'Christmas', id: 'christmas' },
{ name: 'Power Light', id: 'power-light' },
{ name: 'Magic Light', id: 'magic-light' },
{ name: 'Sense Light', id: 'sense-light' },
{ name: 'Charm Light', id: 'charm-light' },
{ name: 'Power Dark', id: 'power-dark' },
{ name: 'Charm Dark', id: 'charm-dark' },
{ name: 'Magic Dark', id: 'dark-lightBlue' },
{ name: 'Sense Dark', id: 'dark-purple' },
];
// Function to apply theme
function applyTheme( themeId ) {
ensureThemeStylesLoaded();
try {
localStorage.setItem( 'mw-theme', themeId );
} catch ( e ) {
// Ignore error
}
if ( themeId === 'default' ) {
document.documentElement.removeAttribute( 'data-theme' );
} else {
document.documentElement.setAttribute( 'data-theme', themeId );
}
}
// Initialize theme immediately
ensureThemeStylesLoaded();
applyTheme( getSavedTheme() );
// Wait for DOM
const domReady = function ( callback ) {
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', callback );
} else {
setTimeout( callback, 0 );
}
};
domReady( function () {
// Prevent duplicate injection
if ( document.getElementById( 'mw-theme-floating' ) ) {
return;
}
// Create Floating Container
// ID matches CSS: #mw-theme-floating
const container = document.createElement( 'div' );
container.id = 'mw-theme-floating';
// Create Inner Wrapper
// Class matches CSS: .themeMenu
const themeMenuDiv = document.createElement( 'div' );
themeMenuDiv.className = 'themeMenu';
// Create Toggle Button
// Class matches CSS: .themeMenu-toggle
const btn = document.createElement( 'button' );
btn.className = 'themeMenu-toggle';
btn.textContent = 'Appearence';
btn.title = 'Change appearence';
btn.type = 'button';
// Create Dropdown List
// Class matches CSS: .themeMenu-dropdown
const dropdown = document.createElement( 'ul' );
dropdown.className = 'themeMenu-dropdown';
// Populate Items
themes.forEach( function ( theme ) {
// Item Wrapper
// CSS doesn't strictly require this wrapper for floating,
// but theme-menu.css might use .themeMenu-itemWrap
const itemWrap = document.createElement( 'li' );
itemWrap.className = 'themeMenu-itemWrap';
const themeLink = document.createElement( 'a' );
themeLink.className = 'themeMenu-item';
themeLink.href = '#';
themeLink.textContent = theme.name;
themeLink.dataset.themeId = theme.id;
// Highlight current
const currentTheme = getSavedTheme();
if ( theme.id === currentTheme ) {
themeLink.classList.add( 'is-current' );
}
themeLink.addEventListener( 'click', function ( e ) {
e.preventDefault();
ensureThemeStylesLoaded();
applyTheme( theme.id );
// Update highlighting
dropdown.querySelectorAll( '.themeMenu-item' ).forEach( function ( link ) {
link.classList.remove( 'is-current' );
} );
themeLink.classList.add( 'is-current' );
// Close menu
themeMenuDiv.classList.remove( 'is-open' );
} );
itemWrap.appendChild( themeLink );
dropdown.appendChild( itemWrap );
} );
// Toggle Logic
// CSS uses .themeMenu.is-open .themeMenu-dropdown { display: block }
btn.addEventListener( 'click', function ( e ) {
e.preventDefault();
e.stopPropagation();
themeMenuDiv.classList.toggle( 'is-open' );
} );
// Click Outside Logic
document.addEventListener( 'click', function ( e ) {
if ( !themeMenuDiv.contains( e.target ) ) {
themeMenuDiv.classList.remove( 'is-open' );
}
} );
// Assemble
themeMenuDiv.appendChild( btn );
themeMenuDiv.appendChild( dropdown );
container.appendChild( themeMenuDiv );
// Inject into Body
document.body.appendChild( container );
} );
}() );