No edit summary |
No edit summary |
||
| Line 251: | Line 251: | ||
} | } | ||
/* Page Preview Popup - inside $(document).ready */ | |||
/* Page Preview Popup */ | |||
(function() { | (function() { | ||
var popup = null; | var popup = null; | ||
var hideTimer = null; | var hideTimer = null; | ||
var showTimer = null; | var showTimer = null; | ||
var | var previewCache = {}; | ||
function createPopup() { | function createPopup() { | ||
| Line 294: | Line 291: | ||
function fetchPreview(title, callback) { | function fetchPreview(title, callback) { | ||
if ( | if (previewCache[title]) { | ||
callback( | callback(previewCache[title]); | ||
return; | return; | ||
} | } | ||
var | var apiUrl = mw.util.wikiScript('api') + '?action=parse&page=' + encodeURIComponent(title) + '&prop=text&format=json&redirects=1'; | ||
$.ajax({ | |||
url: apiUrl, | |||
dataType: 'json', | |||
success: function(data) { | |||
if (data.parse && data.parse.text) { | if (data.parse && data.parse.text) { | ||
var html = data.parse.text['*']; | var html = data.parse.text['*']; | ||
| Line 339: | Line 333: | ||
var result = { image: img, text: text, title: title }; | var result = { image: img, text: text, title: title }; | ||
previewCache[title] = result; | |||
callback(result); | callback(result); | ||
} | } | ||
} | }, | ||
console.log('Preview | error: function() { | ||
console.log('Preview request failed for:', title); | |||
} | } | ||
} | }); | ||
} | } | ||
| Line 386: | Line 377: | ||
} | } | ||
var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body; | |||
// Strip all native tooltips from content links | |||
$(content).find('a[title]').removeAttr('title'); | |||
$(content).on('mouseover', 'a', function(e) { | |||
var link = this; | |||
if ($(link).closest('.flatmmo-preview').length) return; | |||
clearTimeout(hideTimer); | |||
clearTimeout(showTimer); | |||
// Catch any title that got added dynamically | |||
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'); | |||
})(); | |||
}); | |||
Revision as of 05:04, 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
62 // --- Search bar toggle + compact header search bar ---
63 (function() {
64 var searchMode = localStorage.getItem('flatmmo-search') || 'top';
65
66 document.body.classList.remove('search-top', 'search-header');
67 document.body.classList.add('search-' + searchMode);
68
69 if (searchMode === 'header') {
70 window.scrollTo(0, 0);
71 document.addEventListener('DOMContentLoaded', function() {
72 window.scrollTo(0, 0);
73 });
74 }
75
76 var searchToggle = document.createElement('button');
77 searchToggle.className = 'search-toggle-btn';
78 searchToggle.title = 'Toggle search bar position';
79 searchToggle.textContent = searchMode === 'top' ? '🔍' : '🔎';
80
81 searchToggle.addEventListener('click', function() {
82 var isTop = document.body.classList.contains('search-top');
83 var newMode = isTop ? 'header' : 'top';
84
85 document.body.classList.remove('search-top', 'search-header');
86 document.body.classList.add('search-' + newMode);
87 document.documentElement.classList.remove('search-top', 'search-header');
88 document.documentElement.classList.add('search-' + newMode);
89
90 localStorage.setItem('flatmmo-search', newMode);
91 searchToggle.textContent = newMode === 'top' ? '🔍' : '🔎';
92 });
93
94 var searchWrap = document.createElement('div');
95 searchWrap.className = 'header-search-wrap';
96
97 var searchInput = document.createElement('input');
98 searchInput.type = 'text';
99 searchInput.className = 'header-search-input';
100 searchInput.placeholder = 'Search wiki...';
101 searchInput.setAttribute('autocomplete', 'off');
102
103 var searchBtn = document.createElement('button');
104 searchBtn.className = 'header-search-btn';
105 searchBtn.innerHTML = '🔍';
106 searchBtn.title = 'Search';
107
108 function doSearch() {
109 var q = searchInput.value.trim();
110 if (q) {
111 window.location.href = mw.util.getUrl('Special:Search') + '?search=' + encodeURIComponent(q);
112 }
113 }
114
115 searchBtn.addEventListener('click', doSearch);
116 searchInput.addEventListener('keydown', function(e) {
117 if (e.key === 'Enter') doSearch();
118 });
119
120 searchWrap.appendChild(searchInput);
121 searchWrap.appendChild(searchBtn);
122
123 var target = document.querySelector('.cosmos-header__wiki-buttons')
124 || document.querySelector('.cosmos-actions')
125 || document.querySelector('.wds-button-group')
126 || document.querySelector('#content');
127 if (target && target.id !== 'content') {
128 target.appendChild(searchToggle);
129 target.style.position = 'relative';
130 target.appendChild(searchWrap);
131
132 var bannerUser = document.querySelector('.cosmos-userButton-label')
133 || document.querySelector('#p-personal-label');
134 var userName = bannerUser ? bannerUser.textContent.trim() : '';
135 if (userName) {
136 var userLink = document.createElement('a');
137 userLink.className = 'relocated-user';
138 userLink.href = mw.util.getUrl('User:' + userName);
139 userLink.title = userName;
140
141 var userIcon = document.createElement('span');
142 userIcon.className = 'relocated-user-icon';
143 userIcon.innerHTML = '👤';
144
145 var userText = document.createElement('span');
146 userText.className = 'relocated-user-name';
147 userText.textContent = userName;
148
149 userLink.appendChild(userIcon);
150 userLink.appendChild(userText);
151 target.appendChild(userLink);
152 }
153 }
154 })();
155
156 $.getScript(mw.util.getUrl("MediaWiki:ProfileTags.js") + "?action=raw&ctype=text/javascript");
157 if (document.getElementById("interactiveMap")) {
158 console.log("map loaded")
159 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() {
160 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() {
161 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() {
162 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap.js") + "?action=raw&ctype=text/javascript", function() {
163 });
164 });
165 });
166 });
167 }
168
169 if (document.getElementById("wardrobe")) {
170 $.getScript(mw.util.getUrl("MediaWiki:Wardrobe.js") + "?action=raw&ctype=text/javascript");
171 console.log("wardrobe loaded")
172 }
173
174 if (document.getElementById("mapEditor")) {
175 $.getScript("https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js", function() {
176 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() {
177 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() {
178 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() {
179 $.getScript(mw.util.getUrl("MediaWiki:MapEditor.js") + "?action=raw&ctype=text/javascript", function() {
180 });
181 });
182 });
183 });
184 });
185 }
186 if (document.querySelector(".code")) {
187 $.getScript("../custom/highlight.min.js", ()=>{
188 document.querySelectorAll(".code").forEach(el=>hljs.highlightElement(el))
189 console.log('Code highlighted');
190 });
191 }
192
193 if (document.querySelector('[class*="Tracker"]') && !document.querySelector('[class*="page-MediaWiki"]')) {
194 $.getScript(mw.util.getUrl("MediaWiki:Trackers.js") + "?action=raw&ctype=text/javascript");
195 console.log("Tracker loaded");
196 }
197
198 if (document.getElementById("enemiesDB")) {
199 $.getScript(mw.util.getUrl("MediaWiki:Update_DB.js") + "?action=raw&ctype=text/javascript");
200 console.log("DB Updater Loaded")
201 }
202 function hitChance(accuracy, defence) {
203 accuracy = parseInt(accuracy);
204 defence = parseInt(defence);
205 let hitChance = 0;
206 if(accuracy >= defence) {
207 hitChance = 1;
208 } else {
209 hitChance = 1 / (1 + defence - accuracy)
210 }
211 return (hitChance * 100).toFixed(2);
212 }
213 if (document.querySelector('.hitChance')) {
214 document.querySelectorAll(".hitChance").forEach(el => {
215 let [acc, def] = el.innerText.split(",")
216 el.innerText = "";
217 const accSpan = document.createElement("span");
218 const defSpan = document.createElement("span");
219 const hitSpan = document.createElement("span");
220 const accInput = document.createElement("input");
221 const defInput = document.createElement("input");
222 const hitValueSpan = document.createElement("span");
223
224 accSpan.innerText = "Accuracy:";
225 defSpan.innerText = "Defence:";
226 hitSpan.innerText = "Hit Chance:";
227
228 accInput.type = "number";
229 defInput.type = "number";
230 accInput.min = 0;
231 defInput.min = 0;
232 if(acc !== "0") {
233 accInput.disabled = true;
234 }
235 if(def !== "0") {
236 defInput.disabled = true
237 }
238 def = def < 0 ? 0 : def;
239 acc = acc < 0 ? 0 : acc;
240 accInput.defaultValue = acc;
241 defInput.defaultValue = def;
242 accInput.onchange = function(){
243 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
244 }
245 defInput.onchange = function(){
246 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
247 }
248 el.append(accSpan, accInput, defSpan, defInput, hitSpan, hitValueSpan);
249 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
250 })
251 }
252
253 /* Page Preview Popup - inside $(document).ready */
254 (function() {
255 var popup = null;
256 var hideTimer = null;
257 var showTimer = null;
258 var previewCache = {};
259
260 function createPopup() {
261 popup = document.createElement('div');
262 popup.className = 'flatmmo-preview';
263 document.body.appendChild(popup);
264
265 popup.addEventListener('mouseenter', function() {
266 clearTimeout(hideTimer);
267 });
268 popup.addEventListener('mouseleave', function() {
269 hideTimer = setTimeout(function() {
270 popup.style.display = 'none';
271 }, 200);
272 });
273 }
274
275 function positionPopup(e) {
276 var x = e.pageX + 15;
277 var y = e.pageY + 15;
278 var popupWidth = 340;
279 var popupHeight = 200;
280
281 if (x + popupWidth > document.documentElement.scrollLeft + window.innerWidth) {
282 x = e.pageX - popupWidth - 15;
283 }
284 if (y + popupHeight > document.documentElement.scrollTop + window.innerHeight) {
285 y = e.pageY - popupHeight - 15;
286 }
287
288 popup.style.left = x + 'px';
289 popup.style.top = y + 'px';
290 }
291
292 function fetchPreview(title, callback) {
293 if (previewCache[title]) {
294 callback(previewCache[title]);
295 return;
296 }
297
298 var apiUrl = mw.util.wikiScript('api') + '?action=parse&page=' + encodeURIComponent(title) + '&prop=text&format=json&redirects=1';
299
300 $.ajax({
301 url: apiUrl,
302 dataType: 'json',
303 success: function(data) {
304 if (data.parse && data.parse.text) {
305 var html = data.parse.text['*'];
306 var temp = document.createElement('div');
307 temp.innerHTML = html;
308
309 var img = null;
310 var infoboxImg = temp.querySelector('.flatmmo-infobox-image img, .flatmmo-infobox img');
311 if (infoboxImg) {
312 img = infoboxImg.src;
313 } else {
314 var firstImg = temp.querySelector('img');
315 if (firstImg && firstImg.width > 20) {
316 img = firstImg.src;
317 }
318 }
319
320 var text = '';
321 var paragraphs = temp.querySelectorAll('p');
322 for (var i = 0; i < paragraphs.length; i++) {
323 var t = paragraphs[i].textContent.trim();
324 if (t.length > 10) {
325 text = t;
326 break;
327 }
328 }
329
330 if (text.length > 250) {
331 text = text.substring(0, 247) + '...';
332 }
333
334 var result = { image: img, text: text, title: title };
335 previewCache[title] = result;
336 callback(result);
337 }
338 },
339 error: function() {
340 console.log('Preview request failed for:', title);
341 }
342 });
343 }
344
345 function showPreview(link, e) {
346 if (!popup) createPopup();
347
348 var href = link.getAttribute('href');
349 if (!href) return;
350
351 var match = href.match(/\/index\.php\/(.+)/);
352 if (!match) return;
353
354 var title = decodeURIComponent(match[1]).replace(/_/g, ' ');
355
356 if (title.match(/^Special:|^Talk:|^User:|^Category:|^File:|^Template:|^MediaWiki:/i)) return;
357 if (href.indexOf('action=edit') !== -1) return;
358 if (link.classList.contains('new')) return;
359
360 positionPopup(e);
361 popup.innerHTML = '<div class="flatmmo-preview-title">' + title + '</div><div class="flatmmo-preview-loading">Loading...</div>';
362 popup.style.display = 'block';
363
364 fetchPreview(title, function(data) {
365 var html = '<div class="flatmmo-preview-title">' + data.title + '</div>';
366 if (data.image) {
367 html += '<div class="flatmmo-preview-image"><img src="' + data.image + '"></div>';
368 }
369 if (data.text) {
370 html += '<div class="flatmmo-preview-text">' + data.text + '</div>';
371 }
372 if (!data.image && !data.text) {
373 html += '<div class="flatmmo-preview-text" style="color:#999;">No preview available.</div>';
374 }
375 popup.innerHTML = html;
376 });
377 }
378
379 var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body;
380
381 // Strip all native tooltips from content links
382 $(content).find('a[title]').removeAttr('title');
383
384 $(content).on('mouseover', 'a', function(e) {
385 var link = this;
386 if ($(link).closest('.flatmmo-preview').length) return;
387
388 clearTimeout(hideTimer);
389 clearTimeout(showTimer);
390
391 // Catch any title that got added dynamically
392 if (link.getAttribute('title')) {
393 link.removeAttribute('title');
394 }
395
396 showTimer = setTimeout(function() {
397 showPreview(link, e);
398 }, 300);
399 });
400
401 $(content).on('mouseout', 'a', function() {
402 clearTimeout(showTimer);
403 hideTimer = setTimeout(function() {
404 if (popup) popup.style.display = 'none';
405 }, 200);
406 });
407
408 console.log('Page preview popup initialized');
409 })();
410
411 });
