Created
July 4, 2024 01:36
-
-
Save jdlrobson/13cd58574c4248cfec13d353269f3dcd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
const HEADING_TAGS = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ]; | |
/** Cache of headings in page. Cleared any time wikipage.content hook is called. */ | |
let headingsInPageCached; | |
mw.hook( 'wikipage.content' ).add( () => { | |
headingsInPageCached = null; | |
} ); | |
/** | |
* @callback {Function} InsertActionCallback | |
* @param {Element} link | |
* | |
* @typedef {Object} HeadingObject | |
* @property {string} anchor ID of heading for use with document.getElementById | |
* @property {element} element of heading | |
* @property {string} line text of heading | |
* @property {string} level of heading e.g. '2' for h2. | |
* @property {InsertActionCallback} insertAction for adding links to heading | |
*/ | |
/** | |
* Gets all heading elements in the page. | |
* | |
* @param {Element} heading | |
* @return {HeadingObject|null} null if couldn't be resolved to a heading. | |
*/ | |
const getHeading = function ( heading ) { | |
const HEADLINE_SELECTOR = [ '.mw-headline', ...HEADING_TAGS.map( ( tag ) => `${ tag }[id]` ) ] | |
.map( ( sel ) => `.mw-parser-output ${ sel }` ).join( ', ' ); | |
const headlineElement = heading.querySelector( HEADLINE_SELECTOR ); | |
/** | |
* Helper function | |
* @ignore | |
* @param {string} text | |
* @return {Element} | |
*/ | |
const insertBracket = ( text ) => { | |
const bracket = document.createElement( 'span' ); | |
bracket.textContent = text; | |
bracket.setAttribute( 'class', 'mw-editsection-bracket' ); | |
return bracket; | |
}; | |
/** | |
* Helper function | |
* @type {InsertActionCallback} | |
*/ | |
const insertAction = ( action ) => { | |
const node = document.createElement( 'span' ); | |
node.setAttribute( 'class', 'mw-editsection' ); | |
node.appendChild( insertBracket( '[' ) ); | |
node.appendChild( action ); | |
node.appendChild( insertBracket( ']' ) ); | |
heading.appendChild( node ); | |
}; | |
// Keys should match counterparts in skins/components/SkinComponentTableOfContents.php | |
return headlineElement ? { | |
element: heading, | |
level: heading.tagName.replace( 'H', '' ), | |
anchor: headlineElement.id, | |
line: headlineElement.textContent, | |
insertAction | |
} : null; | |
}; | |
mw.util.getHeadings = function () { | |
if ( headingsInPageCached ) { | |
return headingsInPageCached; | |
} | |
// Support two variants of heading markup: (see T13555, T358452) | |
// (old) <h2> <span class="mw-headline" id="...">...</span> ... </h2> | |
// (new) <div class="mw-heading"> <h2 id="...">...</h2> ... </div> | |
// [more information: https://www.mediawiki.org/wiki/Heading_HTML_changes] | |
const HEADING_SELECTOR = [ '.mw-heading', ...HEADING_TAGS.map( ( tag ) => `${ tag }:not([id])` ) ] | |
.map( ( sel ) => `.mw-parser-output ${ sel }` ).join( ', ' ); | |
const contentElement = document.querySelector( '#mw-content-text.mw-body-content' ); | |
if ( contentElement ) { | |
headingsInPageCached = Array.from( | |
contentElement.querySelectorAll( HEADING_SELECTOR ) | |
).map( getHeading ); | |
return headingsInPageCached; | |
} else { | |
return []; | |
} | |
}; | |
}()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment