MediaWiki:Gadget-QuickDiff.js

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.
  1 /* <nowiki>
  2     QuickDiff - quickly view any diff link
  3     Modified to remove Wikia-specific i18n code, relies on [[MediaWiki:Gadget-QDmodal.js]]
  4 
  5     @author OneTwoThreeFall
  6     @source <https://dev.fandom.com/wiki/QuickDiff>
  7     @source <https://dev.fandom.com/wiki/MediaWiki:QuickDiff/code.js>
  8 */
  9 
 10 /*jslint browser, long */
 11 /*global jQuery, mediaWiki, dev */
 12 
 13 $(function () {
 14     "use strict";
 15 
 16     // double-run protection
 17     if (window.quickDiffLoaded) {
 18         return;
 19     }
 20     window.quickDiffLoaded = true;
 21 
 22 
 23     var diffStylesModule = "mediawiki.action.history.diff";
 24     var modal;
 25     var special = {};
 26 
 27     // "Special:Diff/12345" and "Special:ComparePages" link detection
 28     function initSpecialPageStrings() {
 29         special.diffDefault = mw.util.getUrl("Special:Diff/");
 30         special.compareDefault = mw.util.getUrl("Special:ComparePages");
 31 
 32         var wiki = mw.config.get("wgDBname");
 33         var storageKeyDiff = "QuickDiff-specialdiff_" + wiki;
 34         var storageKeyCompare = "QuickDiff-specialcompare_" + wiki;
 35 
 36         try {
 37             special.diff = localStorage.getItem(storageKeyDiff);
 38             special.compare = localStorage.getItem(storageKeyCompare);
 39         } catch (ignore) {}
 40 
 41         if (special.diff && special.compare) {
 42             // using stored values - no need for api request
 43             return;
 44         }
 45 
 46         $.getJSON(mw.util.wikiScript("api"), {
 47             action: "parse",
 48             format: "json",
 49             prop: "text",
 50             text: "<span class='diff'>[[Special:Diff/]]</span><span class='compare'>[[Special:ComparePages]]</span>",
 51             disablepp: "" // note: deprecated in MW 1.26, but needed for older versions
 52         }).done(function (data) {
 53             var $parsed = $(data.parse.text["*"]);
 54 
 55             special.diff = $parsed.find(".diff > a").attr("href");
 56             special.compare = $parsed.find(".compare > a").attr("href");
 57 
 58             try {
 59                 localStorage.setItem(storageKeyDiff, special.diff);
 60                 localStorage.setItem(storageKeyCompare, special.compare);
 61             } catch (ignore) {}
 62         });
 63     }
 64 
 65     function getDiffTitle($diff) {
 66         var prevTitle = $diff.find("#mw-diff-otitle1 a").attr("title");
 67         var currTitle = $diff.find("#mw-diff-ntitle1 a").attr("title");
 68 
 69         if (prevTitle && prevTitle !== currTitle) {
 70             return "Differences between " + prevTitle + " and " + currTitle;
 71         }
 72 
 73         return "Differences: " + currTitle;
 74     }
 75 
 76     function loadDiff(url) {
 77         modal.show({
 78             loading: true,
 79             title: !modal.visible && "Loading..."
 80         });
 81 
 82         // add 'action=render' and 'diffonly' params to save some bytes on each request
 83         url.extend({
 84             action: "render",
 85             diffonly: "1"
 86         });
 87 
 88         // pass through 'bot' param for rollback links if it's in use on the current page
 89         if (mw.util.getParamValue("bot")) {
 90             url.extend({bot: "1"});
 91         }
 92 
 93         $.when(
 94             $.get(url.getRelativePath()),
 95             mw.loader.using(diffStylesModule)
 96         ).always(function (response) {
 97             delete url.query.action;
 98             delete url.query.diffonly;
 99             delete url.query.bot;
100 
101             var data = {
102                 buttons: [{
103                     text: "open link",
104                     href: url.toString(),
105                     attr: {"data-disable-quickdiff": ""}
106                 }]
107             };
108             var $diff;
109 
110             if (typeof response[0] === "string") {
111                 var $content = $(response[0]);
112                 $diff = $content.filter("table.diff, #mw-rev-deleted-no-diff");
113 
114                 if (!$diff.length) {
115                     // $content is a complete page - see if a diff can be found
116                     // needed for diffs from special pages as they ignore action=render URL parameter
117                     $diff = $content.find("table.diff");
118                 }
119             }
120 
121             if ($diff && $diff.length) {
122                 data.content = $diff;
123                 data.hook = "quickdiff.ready";
124                 data.title = getDiffTitle($diff);
125             } else {
126                 data.content = "Something went wrong while getting the page at " + url.toString() + ".";
127             }
128 
129             modal.show(data);
130         });
131     }
132 
133     function linkClickHandler(event) {
134         // ignore clicks with modifier keys to avoid overriding browser features
135         if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
136             return;
137         }
138 
139         // ignore click if link has "data-disable-quickdiff" attribute set
140         if (event.currentTarget.dataset.disableQuickdiff !== undefined) {
141             return;
142         }
143 
144         var url = event.currentTarget.href;
145 
146         try {
147             url = new mw.Uri(url);
148         } catch (ignore) {
149             // quit if url couldn't be parsed
150             // it wouldn't be a link QuickDiff could handle anyway
151             return;
152         }
153 
154         // cross-domain requests not supported
155         if (url.host !== location.hostname) {
156             return;
157         }
158 
159         // no fragment check is to ensure section links/collapsible trigger links on diff pages are ignored
160         var hasDiffParam = url.query.diff !== undefined
161                 && url.fragment === undefined;
162         var isSpecialDiffLink = url.path.indexOf(special.diff) === 0
163                 || url.path.indexOf(special.diffDefault) === 0;
164         var isSpecialCompareLink = url.path.indexOf(special.compare) === 0
165                 || url.path.indexOf(special.compareDefault) === 0;
166 
167         if (hasDiffParam || isSpecialDiffLink || isSpecialCompareLink) {
168             event.preventDefault();
169             loadDiff(url);
170         }
171     }
172 
173     function init() {
174         modal = new mw.libs.QDmodal("quickdiff-modal");
175 
176         // full screen modal
177         mw.util.addCSS("#quickdiff-modal { height: 100%; width: 100% }");
178 
179         // diff styles module was renamed in MW 1.28
180         if (mw.loader.getState("mediawiki.diff.styles")) {
181             diffStylesModule = "mediawiki.diff.styles";
182         }
183 
184         // attach to body for compatibility with ajax-loaded content
185         // also, one attached event handler is better than hundreds!
186         $(document.body).on("click.quickdiff", "a[href]", linkClickHandler);
187 
188         initSpecialPageStrings();
189     }
190 
191 	init();
192 
193     // collect action links (edit, undo, rollback, patrol) and add them to footer
194     mw.hook("quickdiff.ready").add(function (modal) {
195         // edit/undo links use "mw-rev-head-action" class on Wikia,
196         // and "mw-diff-edit" or "-undo" class on MW 1.24+
197         var $buttons = modal.$content.find(".diff-ntitle").find(
198             ".mw-rev-head-action, .mw-diff-edit, .mw-diff-undo, .mw-rollback-link, .patrollink"
199         ).clone();
200 
201         // remove text nodes (the brackets around each link)
202         $buttons.contents().filter(function (ignore, element) {
203             return element.nodeType === 3;
204         }).remove();
205 
206         $buttons.find("a")
207             .addClass("qdmodal-button")
208             .attr("target", "_blank");
209 
210         modal.$footer.append($buttons);
211     });
212 })