MediaWiki:Common.js: Difference between revisions

Undo revision 4772 by Chandrashekars (talk)
Tag: Undo
No edit summary
Line 182: Line 182:


   // ── TOC active-item highlight + lazy TOC tagging ───────────────
   // ── TOC active-item highlight + lazy TOC tagging ───────────────
   // MutationObserver watches Vector 2022 TOC class changes and colours
   // ── TOC active-item highlight + lazy TOC tagging ───────────────
  // the active link orange.  This block is not modified for the highlight
  // logic, but we additionally tag any TOC text nodes that were not yet
  // in the DOM when tagTextNodes() ran at boot (Vector 2022 renders the
  // TOC lazily on first scroll).
   function watchTocActive() {
   function watchTocActive() {
     var toc = document.querySelector( '.vector-toc' );
     var toc = document.querySelector( '.vector-toc' );
Line 192: Line 188:
     toc._grObserved = true;
     toc._grObserved = true;


     // Tag any TOC text nodes that appeared after initial tagTextNodes() run
     var _tagging = false;
     function tagAndApplyToc() {
     function tagAndApplyToc() {
      if ( _tagging ) return;
      _tagging = true;
       var walker = document.createTreeWalker( toc, NodeFilter.SHOW_TEXT );
       var walker = document.createTreeWalker( toc, NodeFilter.SHOW_TEXT );
       var nodes  = [];
       var nodes  = [];
Line 211: Line 209:
         newSpans.push( span );
         newSpans.push( span );
       } );
       } );
      // Apply current script to any newly tagged spans
       if ( currentScript !== 'deva' && newSpans.length ) {
       if ( currentScript !== 'deva' && newSpans.length ) {
         newSpans.forEach( function ( span ) {
         newSpans.forEach( function ( span ) {
Line 217: Line 214:
         } );
         } );
       }
       }
      _tagging = false;
     }
     }


     // Tag immediately (catches TOC if it was already rendered)
     // Tag immediately in case TOC is already in the DOM
     tagAndApplyToc();
     tagAndApplyToc();


     var observer = new MutationObserver( function ( mutations ) {
     if ( window.MutationObserver ) {
      mutations.forEach( function ( m ) {
      // Separate observer just for active-item highlight — attribute changes only,
        // Tag any new text nodes added to the TOC (lazy render)
      // never fires from our own DOM writes, safe to run forever
        if ( m.addedNodes && m.addedNodes.length ) {
      var attrObserver = new MutationObserver( function ( mutations ) {
           tagAndApplyToc();
        mutations.forEach( function ( m ) {
        }
           if ( m.attributeName !== 'class' ) return;
        // Highlight active item
        if ( m.attributeName === 'class' ) {
           var li  = m.target;
           var li  = m.target;
           var link = li.querySelector( ':scope > .vector-toc-link' );
           var link = li.querySelector( ':scope > .vector-toc-link' );
Line 240: Line 236:
             link.style.fontWeight = '';
             link.style.fontWeight = '';
           }
           }
         }
         } );
      } );
      toc.querySelectorAll( '.vector-toc-list-item' ).forEach( function ( li ) {
        attrObserver.observe( li, { attributes: true, attributeFilter: [ 'class' ] } );
       } );
       } );
    } );


    toc.querySelectorAll( '.vector-toc-list-item' ).forEach( function ( li ) {
      // Separate observer for lazy TOC population — watches childList but
      observer.observe( li, { attributes: true, attributeFilter: [ 'class' ] } );
      // ignores mutations caused by our own span insertions (those have
    } );
      // addedNodes that are <span data-deva="…"> elements we just created)
 
      var childObserver = new MutationObserver( function ( mutations ) {
    // Also watch for new list items being added (TOC populated lazily)
        var hasExternalAddition = mutations.some( function ( m ) {
    observer.observe( toc, { childList: true, subtree: true } );
          return Array.prototype.some.call( m.addedNodes, function ( n ) {
            return !( n.nodeType === 1 && n.hasAttribute( 'data-deva' ) );
          } );
        } );
        if ( !hasExternalAddition ) return;
        tagAndApplyToc();
        // Attach highlight observer to any newly added list items
        toc.querySelectorAll( '.vector-toc-list-item' ).forEach( function ( li ) {
          attrObserver.observe( li, { attributes: true, attributeFilter: [ 'class' ] } );
        } );
      } );
      childObserver.observe( toc, { childList: true, subtree: true } );
    }
   }
   }
 
   // ── Init ──────────────────────────────────────────────────────
   // ── Init ────────────────────────────────────────────────────────
   function init() {
   function init() {
     var content      = document.querySelector( '.mw-parser-output' );
     var content      = document.querySelector( '.mw-parser-output' );