MediaWiki:Common.js: Difference between revisions
Appearance
Show section trees above Contents in the left column |
No edit summary |
||
| (One intermediate revision by one other user not shown) | |||
| Line 1: | Line 1: | ||
/* Section trees ({{… sidebar}} templates, class bc-section-nav). | /* Section trees ({{… sidebar}} templates, class bc-section-nav). | ||
* Copies the tree on an article into a panel | * Copies the tree on an article into a panel in the left column, below Contents, | ||
* | * styled like the Contents panel: the section name is the heading, the current | ||
* in-page box stays as the fallback where Vector hides that column | * page is in bold, and "hide"/"show" collapses the list (remembered per browser). | ||
* The in-page box stays as the fallback where Vector hides that column | |||
* (see .bc-section-nav--moved in MediaWiki:Common.css). */ | * (see .bc-section-nav--moved in MediaWiki:Common.css). */ | ||
mw.hook("wikipage.content").add(function ($content) { | mw.hook("wikipage.content").add(function ($content) { | ||
var box = $content[0] && $content[0].querySelector(".bc-section-nav"); | var box = $content[0] && $content[0].querySelector(".bc-section-nav"); | ||
var column = document.querySelector(".vector-column-start"); | var column = document.querySelector(".vector-column-start .vector-sticky-pinned-container"); | ||
if (!box || !column || document.getElementById("bc-section-panel")) { | if (!box || !column || document.getElementById("bc-section-panel")) { | ||
return; | return; | ||
} | } | ||
var storageKey = "bc-section-panel-hidden"; | |||
var isHidden = function () { | |||
try { | |||
return localStorage.getItem(storageKey) === "1"; | |||
} catch (e) { | |||
return false; | |||
} | |||
}; | |||
var panel = document.createElement("nav"); | var panel = document.createElement("nav"); | ||
panel.id = "bc-section-panel"; | panel.id = "bc-section-panel"; | ||
panel.className = "vector-pinned-container bc-section-panel"; | panel.className = "vector-pinned-container bc-section-panel"; | ||
panel.setAttribute("aria-label", box.getAttribute("aria-label") || ""); | panel.setAttribute("aria-label", box.getAttribute("aria-label") || ""); | ||
// Header: section name (linked) plus a hide/show toggle, like Contents. | |||
var header = document.createElement("div"); | |||
header.className = | |||
"vector-pinnable-header bc-section-pinnable-header vector-pinnable-header-pinned"; | |||
var label = document.createElement("div"); | |||
label.className = "vector-pinnable-header-label"; | |||
var titleLink = box.querySelector(".bc-section-nav-title a"); | |||
if (titleLink) { | |||
var headLink = document.createElement("a"); | |||
headLink.href = titleLink.getAttribute("href") || location.pathname; | |||
headLink.textContent = titleLink.textContent; | |||
if (titleLink.classList.contains("mw-selflink")) { | |||
label.className += " bc-section-current"; | |||
} | |||
label.appendChild(headLink); | |||
} else { | |||
label.textContent = panel.getAttribute("aria-label"); | |||
} | |||
var toggle = document.createElement("button"); | |||
toggle.type = "button"; | |||
toggle.className = | |||
"vector-pinnable-header-toggle-button vector-pinnable-header-unpin-button"; | |||
header.appendChild(label); | |||
header.appendChild(toggle); | |||
panel.appendChild(header); | |||
var list = document.createElement("ul"); | var list = document.createElement("ul"); | ||
var addItem = function (link, text, depth) { | var addItem = function (link, text, depth) { | ||
| Line 31: | Line 68: | ||
list.appendChild(li); | list.appendChild(li); | ||
}; | }; | ||
box.querySelectorAll("li").forEach(function (item) { | box.querySelectorAll("li").forEach(function (item) { | ||
var depth = 0; | var depth = 0; | ||
| Line 53: | Line 86: | ||
}); | }); | ||
panel.appendChild(list); | panel.appendChild(list); | ||
panel, | var render = function (hidden) { | ||
list.hidden = hidden; | |||
); | panel.classList.toggle("bc-section-panel--collapsed", hidden); | ||
toggle.textContent = hidden ? "show" : "hide"; | |||
toggle.setAttribute("aria-expanded", hidden ? "false" : "true"); | |||
}; | |||
toggle.addEventListener("click", function () { | |||
var hidden = !list.hidden; | |||
try { | |||
localStorage.setItem(storageKey, hidden ? "1" : "0"); | |||
} catch (e) {} | |||
render(hidden); | |||
}); | |||
render(isHidden()); | |||
column.appendChild(panel); | |||
box.classList.add("bc-section-nav--moved"); | box.classList.add("bc-section-nav--moved"); | ||
}); | }); | ||
Latest revision as of 15:04, 4 November 2026
/* Section trees ({{… sidebar}} templates, class bc-section-nav).
* Copies the tree on an article into a panel in the left column, below Contents,
* styled like the Contents panel: the section name is the heading, the current
* page is in bold, and "hide"/"show" collapses the list (remembered per browser).
* The in-page box stays as the fallback where Vector hides that column
* (see .bc-section-nav--moved in MediaWiki:Common.css). */
mw.hook("wikipage.content").add(function ($content) {
var box = $content[0] && $content[0].querySelector(".bc-section-nav");
var column = document.querySelector(".vector-column-start .vector-sticky-pinned-container");
if (!box || !column || document.getElementById("bc-section-panel")) {
return;
}
var storageKey = "bc-section-panel-hidden";
var isHidden = function () {
try {
return localStorage.getItem(storageKey) === "1";
} catch (e) {
return false;
}
};
var panel = document.createElement("nav");
panel.id = "bc-section-panel";
panel.className = "vector-pinned-container bc-section-panel";
panel.setAttribute("aria-label", box.getAttribute("aria-label") || "");
// Header: section name (linked) plus a hide/show toggle, like Contents.
var header = document.createElement("div");
header.className =
"vector-pinnable-header bc-section-pinnable-header vector-pinnable-header-pinned";
var label = document.createElement("div");
label.className = "vector-pinnable-header-label";
var titleLink = box.querySelector(".bc-section-nav-title a");
if (titleLink) {
var headLink = document.createElement("a");
headLink.href = titleLink.getAttribute("href") || location.pathname;
headLink.textContent = titleLink.textContent;
if (titleLink.classList.contains("mw-selflink")) {
label.className += " bc-section-current";
}
label.appendChild(headLink);
} else {
label.textContent = panel.getAttribute("aria-label");
}
var toggle = document.createElement("button");
toggle.type = "button";
toggle.className =
"vector-pinnable-header-toggle-button vector-pinnable-header-unpin-button";
header.appendChild(label);
header.appendChild(toggle);
panel.appendChild(header);
var list = document.createElement("ul");
var addItem = function (link, text, depth) {
var li = document.createElement("li");
li.className = "bc-section-depth-" + depth;
if (link && link.classList.contains("mw-selflink")) {
li.className += " bc-section-current";
}
var inner = document.createElement(link ? "a" : "span");
if (link) {
inner.href = link.getAttribute("href") || location.pathname;
} else {
li.className += " bc-section-label";
}
inner.textContent = text;
li.appendChild(inner);
list.appendChild(li);
};
box.querySelectorAll("li").forEach(function (item) {
var depth = 0;
for (var el = item.parentElement; el && el !== box; el = el.parentElement) {
if (el.tagName === "UL") {
depth++;
}
}
var link = item.querySelector(":scope > a");
var text = link
? link.textContent
: item.firstChild && item.firstChild.nodeType === 3
? item.firstChild.textContent.trim()
: "";
if (text) {
addItem(link, text, depth);
}
});
panel.appendChild(list);
var render = function (hidden) {
list.hidden = hidden;
panel.classList.toggle("bc-section-panel--collapsed", hidden);
toggle.textContent = hidden ? "show" : "hide";
toggle.setAttribute("aria-expanded", hidden ? "false" : "true");
};
toggle.addEventListener("click", function () {
var hidden = !list.hidden;
try {
localStorage.setItem(storageKey, hidden ? "1" : "0");
} catch (e) {}
render(hidden);
});
render(isHidden());
column.appendChild(panel);
box.classList.add("bc-section-nav--moved");
});