MediaWiki:Common.js: Difference between revisions
No edit summary |
No edit summary Tag: Reverted |
||
| 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 ─────────────── | ||
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; | ||
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 ); | ||
} ); | } ); | ||
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 | // Tag immediately in case TOC is already in the DOM | ||
tagAndApplyToc(); | tagAndApplyToc(); | ||
var | if ( window.MutationObserver ) { | ||
// Separate observer just for active-item highlight — attribute changes only, | |||
// never fires from our own DOM writes, safe to run forever | |||
var attrObserver = new MutationObserver( function ( mutations ) { | |||
mutations.forEach( function ( m ) { | |||
if ( m.attributeName !== 'class' ) return; | |||
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' ] } ); | |||
} ); | } ); | ||
// Separate observer for lazy TOC population — watches childList but | |||
// 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 ) { | |||
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 } ); | |||
} | |||
} | } | ||
if ( !alreadyTagged ) { | if ( !alreadyTagged ) { | ||
translatableSpans = []; | translatableSpans = []; | ||