User:Guyus24/common.js

From Tardis Wiki, the free Doctor Who reference
Clear your cache often around here

After changes are made to this site's CSS or Javascript, you have to bypass your browser's cache to see the changes. You can always do this by going to your browser's preferences panel. But many browsers also offer keyboard shortcuts to save you that trouble. The following shortcuts work in the versions of the browsers that Tardis currently supports. They may not work in earlier versions.

  • Firefox: hold down Shift while performing a page reload.
  • Opera offers no default keyboard shortcut, but you can create a custom keyboard shortcut with the value Clear disk cache
  • Safari users should simultaneously hold down + Option + E. You may need to enable the Develop menu first
  • Chrome: press Ctrl + F5 or Shift + F5 while performing a page reload.
/* FROM https://dev.fandom.com/wiki/QuickDiff, BY OneTwoThreeFall */

/* [[QuickDiff]] - quickly view any diff link */

/*jslint browser, long */
/*global jQuery, mediaWiki, dev */

(function ($, mw) {
    "use strict";

    // double-run protection
    if (window.quickDiffLoaded) {
        return;
    }
    window.quickDiffLoaded = true;

    var i18n;
    var modal;
    var special = {};

    function isElementOrChildFrontmost(element) {
        var pos = element.getBoundingClientRect();
        var frontmostElement = document.elementFromPoint(pos.left, pos.top);
        return element.contains(frontmostElement);
    }

    // "Special:Diff/12345" and "Special:ComparePages" link detection
    function initSpecialPageStrings() {
        special.diffDefault = mw.util.getUrl("Special:Diff/");
        special.compareDefault = mw.util.getUrl("Special:ComparePages");

        var wiki = mw.config.get("wgDBname");
        var storageKeyDiff = "QuickDiff-specialdiff_" + wiki;
        var storageKeyCompare = "QuickDiff-specialcompare_" + wiki;

        try {
            special.diff = localStorage.getItem(storageKeyDiff);
            special.compare = localStorage.getItem(storageKeyCompare);
        } catch (ignore) {}

        if (special.diff && special.compare) {
            // using stored values - no need for api request
            return;
        }

        $.getJSON(mw.util.wikiScript("api"), {
            action: "parse",
            contentmodel: "wikitext",
            format: "json",
            prop: "text",
            text: "<span class='diff'>[[Special:Diff/]]</span><span class='compare'>[[Special:ComparePages]]</span>",
            disablelimitreport: ""
        }).done(function (data) {
            var $parsed = $(data.parse.text["*"]);

            special.diff = $parsed.find(".diff > a").attr("href");
            special.compare = $parsed.find(".compare > a").attr("href");

            try {
                localStorage.setItem(storageKeyDiff, special.diff);
                localStorage.setItem(storageKeyCompare, special.compare);
            } catch (ignore) {}
        });
    }

    // support for patrolling edits directly from modal
    // ideally this wouldn't be needed and we'd rely on MediaWiki's own handler,
    // but that's run only on document ready and isn't easily reusable
    function initAjaxPatrolHandler() {
        var $spinner = mw.libs.QDmodal.getSpinner();

        $spinner.css({
            "--qdmodal-spinner-size": "2em",
            position: "relative",
            top: "-6px",
            verticalAlign: "top"
        });

        mw.hook("quickdiff.ready").add(function (modal) {
            var $patrolLinks = modal.$element.find(".patrollink[data-mw='interface'] > a");

            $patrolLinks.on("click", function (event) {
                event.preventDefault();

                if ($patrolLinks.is("[disabled]")) {
                    return;
                }

                $patrolLinks.find(".qdmodal-spinner-container").remove().end()
                    .attr("disabled", "").append(" ", $spinner.clone());

                var $spinners = $patrolLinks.find(".qdmodal-spinner-container");

                mw.loader.using("mediawiki.api").done(function () {
                    new mw.Api().postWithToken("patrol", {
                        action: "patrol",
                        rcid: mw.util.getParamValue("rcid", event.target.href)
                    }).done(function (data) {
                        $spinners.removeAttr("style").text("✅")
                            .parent().wrap("<s>");
                    }).fail(function (data) {
                        $spinners.removeAttr("style").text("❌")
                            .parent().removeAttr("disabled");
                    });
                });
            });
        });
    }

    function getDiffTitle($diff) {
        var prevTitle = $diff.find("#mw-diff-otitle1 a").attr("title");
        var currTitle = $diff.find("#mw-diff-ntitle1 a").attr("title");

        if (prevTitle && prevTitle !== currTitle) {
            return i18n("differences-multipage", prevTitle, currTitle).plain();
        }

        return i18n("differences", currTitle).plain();
    }

    function addDiffActions() {
        var prevTitle = modal.$content.find("#mw-diff-otitle1 a").attr("title");
        var currTitle = modal.$content.find("#mw-diff-ntitle1 a").attr("title");

        // collect action links (edit, undo, rollback, patrol) from the diff
        var $actions = modal.$content.find(".diff-ntitle").find(
            ".mw-diff-edit, .mw-diff-undo, .mw-rollback-link, .patrollink, .mw-diff-tool"
        ).clone();

        // remove text nodes (the brackets around each link)
        $actions.contents().filter(function (ignore, element) {
            return element.nodeType === 3;
        }).remove();

        $actions.find("a")
            .addClass("qdmodal-button")
            .attr("target", "_blank");

        // if diff is for one page, add a page history action
        if (prevTitle === currTitle) {
            $actions = $actions.add(
                $("<a>").attr({
                    "class": "qdmodal-button",
                    href: mw.util.getUrl(currTitle, {action: "history"}),
                    target: "_blank"
                }).text(i18n("history").plain())
            );
        }

        modal.$footer.append($actions);
    }

    function loadDiff(url) {
        modal.show({
            loading: true,
            title: !modal.visible && i18n("loading").plain()
        });

        // add 'action=render' and 'diffonly' params to save some bytes on each request
        url.extend({
            action: "render",
            diffonly: "1"
        });

        // pass through 'bot' param for rollback links if it's in use on the current page
        if (mw.util.getParamValue("bot")) {
            url.extend({bot: "1"});
        }

        $.when(
            $.get(url.getRelativePath()),
            mw.loader.using(["mediawiki.diff.styles", "mediawiki.interface.helpers.styles"])
        ).always(function (response) {
            delete url.query.action;
            delete url.query.diffonly;
            delete url.query.bot;

            var data = {
                url: url,
                buttons: [{
                    text: i18n("link").plain(),
                    href: url.toString(),
                    attr: {"data-disable-quickdiff": ""}
                }],
                content: i18n("error", url.toString()).escape()
            };
            var $diff;

            if (typeof response[0] === "string") {
                var $content = $(response[0]);
                $diff = $content.filter("table.diff, #mw-rev-deleted-no-diff");

                if (!$diff.length) {
                    // $content is a complete page - see if a diff can be found
                    // needed for diffs from special pages as they ignore action=render URL parameter
                    $diff = $content.find("table.diff");
                }
            }

            if (!$diff || $diff.length === 0) {
                // default content is error msg
                return modal.show(data);
            }

            data.content = $diff;
            data.hook = "quickdiff.ready";
            data.onBeforeShow = addDiffActions;
            data.title = getDiffTitle($diff);

            // if a diff, fire the standard MW hook
            if ($diff.is("table.diff[data-mw='interface']")) {
                mw.hook("wikipage.diff").fire($diff);
            }

            modal.show(data);
        });
    }

    function keydownHandler(event) {
        // only handle key presses if QuickDiff is frontmost
        if (!isElementOrChildFrontmost(modal.$container[0])) {
            return;
        }

        if (event.key === "ArrowLeft") {
            modal.$content.find("#differences-prevlink").trigger("click");
        } else if (event.key === "ArrowRight") {
            modal.$content.find("#differences-nextlink").trigger("click");
        }
    }

    function linkClickHandler(event) {
        // ignore clicks with modifier keys to avoid overriding browser features
        if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
            return;
        }

        // ignore click if link has "data-disable-quickdiff" attribute set
        if (event.currentTarget.dataset.disableQuickdiff !== undefined) {
            return;
        }

        var url = event.currentTarget.href;

        try {
            url = new mw.Uri(url);
        } catch (ignore) {
            // quit if url couldn't be parsed
            // it wouldn't be a link QuickDiff could handle anyway
            return;
        }

        // cross-domain requests not supported
        if (url.host !== location.hostname) {
            return;
        }

        // no fragment check is to ensure section links/collapsible trigger links on diff pages are ignored
        var hasDiffParam = url.query.diff !== undefined
                && url.fragment === undefined;
        var isSpecialDiffLink = url.path.indexOf(special.diff) === 0
                || url.path.indexOf(special.diffDefault) === 0;
        var isSpecialCompareLink = url.path.indexOf(special.compare) === 0
                || url.path.indexOf(special.compareDefault) === 0;

        if (hasDiffParam || isSpecialDiffLink || isSpecialCompareLink) {
            event.preventDefault();
            loadDiff(url);
        }
    }

    function init() {
        var $body = $(document.body);
        modal = new mw.libs.QDmodal("quickdiff-modal");

        // full screen modal
        var css = "#quickdiff-modal { height: 100%; width: 100% }";
        // always show modal footer for UI consistency
        css += "#quickdiff-modal > footer { display: flex }";
        // hide square brackets around rollback link in footer
        css += "#quickdiff-modal > footer .mw-rollback-link::before, #quickdiff-modal > footer .mw-rollback-link::after { content: none }";
        mw.util.addCSS(css);

        // attach to body for compatibility with ajax-loaded content
        // also, one attached event handler is better than hundreds!
        $body.on("click.quickdiff", "a[href]", linkClickHandler);

        // listen for left/right arrow keys, to move between prev/next diff
        $body.on("keydown.quickdiff", keydownHandler);

        initSpecialPageStrings();
        initAjaxPatrolHandler();
    }

    function initDependencies() {
        var devLoadUrl = "https://dev.fandom.com/load.php?mode=articles&only=scripts&articles=MediaWiki:";
        var i18nMsgs = new $.Deferred();
        var waitFor = [
            i18nMsgs,
            mw.loader.using(["mediawiki.Uri", "mediawiki.util"])
        ];

        if (!(mw.libs.QDmodal && mw.libs.QDmodal.version >= 20201108)) {
            waitFor.push($.ajax({
                cache: true,
                dataType: "script",
                url: devLoadUrl + "QDmodal.js&cb=20201108"
            }));
        }

        if (!(window.dev && dev.i18n && dev.i18n.loadMessages)) {
            mw.loader.load(devLoadUrl + "I18n-js/code.js&*");
        }

        mw.hook("dev.i18n").add(function (i18njs) {
            i18njs.loadMessages("QuickDiff").done(function (i18nData) {
                i18n = i18nData.msg;
                i18nMsgs.resolve();
            });
        });

        $.when.apply($, waitFor).done(init);
    }

    initDependencies();
}(jQuery, mediaWiki));