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 })