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.
const activeTags = new Set();
/* TAG CLICK HANDLING */
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();
});
});
/* FILTER FUNCTION */
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";
}
});
}
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;
document.getElementById("listView").style.display =
view === "list" ? "block" : "none";
document.getElementById("networkCanvas").style.display =
view === "network" ? "block" : "none";
drawNetwork();
});
});
// SIMPLE NETWORK GRAPH
function buildNetwork() {
const container = document.getElementById("networkView");
container.innerHTML = "";
const entries = document.querySelectorAll(".bib-entry");
const tagNodes = new Map();
const entryNodes = [];
let centerX = 400;
let centerY = 300;
// 1. ENTRY NODES
entries.forEach((entry, i) => {
const node = document.createElement("div");
node.className = "node entry";
node.innerText = entry.querySelector("h3").innerText;
let x = centerX + Math.cos(i) * 200;
let y = centerY + Math.sin(i) * 200;
node.style.left = x + "px";
node.style.top = y + "px";
container.appendChild(node);
entryNodes.push({ node, entry, x, y });
// click highlight
node.addEventListener("click", () => {
document.querySelectorAll(".node").forEach(n =>
n.classList.remove("highlight")
);
node.classList.add("highlight");
});
// TAG LINKS
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;
let tx = Math.random() * 600 + 100;
let ty = Math.random() * 400 + 100;
tnode.style.left = tx + "px";
tnode.style.top = ty + "px";
container.appendChild(tnode);
tagNodes.set(tag, { node: tnode, x: tx, y: ty });
}
});
});
// 2. EDGES (entry → tag)
entryNodes.forEach(e => {
const tags = e.entry.dataset.tags.split(" ");
tags.forEach(tag => {
const t = tagNodes.get(tag);
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);
});
});
}
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";
});
});
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;
document.getElementById("listView").style.display =
view === "list" ? "block" : "none";
document.getElementById("networkView").classList.toggle(
"hidden",
view !== "network"
);
if (view === "network") {
buildNetwork();
}
});
});