MediaWiki:Common.js: Difference between revisions
No edit summary Tag: Reverted |
No edit summary Tag: Reverted |
||
| Line 1,246: | Line 1,246: | ||
/* ═══════════════════════════════════════════════════════════════ | /* ═══════════════════════════════════════════════════════════════ | ||
Mobile addon — paste at bottom of MediaWiki:Common.js | Mobile addon — paste at bottom of MediaWiki:Common.js | ||
Only runs on Minerva (mobile) skin | |||
═══════════════════════════════════════════════════════════════ */ | ═══════════════════════════════════════════════════════════════ */ | ||
( function () { | ( function () { | ||
if ( !document.body.classList.contains( 'skin-minerva' ) ) return; | if ( !document.body.classList.contains( 'skin-minerva' ) ) return; | ||
/* ── 1. | /* ── 1. CSS injected into <head> — beats all other stylesheets ── */ | ||
function | function injectCSS() { | ||
if ( document.getElementById( 'gr- | if ( document.getElementById( 'gr-mob-css' ) ) return; | ||
var s = document.createElement( 'style' ); | var s = document.createElement( 'style' ); | ||
s.id = 'gr- | s.id = 'gr-mob-css'; | ||
s.textContent = | s.textContent = | ||
/* | /* Body padding — readerToolbar sets this, we clear it */ | ||
'body,#mw-mf-viewport,#mw-mf-page-center{padding-top:0!important;margin-top:0!important;}', | 'body,#mw-mf-viewport,#mw-mf-page-center{padding-top:0!important;margin-top:0!important;}' + | ||
'html,body,#mw-mf-viewport,#mw-mf-page-center{overflow-x:hidden!important;max-width:100vw!important;}' + | |||
/* Header orange + sticky */ | /* Header orange + sticky */ | ||
'header.header-container{background:#b5451b!important;position:sticky!important;top:0!important;z-index:300!important;}' | 'header.header-container{background:#b5451b!important;position:sticky!important;top:0!important;z-index:300!important;}' + | ||
'.minerva-header{background:#b5451b!important;min-height: | '.minerva-header{background:#b5451b!important;min-height:54px!important;}' + | ||
/* | /* Header: keep only hamburger + branding, hide search */ | ||
'.minerva-header .search-toggle,.minerva-header .minerva-user-notifications{display:none!important;}' + | |||
'.minerva-header .search-toggle | |||
/* | /* Logo row: icon + title wrap cleanly */ | ||
'.branding-box a{display:flex!important;align-items:center!important;text-decoration:none!important;flex-wrap:wrap!important;}' | '.branding-box a{display:flex!important;align-items:center!important;' + | ||
'.branding-box a span{color:#fff!important;font-size: | 'text-decoration:none!important;flex-wrap:wrap!important;max-width:calc(100vw - 80px)!important;}' + | ||
'.branding-box a::before{content:"";display:block;width:30px;height:30px;flex-shrink:0;' + | |||
'.branding-box a::after{content:"A Digital Archive of Dvaita Vedanta Literature";display:block;flex-basis:100%;font-size:10px;color:rgba(255,255,255,0.82);font-family:sans-serif | 'background:url("/favicon.png") center/contain no-repeat;' + | ||
'margin-right:8px;}' + | |||
'.branding-box a span{color:#fff!important;font-size:16px!important;font-weight:700!important;' + | |||
'font-family:system-ui,sans-serif!important;line-height:1.2!important;' + | |||
'flex:1 1 auto!important;min-width:0!important;}' + | |||
'.branding-box a::after{content:"A Digital Archive of Dvaita Vedanta Literature";' + | |||
'display:block;width:100%;flex-basis:100%;' + | |||
'padding-left:38px;' + | |||
'font-size:10px;font-weight:400;color:rgba(255,255,255,0.82);font-family:sans-serif;margin-top:1px;}' + | |||
/* | /* Header icons white */ | ||
'. | '.minerva-header svg path,.minerva-header svg rect,.minerva-header svg circle{fill:#fff!important;}' + | ||
'.minerva-header | '.minerva-header label{color:#fff!important;}' + | ||
/* Hide | /* Hide Page/Discussion tabs + icon toolbar */ | ||
' | '.minerva-tabs,.mw-portlet-associated-pages,.page-actions-menu,' + | ||
'#page-secondary-actions,.last-modified-bar,.minerva-anon-talk-link{display:none!important;}' + | |||
/* | /* Drawer: hide default items, show ours */ | ||
'#mw-mf-page-left{display:none!important;}' + | |||
'#gr-mob-menu-items{display:block!important;}' + | |||
'#mw-mf-page-left{display:none!important;}' | |||
'#gr-mob- | |||
/* | /* Drawer footer: hide About/Disclaimers */ | ||
'# | '.mw-footer.minerva-footer,.footer-places,.footer-info,' + | ||
'.minerva-footer-logo,#footer-places-about,' + | |||
'#footer-places-disclaimers,#footer-places-privacy{display:none!important;}' + | |||
/* | /* ReaderToolbar below header */ | ||
' | '#gr-static-bar{position:sticky!important;top:54px!important;z-index:200!important;}' + | ||
/* | /* Sections expanded */ | ||
'. | '.mf-section-0,.mf-section-1,.mf-section-2,.mf-section-3,.mf-section-4,' + | ||
'.mf-section-5,.mf-section-6,.mf-section-7,.mf-section-8,.mf-section-9,' + | |||
'. | '.mf-section-10{display:block!important;visibility:visible!important;}' + | ||
'.collapsible-block{display:block!important;}' + | |||
'.section-heading .indicator,.collapsible-heading .indicator{display:none!important;}' + | |||
'.section-heading,.collapsible-heading{pointer-events:none!important;}' + | |||
/* Content | /* Home grid single column */ | ||
'.mw-parser-output{font-size:18px!important;line-height:1.8!important;}' | '.gr-home-grid{flex-direction:column!important;flex-wrap:nowrap!important;' + | ||
'.mw-parser-output h2,.mw-parser-output | 'gap:12px!important;width:100%!important;}' + | ||
'. | '.gr-home-card{width:100%!important;max-width:100%!important;' + | ||
'min-width:unset!important;box-sizing:border-box!important;flex:none!important;}' + | |||
document.head.appendChild(s); | '.gr-home-toggle{flex-wrap:wrap!important;}' + | ||
/* Content */ | |||
'.mw-parser-output{font-size:18px!important;line-height:1.8!important;}' + | |||
'.mw-parser-output h2,.mw-parser-output h3{width:100%!important;}' + | |||
'.bhashyam-block{margin-left:8px!important;}' + | |||
'#footer,.mw-footer,.catlinks,#catlinks{display:none!important;}' + | |||
/* TOC overlay */ | |||
'.gr-mob-toc-panel{position:fixed!important;top:0!important;left:0!important;' + | |||
'bottom:0!important;width:82vw!important;max-width:340px!important;' + | |||
'background:#fff!important;z-index:10400!important;' + | |||
'box-shadow:4px 0 28px rgba(0,0,0,0.22)!important;overflow-y:auto!important;' + | |||
'padding:0 0 40px!important;transform:translateX(-110%)!important;' + | |||
'transition:transform 0.26s cubic-bezier(0.4,0,0.2,1)!important;display:block!important;}' + | |||
'.gr-mob-toc-panel.open{transform:translateX(0)!important;}' + | |||
'.gr-mob-toc-backdrop{display:none!important;position:fixed!important;inset:0!important;' + | |||
'background:rgba(0,0,0,0.4)!important;z-index:10399!important;}' + | |||
'.gr-mob-toc-backdrop.open{display:block!important;}' + | |||
'.gr-mob-toc-header{position:sticky!important;top:0!important;background:#fff!important;' + | |||
'display:flex!important;align-items:center!important;justify-content:space-between!important;' + | |||
'padding:16px 16px 12px!important;border-bottom:1px solid #f0ebe6!important;z-index:1!important;}' + | |||
'.gr-mob-toc-title{font-size:13px!important;font-weight:700!important;text-transform:uppercase!important;' + | |||
'letter-spacing:0.08em!important;color:#b5451b!important;font-family:system-ui,sans-serif!important;}' + | |||
'.gr-mob-toc-close{background:none!important;border:none!important;' + | |||
'font-size:22px!important;color:#999!important;cursor:pointer!important;padding:4px 8px!important;}' + | |||
'.gr-mob-toc-body{padding:12px 16px!important;}' + | |||
'.gr-mob-toc-body a{display:block!important;font-size:16px!important;line-height:1.6!important;' + | |||
'color:#2c1810!important;text-decoration:none!important;padding:8px 0!important;' + | |||
'border-bottom:1px solid #f5f0ed!important;}'; | |||
document.head.appendChild( s ); | |||
} | } | ||
/* ── 2. | /* ── 2. Expand hidden sections ── */ | ||
function expandSections() { | function expandSections() { | ||
document.querySelectorAll( | document.querySelectorAll( '[class*="mf-section-"], .collapsible-block' ) | ||
.forEach( function ( el ) { | |||
el.removeAttribute( 'hidden' ); | |||
el.style.setProperty( 'display', 'block', 'important' ); | |||
el.style.setProperty( 'visibility', 'visible', 'important' ); | |||
el.removeAttribute( 'aria-hidden' ); | |||
} ); | |||
document.querySelectorAll( '.section-heading, .collapsible-heading' ) | |||
document.querySelectorAll('.section-heading, .collapsible-heading').forEach(function(el) { | .forEach( function ( el ) { | ||
el.setAttribute( 'aria-expanded', 'true' ); | |||
el.style.setProperty( 'pointer-events', 'none', 'important' ); | |||
} ); | |||
} | } | ||
/* Persistent observer — MF re- | /* Persistent observer — fight MF re-collapsing */ | ||
function | function watchSections() { | ||
var | var t = null; | ||
var obs = new MutationObserver(function( | var obs = new MutationObserver( function ( ms ) { | ||
if ( ms.some( function(m){ return m.attributeName === 'hidden'; } ) ) { | |||
clearTimeout(t); t = setTimeout( expandSections, 30 ); | |||
clearTimeout( | |||
} | } | ||
}); | } ); | ||
var root = document.querySelector('#mw-content-text | var root = document.querySelector( '#mw-content-text' ) || document.body; | ||
obs.observe( root, { subtree:true, attributes:true, attributeFilter:['hidden','aria-hidden'] } ); | |||
} | } | ||
/* ── 3. Body padding observer ── */ | /* ── 3. Body padding observer ── */ | ||
function watchBodyPadding() { | function watchBodyPadding() { | ||
new MutationObserver( function () { | |||
if (document.body.style.paddingTop && document.body.style.paddingTop !== '0px') { | if ( document.body.style.paddingTop && document.body.style.paddingTop !== '0px' ) { | ||
document.body.style.paddingTop = ''; | document.body.style.paddingTop = ''; | ||
} | } | ||
}) | } ).observe( document.body, { attributes:true, attributeFilter:['style'] } ); | ||
} | } | ||
/* ── 4. | /* ── 4. Inject custom links into drawer ── */ | ||
function | function injectMenuLinks() { | ||
/* Already injected */ | |||
if ( document.getElementById( 'gr-mob-menu-items' ) ) return; | |||
/* The drawer container is .navigation-drawer (the <nav> element) | |||
Our links go AFTER the #mw-mf-page-left div (which we hide via CSS) */ | |||
var navDrawer = document.querySelector( '.navigation-drawer' ); | |||
if ( !navDrawer ) return; | |||
var | |||
if (! | |||
var wrap = document.createElement( 'div' ); | |||
wrap.id = 'gr-mob-menu-items'; | |||
wrap.style.cssText = 'width:100%;background:#fff;margin-top:8px;'; | |||
var itemStyle = 'display:flex;align-items:center;gap:14px;padding:15px 20px;' + | |||
'font-size:16px;color:#2c1810;text-decoration:none;' + | |||
'font-family:system-ui,sans-serif;border-bottom:1px solid #f0ebe6;background:#fff;'; | |||
function makeItem( href, emoji, label ) { | |||
document. | var a = document.createElement( 'a' ); | ||
a.href = href; | |||
' | a.style.cssText = itemStyle; | ||
a.innerHTML = | |||
'<span style="font-size:20px;width:28px;text-align:center;flex-shrink:0">' + emoji + '</span>' + | |||
'<span>' + label + '</span>'; | |||
} | return a; | ||
} | |||
wrap.appendChild( makeItem( '/Main_Page', '🏠', 'Home' ) ); | |||
wrap.appendChild( makeItem( '/Help:Contents', '❓', 'Help' ) ); | |||
wrap.appendChild( makeItem( '/My_wiki:About', 'ℹ️', 'About' ) ); | |||
var userName = window.mw ? mw.config.get( 'wgUserName' ) : null; | |||
if ( userName ) { | |||
var la = document.querySelector( 'a[href*="action=logout"]' ); | |||
wrap.appendChild( makeItem( | |||
la ? la.href : '/index.php?title=Special:UserLogout', '↩', 'Log out' | |||
) ); | |||
} else { | |||
wrap.appendChild( makeItem( '/index.php?title=Special:UserLogin', '→', 'Log in' ) ); | |||
} | |||
/* Insert after the hidden #mw-mf-page-left */ | |||
var pageLeft = document.getElementById( 'mw-mf-page-left' ); | |||
if ( pageLeft && pageLeft.parentNode === navDrawer ) { | |||
navDrawer.insertBefore( wrap, pageLeft.nextSibling ); | |||
} else { | |||
/* Fallback: append to drawer toggle container */ | |||
var toggleContainer = navDrawer.querySelector( '.toggle-list' ) || navDrawer; | |||
toggleContainer.appendChild( wrap ); | |||
/* | |||
} | } | ||
/* | /* Hide footer portlets */ | ||
document.querySelectorAll( | |||
'.mw-footer.minerva-footer,.footer-places,.footer-info,' + | |||
'.minerva-footer-logo,#footer-places-about,' + | |||
'#footer-places-disclaimers,#footer-places-privacy' | |||
).forEach( function(el) { el.style.setProperty('display','none','important'); } ); | |||
} | } | ||
/* ── | /* ── 5. Mobile TOC overlay ── */ | ||
var | var _tocDone = false; | ||
function | function initToc() { | ||
if ( | if ( _tocDone ) return; | ||
var tocList = document.querySelector('.vector-toc-contents, .vector-toc .vector-toc-list'); | var tocList = document.querySelector( '.vector-toc-contents, .vector-toc .vector-toc-list' ); | ||
if (!tocList) return; | if ( !tocList ) return; | ||
if ( !tocList.querySelector( 'li' ) ) return; | |||
_tocDone = true; | |||
var bd = document.createElement('div'); | var bd = document.createElement( 'div' ); | ||
bd.className = 'gr-mob-toc-backdrop'; | bd.className = 'gr-mob-toc-backdrop'; | ||
document.body.appendChild(bd); | document.body.appendChild( bd ); | ||
var panel = document.createElement('div'); | var panel = document.createElement( 'div' ); | ||
panel.className = 'gr-mob-toc-panel'; | panel.className = 'gr-mob-toc-panel'; | ||
var hdr = document.createElement('div'); | var hdr = document.createElement( 'div' ); | ||
hdr.className = 'gr-mob-toc-header'; | hdr.className = 'gr-mob-toc-header'; | ||
var ttl = document.createElement('div'); | var ttl = document.createElement( 'div' ); | ||
ttl.className = 'gr-mob-toc-title'; | ttl.className = 'gr-mob-toc-title'; | ||
ttl.textContent = 'विषयसूची'; | ttl.textContent = 'विषयसूची'; | ||
var cls = document.createElement('button'); | var cls = document.createElement( 'button' ); | ||
cls.className = 'gr-mob-toc-close'; | cls.className = 'gr-mob-toc-close'; | ||
cls.textContent = '✕'; | cls.textContent = '✕'; | ||
hdr.appendChild(ttl); hdr.appendChild(cls); | hdr.appendChild( ttl ); hdr.appendChild( cls ); | ||
panel.appendChild(hdr); | panel.appendChild( hdr ); | ||
var body = document.createElement('div'); | var body = document.createElement( 'div' ); | ||
body.className = 'gr-mob-toc-body'; | body.className = 'gr-mob-toc-body'; | ||
body.appendChild(tocList.cloneNode(true)); | body.appendChild( tocList.cloneNode( true ) ); | ||
panel.appendChild(body); | panel.appendChild( body ); | ||
document.body.appendChild(panel); | document.body.appendChild( panel ); | ||
var btn = document.createElement( 'button' ); | |||
var btn = document.createElement('button') | |||
btn.id = 'gr-mob-toc-btn'; | btn.id = 'gr-mob-toc-btn'; | ||
btn.innerHTML = '☰ Contents'; | btn.innerHTML = '☰ Contents'; | ||
btn.style.cssText = 'position:fixed;bottom:148px;left:16px;z-index:9100;' + | |||
document.body.appendChild(btn); | 'background:#fff;border:1.5px solid #b5451b;border-radius:24px;' + | ||
'padding:10px 16px;font-size:15px;font-family:system-ui,sans-serif;' + | |||
'color:#b5451b;font-weight:600;box-shadow:0 3px 14px rgba(0,0,0,0.15);cursor:pointer;'; | |||
document.body.appendChild( btn ); | |||
function open() { panel.classList.add('open'); bd.classList.add('open'); document.body.style.overflow='hidden'; } | function open() { panel.classList.add('open'); bd.classList.add('open'); document.body.style.overflow='hidden'; } | ||
function close() { panel.classList.remove('open'); bd.classList.remove('open'); document.body.style.overflow=''; } | function close() { panel.classList.remove('open'); bd.classList.remove('open'); document.body.style.overflow=''; } | ||
btn. | btn.onclick = open; cls.onclick = close; bd.onclick = close; | ||
body.querySelectorAll('a').forEach(function(a){ a.onclick = close; }); | |||
body.querySelectorAll('a').forEach(function(a){ a. | |||
} | } | ||
/* ── Boot ── */ | /* ── Boot ── */ | ||
injectCSS(); | |||
watchBodyPadding(); | watchBodyPadding(); | ||
function | function boot() { | ||
expandSections(); | expandSections(); | ||
watchSections(); | |||
injectMenuLinks(); | |||
[100, 400, 900, 1800].forEach(function(ms){ setTimeout(expandSections, ms); }); | |||
setTimeout(initToc, 700); | |||
[100, | |||
setTimeout( | |||
} | } | ||
if (document.readyState === 'loading') { | if ( document.readyState === 'loading' ) { | ||
document.addEventListener('DOMContentLoaded', | document.addEventListener( 'DOMContentLoaded', boot ); | ||
} else { | } else { | ||
boot(); | |||
} | } | ||
if (window.mw) { | if ( window.mw ) { | ||
mw.hook('wikipage.content').add(function() { | mw.hook( 'wikipage.content' ).add(function() { | ||
setTimeout(function() { | setTimeout(function(){ expandSections(); injectMenuLinks(); initToc(); }, 300); | ||
}); | }); | ||
} | } | ||
}() ); | }() ); | ||