MediaWiki

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 = [];
/* =========================
/* =========================
   STATE
   INITIAL LOAD
========================= */
========================= */


const activeTags = new Set();
document.addEventListener("DOMContentLoaded", () => {
 
    loadBibliography();
 
    bindViewButtons();
 
});


/* =========================
/* =========================
   TAG FILTERING (GLOBAL)
   LOAD DATA FROM WIKI PAGE
  (BibliographyData must be JS/JSON)
========================= */
========================= */


function loadBibliography() {


document.querySelectorAll(".tag").forEach(tag => {
    // BibliographyData muss als globales JSON vorliegen
    if (typeof BibliographyData === "undefined") {
        console.error("BibliographyData not found!");
        return;
    }


     tag.addEventListener("click", () => {
     rawData = BibliographyData;


        const value = tag.dataset.tag;
    renderTags(rawData);
    renderList(rawData);


        if (activeTags.has(value)) {
}
            activeTags.delete(value);
        } else {
            activeTags.add(value);
        }


        filterEntries();
/* =========================
        syncTagUI();   //
  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() {


function filterEntries() {
    const entries = document.querySelectorAll(".bib-entry");


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


         const entryTags = entry.dataset.tags.split(" ");
         const tags = (entry.dataset.tags || "").split(" ");


         const matches =
         const match =
             [...activeTags].every(t => entryTags.includes(t));
            activeTags.size === 0 ||
             [...activeTags].every(t => tags.includes(t));


         if (activeTags.size === 0 || matches) {
         entry.style.display = match ? "block" : "none";
            entry.style.display = "block";
        } else {
            entry.style.display = "none";
        }


     });
     });


}
}


/* =========================
/* =========================
   VIEW SWITCH (LIST / NETWORK)
   RENDER LIST VIEW
========================= */
========================= */


document.querySelectorAll(".view-btn").forEach(btn => {
function renderList(data) {


     btn.addEventListener("click", () => {
     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.querySelectorAll(".view-btn")
         const el = document.createElement("div");
            .forEach(b => b.classList.remove("active"));
        el.className = "bib-entry";
        el.dataset.tags = tags;


         btn.classList.add("active");
         const author = item.author?.[0]?.family || "Unknown";


         const view = btn.dataset.view;
         el.innerHTML = `
            <h3>${author}. <i>${item.title || "No Title"}</i>. ${item.date || ""}</h3>


        const listView = document.getElementById("listView");
            <div class="bib-tags">
        const networkView = document.getElementById("networkView");
                ${(item.tags || []).map(t =>
                    `<span class="tag" data-tag="${t}">${t}</span>`
                ).join(" ")}
            </div>


        listView.style.display = (view === "list") ? "block" : "none";
            <p class="short-abstract">
        networkView.classList.toggle("hidden", view !== "network");
                ${item.abstractNote || ""}
            </p>


        if (view === "network") {
            <button class="expand-btn">Show Abstract</button>
             buildNetwork();
 
        }
            <div class="abstract hidden">
                <p>${item.abstractNote || ""}</p>
             </div>
        `;
 
        container.appendChild(el);


     });
     });


});
    rebindUI();


}


/* =========================
/* =========================
   EXPAND ABSTRACTS
   UI REBIND (after render)
========================= */
========================= */


document.querySelectorAll(".expand-btn").forEach(btn => {
function rebindUI() {
 
    // expand abstracts
    document.querySelectorAll(".expand-btn").forEach(btn => {


    btn.addEventListener("click", () => {
        btn.onclick = () => {


        const abstract = btn.nextElementSibling;
            const abs = btn.nextElementSibling;
            abs.classList.toggle("hidden");


        abstract.classList.toggle("hidden");
            btn.textContent =
                abs.classList.contains("hidden")
                    ? "Show Abstract"
                    : "Hide Abstract";


         btn.textContent =
         };
            abstract.classList.contains("hidden")
                ? "Show Abstract"
                : "Hide Abstract";


     });
     });


});
    // entry-level tag clicks (optional: mirror global filter)
 
    document.querySelectorAll(".bib-entry .tag").forEach(tag => {


        tag.onclick = () => {


function syncTagUI() {
            const value = tag.dataset.tag;


    document.querySelectorAll(".tag").forEach(tagEl => {
            const globalTag = document.querySelector(
                `.bib-tags#globalTags .tag[data-tag="${value}"]`
            );


        const value = tagEl.dataset.tag;
            if (globalTag) globalTag.click();


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


     });
     });
Line 119: Line 199:
}
}


/* =========================
  VIEW SWITCH
========================= */
function bindViewButtons() {
    document.querySelectorAll(".view-btn").forEach(btn => {
        btn.addEventListener("click", () => {


function sortEntriesAlphabetically() {
            document.querySelectorAll(".view-btn")
                .forEach(b => b.classList.remove("active"));


    const container = document.getElementById("listView");
            btn.classList.add("active");
    if (!container) return;


    const entries = Array.from(container.querySelectorAll(".bib-entry"));
            const view = btn.dataset.view;


    entries.sort((a, b) => {
            document.getElementById("listView").style.display =
                view === "list" ? "block" : "none";


        const titleA = a.querySelector("h3")?.innerText.trim().toLowerCase() || "";
            document.getElementById("networkView").classList.toggle(
        const titleB = b.querySelector("h3")?.innerText.trim().toLowerCase() || "";
                "hidden",
                view !== "network"
            );


         return titleA.localeCompare(titleB, "en", { sensitivity: "base" });
         });


     });
     });
    entries.forEach(entry => container.appendChild(entry));


}
}
sortEntriesAlphabetically();

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"
            );

        });

    });

}