MediaWiki:TeamBingo.js

From Roat Pkz
Revision as of 15:43, 7 March 2026 by Hefner (talk | contribs)
Jump to navigation Jump to search

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)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
mw.hook('wikipage.content').add(function () {
    const JSON_PAGE = "TeamBingoData"; // wiki page where JSON is stored
    const POLL_INTERVAL = 5000; // 5 seconds
    const username = mw.config.get("wgUserName");

    const infoBox = document.getElementById("teamBingoInfoBox");

    const containers = document.querySelectorAll(".teamBingoContainer");
    if (!containers.length) return;

    let boardData = {}; // current state of tiles for all teams

    // Initialize boards
    containers.forEach(container => {
        container.innerHTML = "";
        const team = container.id;
        const captain = container.getAttribute("data-captain");
        const itemsAttr = container.getAttribute("data-items");
        const items = itemsAttr.split("|").filter(i => i.trim() !== "");
        const parsedItems = items.map((entry, idx) => {
            const parts = entry.split("::");
            return { name: parts[0].trim(), tooltip: parts[1] ? parts[1].trim() : parts[0].trim(), index: idx };
        });

        const table = document.createElement("table");
        table.style.width = "100%";
        table.style.tableLayout = "fixed";
        table.style.border = "2px solid #596e96";
        table.style.borderCollapse = "collapse";
        container.appendChild(table);

        const rows = Math.ceil(Math.sqrt(parsedItems.length));
        const cols = Math.ceil(parsedItems.length / rows);

        const allTemplates = parsedItems.map(item => `{{plinkp|${item.name}}}`).join("\n");

        // Fetch images via API
        $.getJSON("/api.php", { action: "parse", text: allTemplates, format: "json" }).done(function(data){
            if(!data.parse || !data.parse.text) return;
            const tempDiv = document.createElement("div");
            tempDiv.innerHTML = data.parse.text["*"];
            const imgs = tempDiv.querySelectorAll("img");

            for (let r = 0; r < rows; r++){
                const row = table.insertRow();
                for (let c = 0; c < cols; c++){
                    const idx = r*cols + c;
                    if(idx >= parsedItems.length) break;

                    const item = parsedItems[idx];
                    const cell = row.insertCell();
                    cell.style.position = "relative";
                    cell.style.textAlign = "center";
                    cell.style.background = "#313e59";
                    cell.style.border = "1px solid #596e96";
                    cell.style.cursor = "pointer";
                    cell.style.transition = "all 0.2s";
                    cell.style.padding = "10px";

                    const cellContainer = document.createElement("div");
                    cellContainer.style.position = "relative";

                    // Image
                    if(imgs[idx]){
                        const img = document.createElement("img");
                        img.src = imgs[idx].src;
                        img.alt = item.name;
                        img.style.width = "40px";
                        img.style.display = "block";
                        img.style.margin = "0 auto";
                        cellContainer.appendChild(img);
                    }

                    // Name
                    const nameDiv = document.createElement("div");
                    nameDiv.textContent = item.name;
                    nameDiv.style.marginTop = "5px";
                    cellContainer.appendChild(nameDiv);

                    // Checkmark
                    const checkmark = document.createElement("div");
                    checkmark.textContent = "✔";
                    checkmark.style.position = "absolute";
                    checkmark.style.top = "2px";
                    checkmark.style.right = "2px";
                    checkmark.style.color = "#4CAF50";
                    checkmark.style.fontSize = "20px";
                    checkmark.style.display = "none";
                    cellContainer.appendChild(checkmark);

                    cell.appendChild(cellContainer);

                    // Hover info
                    cell.addEventListener("mouseenter", ()=>{
                        infoBox.innerHTML = "";
                        const header = document.createElement("div");
                        header.style.fontWeight = "bold";
                        header.style.marginBottom = "5px";
                        header.textContent = item.name;
                        infoBox.appendChild(header);

                        if(imgs[idx]){
                            const img = document.createElement("img");
                            img.src = imgs[idx].src;
                            img.style.width = "40px";
                            img.style.display = "block";
                            img.style.marginBottom = "5px";
                            infoBox.appendChild(img);
                        }

                        item.tooltip.split("%%").forEach(line=>{
                            const div = document.createElement("div");
                            div.innerHTML = line.trim();
                            infoBox.appendChild(div);
                        });
                    });

                    cell.addEventListener("mouseleave", ()=>{
                        infoBox.innerHTML = "Hover over a tile to see its info here.";
                    });

                    // Click only if captain
                    cell.addEventListener("click", function(){
                        if(username !== captain) return;

                        const key = `${team}_tile_${idx}`;
                        boardData[key] = !boardData[key];
                        saveBoardData();
                        renderBoard();
                    });
                }
            }
        });
    });

    // Fetch board state from JSON page
    function fetchBoardData(){
        $.getJSON(`/api.php?action=parse&page=${JSON_PAGE}&format=json`).done(data=>{
            try{
                const text = data.parse.text["*"];
                boardData = JSON.parse(text);
                renderBoard();
            }catch(e){ console.error(e);}
        });
    }

    // Save board state to JSON page
    function saveBoardData(){
        const content = JSON.stringify(boardData);
        $.post("/api.php", {
            action:"edit",
            title: JSON_PAGE,
            token: mw.user.tokens.get("csrfToken"),
            format: "json",
            text: content,
            summary: "Update bingo board"
        });
    }

    // Update checkmarks based on boardData
    function renderBoard(){
        containers.forEach(container=>{
            const team = container.id;
            const cells = container.querySelectorAll("td");
            cells.forEach((cell, idx)=>{
                const key = `${team}_tile_${idx}`;
                const check = cell.querySelector(".bingoCheckmark");
                if(check) check.style.display = boardData[key] ? "block" : "none";
                cell.style.background = boardData[key] ? "rgba(76,175,80,0.5)" : "#313e59";
            });
        });
    }

    fetchBoardData();
    setInterval(fetchBoardData, 5000); // poll every 5s
});