Difference between revisions of "MediaWiki:Gadget-QuickDiff.js"

From Zeah RSPS - Wiki
Jump to navigation Jump to search
 
 
Line 1: Line 1:
/* <nowiki>
/* <nowiki>
     QDmodal - flexbox-based modal library
     QuickDiff - quickly view any diff link
     CSS located at [[MediaWiki:Gadget-QDmodal.css]]
     Modified to remove Wikia-specific i18n code, relies on [[MediaWiki:Gadget-QDmodal.js]]


     @author OneTwoThreeFall
     @author OneTwoThreeFall
     @source <https://dev.fandom.com/wiki/QDmodal>
     @source <https://dev.fandom.com/wiki/QuickDiff>
     @source <https://dev.fandom.com/wiki/MediaWiki:QDmodal.js>
     @source <https://dev.fandom.com/wiki/MediaWiki:QuickDiff/code.js>
*/
*/


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


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


     var version = 20180212;
     // double-run protection
 
     if (window.quickDiffLoaded) {
     if (mw.libs.QDmodal && mw.libs.QDmodal.version >= version) {
         return;
         return;
     }
     }
    window.quickDiffLoaded = true;
    var diffStylesModule = "mediawiki.action.history.diff";
    var modal;
    var special = {};


     var visibleModals = document.getElementsByClassName("qdmodal");
     // "Special:Diff/12345" and "Special:ComparePages" link detection
     var $window = $(window);
     function initSpecialPageStrings() {
    var $body = $(document.body);
        special.diffDefault = mw.util.getUrl("Special:Diff/");
    var $closeIcon = $(
         special.compareDefault = mw.util.getUrl("Special:ComparePages");
         "<svg class='qdmodal-close' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'>"
          + "<title>Close</title>"
          + "<path stroke='currentColor' d='M 3,3 13,13 M 13,3 3,13'/>"
        + "</svg>"
    );


    function addButton(button) {
        var wiki = mw.config.get("wgDBname");
         var $button = $("<span>");
         var storageKeyDiff = "QuickDiff-specialdiff_" + wiki;
        var storageKeyCompare = "QuickDiff-specialcompare_" + wiki;


         if (button.href) {
         try {
             $button = $("<a>").attr({
             special.diff = localStorage.getItem(storageKeyDiff);
                href: button.href,
            special.compare = localStorage.getItem(storageKeyCompare);
                target: "_blank"
         } catch (ignore) {}
            });
         }


         if (typeof button.handler === "function") {
         if (special.diff && special.compare) {
             $button.on("click", button.handler);
             // using stored values - no need for api request
            return;
         }
         }


         if (button.attr) {
         $.getJSON(mw.util.wikiScript("api"), {
             $button.attr(button.attr);
            action: "parse",
        }
            format: "json",
            prop: "text",
            text: "<span class='diff'>[[Special:Diff/]]</span><span class='compare'>[[Special:ComparePages]]</span>",
            disablepp: "" // note: deprecated in MW 1.26, but needed for older versions
        }).done(function (data) {
             var $parsed = $(data.parse.text["*"]);


        $button.addClass("qdmodal-button").text(button.text);
            special.diff = $parsed.find(".diff > a").attr("href");
            special.compare = $parsed.find(".compare > a").attr("href");


        this.$footer.append($button);
            try {
                localStorage.setItem(storageKeyDiff, special.diff);
                localStorage.setItem(storageKeyCompare, special.compare);
            } catch (ignore) {}
        });
     }
     }


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


    mw.libs.QDmodal = function (id) {
         if (prevTitle && prevTitle !== currTitle) {
         if (this === mw.libs) {
             return "Differences between " + prevTitle + " and " + currTitle;
             throw new Error("mw.libs.QDmodal should be called as a constructor.");
         }
         }


         var $close = $closeIcon.clone();
         return "Differences: " + currTitle;
    }
 
    function loadDiff(url) {
        modal.show({
            loading: true,
            title: !modal.visible && "Loading..."
        });


         this.$container = $("<div>").addClass("qdmodal-container");
         // add 'action=render' and 'diffonly' params to save some bytes on each request
         this.$element = $("<div>").addClass("qdmodal");
         url.extend({
        this.$title = $("<h3>");
            action: "render",
        this.$content = $("<section>");
            diffonly: "1"
         this.$footer = $("<footer>");
         });


         this.$container.append(
         // pass through 'bot' param for rollback links if it's in use on the current page
            this.$element.append(
        if (mw.util.getParamValue("bot")) {
                $("<header>").append(
            url.extend({bot: "1"});
                    this.$title,
         }
                    $close
                ),
                this.$content,
                this.$footer
            )
         );


         this.visible = false;
         $.when(
        this.data = null;
            $.get(url.getRelativePath()),
            mw.loader.using(diffStylesModule)
        ).always(function (response) {
            delete url.query.action;
            delete url.query.diffonly;
            delete url.query.bot;


        if (typeof id === "string") {
            var data = {
            this.$element.attr("id", id);
                buttons: [{
        }
                    text: "open link",
                    href: url.toString(),
                    attr: {"data-disable-quickdiff": ""}
                }]
            };
            var $diff;


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


        // close modal if the background outside the modal is clicked
                if (!$diff.length) {
        this.$container.on("click", function (event) {
                    // $content is a complete page - see if a diff can be found
            if (event.target === event.delegateTarget) {
                    // needed for diffs from special pages as they ignore action=render URL parameter
                 this.hide();
                    $diff = $content.find("table.diff");
                 }
             }
             }
        }.bind(this));


        // close modal if the escape key is pressed
            if ($diff && $diff.length) {
        $window.on("keydown", function (event) {
                data.content = $diff;
            if (this.visible && event.which === 27) {
                data.hook = "quickdiff.ready";
                 this.hide();
                data.title = getDiffTitle($diff);
            } else {
                 data.content = "Something went wrong while getting the page at " + url.toString() + ".";
             }
             }
        }.bind(this));
    };


    mw.libs.QDmodal.prototype.hide = function () {
            modal.show(data);
         if (this.data && typeof this.data.onHide === "function") {
         });
            this.data.onHide(this);
    }
        }


        this.visible = false;
    function linkClickHandler(event) {
        this.data = null;
        // ignore clicks with modifier keys to avoid overriding browser features
        this.$container.detach();
         if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
 
             return;
         if (!visibleModals.length) {
             $body.removeClass("qdmodal-no-scroll");
         }
         }
    };


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


         this.data = data;
         var url = event.currentTarget.href;


         this.$content.toggleClass("mw-ajax-loader", Boolean(data.loading));
         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;
        }


         // only set title if one is given, else keep previous title
         // cross-domain requests not supported
         if (data.title) {
         if (url.host !== location.hostname) {
             this.$title.text(data.title);
             return;
         }
         }


         this.$content.html(data.content || "");
         // 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;


         this.$footer.empty();
         if (hasDiffParam || isSpecialDiffLink || isSpecialCompareLink) {
 
            event.preventDefault();
        if (Array.isArray(data.buttons)) {
             loadDiff(url);
             data.buttons.forEach(addButton.bind(this));
         }
         }
    }


        if (data.hook) {
    function init() {
            mw.hook(data.hook).fire(this);
        modal = new mw.libs.QDmodal("quickdiff-modal");
        }


         if (!this.visible) {
         // full screen modal
            $body
        mw.util.addCSS("#quickdiff-modal { height: 100%; width: 100% }");
                .addClass("qdmodal-no-scroll")
                .append(this.$container);
            this.visible = true;
        }


         if (typeof this.data.onShow === "function") {
        // diff styles module was renamed in MW 1.28
             this.data.onShow(this);
         if (mw.loader.getState("mediawiki.diff.styles")) {
             diffStylesModule = "mediawiki.diff.styles";
         }
         }
    };


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


    // fire hook for convenience
        initSpecialPageStrings();
    mw.hook("dev.qdmodal").fire(mw.libs.QDmodal);
    }


    //// QDmodal theming ////
init();


     function initStyles() {
     // collect action links (edit, undo, rollback, patrol) and add them to footer
         var theme = {
    mw.hook("quickdiff.ready").add(function (modal) {
             scrollbarWidth: window.innerWidth - document.body.offsetWidth
        // edit/undo links use "mw-rev-head-action" class on Wikia,
         };
        // and "mw-diff-edit" or "-undo" class on MW 1.24+
         var $buttons = modal.$content.find(".diff-ntitle").find(
             ".mw-rev-head-action, .mw-diff-edit, .mw-diff-undo, .mw-rollback-link, .patrollink"
         ).clone();


         var styles = (
         // remove text nodes (the brackets around each link)
            "body.qdmodal-no-scroll {"
        $buttons.contents().filter(function (ignore, element) {
              // add a margin equivalent to the scrollbar width to
             return element.nodeType === 3;
              // prevent page content moving due to hidden overflow
         }).remove();
              + "margin-right: ${scrollbarWidth}px;"
             + "}"
         );


         // replace placeholders with theme data
         $buttons.find("a")
        mw.util.addCSS(styles.replace(/\$\{([^}]+)\}/g, function (ignore, p1) {
            .addClass("qdmodal-button")
            return theme[p1];
            .attr("target", "_blank");
        }));
    }


    mw.loader.using("mediawiki.util").then(initStyles);
        modal.$footer.append($buttons);
    });
}(jQuery, mediaWiki));
}(jQuery, mediaWiki));

Latest revision as of 08:39, 16 February 2022

/* <nowiki>
    QuickDiff - quickly view any diff link
    Modified to remove Wikia-specific i18n code, relies on [[MediaWiki:Gadget-QDmodal.js]]

    @author OneTwoThreeFall
    @source <https://dev.fandom.com/wiki/QuickDiff>
    @source <https://dev.fandom.com/wiki/MediaWiki:QuickDiff/code.js>
*/

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

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

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


    var diffStylesModule = "mediawiki.action.history.diff";
    var modal;
    var special = {};

    // "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",
            format: "json",
            prop: "text",
            text: "<span class='diff'>[[Special:Diff/]]</span><span class='compare'>[[Special:ComparePages]]</span>",
            disablepp: "" // note: deprecated in MW 1.26, but needed for older versions
        }).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) {}
        });
    }

    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 "Differences between " + prevTitle + " and " + currTitle;
        }

        return "Differences: " + currTitle;
    }

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

        // 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(diffStylesModule)
        ).always(function (response) {
            delete url.query.action;
            delete url.query.diffonly;
            delete url.query.bot;

            var data = {
                buttons: [{
                    text: "open link",
                    href: url.toString(),
                    attr: {"data-disable-quickdiff": ""}
                }]
            };
            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) {
                data.content = $diff;
                data.hook = "quickdiff.ready";
                data.title = getDiffTitle($diff);
            } else {
                data.content = "Something went wrong while getting the page at " + url.toString() + ".";
            }

            modal.show(data);
        });
    }

    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() {
        modal = new mw.libs.QDmodal("quickdiff-modal");

        // full screen modal
        mw.util.addCSS("#quickdiff-modal { height: 100%; width: 100% }");

        // diff styles module was renamed in MW 1.28
        if (mw.loader.getState("mediawiki.diff.styles")) {
            diffStylesModule = "mediawiki.diff.styles";
        }

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

        initSpecialPageStrings();
    }

	init();

    // collect action links (edit, undo, rollback, patrol) and add them to footer
    mw.hook("quickdiff.ready").add(function (modal) {
        // edit/undo links use "mw-rev-head-action" class on Wikia,
        // and "mw-diff-edit" or "-undo" class on MW 1.24+
        var $buttons = modal.$content.find(".diff-ntitle").find(
            ".mw-rev-head-action, .mw-diff-edit, .mw-diff-undo, .mw-rollback-link, .patrollink"
        ).clone();

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

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

        modal.$footer.append($buttons);
    });
}(jQuery, mediaWiki));