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' ); | ||
/* | /* Colour ALL descendant elements — covers both: | ||
link.querySelectorAll( ' | * • data-deva <span> wrappers (Devanagari mode, textContent replaced) | ||
* • .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( ' | link.querySelectorAll( '*' ).forEach( function ( el ) { | ||
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 ) { | ||
/* | /* Find the scrollable ancestor within the TOC container. | ||
var | * Vector 2022 uses .vector-sticky-pinned-container as the | ||
var | * scroll host in some versions, and .vector-toc in others. */ | ||
if ( | var scrollHost = null; | ||
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 | /* Remove appearance panel + watchlist overflow. | ||
* | * Vector injects some of these elements via its own JS after DOMContentLoaded, | ||
* | * 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', | ||
' | '[aria-controls="vector-appearance"]' | ||
].forEach( function ( sel ) { | ]; | ||
function removeHiddenEls() { | |||
HIDE_SELS.forEach( function ( sel ) { | |||
document.querySelectorAll( sel ).forEach( function ( el ) { | |||
if ( el.parentNode ) el.parentNode.removeChild( el ); | |||
} ); | |||
} ); | } ); | ||
} ); | } | ||
/* | removeHiddenEls(); | ||
if ( window.MutationObserver ) { | |||
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' ); | ||