MediaWiki:Common.js: Difference between revisions

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


   // ── TOC active-item highlight + lazy TOC tagging ───────────────
   // ── TOC active-item highlight + lazy TOC tagging ───────────────
   // ── TOC active-item highlight + lazy TOC tagging ───────────────
   // MutationObserver watches Vector 2022 TOC class changes and colours
  // 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 188: Line 192:
     toc._grObserved = true;
     toc._grObserved = true;


     var _tagging = false;
     // Tag any TOC text nodes that appeared after initial tagTextNodes() run
     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 209: Line 211:
         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 214: Line 217:
         } );
         } );
       }
       }
      _tagging = false;
     }
     }


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


     if ( window.MutationObserver ) {
     var observer = new MutationObserver( function ( mutations ) {
      // Separate observer just for active-item highlight — attribute changes only,
      mutations.forEach( function ( m ) {
      // never fires from our own DOM writes, safe to run forever
        // Tag any new text nodes added to the TOC (lazy render)
      var attrObserver = new MutationObserver( function ( mutations ) {
        if ( m.addedNodes && m.addedNodes.length ) {
        mutations.forEach( function ( m ) {
           tagAndApplyToc();
           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 236: Line 240:
             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 ) {
      observer.observe( li, { attributes: true, attributeFilter: [ 'class' ] } );
    } );


      // Separate observer for lazy TOC population — watches childList but
    // Also watch for new list items being added (TOC populated lazily)
      // ignores mutations caused by our own span insertions (those have
    observer.observe( toc, { childList: true, subtree: true } );
      // addedNodes that are <span data-deva="…"> elements we just created)
      var childObserver = new MutationObserver( function ( mutations ) {
        var hasExternalAddition = mutations.some( function ( m ) {
          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 ────────────────────────────────────────────────────────
  function init() {
    var content      = document.querySelector( '.mw-parser-output' );
    var alreadyTagged = content && content.querySelector( '[data-deva]' );
     if ( !alreadyTagged ) {
     if ( !alreadyTagged ) {
       translatableSpans = [];
       translatableSpans = [];