Tip of the day
Bank space is unlimited, if you are worried about the usage of something, bank it!
MediaWiki:Gadget-CollapsibleHeaders.js
From Walkscape Walkthrough
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* CollapsibleHeaders
* Adds expand/collapse toggles to top-level article headings.
*
* Section logic:
* - Clicking a heading hides/shows everything until the next heading
* of the same or higher level.
* - Headings remain open by default.
* - Only direct article-content headings are processed, avoiding most
* headings inside infoboxes, navboxes, tables, and templates.
*/
(function () {
'use strict';
const CONTENT_SELECTOR = '#mw-content-text .mw-parser-output';
const HEADING_SELECTOR = 'h1, h2, h3, h4, h5, h6';
const WRAPPER_SELECTOR = '.mw-heading';
function getHeadingLevel(heading) {
return Number(heading.tagName.slice(1));
}
function getHeadingWrapper(heading) {
return heading.closest(WRAPPER_SELECTOR) || heading;
}
function getBoundaryHeading(element) {
if (element.matches(HEADING_SELECTOR)) {
return element;
}
if (element.matches(WRAPPER_SELECTOR)) {
return element.querySelector(HEADING_SELECTOR);
}
return null;
}
function getDirectArticleHeadings(content) {
const headings = [];
Array.from(content.children).forEach((child) => {
if (child.matches(HEADING_SELECTOR)) {
headings.push(child);
return;
}
if (child.matches(WRAPPER_SELECTOR)) {
const heading = child.querySelector(HEADING_SELECTOR);
if (heading) {
headings.push(heading);
}
}
});
return headings;
}
function getSectionNodes(heading) {
const level = getHeadingLevel(heading);
const wrapper = getHeadingWrapper(heading);
const nodes = [];
let node = wrapper.nextElementSibling;
while (node) {
const boundaryHeading = getBoundaryHeading(node);
if (boundaryHeading && getHeadingLevel(boundaryHeading) <= level) {
break;
}
nodes.push(node);
node = node.nextElementSibling;
}
return nodes;
}
function initCollapsibleHeaders($content) {
const content = $content && $content[0]
? $content[0].querySelector(CONTENT_SELECTOR) || $content[0]
: document.querySelector(CONTENT_SELECTOR);
if (!content || content.dataset.wsCollapsibleHeadersLoaded === '1') {
return;
}
const headings = getDirectArticleHeadings(content);
if (!headings.length) {
return;
}
content.dataset.wsCollapsibleHeadersLoaded = '1';
const sections = headings.map((heading, index) => {
const wrapper = getHeadingWrapper(heading);
const button = document.createElement('button');
button.type = 'button';
button.className = 'ws-collapsible-header-toggle';
button.setAttribute('aria-expanded', 'true');
button.setAttribute('aria-label', 'Collapse section');
button.title = 'Collapse section';
button.textContent = '▾';
heading.classList.add('ws-collapsible-header');
wrapper.classList.add('ws-collapsible-header-wrapper');
heading.insertBefore(button, heading.firstChild);
return {
id: index,
heading,
wrapper,
button,
nodes: getSectionNodes(heading),
collapsed: false
};
});
function applyState() {
const hiddenNodes = new Set();
sections.forEach((section) => {
if (section.collapsed) {
section.nodes.forEach((node) => hiddenNodes.add(node));
}
});
sections.forEach((section) => {
section.nodes.forEach((node) => {
const hidden = hiddenNodes.has(node);
node.hidden = hidden;
node.classList.toggle('ws-collapsible-header-hidden', hidden);
});
section.wrapper.classList.toggle(
'ws-collapsible-header-collapsed',
section.collapsed
);
section.button.textContent = section.collapsed ? '▸' : '▾';
section.button.setAttribute('aria-expanded', String(!section.collapsed));
section.button.setAttribute(
'aria-label',
section.collapsed ? 'Expand section' : 'Collapse section'
);
section.button.title = section.collapsed ? 'Expand section' : 'Collapse section';
});
}
sections.forEach((section) => {
section.button.addEventListener('click', (event) => {
event.preventDefault();
event.stopPropagation();
section.collapsed = !section.collapsed;
applyState();
});
});
}
mw.hook('wikipage.content').add(initCollapsibleHeaders);
}());
