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:
(async function () {
(function () {


const DATA_URL = "https://illus.twainframe.org/index.php?title=BibliographyData&action=raw&ctype=application/json";
const DATA_URL = "/index.php?title=BibliographyData&action=raw&ctype=application/json";


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


// -------------------- INIT --------------------
// MediaWiki-safe init
 
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
    document.addEventListener("DOMContentLoaded", init);
} else {
    init();
}


async function init() {
async function init() {
     await loadData();
     try {
    renderTags();
        await loadData();
     renderList();
        renderTags();
        renderList();
     } catch (e) {
        console.error("Bibliography load error:", e);
    }
}
}


Line 22: Line 29:
     DATA = await res.json();
     DATA = await res.json();


     // Alphabetisch nach Titel
     // alphabetisch sortieren
     DATA.sort((a, b) =>
     DATA.sort((a, b) =>
         (a.title || "").localeCompare(b.title || "")
         (a.title || "").localeCompare(b.title || "")
Line 28: Line 35:
}
}


// -------------------- TAG BAR --------------------
// -------------------- TAGS --------------------


function renderTags() {
function renderTags() {
     const tagBar = document.getElementById("tagBar");
     const tagBar = document.getElementById("tagBar");
    if (!tagBar) return;
     tagBar.innerHTML = "";
     tagBar.innerHTML = "";


     const allTags = new Set();
     const tags = new Set();


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


     [...allTags].sort().forEach(tag => {
     [...tags].sort().forEach(tag => {
         const el = document.createElement("span");
         const el = document.createElement("span");
         el.className = "tag inactive";
         el.className = "tag inactive";
         el.textContent = tag;
         el.textContent = tag;
        el.dataset.tag = tag;


         el.onclick = () => toggleTag(tag, el);
         el.onclick = () => toggleTag(tag);


         tagBar.appendChild(el);
         tagBar.appendChild(el);
Line 52: Line 60:
}
}


function toggleTag(tag, el) {
function toggleTag(tag) {
     if (ACTIVE_TAGS.has(tag)) {
     if (ACTIVE_TAGS.has(tag)) {
         ACTIVE_TAGS.delete(tag);
         ACTIVE_TAGS.delete(tag);
        el.classList.remove("active");
        el.classList.add("inactive");
     } else {
     } else {
         ACTIVE_TAGS.add(tag);
         ACTIVE_TAGS.add(tag);
        el.classList.add("active");
        el.classList.remove("inactive");
     }
     }


    updateTagStyles();
     renderList();
     renderList();
}
}


// -------------------- LIST VIEW --------------------
function updateTagStyles() {
    document.querySelectorAll("#tagBar .tag").forEach(el => {
        const t = el.textContent;
 
        if (ACTIVE_TAGS.has(t)) {
            el.classList.add("active");
            el.classList.remove("inactive");
        } else {
            el.classList.remove("active");
            el.classList.add("inactive");
        }
    });
}
 
// -------------------- LIST --------------------


function renderList() {
function renderList() {
     const container = document.getElementById("listView");
     const container = document.getElementById("listView");
    if (!container) return;
     container.innerHTML = "";
     container.innerHTML = "";


Line 76: Line 97:
     if (ACTIVE_TAGS.size > 0) {
     if (ACTIVE_TAGS.size > 0) {
         filtered = DATA.filter(item =>
         filtered = DATA.filter(item =>
             item.tags && item.tags.some(t => ACTIVE_TAGS.has(t))
             (item.tags || []).some(t => ACTIVE_TAGS.has(t))
         );
         );
     }
     }
Line 84: Line 105:
         div.className = "bib-entry";
         div.className = "bib-entry";


         div.innerHTML = buildEntry(item);
         div.innerHTML = renderEntry(item);


         container.appendChild(div);
         container.appendChild(div);
Line 90: Line 111:
}
}


// -------------------- ENTRY TEMPLATE --------------------
// -------------------- ENTRY --------------------


function buildEntry(item) {
function renderEntry(item) {


     const authors = (item.authors || [])
     const authors = (item.authors || [])
         .map(a => {
         .map(a => typeof a === "string"
            if (typeof a === "string") return a;
            ? a
             return (a.family || "") + (a.given ? ", " + a.given : "");
             : (a.family || "Unknown"))
        })
         .join(", ");
         .join(", ");


     const tags = (item.tags || []).map(t =>
     const tags = (item.tags || []).map(t =>
         `<span class="tag ${ACTIVE_TAGS.has(t) ? 'active' : 'inactive'}"
         `<span class="tag ${ACTIVE_TAGS.has(t) ? 'active' : 'inactive'}">
              data-tag="${t}"
              onclick="window.__toggleTagFromEntry('${t}')">
             ${t}
             ${t}
         </span>`
         </span>`
Line 110: Line 128:


     return `
     return `
         <h3>${authors || "Unknown"}. <i>${item.title || "Untitled"}</i>. ${item.year || ""}</h3>
         <h3>
            ${authors || "Unknown"}.
            <i>${item.title || "Untitled"}</i>.
            ${item.year || ""}
        </h3>


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


         <p class="short-abstract">${item.abstract || ""}</p>
         ${item.container ? `<p><em>${item.container}</em></p>` : ""}


         ${item.url ? `<a href="${item.url}" target="_blank">Source</a>` : ""}
         ${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();
};


})();
})();

Revision as of 23:46, 11 May 2026

(function () {

const DATA_URL = "/index.php?title=BibliographyData&action=raw&ctype=application/json";

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

// MediaWiki-safe init
if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
} else {
    init();
}

async function init() {
    try {
        await loadData();
        renderTags();
        renderList();
    } catch (e) {
        console.error("Bibliography load error:", e);
    }
}

// -------------------- LOAD DATA --------------------

async function loadData() {
    const res = await fetch(DATA_URL);
    DATA = await res.json();

    // alphabetisch sortieren
    DATA.sort((a, b) =>
        (a.title || "").localeCompare(b.title || "")
    );
}

// -------------------- TAGS --------------------

function renderTags() {
    const tagBar = document.getElementById("tagBar");
    if (!tagBar) return;

    tagBar.innerHTML = "";

    const tags = new Set();

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

    [...tags].sort().forEach(tag => {
        const el = document.createElement("span");
        el.className = "tag inactive";
        el.textContent = tag;

        el.onclick = () => toggleTag(tag);

        tagBar.appendChild(el);
    });
}

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

    updateTagStyles();
    renderList();
}

function updateTagStyles() {
    document.querySelectorAll("#tagBar .tag").forEach(el => {
        const t = el.textContent;

        if (ACTIVE_TAGS.has(t)) {
            el.classList.add("active");
            el.classList.remove("inactive");
        } else {
            el.classList.remove("active");
            el.classList.add("inactive");
        }
    });
}

// -------------------- LIST --------------------

function renderList() {
    const container = document.getElementById("listView");
    if (!container) return;

    container.innerHTML = "";

    let filtered = DATA;

    if (ACTIVE_TAGS.size > 0) {
        filtered = DATA.filter(item =>
            (item.tags || []).some(t => ACTIVE_TAGS.has(t))
        );
    }

    filtered.forEach(item => {
        const div = document.createElement("div");
        div.className = "bib-entry";

        div.innerHTML = renderEntry(item);

        container.appendChild(div);
    });
}

// -------------------- ENTRY --------------------

function renderEntry(item) {

    const authors = (item.authors || [])
        .map(a => typeof a === "string"
            ? a
            : (a.family || "Unknown"))
        .join(", ");

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

    return `
        <h3>
            ${authors || "Unknown"}.
            <i>${item.title || "Untitled"}</i>.
            ${item.year || ""}
        </h3>

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

        ${item.container ? `<p><em>${item.container}</em></p>` : ""}

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

})();