|
|
| Line 951: |
Line 951: |
| wireUllekhaLinks(); | | wireUllekhaLinks(); |
| } | | } |
| }() );
| |
| /* ── Mobile TOC overlay — add to bottom of Common.js ─────────── */
| |
| ( function () {
| |
| if ( window.innerWidth > 768 ) return;
| |
|
| |
| function initMobileToc() {
| |
| if ( document.getElementById( 'gr-mob-toc-btn' ) ) return;
| |
|
| |
| var toc = document.querySelector( '.vector-toc' );
| |
| if ( !toc ) return;
| |
|
| |
| /* Backdrop */
| |
| var backdrop = document.createElement( 'div' );
| |
| backdrop.className = 'gr-mobile-toc-backdrop';
| |
| backdrop.id = 'gr-mob-toc-backdrop';
| |
| document.body.appendChild( backdrop );
| |
|
| |
| /* Panel */
| |
| var panel = document.createElement( 'div' );
| |
| panel.className = 'gr-mobile-toc-panel';
| |
| panel.id = 'gr-mob-toc-panel';
| |
|
| |
| /* Panel header */
| |
| var header = document.createElement( 'div' );
| |
| header.className = 'gr-mobile-toc-header';
| |
| var titleEl = document.createElement( 'div' );
| |
| titleEl.className = 'gr-mobile-toc-title';
| |
| titleEl.textContent = 'विषयसूची';
| |
| var closeBtn = document.createElement( 'button' );
| |
| closeBtn.className = 'gr-mobile-toc-close';
| |
| closeBtn.innerHTML = '✕';
| |
| header.appendChild( titleEl );
| |
| header.appendChild( closeBtn );
| |
| panel.appendChild( header );
| |
|
| |
| /* Clone TOC contents */
| |
| var tocContents = toc.querySelector( '.vector-toc-contents' );
| |
| if ( tocContents ) {
| |
| var clone = tocContents.cloneNode( true );
| |
| panel.appendChild( clone );
| |
| }
| |
|
| |
| document.body.appendChild( panel );
| |
|
| |
| /* Toggle button */
| |
| var btn = document.createElement( 'button' );
| |
| btn.className = 'gr-mobile-toc-btn';
| |
| btn.id = 'gr-mob-toc-btn';
| |
| btn.innerHTML = '☰ Contents';
| |
| document.body.appendChild( btn );
| |
|
| |
| function openToc() {
| |
| panel.classList.add( 'open' );
| |
| backdrop.classList.add( 'open' );
| |
| }
| |
| function closeToc() {
| |
| panel.classList.remove( 'open' );
| |
| backdrop.classList.remove( 'open' );
| |
| }
| |
|
| |
| btn.addEventListener( 'click', openToc );
| |
| closeBtn.addEventListener( 'click', closeToc );
| |
| backdrop.addEventListener( 'click', closeToc );
| |
|
| |
| /* Close on link click */
| |
| panel.querySelectorAll( 'a' ).forEach( function ( a ) {
| |
| a.addEventListener( 'click', closeToc );
| |
| } );
| |
| }
| |
|
| |
| if ( document.readyState === 'loading' ) {
| |
| document.addEventListener( 'DOMContentLoaded', function () {
| |
| setTimeout( initMobileToc, 400 );
| |
| } );
| |
| } else {
| |
| setTimeout( initMobileToc, 400 );
| |
| }
| |
| }() );/* ═══════════════════════════════════════════════════════════════
| |
| Mobile fixes — paste at bottom of MediaWiki:Common.js
| |
| Injects a <style> tag AFTER readerToolbar's inline style
| |
| so it wins the cascade without touching the extension.
| |
| ═══════════════════════════════════════════════════════════════ */
| |
| ( function () {
| |
| if ( window.innerWidth > 768 ) return;
| |
|
| |
| /* ── 1. Inject mobile CSS after readerToolbar's <style> ─────── */
| |
| function injectMobileCSS() {
| |
| if ( document.getElementById( 'gr-mobile-css' ) ) return;
| |
| var s = document.createElement( 'style' );
| |
| s.id = 'gr-mobile-css';
| |
| s.textContent = [
| |
| /* Font scale */
| |
| 'html { font-size: 18px !important; }',
| |
|
| |
| /* Full-width layout — kill x-scroll everywhere */
| |
| 'html body, html body .mw-page-container, html body .vector-page-container,',
| |
| 'html body .mw-content-container, html body .vector-body-container,',
| |
| 'html body .vector-page-content, html body .mw-body,',
| |
| 'html body .mw-body-content, html body #mw-content-text {',
| |
| ' max-width: 100% !important; width: 100% !important;',
| |
| ' overflow-x: hidden !important; box-sizing: border-box !important;',
| |
| ' margin: 0 !important; padding: 0 !important; }',
| |
|
| |
| /* Content padding */
| |
| 'html body #mw-content-text { padding: 8px 14px 48px !important; }',
| |
|
| |
| /* Content font */
| |
| 'html body .mw-parser-output {',
| |
| ' font-size: 18px !important; line-height: 1.8 !important;',
| |
| ' max-width: 100% !important; overflow-x: hidden !important; }',
| |
|
| |
| /* Headings full width */
| |
| 'html body .mw-parser-output h2, html body .mw-parser-output .mw-heading2 h2 {',
| |
| ' font-size: 1.1em !important; width: 100% !important; margin-top: 1.2em !important; }',
| |
| 'html body .mw-parser-output h3, html body .mw-parser-output .mw-heading3 h3 {',
| |
| ' font-size: 1em !important; width: 100% !important; }',
| |
|
| |
| /* Hide Vector sidebar TOC — replaced by overlay */
| |
| 'html body .vector-column-start, html body #vector-toc,',
| |
| 'html body .vector-toc-landmark, html body .mw-table-of-contents-container,',
| |
| 'html body .vector-sticky-pinned-container,',
| |
| 'html body .vector-pinnable-element.vector-toc-pinnable-element {',
| |
| ' display: none !important; }',
| |
|
| |
| /* Home grid — single column, no x-scroll */
| |
| 'html body .gr-home { overflow-x: hidden !important; max-width: 100% !important; }',
| |
| 'html body .gr-home-grid {',
| |
| ' flex-direction: column !important; flex-wrap: nowrap !important;',
| |
| ' gap: 14px !important; overflow-x: hidden !important; width: 100% !important; }',
| |
| 'html body .gr-home-card {',
| |
| ' flex: 0 0 auto !important; width: 100% !important;',
| |
| ' max-width: 100% !important; min-width: unset !important;',
| |
| ' box-sizing: border-box !important; }',
| |
|
| |
| /* Toolbar */
| |
| 'html body #gr-static-bar {',
| |
| ' height: auto !important; min-height: 52px !important;',
| |
| ' padding: 6px 8px !important; flex-wrap: nowrap !important;',
| |
| ' overflow-x: auto !important; overflow-y: hidden !important;',
| |
| ' scrollbar-width: none !important; gap: 4px !important; }',
| |
| 'html body #gr-static-bar::-webkit-scrollbar { display: none !important; }',
| |
| 'html body .gr-controls .gr-btn {',
| |
| ' height: 44px !important; min-width: 44px !important;',
| |
| ' font-size: 15px !important; padding: 0 10px !important; flex-shrink: 0 !important; }',
| |
| 'html body .gr-controls .gr-icon-btn { width: 44px !important; padding: 0 !important; }',
| |
| 'html body .gr-script-sel {',
| |
| ' height: 40px !important; font-size: 14px !important;',
| |
| ' min-width: 90px !important; max-width: 120px !important; }',
| |
| 'html body .gr-controls .gr-sep { display: none !important; }',
| |
| 'html body .gr-btn-staging { display: none !important; }',
| |
|
| |
| /* TOC overlay styles */
| |
| '.gr-mob-toc-btn {',
| |
| ' display: flex !important; position: fixed !important;',
| |
| ' bottom: 148px !important; left: 16px !important; z-index: 9100 !important;',
| |
| ' background: #fff !important; border: 1.5px solid #b5451b !important;',
| |
| ' border-radius: 24px !important; padding: 10px 16px !important;',
| |
| ' font-size: 15px !important; font-family: system-ui, sans-serif !important;',
| |
| ' color: #b5451b !important; font-weight: 600 !important;',
| |
| ' box-shadow: 0 3px 14px rgba(0,0,0,0.15) !important;',
| |
| ' cursor: pointer !important; align-items: center !important;',
| |
| ' gap: 6px !important; white-space: nowrap !important; }',
| |
|
| |
| '.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; line-height: 1 !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;',
| |
| " font-family: 'Adishila','Noto Serif Devanagari',system-ui,sans-serif !important; }",
| |
| '.gr-mob-toc-body .vector-toc-level-2 a {',
| |
| ' padding-left: 16px !important; font-size: 15px !important; color: #555 !important; }',
| |
|
| |
| /* Annotation toggle button position */
| |
| 'html body #gra-toggle {',
| |
| ' bottom: 80px !important; right: 14px !important;',
| |
| ' width: 54px !important; height: 54px !important; }',
| |
| ].join( '\n' );
| |
| document.head.appendChild( s );
| |
| }
| |
|
| |
| /* ── 2. Mobile TOC overlay ────────────────────────────────────── */
| |
| function initMobileToc() {
| |
| if ( document.getElementById( 'gr-mob-toc-btn' ) ) return;
| |
|
| |
| var tocList = document.querySelector(
| |
| '.vector-toc-contents, .vector-toc .vector-toc-list'
| |
| );
| |
| if ( !tocList ) { setTimeout( initMobileToc, 500 ); return; }
| |
|
| |
| /* Check if page actually has TOC items */
| |
| var hasItems = tocList.querySelector( '.vector-toc-list-item' );
| |
|
| |
| /* Backdrop */
| |
| var bd = document.createElement( 'div' );
| |
| bd.className = 'gr-mob-toc-backdrop';
| |
| document.body.appendChild( bd );
| |
|
| |
| /* Panel */
| |
| var panel = document.createElement( 'div' );
| |
| panel.className = 'gr-mob-toc-panel';
| |
|
| |
| var hdr = document.createElement( 'div' );
| |
| hdr.className = 'gr-mob-toc-header';
| |
| var ttl = document.createElement( 'div' );
| |
| ttl.className = 'gr-mob-toc-title';
| |
| ttl.textContent = 'विषयसूची';
| |
| var cls = document.createElement( 'button' );
| |
| cls.className = 'gr-mob-toc-close';
| |
| cls.textContent = '✕';
| |
| hdr.appendChild( ttl ); hdr.appendChild( cls );
| |
| panel.appendChild( hdr );
| |
|
| |
| var body = document.createElement( 'div' );
| |
| body.className = 'gr-mob-toc-body';
| |
| body.appendChild( tocList.cloneNode( true ) );
| |
| panel.appendChild( body );
| |
| document.body.appendChild( panel );
| |
|
| |
| /* Toggle button — only show if page has TOC */
| |
| var btn = document.createElement( 'button' );
| |
| btn.className = 'gr-mob-toc-btn';
| |
| btn.id = 'gr-mob-toc-btn';
| |
| btn.innerHTML = '☰ Contents';
| |
| if ( !hasItems ) btn.style.display = 'none';
| |
| document.body.appendChild( btn );
| |
|
| |
| 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 = '';
| |
| }
| |
|
| |
| btn.addEventListener( 'click', open );
| |
| cls.addEventListener( 'click', close );
| |
| bd.addEventListener( 'click', close );
| |
| body.querySelectorAll( 'a' ).forEach( function ( a ) {
| |
| a.addEventListener( 'click', close );
| |
| } );
| |
| }
| |
|
| |
| /* ── 3. Mobile hamburger menu ─────────────────────────────────── */
| |
| function initMobileMenu() {
| |
| if ( document.getElementById( 'gr-mob-menu-btn' ) ) return;
| |
|
| |
| var headerStart = document.querySelector( '.vector-header-start' );
| |
| if ( !headerStart ) return;
| |
|
| |
| /* Hamburger button — prepend to header start */
| |
| var btn = document.createElement( 'button' );
| |
| btn.id = 'gr-mob-menu-btn';
| |
| btn.className = 'gr-mob-menu-btn';
| |
| btn.setAttribute( 'aria-label', 'Open menu' );
| |
| btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
| |
| headerStart.insertBefore( btn, headerStart.firstChild );
| |
|
| |
| /* Backdrop */
| |
| var bd = document.createElement( 'div' );
| |
| bd.className = 'gr-mob-menu-backdrop';
| |
| document.body.appendChild( bd );
| |
|
| |
| /* Panel */
| |
| var panel = document.createElement( 'div' );
| |
| panel.className = 'gr-mob-menu-panel';
| |
|
| |
| /* Header */
| |
| var hdr = document.createElement( 'div' );
| |
| hdr.className = 'gr-mob-menu-header';
| |
| var ttl = document.createElement( 'div' );
| |
| ttl.className = 'gr-mob-menu-header-title';
| |
| ttl.textContent = 'Anandamakaranda';
| |
| var cls = document.createElement( 'button' );
| |
| cls.className = 'gr-mob-menu-close';
| |
| cls.textContent = '✕';
| |
| hdr.appendChild( ttl ); hdr.appendChild( cls );
| |
| panel.appendChild( hdr );
| |
|
| |
| /* Body — collect links from vector-header-end */
| |
| var body = document.createElement( 'div' );
| |
| body.className = 'gr-mob-menu-body';
| |
|
| |
| /* Username / user page */
| |
| var userName = window.mw ? mw.config.get( 'wgUserName' ) : null;
| |
| if ( userName ) {
| |
| var userLink = document.createElement( 'a' );
| |
| userLink.className = 'gr-mob-menu-item gr-mob-menu-item-user';
| |
| userLink.href = '/User:' + encodeURIComponent( userName );
| |
| userLink.textContent = '👤 ' + userName;
| |
| body.appendChild( userLink );
| |
| var div0 = document.createElement( 'div' );
| |
| div0.className = 'gr-mob-menu-divider';
| |
| body.appendChild( div0 );
| |
| }
| |
|
| |
| /* Collect links from header-end */
| |
| var headerEnd = document.querySelector( '.vector-header-end' );
| |
| if ( headerEnd ) {
| |
| var links = headerEnd.querySelectorAll( 'a' );
| |
| links.forEach( function ( a ) {
| |
| var item = document.createElement( 'a' );
| |
| item.className = 'gr-mob-menu-item';
| |
| item.href = a.href;
| |
| item.textContent = a.textContent.trim();
| |
| if ( item.textContent ) body.appendChild( item );
| |
| } );
| |
| }
| |
|
| |
| /* Static links */
| |
| var statics = [
| |
| { label: 'Help', href: '/Help:Contents' },
| |
| { label: 'About', href: '/Anandamakaranda:About' },
| |
| ];
| |
| var div1 = document.createElement( 'div' );
| |
| div1.className = 'gr-mob-menu-divider';
| |
| body.appendChild( div1 );
| |
|
| |
| /* Login / logout */
| |
| var isLoggedIn = userName !== null;
| |
| var authItem = document.createElement( 'a' );
| |
| authItem.className = 'gr-mob-menu-item';
| |
| if ( isLoggedIn ) {
| |
| var logoutLink = document.querySelector( '#pt-logout a, a[href*="action=logout"]' );
| |
| authItem.href = logoutLink ? logoutLink.href : '/index.php?title=Special:UserLogout';
| |
| authItem.textContent = 'Log out';
| |
| } else {
| |
| authItem.href = '/index.php?title=Special:UserLogin';
| |
| authItem.textContent = 'Log in';
| |
| }
| |
| body.appendChild( authItem );
| |
|
| |
| panel.appendChild( body );
| |
| document.body.appendChild( panel );
| |
|
| |
| 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 = ''; }
| |
|
| |
| btn.addEventListener( 'click', open );
| |
| cls.addEventListener( 'click', close );
| |
| bd.addEventListener( 'click', close );
| |
| body.querySelectorAll( 'a' ).forEach( function(a){ a.addEventListener( 'click', close ); } );
| |
| }
| |
|
| |
| /* ── Boot ─────────────────────────────────────────────────────── */
| |
| injectMobileCSS(); /* CSS first — synchronous */
| |
| initMobileMenu();
| |
|
| |
| if ( document.readyState === 'loading' ) {
| |
| document.addEventListener( 'DOMContentLoaded', function () {
| |
| setTimeout( initMobileToc, 600 );
| |
| } );
| |
| } else {
| |
| setTimeout( initMobileToc, 600 );
| |
| }
| |
|
| |
| if ( window.mw ) {
| |
| mw.hook( 'wikipage.content' ).add( function () {
| |
| setTimeout( initMobileToc, 600 );
| |
| } );
| |
| }
| |
|
| |
| }() ); | | }() ); |