MediaWiki:BibTest.js
From Illustrations in German Translations of Mark Twain's Works
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.
/* =========================
STATE
========================= */
const activeTags = new Set();
/* =========================
TAG FILTERING (GLOBAL)
========================= */
document.querySelectorAll(".tag").forEach(tag => {
tag.addEventListener("click", () => {
const value = tag.dataset.tag;
if (activeTags.has(value)) {
activeTags.delete(value);
tag.classList.remove("active");
} else {
activeTags.add(value);
tag.classList.add("active");
}
filterEntries();
});
});
function filterEntries() {
document.querySelectorAll(".bib-entry").forEach(entry => {
const entryTags = entry.dataset.tags.split(" ");
const matches =
[...activeTags].every(t => entryTags.includes(t));
if (activeTags.size === 0 || matches) {
entry.style.display = "block";
} else {
entry.style.display = "none";
}
});
}
/* =========================
VIEW SWITCH (LIST / NETWORK)
========================= */
document.querySelectorAll(".view-btn").forEach(btn => {
btn.addEventListener("click", () => {
document.querySelectorAll(".view-btn")
.forEach(b => b.classList.remove("active"));
btn.classList.add("active");
const view = btn.dataset.view;
const listView = document.getElementById("listView");
const networkView = document.getElementById("networkView");
listView.style.display = (view === "list") ? "block" : "none";
networkView.classList.toggle("hidden", view !== "network");
if (view === "network") {
buildNetwork();
}
});
});
/* =========================
EXPAND ABSTRACTS
========================= */
document.querySelectorAll(".expand-btn").forEach(btn => {
btn.addEventListener("click", () => {
const abstract = btn.nextElementSibling;
abstract.classList.toggle("hidden");
btn.textContent =
abstract.classList.contains("hidden")
? "Show Abstract"
: "Hide Abstract";
});
});
/* =========================
NETWORK VIEW
========================= */
function buildNetwork() {
const container = document.getElementById("networkView");
container.innerHTML = "";
const entries = document.querySelectorAll(".bib-entry");
const tagNodes = new Map();
const entryNodes = [];
const centerX = container.clientWidth / 2;
const centerY = container.clientHeight / 2;
/* -------------------------
ENTRY NODES
------------------------- */
entries.forEach((entry, i) => {
const node = document.createElement("div");
node.className = "node entry";
node.innerText = entry.querySelector("h3").innerText;
const angle = (i / entries.length) * Math.PI * 2;
const x = centerX + Math.cos(angle) * 250;
const y = centerY + Math.sin(angle) * 250;
node.style.left = x + "px";
node.style.top = y + "px";
container.appendChild(node);
entryNodes.push({ node, entry, x, y });
node.addEventListener("click", () => {
document.querySelectorAll(".node")
.forEach(n => n.classList.remove("highlight"));
node.classList.add("highlight");
});
/* -------------------------
TAG NODES
------------------------- */
const tags = entry.dataset.tags.split(" ");
tags.forEach(tag => {
if (!tagNodes.has(tag)) {
const tnode = document.createElement("div");
tnode.className = "node tag";
tnode.innerText = tag;
const tx = Math.random() * (container.clientWidth - 100) + 50;
const ty = Math.random() * (container.clientHeight - 100) + 50;
tnode.style.left = tx + "px";
tnode.style.top = ty + "px";
container.appendChild(tnode);
tagNodes.set(tag, { node: tnode, x: tx, y: ty });
}
});
});
/* -------------------------
EDGES
------------------------- */
entryNodes.forEach(e => {
const tags = e.entry.dataset.tags.split(" ");
tags.forEach(tag => {
const t = tagNodes.get(tag);
if (!t) return;
const line = document.createElement("div");
line.className = "edge";
const dx = t.x - e.x;
const dy = t.y - e.y;
const length = Math.sqrt(dx * dx + dy * dy);
line.style.width = length + "px";
line.style.left = e.x + "px";
line.style.top = e.y + "px";
line.style.transform = `rotate(${Math.atan2(dy, dx)}rad)`;
container.appendChild(line);
});
});
}