BibTest.js: Difference between revisions
From Illustrations in German Translations of Mark Twain's Works
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
let activeTags = new Set(); | |||
let rawData = []; | |||
/* ========================= | /* ========================= | ||
INITIAL LOAD | |||
========================= */ | ========================= */ | ||
document.addEventListener("DOMContentLoaded", () => { | |||
loadBibliography(); | |||
bindViewButtons(); | |||
}); | |||
/* ========================= | /* ========================= | ||
LOAD DATA FROM WIKI PAGE | |||
(BibliographyData must be JS/JSON) | |||
========================= */ | ========================= */ | ||
function loadBibliography() { | |||
// BibliographyData muss als globales JSON vorliegen | |||
if (typeof BibliographyData === "undefined") { | |||
console.error("BibliographyData not found!"); | |||
return; | |||
} | |||
rawData = BibliographyData; | |||
renderTags(rawData); | |||
renderList(rawData); | |||
} | |||
/* ========================= | |||
TAG RENDER (GLOBAL FILTER BAR) | |||
========================= */ | |||
function renderTags(data) { | |||
const container = document.getElementById("globalTags"); | |||
const tagSet = new Set(); | |||
data.forEach(item => { | |||
(item.tags || []).forEach(t => tagSet.add(t)); | |||
}); | }); | ||
}); | container.innerHTML = ""; | ||
[...tagSet].sort().forEach(tag => { | |||
const span = document.createElement("span"); | |||
span.className = "tag"; | |||
span.dataset.tag = tag; | |||
span.innerText = tag; | |||
span.addEventListener("click", () => toggleTag(tag, span)); | |||
container.appendChild(span); | |||
}); | |||
} | |||
/* ========================= | |||
TAG TOGGLE | |||
========================= */ | |||
function toggleTag(tag, el) { | |||
if (activeTags.has(tag)) { | |||
activeTags.delete(tag); | |||
el.classList.remove("active"); | |||
} else { | |||
activeTags.add(tag); | |||
el.classList.add("active"); | |||
} | |||
applyFilter(); | |||
} | |||
/* ========================= | |||
FILTER LOGIC | |||
========================= */ | |||
function applyFilter() { | |||
const entries = document.querySelectorAll(".bib-entry"); | |||
entries.forEach(entry => { | |||
const | const tags = (entry.dataset.tags || "").split(" "); | ||
const | const match = | ||
[...activeTags].every(t => | activeTags.size === 0 || | ||
[...activeTags].every(t => tags.includes(t)); | |||
entry.style.display = match ? "block" : "none"; | |||
}); | }); | ||
} | } | ||
/* ========================= | /* ========================= | ||
VIEW | RENDER LIST VIEW | ||
========================= */ | ========================= */ | ||
function renderList(data) { | |||
const container = document.getElementById("listView"); | |||
container.innerHTML = ""; | |||
// alphabetisch sortieren (Titel) | |||
data.sort((a, b) => | |||
(a.title || "").localeCompare(b.title || "") | |||
); | |||
data.forEach(item => { | |||
const tags = (item.tags || []).join(" "); | |||
document. | const el = document.createElement("div"); | ||
el.className = "bib-entry"; | |||
el.dataset.tags = tags; | |||
const author = item.author?.[0]?.family || "Unknown"; | |||
el.innerHTML = ` | |||
<h3>${author}. <i>${item.title || "No Title"}</i>. ${item.date || ""}</h3> | |||
<div class="bib-tags"> | |||
${(item.tags || []).map(t => | |||
`<span class="tag" data-tag="${t}">${t}</span>` | |||
).join(" ")} | |||
</div> | |||
<p class="short-abstract"> | |||
${item.abstractNote || ""} | |||
</p> | |||
<button class="expand-btn">Show Abstract</button> | |||
<div class="abstract hidden"> | |||
<p>${item.abstractNote || ""}</p> | |||
</div> | |||
`; | |||
container.appendChild(el); | |||
}); | }); | ||
rebindUI(); | |||
} | |||
/* ========================= | /* ========================= | ||
UI REBIND (after render) | |||
========================= */ | ========================= */ | ||
document.querySelectorAll(".expand-btn").forEach(btn => { | function rebindUI() { | ||
// expand abstracts | |||
document.querySelectorAll(".expand-btn").forEach(btn => { | |||
btn.onclick = () => { | |||
const abs = btn.nextElementSibling; | |||
abs.classList.toggle("hidden"); | |||
btn.textContent = | |||
abs.classList.contains("hidden") | |||
? "Show Abstract" | |||
: "Hide Abstract"; | |||
}; | |||
}); | }); | ||
// entry-level tag clicks (optional: mirror global filter) | |||
document.querySelectorAll(".bib-entry .tag").forEach(tag => { | |||
tag.onclick = () => { | |||
const value = tag.dataset.tag; | |||
const globalTag = document.querySelector( | |||
`.bib-tags#globalTags .tag[data-tag="${value}"]` | |||
); | |||
if (globalTag) globalTag.click(); | |||
}; | |||
} | |||
}); | }); | ||
| Line 119: | Line 199: | ||
} | } | ||
/* ========================= | |||
VIEW SWITCH | |||
========================= */ | |||
function bindViewButtons() { | |||
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" | |||
); | |||
}); | |||
}); | }); | ||
} | } | ||
Revision as of 22:58, 11 May 2026
let activeTags = new Set();
let rawData = [];
/* =========================
INITIAL LOAD
========================= */
document.addEventListener("DOMContentLoaded", () => {
loadBibliography();
bindViewButtons();
});
/* =========================
LOAD DATA FROM WIKI PAGE
(BibliographyData must be JS/JSON)
========================= */
function loadBibliography() {
// BibliographyData muss als globales JSON vorliegen
if (typeof BibliographyData === "undefined") {
console.error("BibliographyData not found!");
return;
}
rawData = BibliographyData;
renderTags(rawData);
renderList(rawData);
}
/* =========================
TAG RENDER (GLOBAL FILTER BAR)
========================= */
function renderTags(data) {
const container = document.getElementById("globalTags");
const tagSet = new Set();
data.forEach(item => {
(item.tags || []).forEach(t => tagSet.add(t));
});
container.innerHTML = "";
[...tagSet].sort().forEach(tag => {
const span = document.createElement("span");
span.className = "tag";
span.dataset.tag = tag;
span.innerText = tag;
span.addEventListener("click", () => toggleTag(tag, span));
container.appendChild(span);
});
}
/* =========================
TAG TOGGLE
========================= */
function toggleTag(tag, el) {
if (activeTags.has(tag)) {
activeTags.delete(tag);
el.classList.remove("active");
} else {
activeTags.add(tag);
el.classList.add("active");
}
applyFilter();
}
/* =========================
FILTER LOGIC
========================= */
function applyFilter() {
const entries = document.querySelectorAll(".bib-entry");
entries.forEach(entry => {
const tags = (entry.dataset.tags || "").split(" ");
const match =
activeTags.size === 0 ||
[...activeTags].every(t => tags.includes(t));
entry.style.display = match ? "block" : "none";
});
}
/* =========================
RENDER LIST VIEW
========================= */
function renderList(data) {
const container = document.getElementById("listView");
container.innerHTML = "";
// alphabetisch sortieren (Titel)
data.sort((a, b) =>
(a.title || "").localeCompare(b.title || "")
);
data.forEach(item => {
const tags = (item.tags || []).join(" ");
const el = document.createElement("div");
el.className = "bib-entry";
el.dataset.tags = tags;
const author = item.author?.[0]?.family || "Unknown";
el.innerHTML = `
<h3>${author}. <i>${item.title || "No Title"}</i>. ${item.date || ""}</h3>
<div class="bib-tags">
${(item.tags || []).map(t =>
`<span class="tag" data-tag="${t}">${t}</span>`
).join(" ")}
</div>
<p class="short-abstract">
${item.abstractNote || ""}
</p>
<button class="expand-btn">Show Abstract</button>
<div class="abstract hidden">
<p>${item.abstractNote || ""}</p>
</div>
`;
container.appendChild(el);
});
rebindUI();
}
/* =========================
UI REBIND (after render)
========================= */
function rebindUI() {
// expand abstracts
document.querySelectorAll(".expand-btn").forEach(btn => {
btn.onclick = () => {
const abs = btn.nextElementSibling;
abs.classList.toggle("hidden");
btn.textContent =
abs.classList.contains("hidden")
? "Show Abstract"
: "Hide Abstract";
};
});
// entry-level tag clicks (optional: mirror global filter)
document.querySelectorAll(".bib-entry .tag").forEach(tag => {
tag.onclick = () => {
const value = tag.dataset.tag;
const globalTag = document.querySelector(
`.bib-tags#globalTags .tag[data-tag="${value}"]`
);
if (globalTag) globalTag.click();
};
});
}
/* =========================
VIEW SWITCH
========================= */
function bindViewButtons() {
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"
);
});
});
}