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


/* =========================
/* =========================
Line 6: Line 6:
========================= */
========================= */


document.addEventListener("DOMContentLoaded", () => {
document.addEventListener("DOMContentLoaded", async () => {
 
     await loadData();
     if (typeof BibliographyData !== "undefined") {
    render();
        loadBibliography();
});
    }
 
    document.getElementById("updateBib").addEventListener("click", reloadBibliography);


});


/* =========================
/* =========================
   LOAD + RENDER
   LOAD DATA FROM WIKI
========================= */
========================= */


function loadBibliography() {
async function loadData() {
    const res = await fetch("BibliographyData");
    BIB_DATA = await res.json();


     rawData = normalizeData(BibliographyData);
     console.log("📚 Loaded entries:", BIB_DATA.length);
 
}
    renderTags(rawData);
    renderList(rawData);


}


/* =========================
/* =========================
   NORMALIZE ZOTERO DATA
   TAG EXTRACTION
========================= */
========================= */


function normalizeData(data) {
function getAllTags(data) {
    const tagSet = new Set();


     return data.map(item => ({
     data.forEach(item => {
        (item.tags || []).forEach(t => tagSet.add(t));
    });


        title: item.title || "Untitled",
    return [...tagSet].sort((a, b) => a.localeCompare(b));
        date: item.date || "",
}
        author: item.creators?.[0]?.lastName || "Unknown",


        tags: (item.tags || []).map(t => t.tag),
        abstractNote: item.abstractNote || ""
    }));
}


/* =========================
/* =========================
   GLOBAL TAG BAR
   RENDER TAG BAR
========================= */
========================= */


function renderTags(data) {
function renderTags() {
 
     const container = document.getElementById("tagBar");
     const container = document.getElementById("globalTags");
 
    const tagSet = new Set();
 
    data.forEach(item => {
        item.tags.forEach(t => tagSet.add(t));
    });
 
     container.innerHTML = "";
     container.innerHTML = "";


     [...tagSet].sort().forEach(tag => {
     const tags = getAllTags(BIB_DATA);


    tags.forEach(tag => {
         const el = document.createElement("span");
         const el = document.createElement("span");
         el.className = "tag";
         el.className = "tag" + (ACTIVE_TAGS.has(tag) ? " active" : "");
        el.dataset.tag = tag;
         el.textContent = tag;
         el.innerText = tag;


         el.addEventListener("click", () => toggleTag(tag, el));
         el.onclick = () => {
            if (ACTIVE_TAGS.has(tag)) {
                ACTIVE_TAGS.delete(tag);
            } else {
                ACTIVE_TAGS.add(tag);
            }
            render();
        };


         container.appendChild(el);
         container.appendChild(el);
     });
     });
}


}


/* =========================
/* =========================
   TAG TOGGLE
   FILTER LOGIC
========================= */
========================= */


function toggleTag(tag, el) {
function filterData(data) {
    if (ACTIVE_TAGS.size === 0) return data;


     if (activeTags.has(tag)) {
     return data.filter(item =>
         activeTags.delete(tag);
         (item.tags || []).some(t => ACTIVE_TAGS.has(t))
        el.classList.remove("active");
     );
     } else {
}
        activeTags.add(tag);
        el.classList.add("active");
    }


    applyFilter();
    syncEntryTags();
}


/* =========================
/* =========================
   FILTER ENTRIES
   SORT (ALPHABETICAL)
========================= */
========================= */


function applyFilter() {
function sortData(data) {
 
     return [...data].sort((a, b) =>
     document.querySelectorAll(".bib-entry").forEach(entry => {
         (a.authors?.[0]?.family || "Unknown")
 
             .localeCompare(b.authors?.[0]?.family || "Unknown")
         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
   RENDER LIST VIEW
========================= */
========================= */


function renderList(data) {
function renderList(data) {
     const container = document.getElementById("listView");
     const container = document.getElementById("listView");
     container.innerHTML = "";
     container.innerHTML = "";
    // alphabetisch sortieren
    data.sort((a, b) =>
        a.author.localeCompare(b.author)
    );


     data.forEach(item => {
     data.forEach(item => {


         const el = document.createElement("div");
         const author = item.authors?.[0]
        el.className = "bib-entry";
            ? `${item.authors[0].family}, ${item.authors[0].given || ""}`
        el.dataset.tags = item.tags.join(" ");
            : "Unknown Author";


         el.innerHTML = `
         const tagsHTML = (item.tags || []).map(tag =>
             <h3>${item.author}. <i>${item.title}</i>. ${item.date}</h3>
             `<span class="tag small ${ACTIVE_TAGS.has(tag) ? "active" : ""}"
                  onclick="toggleTag('${tag}')">${tag}</span>`
        ).join(" ");


            <div class="bib-tags">
        const div = document.createElement("div");
                ${item.tags.map(t =>
        div.className = "bib-entry";
                    `<span class="tag" data-tag="${t}">${t}</span>`
        div.innerHTML = `
                ).join(" ")}
            <h3>${author}. <i>${item.title}</i>. ${item.year || ""}</h3>
            </div>


             <p class="short-abstract">
             <div class="bib-tags">${tagsHTML}</div>
                ${item.abstractNote}
            </p>


             <button class="expand-btn">Show Abstract</button>
             <p class="short-abstract">${item.abstract || ""}</p>


             <div class="abstract hidden">
             ${item.url ? `<a href="${item.url}" target="_blank">Source</a>` : ""}
                <p>${item.abstractNote}</p>
            </div>
         `;
         `;


         container.appendChild(el);
         container.appendChild(div);
 
     });
     });
}


    rebindUI();
    syncEntryTags();
    applyFilter();
}


/* =========================
/* =========================
   UI REBIND
   TAG TOGGLE FROM LIST
========================= */
========================= */


function rebindUI() {
function toggleTag(tag) {
    if (ACTIVE_TAGS.has(tag)) {
        ACTIVE_TAGS.delete(tag);
    } else {
        ACTIVE_TAGS.add(tag);
    }
    render();
}


    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
   MAIN RENDER PIPELINE
========================= */
========================= */


function reloadBibliography() {
function render() {
 
     const filtered = filterData(BIB_DATA);
     console.log("🔄 Reloading BibliographyData...");
     const sorted = sortData(filtered);
 
    if (typeof BibliographyData === "undefined") {
        console.error("BibliographyData not found");
        return;
     }
 
    rawData = normalizeData(BibliographyData);
 
    activeTags.clear();
 
    document.getElementById("globalTags").innerHTML = "";
 
    loadBibliography();
 
    console.log("✅ Updated");


    renderTags();
    renderList(sorted);
}
}

Revision as of 23:32, 11 May 2026

let BIB_DATA = [];
let ACTIVE_TAGS = new Set();

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

document.addEventListener("DOMContentLoaded", async () => {
    await loadData();
    render();
});


/* =========================
   LOAD DATA FROM WIKI
========================= */

async function loadData() {
    const res = await fetch("BibliographyData");
    BIB_DATA = await res.json();

    console.log("📚 Loaded entries:", BIB_DATA.length);
}


/* =========================
   TAG EXTRACTION
========================= */

function getAllTags(data) {
    const tagSet = new Set();

    data.forEach(item => {
        (item.tags || []).forEach(t => tagSet.add(t));
    });

    return [...tagSet].sort((a, b) => a.localeCompare(b));
}


/* =========================
   RENDER TAG BAR
========================= */

function renderTags() {
    const container = document.getElementById("tagBar");
    container.innerHTML = "";

    const tags = getAllTags(BIB_DATA);

    tags.forEach(tag => {
        const el = document.createElement("span");
        el.className = "tag" + (ACTIVE_TAGS.has(tag) ? " active" : "");
        el.textContent = tag;

        el.onclick = () => {
            if (ACTIVE_TAGS.has(tag)) {
                ACTIVE_TAGS.delete(tag);
            } else {
                ACTIVE_TAGS.add(tag);
            }
            render();
        };

        container.appendChild(el);
    });
}


/* =========================
   FILTER LOGIC
========================= */

function filterData(data) {
    if (ACTIVE_TAGS.size === 0) return data;

    return data.filter(item =>
        (item.tags || []).some(t => ACTIVE_TAGS.has(t))
    );
}


/* =========================
   SORT (ALPHABETICAL)
========================= */

function sortData(data) {
    return [...data].sort((a, b) =>
        (a.authors?.[0]?.family || "Unknown")
            .localeCompare(b.authors?.[0]?.family || "Unknown")
    );
}


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

function renderList(data) {
    const container = document.getElementById("listView");
    container.innerHTML = "";

    data.forEach(item => {

        const author = item.authors?.[0]
            ? `${item.authors[0].family}, ${item.authors[0].given || ""}`
            : "Unknown Author";

        const tagsHTML = (item.tags || []).map(tag =>
            `<span class="tag small ${ACTIVE_TAGS.has(tag) ? "active" : ""}"
                   onclick="toggleTag('${tag}')">${tag}</span>`
        ).join(" ");

        const div = document.createElement("div");
        div.className = "bib-entry";
        div.innerHTML = `
            <h3>${author}. <i>${item.title}</i>. ${item.year || ""}</h3>

            <div class="bib-tags">${tagsHTML}</div>

            <p class="short-abstract">${item.abstract || ""}</p>

            ${item.url ? `<a href="${item.url}" target="_blank">Source</a>` : ""}
        `;

        container.appendChild(div);
    });
}


/* =========================
   TAG TOGGLE FROM LIST
========================= */

function toggleTag(tag) {
    if (ACTIVE_TAGS.has(tag)) {
        ACTIVE_TAGS.delete(tag);
    } else {
        ACTIVE_TAGS.add(tag);
    }
    render();
}


/* =========================
   MAIN RENDER PIPELINE
========================= */

function render() {
    const filtered = filterData(BIB_DATA);
    const sorted = sortData(filtered);

    renderTags();
    renderList(sorted);
}