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:
/* =========================
  STATE
========================= */
const activeTags = new Set();
const activeTags = new Set();


/* TAG CLICK HANDLING */
/* =========================
  TAG FILTERING (GLOBAL)
========================= */
 
document.querySelectorAll(".tag").forEach(tag => {
document.querySelectorAll(".tag").forEach(tag => {


Line 22: Line 29:
});
});


/* FILTER FUNCTION */
 
function filterEntries() {
function filterEntries() {


Line 41: Line 48:


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


Line 51: Line 65:
         const view = btn.dataset.view;
         const view = btn.dataset.view;


         document.getElementById("listView").style.display =
         const listView = document.getElementById("listView");
            view === "list" ? "block" : "none";
        const networkView = document.getElementById("networkView");


         document.getElementById("networkCanvas").style.display =
         listView.style.display = (view === "list") ? "block" : "none";
            view === "network" ? "block" : "none";
        networkView.classList.toggle("hidden", view !== "network");


         drawNetwork();
         if (view === "network") {
            buildNetwork();
        }


     });
     });
});
});


// SIMPLE NETWORK GRAPH
 
/* =========================
  EXPAND ABSTRACTS
========================= */
 
document.querySelectorAll(".expand-btn").forEach(btn => {
 
    btn.addEventListener("click", () => {
 
        const abstract = btn.nextElementSibling;
 
        abstract.classList.toggle("hidden");
 
        btn.textContent =
            abstract.classList.contains("hidden")
                ? "Show Abstract"
                : "Hide Abstract";
 
    });
 
});
 
 
/* =========================
  NETWORK VIEW
========================= */


function buildNetwork() {
function buildNetwork() {
Line 74: Line 116:
     const entryNodes = [];
     const entryNodes = [];


     let centerX = 400;
     const centerX = container.clientWidth / 2;
     let centerY = 300;
     const centerY = container.clientHeight / 2;
 
    /* -------------------------
      ENTRY NODES
    ------------------------- */


    // 1. ENTRY NODES
     entries.forEach((entry, i) => {
     entries.forEach((entry, i) => {


Line 84: Line 129:
         node.innerText = entry.querySelector("h3").innerText;
         node.innerText = entry.querySelector("h3").innerText;


         let x = centerX + Math.cos(i) * 200;
         const angle = (i / entries.length) * Math.PI * 2;
         let y = centerY + Math.sin(i) * 200;
 
        const x = centerX + Math.cos(angle) * 250;
         const y = centerY + Math.sin(angle) * 250;


         node.style.left = x + "px";
         node.style.left = x + "px";
Line 94: Line 141:
         entryNodes.push({ node, entry, x, y });
         entryNodes.push({ node, entry, x, y });


        // click highlight
         node.addEventListener("click", () => {
         node.addEventListener("click", () => {


             document.querySelectorAll(".node").forEach(n =>
             document.querySelectorAll(".node")
                n.classList.remove("highlight")
                .forEach(n => n.classList.remove("highlight"));
            );


             node.classList.add("highlight");
             node.classList.add("highlight");
Line 105: Line 150:
         });
         });


         // TAG LINKS
         /* -------------------------
          TAG NODES
        ------------------------- */
 
         const tags = entry.dataset.tags.split(" ");
         const tags = entry.dataset.tags.split(" ");


Line 116: Line 164:
                 tnode.innerText = tag;
                 tnode.innerText = tag;


                 let tx = Math.random() * 600 + 100;
                 const tx = Math.random() * (container.clientWidth - 100) + 50;
                 let ty = Math.random() * 400 + 100;
                 const ty = Math.random() * (container.clientHeight - 100) + 50;


                 tnode.style.left = tx + "px";
                 tnode.style.left = tx + "px";
Line 132: Line 180:
     });
     });


     // 2. EDGES (entry → tag)
     /* -------------------------
      EDGES
    ------------------------- */
 
     entryNodes.forEach(e => {
     entryNodes.forEach(e => {


Line 140: Line 191:


             const t = tagNodes.get(tag);
             const t = tagNodes.get(tag);
            if (!t) return;


             const line = document.createElement("div");
             const line = document.createElement("div");
Line 147: Line 199:
             const dy = t.y - e.y;
             const dy = t.y - e.y;


             const length = Math.sqrt(dx*dx + dy*dy);
             const length = Math.sqrt(dx * dx + dy * dy);


             line.style.width = length + "px";
             line.style.width = length + "px";
Line 161: Line 213:


}
}
document.querySelectorAll(".expand-btn").forEach(btn => {
    btn.addEventListener("click", () => {
        const abstract =
            btn.nextElementSibling;
        abstract.classList.toggle("hidden");
        btn.textContent =
            abstract.classList.contains("hidden")
            ? "Show Abstract"
            : "Hide Abstract";
    });
});
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"
        );
        if (view === "network") {
            buildNetwork();
        }
    });
});

Revision as of 22:03, 11 May 2026

/* =========================
   STATE
========================= */

const activeTags = new Set();

/* =========================
   TAG FILTERING (GLOBAL)
========================= */

document.querySelectorAll(".tag").forEach(tag => {

    tag.addEventListener("click", () => {

        const value = tag.dataset.tag;

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

        filterEntries();

    });

});


function filterEntries() {

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

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

        const matches =
            [...activeTags].every(t => entryTags.includes(t));

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

    });

}


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

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;

        const listView = document.getElementById("listView");
        const networkView = document.getElementById("networkView");

        listView.style.display = (view === "list") ? "block" : "none";
        networkView.classList.toggle("hidden", view !== "network");

        if (view === "network") {
            buildNetwork();
        }

    });

});


/* =========================
   EXPAND ABSTRACTS
========================= */

document.querySelectorAll(".expand-btn").forEach(btn => {

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

        const abstract = btn.nextElementSibling;

        abstract.classList.toggle("hidden");

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

    });

});


/* =========================
   NETWORK VIEW
========================= */

function buildNetwork() {

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

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

    const tagNodes = new Map();
    const entryNodes = [];

    const centerX = container.clientWidth / 2;
    const centerY = container.clientHeight / 2;

    /* -------------------------
       ENTRY NODES
    ------------------------- */

    entries.forEach((entry, i) => {

        const node = document.createElement("div");
        node.className = "node entry";
        node.innerText = entry.querySelector("h3").innerText;

        const angle = (i / entries.length) * Math.PI * 2;

        const x = centerX + Math.cos(angle) * 250;
        const y = centerY + Math.sin(angle) * 250;

        node.style.left = x + "px";
        node.style.top = y + "px";

        container.appendChild(node);

        entryNodes.push({ node, entry, x, y });

        node.addEventListener("click", () => {

            document.querySelectorAll(".node")
                .forEach(n => n.classList.remove("highlight"));

            node.classList.add("highlight");

        });

        /* -------------------------
           TAG NODES
        ------------------------- */

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

        tags.forEach(tag => {

            if (!tagNodes.has(tag)) {

                const tnode = document.createElement("div");
                tnode.className = "node tag";
                tnode.innerText = tag;

                const tx = Math.random() * (container.clientWidth - 100) + 50;
                const ty = Math.random() * (container.clientHeight - 100) + 50;

                tnode.style.left = tx + "px";
                tnode.style.top = ty + "px";

                container.appendChild(tnode);

                tagNodes.set(tag, { node: tnode, x: tx, y: ty });

            }

        });

    });

    /* -------------------------
       EDGES
    ------------------------- */

    entryNodes.forEach(e => {

        const tags = e.entry.dataset.tags.split(" ");

        tags.forEach(tag => {

            const t = tagNodes.get(tag);
            if (!t) return;

            const line = document.createElement("div");
            line.className = "edge";

            const dx = t.x - e.x;
            const dy = t.y - e.y;

            const length = Math.sqrt(dx * dx + dy * dy);

            line.style.width = length + "px";
            line.style.left = e.x + "px";
            line.style.top = e.y + "px";
            line.style.transform = `rotate(${Math.atan2(dy, dx)}rad)`;

            container.appendChild(line);

        });

    });

}