No edit summary |
No edit summary |
||
| Line 57: | Line 57: | ||
} | } | ||
} | } | ||
})(); | })(); | ||
| Line 154: | Line 153: | ||
})(); | })(); | ||
// --- Script loaders --- | |||
$.getScript(mw.util.getUrl("MediaWiki:ProfileTags.js") + "?action=raw&ctype=text/javascript"); | $.getScript(mw.util.getUrl("MediaWiki:ProfileTags.js") + "?action=raw&ctype=text/javascript"); | ||
console.log("map loaded") | if (document.getElementById("interactiveMap")) { | ||
console.log("map loaded"); | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap.js") + "?action=raw&ctype=text/javascript", function() { | |||
}); | }); | ||
}); | }); | ||
}); | }); | ||
}); | |||
} | |||
if (document.getElementById("wardrobe")) { | |||
$.getScript(mw.util.getUrl("MediaWiki:Wardrobe.js") + "?action=raw&ctype=text/javascript"); | |||
console.log("wardrobe loaded"); | |||
} | |||
if (document.getElementById("mapEditor")) { | |||
$.getScript("https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() { | |||
$.getScript(mw.util.getUrl("MediaWiki:MapEditor.js") + "?action=raw&ctype=text/javascript", function() { | |||
}); | }); | ||
}); | }); | ||
}); | }); | ||
}); | }); | ||
} | }); | ||
} | |||
if (document.querySelector(".code")) { | if (document.querySelector(".code")) { | ||
$.getScript("../custom/highlight.min.js", function() { | |||
document.querySelectorAll(".code").forEach(function(el) { hljs.highlightElement(el); }); | |||
console.log('Code highlighted'); | |||
}); | |||
} | } | ||
if (document.querySelector('[class*="Tracker"]') && !document.querySelector('[class*="page-MediaWiki"]')) { | if (document.querySelector('[class*="Tracker"]') && !document.querySelector('[class*="page-MediaWiki"]')) { | ||
$.getScript(mw.util.getUrl("MediaWiki:Trackers.js") + "?action=raw&ctype=text/javascript"); | |||
console.log("Tracker loaded"); | console.log("Tracker loaded"); | ||
} | } | ||
if (document.getElementById("enemiesDB")) { | if (document.getElementById("enemiesDB")) { | ||
$.getScript(mw.util.getUrl("MediaWiki:Update_DB.js") + "?action=raw&ctype=text/javascript"); | |||
console.log("DB Updater Loaded"); | |||
} | } | ||
// --- Hit chance calculator --- | |||
function hitChance(accuracy, defence) { | function hitChance(accuracy, defence) { | ||
accuracy = parseInt(accuracy); | accuracy = parseInt(accuracy); | ||
defence = parseInt(defence); | defence = parseInt(defence); | ||
var hc = 0; | |||
if(accuracy >= defence) { | if (accuracy >= defence) { | ||
hc = 1; | |||
} else { | } else { | ||
hc = 1 / (1 + defence - accuracy); | |||
} | } | ||
return ( | return (hc * 100).toFixed(2); | ||
} | } | ||
if (document.querySelector('.hitChance')) { | if (document.querySelector('.hitChance')) { | ||
document.querySelectorAll(".hitChance").forEach(el | document.querySelectorAll(".hitChance").forEach(function(el) { | ||
var parts = el.innerText.split(","); | |||
var acc = parts[0]; | |||
var def = parts[1]; | |||
el.innerText = ""; | el.innerText = ""; | ||
var accSpan = document.createElement("span"); | |||
var defSpan = document.createElement("span"); | |||
var hitSpan = document.createElement("span"); | |||
var accInput = document.createElement("input"); | |||
var defInput = document.createElement("input"); | |||
var hitValueSpan = document.createElement("span"); | |||
accSpan.innerText = "Accuracy:"; | accSpan.innerText = "Accuracy:"; | ||
| Line 230: | Line 237: | ||
accInput.min = 0; | accInput.min = 0; | ||
defInput.min = 0; | defInput.min = 0; | ||
if(acc !== "0") { | if (acc !== "0") { | ||
accInput.disabled = true; | accInput.disabled = true; | ||
} | } | ||
if(def !== "0") { | if (def !== "0") { | ||
defInput.disabled = true | defInput.disabled = true; | ||
} | } | ||
def = def < 0 ? 0 : def; | def = def < 0 ? 0 : def; | ||
| Line 240: | Line 247: | ||
accInput.defaultValue = acc; | accInput.defaultValue = acc; | ||
defInput.defaultValue = def; | defInput.defaultValue = def; | ||
accInput.onchange = function(){ | accInput.onchange = function() { | ||
hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%"; | hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%"; | ||
} | }; | ||
defInput.onchange = function(){ | defInput.onchange = function() { | ||
hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%"; | hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%"; | ||
} | }; | ||
el.append(accSpan, accInput, defSpan, defInput, hitSpan, hitValueSpan); | el.append(accSpan, accInput, defSpan, defInput, hitSpan, hitValueSpan); | ||
hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%"; | hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%"; | ||
}) | }); | ||
} | } | ||
/ | // --- Page Preview Popup --- | ||
(function() { | (function() { | ||
var popup = null; | var popup = null; | ||
| Line 341: | Line 348: | ||
} | } | ||
}); | }); | ||
} | |||
function buildPopupHTML(data, includeClose) { | |||
var html = ''; | |||
if (includeClose) { | |||
html += '<span class="flatmmo-preview-close">×</span>'; | |||
} | |||
html += '<div class="flatmmo-preview-title">' + data.title + '</div>'; | |||
if (data.image) { | |||
html += '<div class="flatmmo-preview-image"><img src="' + data.image + '"></div>'; | |||
} | |||
if (data.text) { | |||
html += '<div class="flatmmo-preview-text">' + data.text + '</div>'; | |||
} | |||
if (!data.image && !data.text) { | |||
html += '<div class="flatmmo-preview-text" style="color:#999;">No preview available.</div>'; | |||
} | |||
return html; | |||
} | |||
function attachClose() { | |||
var closeBtn = popup.querySelector('.flatmmo-preview-close'); | |||
if (closeBtn) { | |||
closeBtn.addEventListener('click', function() { | |||
popup.style.display = 'none'; | |||
}); | |||
} | |||
} | } | ||
| Line 357: | Line 391: | ||
if (href.indexOf('action=edit') !== -1) return; | if (href.indexOf('action=edit') !== -1) return; | ||
if (link.classList.contains('new')) return; | if (link.classList.contains('new')) return; | ||
var isMobile = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0); | |||
positionPopup(e); | positionPopup(e); | ||
popup.innerHTML = '<div class="flatmmo-preview-title">' + title + '</div><div class="flatmmo-preview-loading">Loading...</div>'; | popup.innerHTML = '<span class="flatmmo-preview-close">×</span><div class="flatmmo-preview-title">' + title + '</div><div class="flatmmo-preview-loading">Loading...</div>'; | ||
popup.style.display = 'block'; | popup.style.display = 'block'; | ||
attachClose(); | |||
fetchPreview(title, function(data) { | fetchPreview(title, function(data) { | ||
popup.innerHTML = buildPopupHTML(data, true); | |||
attachClose(); | |||
}); | }); | ||
} | } | ||
var isMobile = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0); | |||
var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body; | var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body; | ||
| Line 382: | Line 411: | ||
$(content).find('a[title]').removeAttr('title'); | $(content).find('a[title]').removeAttr('title'); | ||
$(content).on(' | if (isMobile) { | ||
// Mobile: first tap shows preview, second tap follows link | |||
$(content).on('click', 'a:not(.new)', function(e) { | |||
var link = this; | |||
if ($(link).closest('.flatmmo-preview').length) return; | |||
var href = link.getAttribute('href'); | |||
if (!href || !href.match(/\/index\.php\//)) return; | |||
if (href.indexOf('action=edit') !== -1) return; | |||
if (link.getAttribute('data-preview-shown') === 'true') { | |||
link.removeAttribute('data-preview-shown'); | |||
return; | |||
} | |||
e.preventDefault(); | |||
link.setAttribute('data-preview-shown', 'true'); | |||
showPreview(link, e); | showPreview(link, e); | ||
$(content).on('mouseout', 'a', function() { | setTimeout(function() { | ||
link.removeAttribute('data-preview-shown'); | |||
}, 3000); | |||
}); | |||
// Tap outside closes popup | |||
$(document).on('click', function(e) { | |||
if (popup && !$(e.target).closest('.flatmmo-preview').length && !$(e.target).closest('#mw-content-text a').length) { | |||
popup.style.display = 'none'; | |||
} | |||
}); | |||
} else { | |||
// Desktop: hover behavior | |||
$(content).on('mouseover', 'a', function(e) { | |||
var link = this; | |||
if ($(link).closest('.flatmmo-preview').length) return; | |||
clearTimeout(hideTimer); | |||
clearTimeout(showTimer); | |||
if (link.getAttribute('title')) { | |||
link.removeAttribute('title'); | |||
} | |||
showTimer = setTimeout(function() { | |||
showPreview(link, e); | |||
}, 300); | |||
}); | |||
$(content).on('mouseout', 'a', function() { | |||
clearTimeout(showTimer); | |||
hideTimer = setTimeout(function() { | |||
if (popup) popup.style.display = 'none'; | |||
}, 200); | |||
}); | |||
} | |||
console.log('Page preview popup initialized'); | console.log('Page preview popup initialized'); | ||
})(); | })(); | ||
}); | }); // end $(document).ready | ||
Revision as of 05:11, 18 February 2026
1 /* Any JavaScript here will be loaded for all users on every page load. */
2
3 /* ============================================================
4 THEME TOGGLE — Dark/Light mode switcher
5 Defaults to dark. Saves preference to localStorage.
6 ============================================================ */
7 (function() {
8 var saved = localStorage.getItem('flatmmo-theme') || 'dark';
9 document.documentElement.className += ' ' + saved + '-theme';
10
11 var searchMode = localStorage.getItem('flatmmo-search') || 'top';
12 document.documentElement.className += ' search-' + searchMode;
13
14 document.addEventListener('DOMContentLoaded', function() {
15 document.body.classList.add(saved + '-theme');
16 document.body.classList.add('search-' + searchMode);
17 });
18 })();
19
20 $(document).ready(function () {
21 console.log("loaded");
22
23 // --- Theme toggle button ---
24 (function() {
25 var currentTheme = localStorage.getItem('flatmmo-theme') || 'dark';
26
27 document.body.classList.remove('dark-theme', 'light-theme');
28 document.body.classList.add(currentTheme + '-theme');
29
30 var btn = document.createElement('button');
31 btn.className = 'theme-toggle-btn';
32 btn.title = 'Toggle light/dark mode';
33 btn.textContent = currentTheme === 'dark' ? '☀️' : '🌙';
34
35 btn.addEventListener('click', function() {
36 var isDark = document.body.classList.contains('dark-theme');
37 var newTheme = isDark ? 'light' : 'dark';
38
39 document.body.classList.remove('dark-theme', 'light-theme');
40 document.body.classList.add(newTheme + '-theme');
41 document.documentElement.classList.remove('dark-theme', 'light-theme');
42 document.documentElement.classList.add(newTheme + '-theme');
43
44 localStorage.setItem('flatmmo-theme', newTheme);
45 btn.textContent = newTheme === 'dark' ? '☀️' : '🌙';
46 });
47
48 var target = document.querySelector('.cosmos-header__wiki-buttons')
49 || document.querySelector('.cosmos-actions')
50 || document.querySelector('.wds-button-group')
51 || document.querySelector('#content');
52 if (target) {
53 if (target.id === 'content') {
54 target.insertBefore(btn, target.firstChild);
55 } else {
56 target.appendChild(btn);
57 }
58 }
59 })();
60
61 // --- Search bar toggle + compact header search bar ---
62 (function() {
63 var searchMode = localStorage.getItem('flatmmo-search') || 'top';
64
65 document.body.classList.remove('search-top', 'search-header');
66 document.body.classList.add('search-' + searchMode);
67
68 if (searchMode === 'header') {
69 window.scrollTo(0, 0);
70 document.addEventListener('DOMContentLoaded', function() {
71 window.scrollTo(0, 0);
72 });
73 }
74
75 var searchToggle = document.createElement('button');
76 searchToggle.className = 'search-toggle-btn';
77 searchToggle.title = 'Toggle search bar position';
78 searchToggle.textContent = searchMode === 'top' ? '🔍' : '🔎';
79
80 searchToggle.addEventListener('click', function() {
81 var isTop = document.body.classList.contains('search-top');
82 var newMode = isTop ? 'header' : 'top';
83
84 document.body.classList.remove('search-top', 'search-header');
85 document.body.classList.add('search-' + newMode);
86 document.documentElement.classList.remove('search-top', 'search-header');
87 document.documentElement.classList.add('search-' + newMode);
88
89 localStorage.setItem('flatmmo-search', newMode);
90 searchToggle.textContent = newMode === 'top' ? '🔍' : '🔎';
91 });
92
93 var searchWrap = document.createElement('div');
94 searchWrap.className = 'header-search-wrap';
95
96 var searchInput = document.createElement('input');
97 searchInput.type = 'text';
98 searchInput.className = 'header-search-input';
99 searchInput.placeholder = 'Search wiki...';
100 searchInput.setAttribute('autocomplete', 'off');
101
102 var searchBtn = document.createElement('button');
103 searchBtn.className = 'header-search-btn';
104 searchBtn.innerHTML = '🔍';
105 searchBtn.title = 'Search';
106
107 function doSearch() {
108 var q = searchInput.value.trim();
109 if (q) {
110 window.location.href = mw.util.getUrl('Special:Search') + '?search=' + encodeURIComponent(q);
111 }
112 }
113
114 searchBtn.addEventListener('click', doSearch);
115 searchInput.addEventListener('keydown', function(e) {
116 if (e.key === 'Enter') doSearch();
117 });
118
119 searchWrap.appendChild(searchInput);
120 searchWrap.appendChild(searchBtn);
121
122 var target = document.querySelector('.cosmos-header__wiki-buttons')
123 || document.querySelector('.cosmos-actions')
124 || document.querySelector('.wds-button-group')
125 || document.querySelector('#content');
126 if (target && target.id !== 'content') {
127 target.appendChild(searchToggle);
128 target.style.position = 'relative';
129 target.appendChild(searchWrap);
130
131 var bannerUser = document.querySelector('.cosmos-userButton-label')
132 || document.querySelector('#p-personal-label');
133 var userName = bannerUser ? bannerUser.textContent.trim() : '';
134 if (userName) {
135 var userLink = document.createElement('a');
136 userLink.className = 'relocated-user';
137 userLink.href = mw.util.getUrl('User:' + userName);
138 userLink.title = userName;
139
140 var userIcon = document.createElement('span');
141 userIcon.className = 'relocated-user-icon';
142 userIcon.innerHTML = '👤';
143
144 var userText = document.createElement('span');
145 userText.className = 'relocated-user-name';
146 userText.textContent = userName;
147
148 userLink.appendChild(userIcon);
149 userLink.appendChild(userText);
150 target.appendChild(userLink);
151 }
152 }
153 })();
154
155 // --- Script loaders ---
156 $.getScript(mw.util.getUrl("MediaWiki:ProfileTags.js") + "?action=raw&ctype=text/javascript");
157
158 if (document.getElementById("interactiveMap")) {
159 console.log("map loaded");
160 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() {
161 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() {
162 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() {
163 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap.js") + "?action=raw&ctype=text/javascript", function() {
164 });
165 });
166 });
167 });
168 }
169
170 if (document.getElementById("wardrobe")) {
171 $.getScript(mw.util.getUrl("MediaWiki:Wardrobe.js") + "?action=raw&ctype=text/javascript");
172 console.log("wardrobe loaded");
173 }
174
175 if (document.getElementById("mapEditor")) {
176 $.getScript("https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js", function() {
177 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() {
178 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() {
179 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() {
180 $.getScript(mw.util.getUrl("MediaWiki:MapEditor.js") + "?action=raw&ctype=text/javascript", function() {
181 });
182 });
183 });
184 });
185 });
186 }
187
188 if (document.querySelector(".code")) {
189 $.getScript("../custom/highlight.min.js", function() {
190 document.querySelectorAll(".code").forEach(function(el) { hljs.highlightElement(el); });
191 console.log('Code highlighted');
192 });
193 }
194
195 if (document.querySelector('[class*="Tracker"]') && !document.querySelector('[class*="page-MediaWiki"]')) {
196 $.getScript(mw.util.getUrl("MediaWiki:Trackers.js") + "?action=raw&ctype=text/javascript");
197 console.log("Tracker loaded");
198 }
199
200 if (document.getElementById("enemiesDB")) {
201 $.getScript(mw.util.getUrl("MediaWiki:Update_DB.js") + "?action=raw&ctype=text/javascript");
202 console.log("DB Updater Loaded");
203 }
204
205 // --- Hit chance calculator ---
206 function hitChance(accuracy, defence) {
207 accuracy = parseInt(accuracy);
208 defence = parseInt(defence);
209 var hc = 0;
210 if (accuracy >= defence) {
211 hc = 1;
212 } else {
213 hc = 1 / (1 + defence - accuracy);
214 }
215 return (hc * 100).toFixed(2);
216 }
217
218 if (document.querySelector('.hitChance')) {
219 document.querySelectorAll(".hitChance").forEach(function(el) {
220 var parts = el.innerText.split(",");
221 var acc = parts[0];
222 var def = parts[1];
223 el.innerText = "";
224 var accSpan = document.createElement("span");
225 var defSpan = document.createElement("span");
226 var hitSpan = document.createElement("span");
227 var accInput = document.createElement("input");
228 var defInput = document.createElement("input");
229 var hitValueSpan = document.createElement("span");
230
231 accSpan.innerText = "Accuracy:";
232 defSpan.innerText = "Defence:";
233 hitSpan.innerText = "Hit Chance:";
234
235 accInput.type = "number";
236 defInput.type = "number";
237 accInput.min = 0;
238 defInput.min = 0;
239 if (acc !== "0") {
240 accInput.disabled = true;
241 }
242 if (def !== "0") {
243 defInput.disabled = true;
244 }
245 def = def < 0 ? 0 : def;
246 acc = acc < 0 ? 0 : acc;
247 accInput.defaultValue = acc;
248 defInput.defaultValue = def;
249 accInput.onchange = function() {
250 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
251 };
252 defInput.onchange = function() {
253 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
254 };
255 el.append(accSpan, accInput, defSpan, defInput, hitSpan, hitValueSpan);
256 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
257 });
258 }
259
260 // --- Page Preview Popup ---
261 (function() {
262 var popup = null;
263 var hideTimer = null;
264 var showTimer = null;
265 var previewCache = {};
266
267 function createPopup() {
268 popup = document.createElement('div');
269 popup.className = 'flatmmo-preview';
270 document.body.appendChild(popup);
271
272 popup.addEventListener('mouseenter', function() {
273 clearTimeout(hideTimer);
274 });
275 popup.addEventListener('mouseleave', function() {
276 hideTimer = setTimeout(function() {
277 popup.style.display = 'none';
278 }, 200);
279 });
280 }
281
282 function positionPopup(e) {
283 var x = e.pageX + 15;
284 var y = e.pageY + 15;
285 var popupWidth = 340;
286 var popupHeight = 200;
287
288 if (x + popupWidth > document.documentElement.scrollLeft + window.innerWidth) {
289 x = e.pageX - popupWidth - 15;
290 }
291 if (y + popupHeight > document.documentElement.scrollTop + window.innerHeight) {
292 y = e.pageY - popupHeight - 15;
293 }
294
295 popup.style.left = x + 'px';
296 popup.style.top = y + 'px';
297 }
298
299 function fetchPreview(title, callback) {
300 if (previewCache[title]) {
301 callback(previewCache[title]);
302 return;
303 }
304
305 var apiUrl = mw.util.wikiScript('api') + '?action=parse&page=' + encodeURIComponent(title) + '&prop=text&format=json&redirects=1';
306
307 $.ajax({
308 url: apiUrl,
309 dataType: 'json',
310 success: function(data) {
311 if (data.parse && data.parse.text) {
312 var html = data.parse.text['*'];
313 var temp = document.createElement('div');
314 temp.innerHTML = html;
315
316 var img = null;
317 var infoboxImg = temp.querySelector('.flatmmo-infobox-image img, .flatmmo-infobox img');
318 if (infoboxImg) {
319 img = infoboxImg.src;
320 } else {
321 var firstImg = temp.querySelector('img');
322 if (firstImg && firstImg.width > 20) {
323 img = firstImg.src;
324 }
325 }
326
327 var text = '';
328 var paragraphs = temp.querySelectorAll('p');
329 for (var i = 0; i < paragraphs.length; i++) {
330 var t = paragraphs[i].textContent.trim();
331 if (t.length > 10) {
332 text = t;
333 break;
334 }
335 }
336
337 if (text.length > 250) {
338 text = text.substring(0, 247) + '...';
339 }
340
341 var result = { image: img, text: text, title: title };
342 previewCache[title] = result;
343 callback(result);
344 }
345 },
346 error: function() {
347 console.log('Preview request failed for:', title);
348 }
349 });
350 }
351
352 function buildPopupHTML(data, includeClose) {
353 var html = '';
354 if (includeClose) {
355 html += '<span class="flatmmo-preview-close">×</span>';
356 }
357 html += '<div class="flatmmo-preview-title">' + data.title + '</div>';
358 if (data.image) {
359 html += '<div class="flatmmo-preview-image"><img src="' + data.image + '"></div>';
360 }
361 if (data.text) {
362 html += '<div class="flatmmo-preview-text">' + data.text + '</div>';
363 }
364 if (!data.image && !data.text) {
365 html += '<div class="flatmmo-preview-text" style="color:#999;">No preview available.</div>';
366 }
367 return html;
368 }
369
370 function attachClose() {
371 var closeBtn = popup.querySelector('.flatmmo-preview-close');
372 if (closeBtn) {
373 closeBtn.addEventListener('click', function() {
374 popup.style.display = 'none';
375 });
376 }
377 }
378
379 function showPreview(link, e) {
380 if (!popup) createPopup();
381
382 var href = link.getAttribute('href');
383 if (!href) return;
384
385 var match = href.match(/\/index\.php\/(.+)/);
386 if (!match) return;
387
388 var title = decodeURIComponent(match[1]).replace(/_/g, ' ');
389
390 if (title.match(/^Special:|^Talk:|^User:|^Category:|^File:|^Template:|^MediaWiki:/i)) return;
391 if (href.indexOf('action=edit') !== -1) return;
392 if (link.classList.contains('new')) return;
393
394 var isMobile = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
395
396 positionPopup(e);
397 popup.innerHTML = '<span class="flatmmo-preview-close">×</span><div class="flatmmo-preview-title">' + title + '</div><div class="flatmmo-preview-loading">Loading...</div>';
398 popup.style.display = 'block';
399 attachClose();
400
401 fetchPreview(title, function(data) {
402 popup.innerHTML = buildPopupHTML(data, true);
403 attachClose();
404 });
405 }
406
407 var isMobile = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
408 var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body;
409
410 // Strip all native tooltips from content links
411 $(content).find('a[title]').removeAttr('title');
412
413 if (isMobile) {
414 // Mobile: first tap shows preview, second tap follows link
415 $(content).on('click', 'a:not(.new)', function(e) {
416 var link = this;
417 if ($(link).closest('.flatmmo-preview').length) return;
418
419 var href = link.getAttribute('href');
420 if (!href || !href.match(/\/index\.php\//)) return;
421 if (href.indexOf('action=edit') !== -1) return;
422
423 if (link.getAttribute('data-preview-shown') === 'true') {
424 link.removeAttribute('data-preview-shown');
425 return;
426 }
427
428 e.preventDefault();
429 link.setAttribute('data-preview-shown', 'true');
430 showPreview(link, e);
431
432 setTimeout(function() {
433 link.removeAttribute('data-preview-shown');
434 }, 3000);
435 });
436
437 // Tap outside closes popup
438 $(document).on('click', function(e) {
439 if (popup && !$(e.target).closest('.flatmmo-preview').length && !$(e.target).closest('#mw-content-text a').length) {
440 popup.style.display = 'none';
441 }
442 });
443 } else {
444 // Desktop: hover behavior
445 $(content).on('mouseover', 'a', function(e) {
446 var link = this;
447 if ($(link).closest('.flatmmo-preview').length) return;
448
449 clearTimeout(hideTimer);
450 clearTimeout(showTimer);
451
452 if (link.getAttribute('title')) {
453 link.removeAttribute('title');
454 }
455
456 showTimer = setTimeout(function() {
457 showPreview(link, e);
458 }, 300);
459 });
460
461 $(content).on('mouseout', 'a', function() {
462 clearTimeout(showTimer);
463 hideTimer = setTimeout(function() {
464 if (popup) popup.style.display = 'none';
465 }, 200);
466 });
467 }
468
469 console.log('Page preview popup initialized');
470 })();
471
472 }); // end $(document).ready
