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: | ||
(async function () { | |||
/ | const DATA_URL = "https://illus.twainframe.org/index.php?title=BibliographyData&action=raw&ctype=application/json"; | ||
let DATA = []; | |||
let ACTIVE_TAGS = new Set(); | |||
// -------------------- INIT -------------------- | |||
document.addEventListener("DOMContentLoaded", init); | |||
async function | async function init() { | ||
await loadData(); | |||
renderTags(); | |||
renderList(); | |||
} | } | ||
/ | // -------------------- LOAD DATA -------------------- | ||
function | async function loadData() { | ||
const | const res = await fetch(DATA_URL); | ||
DATA = await res.json(); | |||
// Alphabetisch nach Titel | |||
DATA.sort((a, b) => | |||
(a.title || "").localeCompare(b.title || "") | |||
); | |||
} | } | ||
// -------------------- TAG BAR -------------------- | |||
function renderTags() { | |||
const tagBar = document.getElementById("tagBar"); | |||
tagBar.innerHTML = ""; | |||
const allTags = new Set(); | |||
const | |||
DATA.forEach(item => { | |||
(item.tags || []).forEach(t => allTags.add(t)); | |||
}); | |||
[...allTags].sort().forEach(tag => { | |||
const el = document.createElement("span"); | const el = document.createElement("span"); | ||
el.className = "tag" | el.className = "tag inactive"; | ||
el.textContent = tag; | el.textContent = tag; | ||
el.dataset.tag = tag; | |||
el.onclick = () => | el.onclick = () => toggleTag(tag, el); | ||
tagBar.appendChild(el); | |||
}); | }); | ||
} | } | ||
function toggleTag(tag, el) { | |||
if (ACTIVE_TAGS.has(tag)) { | |||
ACTIVE_TAGS.delete(tag); | |||
el.classList.remove("active"); | |||
el.classList.add("inactive"); | |||
} else { | |||
ACTIVE_TAGS.add(tag); | |||
el.classList.add("active"); | |||
el.classList.remove("inactive"); | |||
} | |||
renderList(); | |||
} | } | ||
// -------------------- LIST VIEW -------------------- | |||
function renderList() { | |||
function renderList( | |||
const container = document.getElementById("listView"); | const container = document.getElementById("listView"); | ||
container.innerHTML = ""; | container.innerHTML = ""; | ||
let filtered = DATA; | |||
if (ACTIVE_TAGS.size > 0) { | |||
filtered = DATA.filter(item => | |||
item.tags && item.tags.some(t => ACTIVE_TAGS.has(t)) | |||
); | |||
} | |||
filtered.forEach(item => { | |||
const div = document.createElement("div"); | const div = document.createElement("div"); | ||
div.className = "bib-entry"; | div.className = "bib-entry"; | ||
div.innerHTML = buildEntry(item); | |||
container.appendChild(div); | container.appendChild(div); | ||
| Line 131: | Line 90: | ||
} | } | ||
// -------------------- ENTRY TEMPLATE -------------------- | |||
function buildEntry(item) { | |||
const authors = (item.authors || []) | |||
.map(a => { | |||
if (typeof a === "string") return a; | |||
return (a.family || "") + (a.given ? ", " + a.given : ""); | |||
}) | |||
.join(", "); | |||
const tags = (item.tags || []).map(t => | |||
`<span class="tag ${ACTIVE_TAGS.has(t) ? 'active' : 'inactive'}" | |||
data-tag="${t}" | |||
onclick="window.__toggleTagFromEntry('${t}')"> | |||
${t} | |||
</span>` | |||
).join(" "); | |||
return ` | |||
<h3>${authors || "Unknown"}. <i>${item.title || "Untitled"}</i>. ${item.year || ""}</h3> | |||
<div class="bib-tags">${tags}</div> | |||
<p class="short-abstract">${item.abstract || ""}</p> | |||
${item.url ? `<a href="${item.url}" target="_blank">Source</a>` : ""} | |||
`; | |||
} | } | ||
// -------------------- GLOBAL TAG CLICK (from entries) -------------------- | |||
window.__toggleTagFromEntry = function(tag) { | |||
const tagBarTags = document.querySelectorAll("#tagBar .tag"); | |||
ACTIVE_TAGS.has(tag) | |||
? ACTIVE_TAGS.delete(tag) | |||
: ACTIVE_TAGS.add(tag); | |||
tagBarTags.forEach(t => { | |||
if (t.dataset.tag === tag) { | |||
t.classList.toggle("active", ACTIVE_TAGS.has(tag)); | |||
t.classList.toggle("inactive", !ACTIVE_TAGS.has(tag)); | |||
} | |||
}); | |||
renderList(); | |||
renderList( | }; | ||
} | |||
})(); | |||
Revision as of 23:43, 11 May 2026
(async function () {
const DATA_URL = "https://illus.twainframe.org/index.php?title=BibliographyData&action=raw&ctype=application/json";
let DATA = [];
let ACTIVE_TAGS = new Set();
// -------------------- INIT --------------------
document.addEventListener("DOMContentLoaded", init);
async function init() {
await loadData();
renderTags();
renderList();
}
// -------------------- LOAD DATA --------------------
async function loadData() {
const res = await fetch(DATA_URL);
DATA = await res.json();
// Alphabetisch nach Titel
DATA.sort((a, b) =>
(a.title || "").localeCompare(b.title || "")
);
}
// -------------------- TAG BAR --------------------
function renderTags() {
const tagBar = document.getElementById("tagBar");
tagBar.innerHTML = "";
const allTags = new Set();
DATA.forEach(item => {
(item.tags || []).forEach(t => allTags.add(t));
});
[...allTags].sort().forEach(tag => {
const el = document.createElement("span");
el.className = "tag inactive";
el.textContent = tag;
el.dataset.tag = tag;
el.onclick = () => toggleTag(tag, el);
tagBar.appendChild(el);
});
}
function toggleTag(tag, el) {
if (ACTIVE_TAGS.has(tag)) {
ACTIVE_TAGS.delete(tag);
el.classList.remove("active");
el.classList.add("inactive");
} else {
ACTIVE_TAGS.add(tag);
el.classList.add("active");
el.classList.remove("inactive");
}
renderList();
}
// -------------------- LIST VIEW --------------------
function renderList() {
const container = document.getElementById("listView");
container.innerHTML = "";
let filtered = DATA;
if (ACTIVE_TAGS.size > 0) {
filtered = DATA.filter(item =>
item.tags && item.tags.some(t => ACTIVE_TAGS.has(t))
);
}
filtered.forEach(item => {
const div = document.createElement("div");
div.className = "bib-entry";
div.innerHTML = buildEntry(item);
container.appendChild(div);
});
}
// -------------------- ENTRY TEMPLATE --------------------
function buildEntry(item) {
const authors = (item.authors || [])
.map(a => {
if (typeof a === "string") return a;
return (a.family || "") + (a.given ? ", " + a.given : "");
})
.join(", ");
const tags = (item.tags || []).map(t =>
`<span class="tag ${ACTIVE_TAGS.has(t) ? 'active' : 'inactive'}"
data-tag="${t}"
onclick="window.__toggleTagFromEntry('${t}')">
${t}
</span>`
).join(" ");
return `
<h3>${authors || "Unknown"}. <i>${item.title || "Untitled"}</i>. ${item.year || ""}</h3>
<div class="bib-tags">${tags}</div>
<p class="short-abstract">${item.abstract || ""}</p>
${item.url ? `<a href="${item.url}" target="_blank">Source</a>` : ""}
`;
}
// -------------------- GLOBAL TAG CLICK (from entries) --------------------
window.__toggleTagFromEntry = function(tag) {
const tagBarTags = document.querySelectorAll("#tagBar .tag");
ACTIVE_TAGS.has(tag)
? ACTIVE_TAGS.delete(tag)
: ACTIVE_TAGS.add(tag);
tagBarTags.forEach(t => {
if (t.dataset.tag === tag) {
t.classList.toggle("active", ACTIVE_TAGS.has(tag));
t.classList.toggle("inactive", !ACTIVE_TAGS.has(tag));
}
});
renderList();
};
})();