MediaWiki:Common.js: Difference between revisions

No edit summary
No edit summary
Line 199: Line 199:
         link.style.setProperty( 'color',      ACTIVE_COLOR,  'important' );
         link.style.setProperty( 'color',      ACTIVE_COLOR,  'important' );
         link.style.setProperty( 'font-weight', ACTIVE_WEIGHT, 'important' );
         link.style.setProperty( 'font-weight', ACTIVE_WEIGHT, 'important' );
         /* Also colour nested spans (e.g. data-deva spans from transliteration) */
         /* Colour ALL descendant elements — covers both:
         link.querySelectorAll( 'span' ).forEach( function ( s ) {
        *  • data-deva <span> wrappers (Devanagari mode, textContent replaced)
           s.style.setProperty( 'color', ACTIVE_COLOR, 'important' );
        *  • .vector-toc-text / .vector-toc-numb spans (all scripts)
        * After applyScript() runs for non-Deva scripts, textContent is a
        * plain text node so querySelectorAll('span') still finds the
        * structural spans (.vector-toc-text etc.) which need colouring. */
         link.querySelectorAll( '*' ).forEach( function ( el ) {
           el.style.setProperty( 'color', ACTIVE_COLOR, 'important' );
         } );
         } );
       } else {
       } else {
         link.style.removeProperty( 'color' );
         link.style.removeProperty( 'color' );
         link.style.removeProperty( 'font-weight' );
         link.style.removeProperty( 'font-weight' );
         link.querySelectorAll( 'span' ).forEach( function ( s ) {
         link.querySelectorAll( '*' ).forEach( function ( el ) {
           s.style.removeProperty( 'color' );
           el.style.removeProperty( 'color' );
         } );
         } );
       }
       }
Line 247: Line 252:
               var cRect  = container.getBoundingClientRect();
               var cRect  = container.getBoundingClientRect();
               if ( liRect.top < cRect.top + 8 || liRect.bottom > cRect.bottom - 8 ) {
               if ( liRect.top < cRect.top + 8 || liRect.bottom > cRect.bottom - 8 ) {
                 /* Scroll only inside the TOC container, not the page */
                 /* Find the scrollable ancestor within the TOC container.
                 var scrollParent = container.querySelector( '.vector-toc' ) || container;
                * Vector 2022 uses .vector-sticky-pinned-container as the
                 var offset = liRect.top - cRect.top;
                * scroll host in some versions, and .vector-toc in others. */
                 if ( offset < 8 || offset > cRect.height - 48 ) {
                 var scrollHost = null;
                   scrollParent.scrollTop += offset - ( cRect.height / 2 );
                 var candidate  = li.parentNode;
                 while ( candidate && candidate !== document.body ) {
                  if ( candidate.scrollHeight > candidate.clientHeight + 4 ) {
                    scrollHost = candidate;
                    break;
                   }
                  candidate = candidate.parentNode;
                }
                if ( scrollHost ) {
                  var targetTop = li.offsetTop - ( scrollHost.clientHeight / 2 );
                  scrollHost.scrollTop = Math.max( 0, targetTop );
                 }
                 }
               }
               }
Line 311: Line 326:
   // ── Init ────────────────────────────────────────────────────────
   // ── Init ────────────────────────────────────────────────────────
   function init() {
   function init() {
     /* Remove appearance panel + watchlist overflow from DOM entirely
     /* Remove appearance panel + watchlist overflow.
     * so they cannot be toggled open even by JS. CSS display:none is
     * Vector injects some of these elements via its own JS after DOMContentLoaded,
     * enough for most cases but DOM removal prevents any JS re-showing. */
     * so we use a MutationObserver to catch them whenever they appear. */
     [ '#vector-appearance',
     var HIDE_SELS = [
      '#vector-appearance',
       '#vector-appearance-pinned-container',
       '#vector-appearance-pinned-container',
       '#vector-appearance-unpinned-container',
       '#vector-appearance-unpinned-container',
       '.mw-portlet-appearance',
       '.mw-portlet-appearance',
       '.mw-portlet-vector-user-menu-overflow',
       '.mw-portlet-vector-user-menu-overflow',
       '#p-vector-user-menu-overflow',
       '[aria-controls="vector-appearance"]'
     ].forEach( function ( sel ) {
     ];
      document.querySelectorAll( sel ).forEach( function ( el ) {
    function removeHiddenEls() {
        el.parentNode && el.parentNode.removeChild( el );
      HIDE_SELS.forEach( function ( sel ) {
        document.querySelectorAll( sel ).forEach( function ( el ) {
          if ( el.parentNode ) el.parentNode.removeChild( el );
        } );
       } );
       } );
     } );
     }
     /* Remove the appearance toggle BUTTON (aria-controls="vector-appearance") */
    removeHiddenEls();
    document.querySelectorAll( '[aria-controls="vector-appearance"]' ).forEach( function ( el ) {
     if ( window.MutationObserver ) {
      el.parentNode && el.parentNode.removeChild( el );
      var hideObserver = new MutationObserver( function ( mutations ) {
     } );
        var needsClean = false;
        mutations.forEach( function ( m ) {
          if ( m.addedNodes.length ) needsClean = true;
        } );
        if ( needsClean ) removeHiddenEls();
      } );
      /* Watch only direct children of body — NOT subtree.
      * Vector appends the appearance panel as a direct child of body.
      * Using subtree:true would fire on every inner DOM change (including
      * Vector setting active classes on TOC items) and interfere with the
      * liObserver that handles active highlight colouring. */
      hideObserver.observe( document.body, { childList: true, subtree: false } );
      /* Also check the header area where Vector sometimes injects the button */
      var mwHeader = document.querySelector( '.mw-header' ) || document.querySelector( '#mw-head' );
      if ( mwHeader ) {
        hideObserver.observe( mwHeader, { childList: true, subtree: true } );
      }
      /* Stop observing after 8s — Vector will have finished by then */
      setTimeout( function () { hideObserver.disconnect(); }, 8000 );
     }


     var content      = document.querySelector( '.mw-parser-output' );
     var content      = document.querySelector( '.mw-parser-output' );