MediaWiki

Difference between revisions of "Gadget-Bibliography.js"

From ACES

 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
(function($, mw) {
(function ($, mw) {
     "use strict";
     "use strict";
     var allowedPages = ["Publications", "Home"];
     var allowedPages = ["Publications", "Home"];
Line 28: Line 28:


         document.body.removeChild(el);
         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
     }
     }


Line 35: Line 44:
         var dataTable = undefined;
         var dataTable = undefined;
         var rawBib = $(e).find(".bibliography-data")[0].textContent;
         var rawBib = $(e).find(".bibliography-data")[0].textContent;
        var pdfMap = getPDF(rawBib)
         var bib = Cite(rawBib);
         var bib = Cite(rawBib);
         var data = [];
         var data = [];
         var pageTitleIter = rawBib.matchAll(/^_pageName = \{(.+)\}\s*,?\s*$/gm);
         var pageTitleIter = rawBib.matchAll(/^_pageName = \{(.+)\}\s*,?\s*$/gm);
 
         bib.data.forEach(function (entry) {
         bib.data.forEach(function(entry) {
             var linkTarget = new URL(
             var linkTarget = new URL(
                 articlePath.replace("$1", pageTitleIter.next().value[1])
                 articlePath.replace("$1", pageTitleIter.next().value[1])
Line 53: Line 62:
             editLink.attr("target", "_blank");
             editLink.attr("target", "_blank");


            var urlData = entry.URL
            entry.URL = undefined
             entry.render = Cite(entry).format("bibliography", {
             entry.render = Cite(entry).format("bibliography", {
                 format: "html",
                 format: "html",
Line 58: Line 69:
                 lang: "en-US",
                 lang: "en-US",
             });
             });
            entry.URL = urlData
            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');
            }
            if (urlData && urlData.startsWith("http")) {
                entry.render += " " + $("<a />")
                    .text("[URL]")
                    .attr(
                        "href",
                        urlData
                    )
                    .prop('outerHTML');
            }
             entry.pageTitle = editLink[0].outerHTML + linkEle[0].outerHTML;
             entry.pageTitle = editLink[0].outerHTML + linkEle[0].outerHTML;
             entry.year = entry.issued["date-parts"][0][0] || 1970;
             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;
             yearGroup[parseInt(entry.year)] = false;


Line 73: Line 106:


         // Generate buttons
         // Generate buttons
         var orderedYears = Object.keys(yearGroup).sort(function(x, y) {
         var orderedYears = Object.keys(yearGroup).sort(function (x, y) {
             if (x < y) return 1;
             if (x < y) return 1;
             if (x > y) return -1;
             if (x > y) return -1;
Line 82: Line 115:
             dt.column("year:name").search(
             dt.column("year:name").search(
                 orderedYears
                 orderedYears
                .filter(function(e) {
                    .filter(function (e) {
                    return yearGroup[e];
                        return yearGroup[e];
                })
                    })
                .join("|"),
                    .join("|"),
                 true,
                 true,
                 false
                 false
Line 91: Line 124:
             dt.draw();
             dt.draw();
         }
         }
         var buttons = orderedYears.slice(0, nYearButtons).map(function(year) {
         var buttons = orderedYears.slice(0, nYearButtons).map(function (year) {
             return {
             return {
                 text: year,
                 text: year,
                 action: function(e, dt, node, config) {
                 action: function (e, dt, node, config) {
                     yearGroup[year] = !yearGroup[year];
                     yearGroup[year] = !yearGroup[year];
                     node.toggleClass("active", yearGroup[year]);
                     node.toggleClass("active", yearGroup[year]);
Line 107: Line 140:
             buttons.push({
             buttons.push({
                 text: "Rest",
                 text: "Rest",
                 action: function(e, dt, node, config) {
                 action: function (e, dt, node, config) {
                     statusRest = !statusRest;
                     statusRest = !statusRest;
                     restYears.forEach(function(el) {
                     restYears.forEach(function (el) {
                         yearGroup[el] = !yearGroup[el];
                         yearGroup[el] = !yearGroup[el];
                     });
                     });
Line 120: Line 153:
         buttons.push({
         buttons.push({
             text: "Export BibTeX",
             text: "Export BibTeX",
             action: function(e, dt, node, config) {
             action: function (e, dt, node, config) {
                 var text = Cite(dt.rows({ page: "current" }).data().toArray()).format(
                 var text = Cite(dt.rows({ page: "current" }).data().toArray()).format(
                     "bibtex"
                     "bibtex"
Line 132: Line 165:
             data: data,
             data: data,
             columns: [{
             columns: [{
                    data: "render",
                className: "cell-apa",
                    title: "APA",
                data: "render",
                    render: function(data, type, row) {
                title: "APA",
                        // If display or filter data is requested, format the date
                render: function (data, type, row) {
                        if (type === "sort") return row.year;
                    // If display or filter data is requested, format the date
                        return data;
                    if (type === "sort") return row.year;
                    },
                    return data;
                },
                {
                    name: "year",
                    data: "year",
                    visible: false,
                 },
                 },
            },
            {
                name: "year",
                data: "year",
                visible: false,
            },
             ],
             ],
             paging: false,
             paging: false,
Line 158: Line 192:
         if (!isAnon) {
         if (!isAnon) {
             options.columns.unshift({
             options.columns.unshift({
                className: "cell-pageTitle",
                 data: "pageTitle",
                 data: "pageTitle",
                 title: "In-site Page",
                 title: "In-site Page",
Line 171: Line 206:
         var Cite = window.require("citation-js");
         var Cite = window.require("citation-js");
         var rawBib = $(e).find(".bibliography-data")[0].textContent;
         var rawBib = $(e).find(".bibliography-data")[0].textContent;
        var pdfMap = getPDF(rawBib)
         var bib = Cite(rawBib);
         var bib = Cite(rawBib);
         var ul = $("<ul  />", { class: "csl-bib-body" });
         var ul = $("<ul  />", { class: "csl-bib-body" });
         bib.data.forEach(function(entry) {
         bib.data.forEach(function (entry) {
             var li = $("<li/>", { class: "bib-entry" });
             var li = $("<li/>", { class: "bib-entry" });
             var link = $("<a />").text("[PDF]");
             if (pdfMap[entry.id]) {
             li.append(link);
                var link = $("<a />").text("[PDF]");
            li.append(" ");
                link.attr(
                    "href",
                    new URL(articlePath.replace("$1", "Special:filepath/" + pdfMap[entry.id])).toString()
                );
                li.append(link);
                li.append(" ");
            }
             if (entry.URL) {
                var link = $("<a />").text("[URL]");
                link.attr(
                    "href",
                    entry.URL
                );
                li.append(link);
                li.append(" ");
            }
 
            var urlData = entry.URL
            entry.URL = undefined
             li.append(
             li.append(
                 $(
                 $(
Line 190: Line 243:
                 ).css("display", "inline")
                 ).css("display", "inline")
             );
             );
            entry.URL = urlData
             ul.append(li);
             ul.append(li);
         });
         });
Line 205: Line 259:


     function run() {
     function run() {
         $(".bibliography:not(.test)").each(function(i, e) {
         $(".bibliography:not(.test)").each(function (i, e) {
             var style = e.getAttribute("data-style");
             var style = e.getAttribute("data-style");
             if (style === "list") {
             if (style === "list") {
Line 220: Line 274:
                 mw.hook("wikipage.content").add(callback);
                 mw.hook("wikipage.content").add(callback);
         }
         }
         scripts.forEach(function(s) {
         scripts.forEach(function (s) {
             mw.loader.getScript(s).then(onLoaded);
             mw.loader.getScript(s).then(onLoaded);
         });
         });

Latest revision as of 19:21, 9 November 2021

(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");

            var urlData = entry.URL
            entry.URL = undefined
            entry.render = Cite(entry).format("bibliography", {
                format: "html",
                template: "apa",
                lang: "en-US",
            });
            entry.URL = urlData

            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');
            }
            if (urlData && urlData.startsWith("http")) {
                entry.render += " " + $("<a />")
                    .text("[URL]")
                    .attr(
                        "href",
                        urlData
                    )
                    .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: [{
                className: "cell-apa",
                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({
                className: "cell-pageTitle",
                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(" ");
            }
            if (entry.URL) {
                var link = $("<a />").text("[URL]");
                link.attr(
                    "href",
                    entry.URL
                );
                li.append(link);
                li.append(" ");
            }

            var urlData = entry.URL
            entry.URL = undefined
            li.append(
                $(
                    $(
                        Cite(entry).format("bibliography", {
                            format: "html",
                            template: "apa",
                            lang: "en-US",
                        })
                    ).html()
                ).css("display", "inline")
            );
            entry.URL = urlData
            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);