Tags: Reverted Mobile edit Mobile web edit |
|
| Line 1,242: |
Line 1,242: |
| /* ── Expose storeQueryForLink for readerToolbar to call ── */ | | /* ── Expose storeQueryForLink for readerToolbar to call ── */ |
| window.grStoreSearchHL = storeQueryForLink; | | window.grStoreSearchHL = storeQueryForLink; |
|
| |
| }() );
| |
| /* ═══════════════════════════════════════════════════════════════
| |
| 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 */
| |
|
| |
| /* ── Fix Minerva header: remove top gap, ensure orange, show logo ── */
| |
| function fixMinervaHeader() {
| |
| if ( !document.body.classList.contains( 'skin-minerva' ) ) return;
| |
|
| |
| /* Remove any top margin/padding on body — readerToolbar may have set it */
| |
| document.body.style.paddingTop = '';
| |
| document.body.style.marginTop = '0';
| |
|
| |
| /* Also watch for readerToolbar setting paddingTop after us */
| |
| var _bodyObserver = new MutationObserver( function() {
| |
| if ( document.body.style.paddingTop && document.body.style.paddingTop !== '0px' ) {
| |
| document.body.style.paddingTop = '';
| |
| }
| |
| } );
| |
| _bodyObserver.observe( document.body, { attributes: true, attributeFilter: ['style'] } );
| |
|
| |
| /* Force orange header */
| |
| var headerEl = document.querySelector( 'header.header-container' );
| |
| if ( headerEl ) headerEl.style.background = '#b5451b';
| |
|
| |
| /* Add quill logo before site name */
| |
| var brandingLink = document.querySelector( '.branding-box a' );
| |
| if ( brandingLink && !brandingLink.querySelector( '.gr-mob-logo' ) ) {
| |
| var quillSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="28" height="28" fill="none" style="margin-right:8px;flex-shrink:0;">' +
| |
| '<path stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" d="M32 4C26 4 14 10 8 28L6 34l6-1c4-1 8-4 11-8"/>' +
| |
| '<path stroke="#fff" stroke-width="1.8" stroke-linecap="round" d="M32 4C28 12 22 20 12 26"/>' +
| |
| '<path stroke="#fff" stroke-width="1.8" stroke-linecap="round" d="M8 28c2-2 4-3 6-2s3 3 2 5"/>' +
| |
| '<path stroke="#fff" stroke-width="1.5" stroke-linecap="round" d="M12 26L6 34" opacity="0.6"/></svg>';
| |
| var logoEl = document.createElement( 'span' );
| |
| logoEl.className = 'gr-mob-logo';
| |
| logoEl.innerHTML = quillSvg;
| |
| brandingLink.style.cssText = 'display:flex;align-items:center;text-decoration:none;';
| |
| brandingLink.insertBefore( logoEl, brandingLink.firstChild );
| |
|
| |
| /* Style the text span */
| |
| var textSpan = brandingLink.querySelector( 'span:not(.gr-mob-logo)' );
| |
| if ( textSpan ) {
| |
| textSpan.style.cssText = 'color:#fff;font-size:17px;font-weight:700;font-family:system-ui,sans-serif;line-height:1.2;';
| |
| }
| |
| }
| |
| }
| |
|
| |
| if ( document.readyState === 'loading' ) {
| |
| document.addEventListener( 'DOMContentLoaded', fixMinervaHeader );
| |
| } else {
| |
| fixMinervaHeader();
| |
| }
| |
|
| |
| 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 );
| |
| setTimeout( function() { expandAllSections(); watchSections(); }, 100 );
| |
| setTimeout( expandAllSections, 600 );
| |
| } );
| |
| }
| |
|
| |
| /* ── Force expand all Minerva collapsed sections ──────────────
| |
| * MobileFrontend JS runs AFTER our code and re-collapses sections.
| |
| * We use a MutationObserver to immediately re-expand anything
| |
| * that gets hidden, plus run on load and on MW hooks.
| |
| * ─────────────────────────────────────────────────────────── */
| |
| function expandAllSections() {
| |
| if ( !document.body.classList.contains( 'skin-minerva' ) ) return;
| |
|
| |
| /* THE KEY FIX: MobileFrontend uses hidden="until-found" attribute
| |
| * which CSS display:block cannot override. Must remove the attribute. */
| |
| document.querySelectorAll( '[hidden]' ).forEach( function(el) {
| |
| var h = el.getAttribute( 'hidden' );
| |
| if ( h === 'until-found' || h === '' || h === 'hidden' ) {
| |
| if ( el.closest( '[class*="mf-section-"], .collapsible-block' )
| |
| || el.classList.contains( 'collapsible-block' )
| |
| || /mf-section-/.test( el.className ) ) {
| |
| el.removeAttribute( 'hidden' );
| |
| }
| |
| }
| |
| } );
| |
|
| |
| /* Also remove hidden from all mf-section and collapsible-block directly */
| |
| 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.style.setProperty( 'content-visibility', 'visible', 'important' );
| |
| el.removeAttribute( 'aria-hidden' );
| |
| } );
| |
|
| |
| /* Mark headings as open, disable pointer events to prevent re-collapse */
| |
| document.querySelectorAll( '.section-heading, .collapsible-heading' ).forEach( function(el) {
| |
| el.setAttribute( 'aria-expanded', 'true' );
| |
| el.style.setProperty( 'pointer-events', 'none', 'important' );
| |
| } );
| |
|
| |
| /* Hide collapse indicators */
| |
| document.querySelectorAll(
| |
| '.section-heading .indicator, .collapsible-heading .indicator'
| |
| ).forEach( function(el) {
| |
| el.style.setProperty( 'display', 'none', 'important' );
| |
| } );
| |
| }
| |
|
| |
| /* Persistent observer — fight back when MF re-collapses */
| |
| var _sectionObserver = null;
| |
| function watchSections() {
| |
| if ( !document.body.classList.contains( 'skin-minerva' ) ) return;
| |
| if ( _sectionObserver ) return;
| |
|
| |
| var _timer = null;
| |
| _sectionObserver = new MutationObserver( function( mutations ) {
| |
| var needExpand = mutations.some( function(m) {
| |
| /* Watch for hidden attribute being added or style=display:none */
| |
| if ( m.type === 'attributes' ) {
| |
| if ( m.attributeName === 'hidden' ) return true;
| |
| if ( m.attributeName === 'style' && m.target.style.display === 'none' ) return true;
| |
| }
| |
| return false;
| |
| } );
| |
| if ( needExpand ) {
| |
| clearTimeout( _timer );
| |
| _timer = setTimeout( expandAllSections, 30 );
| |
| }
| |
| } );
| |
|
| |
| /* Observe the content area for attribute changes including hidden */
| |
| var contentEl = document.querySelector( '#mw-content-text, #mw-mf-page-center' );
| |
| if ( contentEl ) {
| |
| _sectionObserver.observe( contentEl, {
| |
| subtree: true, attributes: true,
| |
| attributeFilter: ['style', 'class', 'hidden', 'aria-hidden']
| |
| } );
| |
| }
| |
| }
| |
|
| |
| /* Run on load */
| |
| if ( document.readyState === 'loading' ) {
| |
| document.addEventListener( 'DOMContentLoaded', function() {
| |
| setTimeout( function() { expandAllSections(); watchSections(); }, 100 );
| |
| setTimeout( expandAllSections, 500 );
| |
| setTimeout( expandAllSections, 1200 );
| |
| } );
| |
| } else {
| |
| setTimeout( function() { expandAllSections(); watchSections(); }, 100 );
| |
| setTimeout( expandAllSections, 500 );
| |
| setTimeout( expandAllSections, 1200 );
| |
| }
| |
|
| |
|
| }() ); | | }() ); |