|
|
| Line 179: |
Line 179: |
|
| |
|
| // ── TOC: rename "Contents" → "विषयसूची" ──────────────────────── | | // ── TOC: rename "Contents" → "विषयसूची" ──────────────────────── |
| function renameTocTitle() {
| | function renameTocTitle() { |
| if ( _isNoTocPage() ) return;
| | if ( _isNoTocPage() ) return; |
| var toc = document.querySelector( '.vector-toc' );
| | |
| if ( !toc ) return;
| | var toc = document.querySelector('.vector-toc'); |
| var titleEl = toc.querySelector( '.vector-toc-title' );
| | if ( !toc ) return; |
| if ( !titleEl ) return;
| | |
| var TITLE = 'विषयसूची';
| | var titleEl = |
| var replaced = false;
| | toc.querySelector('.vector-toc-title') || |
| titleEl.childNodes.forEach( function ( n ) {
| | toc.querySelector('.vector-pinnable-header-label'); |
| if ( n.nodeType === 3 && n.textContent.trim() ) {
| | |
| n.textContent = TITLE;
| | if ( !titleEl ) return; |
| replaced = true;
| | |
| }
| | var LABEL = 'विषयसूची'; |
| } );
| | |
| if ( !replaced && titleEl.childElementCount === 0 ) {
| | /* If already inserted, just refresh text */ |
| titleEl.textContent = TITLE;
| | var span = titleEl.querySelector('.gr-toc-title'); |
| }
| | |
| // Fix up any <span data-deva> wrappers that tagTextNodes created | | if ( !span ) { |
| // over "Contents" — update their data-deva to the new Sanskrit text | | titleEl.innerHTML = ''; |
| titleEl.querySelectorAll( '[data-deva]' ).forEach( function ( span ) {
| | |
| span.setAttribute( 'data-deva', TITLE );
| | span = document.createElement('span'); |
| if ( currentScript !== 'deva' ) {
| | span.className = 'gr-toc-title'; |
| span.textContent = transliterateText( TITLE, currentScript );
| | span.setAttribute('data-deva', LABEL); |
| } else {
| | |
| span.textContent = TITLE;
| | titleEl.appendChild(span); |
| }
| | translatableSpans.push(span); // uses your internal array |
| } );
| |
| } | | } |
|
| |
|
| | span.textContent = |
| | currentScript === 'deva' |
| | ? LABEL |
| | : transliterateText(LABEL, currentScript); |
| | } |
| // ── TOC: Remove the "Beginning" / top-of-page link ───────────── | | // ── TOC: Remove the "Beginning" / top-of-page link ───────────── |
| function removeTocBeginning() { | | function removeTocBeginning() { |
| Line 613: |
Line 617: |
| } | | } |
|
| |
|
| // ── Scroll-based active anchor detection ────────────────────── | | // Track which anchors are visible |
| // Find the last anchor whose top edge is above the scroll threshold | | var _visibleIds = new Set(); |
| // (1/3 of viewport height). This is robust for zero-height anchor spans
| |
| // and matches how the ref site tracks active sections.
| |
| var SCROLL_THRESHOLD_RATIO = 0.33; // top 1/3 of viewport
| |
|
| |
|
| function findActiveAnchor() { | | var observer = new IntersectionObserver( function ( entries ) { |
| var threshold = window.innerHeight * SCROLL_THRESHOLD_RATIO; | | entries.forEach( function ( entry ) { |
| var best = null;
| | var id = entry.target.id; |
| // Walk anchors in order; keep updating best as long as anchor is above threshold
| | if ( entry.isIntersecting ) { |
| for ( var k = 0; k < anchors.length; k++ ) {
| | _visibleIds.add( id ); |
| var r = anchors[ k ].getBoundingClientRect(); | |
| // Use top of the heading AFTER the anchor (anchor is height:0)
| |
| // The anchor has padding-top:60px so its effective visual top is r.top
| |
| if ( r.top <= threshold ) { | |
| best = anchors[ k ].id; | |
| } else { | | } else { |
| break; // anchors are in document order — no need to continue | | _visibleIds.delete( id ); |
| } | | } |
| | } ); |
| | |
| | // Find the topmost visible anchor |
| | var topId = null; |
| | var topY = Infinity; |
| | _visibleIds.forEach( function ( id ) { |
| | var el = document.getElementById( id ); |
| | if ( el ) { |
| | var y = el.getBoundingClientRect().top; |
| | if ( y < topY ) { topY = y; topId = id; } |
| | } |
| | } ); |
| | |
| | // If nothing visible (scrolled past), find the last anchor above viewport |
| | if ( !topId ) { |
| | var best = null, bestBottom = -Infinity; |
| | anchors.forEach( function ( span ) { |
| | var r = span.getBoundingClientRect(); |
| | if ( r.bottom < 80 && r.bottom > bestBottom ) { |
| | bestBottom = r.bottom; |
| | best = span.id; |
| | } |
| | } ); |
| | topId = best; |
| } | | } |
| return best;
| |
| }
| |
|
| |
|
| var _scrollRaf = null;
| | setTocActive( topId ); |
| function onScroll() {
| | }, { rootMargin: '-60px 0px -70% 0px', threshold: 0 } ); |
| if ( _scrollRaf ) return; | |
| _scrollRaf = requestAnimationFrame( function () {
| |
| _scrollRaf = null;
| |
| setTocActive( findActiveAnchor() );
| |
| } );
| |
| }
| |
|
| |
|
| window.addEventListener( 'scroll', onScroll, { passive: true } ); | | anchors.forEach( function ( span ) { observer.observe( span ); } ); |
| // Also run once on load so initial position is highlighted
| |
| setTimeout( function () { setTocActive( findActiveAnchor() ); }, 200 );
| |
| } | | } |
|
| |
|
| Line 976: |
Line 986: |
| wireUllekhaLinks(); | | wireUllekhaLinks(); |
| } | | } |
| }() );
| |
|
| |
|
| |
| // ── Special pages: remove MW branding + wire "Forgot password" ───────
| |
| // Runs on Special:UserLogin, Special:CreateAccount, Special:UserLogout
| |
| // Hides all elements that reveal the site is built on MediaWiki.
| |
| ( function () {
| |
| var ns = window.mw && mw.config.get( 'wgNamespaceNumber' );
| |
| if ( ns !== -1 ) return; // -1 = Special namespace
| |
|
| |
| var specialPage = ( window.mw && mw.config.get( 'wgCanonicalSpecialPageName' ) ) || '';
| |
| var isLogin = specialPage === 'Userlogin';
| |
| var isCreate = specialPage === 'CreateAccount';
| |
| var isLogout = specialPage === 'UserLogout';
| |
| var isPwReset = specialPage === 'PasswordReset';
| |
|
| |
| function hideEl( sel ) {
| |
| document.querySelectorAll( sel ).forEach( function ( el ) {
| |
| el.style.setProperty( 'display', 'none', 'important' );
| |
| } );
| |
| }
| |
|
| |
| function cleanSpecialPage() {
| |
|
| |
| // ── Always: remove "Powered by MediaWiki" and footer ─────────────
| |
| hideEl( '#footer, .mw-footer, #footer-icons, #footer-places' );
| |
| hideEl( 'a[href*="mediawiki.org"], img[alt*="MediaWiki"]' );
| |
| hideEl( '#mw-panel, .vector-sidebar, .vector-sidebar-container' );
| |
|
| |
| if ( isLogin ) {
| |
| // "Help with logging in" → external MW help link
| |
| hideEl( '.mw-userlogin-help' );
| |
|
| |
| // "Don't have an account?" CTA block + avatar
| |
| hideEl( '#mw-createaccount-cta' );
| |
| hideEl( '.mw-createacct-benefits-container' );
| |
|
| |
| // "Forgot your password?" — replace href with mailto
| |
| document.querySelectorAll( 'a[href*="PasswordReset"], .mw-userlogin-forgotpassword a' )
| |
| .forEach( function ( a ) {
| |
| a.href = 'mailto:feedback@anandamakaranda.in?subject=Password%20Reset%20Request';
| |
| a.textContent = 'Forgot your password?';
| |
| } );
| |
| }
| |
|
| |
| if ( isCreate ) {
| |
| hideEl( '.mw-createacct-benefits-container' );
| |
| hideEl( '.mw-createacct-help' );
| |
| // Replace any MW-branded heading
| |
| var h1 = document.querySelector( '#firstHeading, h1.firstHeading' );
| |
| if ( h1 ) h1.style.display = 'none';
| |
| }
| |
| }
| |
|
| |
| if ( document.readyState === 'loading' ) {
| |
| document.addEventListener( 'DOMContentLoaded', cleanSpecialPage );
| |
| } else {
| |
| cleanSpecialPage();
| |
| }
| |
|
| |
| // Re-run after a short delay in case Vector injects elements dynamically
| |
| setTimeout( cleanSpecialPage, 500 );
| |
|
| |
| }() ); | | }() ); |