MediaWiki

Gadget-Bibliography.js

From ACES

Revision as of 16:10, 9 November 2021 by Yid010 (talk | contribs) (fix)

Note: After saving, 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.
(function ($, mw) {
    "use strict";
    var allowedPages = ["Publications", "Home"];
    var nYearButtons = 5;
    if (!allowedPages.includes(mw.config.get("wgPageName"))) return;
    if (window.BibLoaded) return;
    window.BibLoaded = true;

    console.log("[Bibliography] 0.0.1");
    var scriptLoaded = 0;
    var mwConfig = mw.config.get(["wgUserName", "wgServer", "wgArticlePath"]);

    var isAnon = mwConfig.wgUserName === null;
    var articlePath = mwConfig.wgServer + mwConfig.wgArticlePath;

    function download(filename, text) {
        var el = document.createElement("a");
        el.setAttribute(
            "href",
            "data:text/plain;charset=utf-8," + encodeURIComponent(text)
        );
        el.setAttribute("download", filename);

        el.style.display = "none";
        document.body.appendChild(el);

        el.click();

        document.body.removeChild(el);
    }

    function getPDF(rawBib) {
        var pdfMap = {}
        Array.from(rawBib.matchAll(/^@.+?\{(.+?),\s*(?:\n(?!@).*?)*?\npdf\s*=\s*\{(.*)\}/mg))
            .forEach(function (m) {
                pdfMap[m[1]] = m[2]
            })
        return pdfMap
    }

    function genDataTable(e) {
        var Cite = window.require("citation-js");
        var yearGroup = {};
        var dataTable = undefined;
        var rawBib = $(e).find(".bibliography-data")[0].textContent;
        var pdfMap = getPDF(rawBib)
        var bib = Cite(rawBib);
        var data = [];
        var pageTitleIter = rawBib.matchAll(/^_pageName = \{(.+)\}\s*,?\s*$/gm);
        bib.data.forEach(function (entry) {
            var linkTarget = new URL(
                articlePath.replace("$1", pageTitleIter.next().value[1])
            );
            var linkEle = $("<a>").text(entry.id);
            linkEle.attr("href", linkTarget.toString());

            var editLink = $("<a>").html(
                '<span class="material-icons-outlined">edit</span>'
            );
            linkTarget.searchParams.append("action", "formedit");
            editLink.attr("href", linkTarget.toString());
            editLink.attr("target", "_blank");

            entry.render = Cite(entry).format("bibliography", {
                format: "html",
                template: "apa",
                lang: "en-US",
            });
            entry.pdf = pdfMap[entry.id]
            if (entry.pdf) {
                entry.render += $("<a />")
                    .text("[PDF]")
                    .attr(
                        "href",
                        new URL(articlePath.replace("$1", "Special:filepath/" + pdfMap[entry.id])).toString()
                    )
                    .prop('outerHTML');
            }

            entry.pageTitle = editLink[0].outerHTML + linkEle[0].outerHTML;
            entry.year = entry.issued && entry.issued["date-parts"] && entry.issued["date-parts"][0] && entry.issued["date-parts"][0][0] || 1970;
            yearGroup[parseInt(entry.year)] = false;

            data.push(entry);
        });

        var tb = $("<table></table>")[0];
        e.replaceWith(tb);
        tb = $(tb);
        tb.append($("<thead>"));
        tb.append($("<tbody>"));
        tb.addClass("display");

        // Generate buttons
        var orderedYears = Object.keys(yearGroup).sort(function (x, y) {
            if (x < y) return 1;
            if (x > y) return -1;
            return 0;
        });

        function draw(dt) {
            dt.column("year:name").search(
                orderedYears
                    .filter(function (e) {
                        return yearGroup[e];
                    })
                    .join("|"),
                true,
                false
            );
            dt.draw();
        }
        var buttons = orderedYears.slice(0, nYearButtons).map(function (year) {
            return {
                text: year,
                action: function (e, dt, node, config) {
                    yearGroup[year] = !yearGroup[year];
                    node.toggleClass("active", yearGroup[year]);
                    draw(dt);
                },
            };
        });
        if (orderedYears.length > nYearButtons) {
            var statusRest = false;
            var restYears = orderedYears.slice(nYearButtons);

            buttons.push({
                text: "Rest",
                action: function (e, dt, node, config) {
                    statusRest = !statusRest;
                    restYears.forEach(function (el) {
                        yearGroup[el] = !yearGroup[el];
                    });
                    node.toggleClass("active", statusRest);
                    draw(dt);
                },
            });
        }
        // export BibTeX button
        buttons.push({
            text: "Export BibTeX",
            action: function (e, dt, node, config) {
                var text = Cite(dt.rows({ page: "current" }).data().toArray()).format(
                    "bibtex"
                );
                download("bibtex.bib", text);
            },
            titleAttr: "export",
        });

        var options = {
            data: data,
            columns: [{
                data: "render",
                title: "APA",
                render: function (data, type, row) {
                    // If display or filter data is requested, format the date
                    if (type === "sort") return row.year;
                    return data;
                },
            },
            {
                name: "year",
                data: "year",
                visible: false,
            },
            ],
            paging: false,
            order: [
                [0, "desc"]
            ],
            rowGroup: {
                dataSrc: "year",
            },
            dom: "fBrtip",
            buttons: buttons,
        };
        if (!isAnon) {
            options.columns.unshift({
                data: "pageTitle",
                title: "In-site Page",
            });
            options.order[0][0] += 1;
            options.order.push([0, "asc"]);
        }
        dataTable = tb.dataTable(options);
        dataTable = dataTable.DataTable();
    }

    function genList(e) {
        var Cite = window.require("citation-js");
        var rawBib = $(e).find(".bibliography-data")[0].textContent;
        var pdfMap = getPDF(rawBib)
        var bib = Cite(rawBib);
        var ul = $("<ul  />", { class: "csl-bib-body" });
        bib.data.forEach(function (entry) {
            var li = $("<li/>", { class: "bib-entry" });
            if (pdfMap[entry.id]) {
                var link = $("<a />").text("[PDF]");
                link.attr(
                    "href",
                    new URL(articlePath.replace("$1", "Special:filepath/" + pdfMap[entry.id])).toString()
                );
                li.append(link);
            }
            li.append(" ");
            li.append(
                $(
                    $(
                        Cite(entry).format("bibliography", {
                            format: "html",
                            template: "apa",
                            lang: "en-US",
                        })
                    ).html()
                ).css("display", "inline")
            );
            ul.append(li);
        });
        if (e.getAttribute("data-more")) {
            var linkMore = $("<a />").text("More...");
            linkMore.attr(
                "href",
                new URL(articlePath.replace("$1", "Publications")).toString()
            );
            ul.append(linkMore);
        }
        e.replaceWith(ul[0]);
        return ul;
    }

    function run() {
        $(".bibliography:not(.test)").each(function (i, e) {
            var style = e.getAttribute("data-style");
            if (style === "list") {
                return genList(e);
            }
            return genDataTable(e);
        });
    }

    function loadScripts(scripts, callback) {
        function onLoaded() {
            scriptLoaded++;
            if (scriptLoaded === scripts.length)
                mw.hook("wikipage.content").add(callback);
        }
        scripts.forEach(function (s) {
            mw.loader.getScript(s).then(onLoaded);
        });
    }

    loadScripts(
        [
            "https://cdn.jsdelivr.net/npm/citation-js@0.5.1",
            "https://cdn.datatables.net/v/dt/dt-1.11.1/b-2.0.0/rg-1.1.3/datatables.min.js",
        ],
        run
    );
    mw.loader.load(
        "https://cdn.datatables.net/v/dt/dt-1.11.1/b-2.0.0/rg-1.1.3/datatables.min.css",
        "text/css"
    );
})(jQuery, mediaWiki);