MediaWiki

MediaWiki:BibTest.js

From Illustrations in German Translations of Mark Twain's Works

Revision as of 23:01, 11 May 2026 by HMHTEST (talk | contribs)

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.
let rawData = [];
let activeTags = new Set();

/* =========================
   INIT
========================= */

document.addEventListener("DOMContentLoaded", () => {

    if (typeof BibliographyData !== "undefined") {
        loadBibliography();
    }

    document.getElementById("updateBib").addEventListener("click", reloadBibliography);

});

/* =========================
   LOAD + RENDER
========================= */

function loadBibliography() {

    rawData = normalizeData(BibliographyData);

    renderTags(rawData);
    renderList(rawData);

}

/* =========================
   NORMALIZE ZOTERO DATA
========================= */

function normalizeData(data) {

    return data.map(item => ({

        title: item.title || "Untitled",
        date: item.date || "",
        author: item.creators?.[0]?.lastName || "Unknown",

        tags: (item.tags || []).map(t => t.tag),

        abstractNote: item.abstractNote || ""

    }));

}

/* =========================
   GLOBAL TAG 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 el = document.createElement("span");
        el.className = "tag";
        el.dataset.tag = tag;
        el.innerText = tag;

        el.addEventListener("click", () => toggleTag(tag, el));

        container.appendChild(el);

    });

}

/* =========================
   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();
    syncEntryTags();

}

/* =========================
   FILTER ENTRIES
========================= */

function applyFilter() {

    document.querySelectorAll(".bib-entry").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";

    });

}

/* =========================
   SYNC TAG VISUAL STATE
========================= */

function syncEntryTags() {

    document.querySelectorAll(".bib-entry .tag").forEach(tag => {

        const value = tag.dataset.tag;

        if (activeTags.has(value)) {
            tag.classList.add("active");
        } else {
            tag.classList.remove("active");
        }

    });

}

/* =========================
   RENDER LIST
========================= */

function renderList(data) {

    const container = document.getElementById("listView");
    container.innerHTML = "";

    // alphabetisch sortieren
    data.sort((a, b) =>
        a.author.localeCompare(b.author)
    );

    data.forEach(item => {

        const el = document.createElement("div");
        el.className = "bib-entry";
        el.dataset.tags = item.tags.join(" ");

        el.innerHTML = `
            <h3>${item.author}. <i>${item.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();

    syncEntryTags();

    applyFilter();

}

/* =========================
   UI REBIND
========================= */

function rebindUI() {

    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 tags → trigger global filter
    document.querySelectorAll(".bib-entry .tag").forEach(tag => {

        tag.onclick = () => {

            const value = tag.dataset.tag;

            const global = document.querySelector(
                `.bib-tags#globalTags .tag[data-tag="${value}"]`
            );

            if (global) global.click();

        };

    });

}

/* =========================
   UPDATE BUTTON
========================= */

function reloadBibliography() {

    console.log("🔄 Reloading BibliographyData...");

    if (typeof BibliographyData === "undefined") {
        console.error("BibliographyData not found");
        return;
    }

    rawData = normalizeData(BibliographyData);

    activeTags.clear();

    document.getElementById("globalTags").innerHTML = "";

    loadBibliography();

    console.log("✅ Updated");

}