Anonymous
×
Create a new article
Write your page title here:
We currently have 922 articles on WIKI - Flat MMO. Type your article name above or click on one of the titles below and start writing!



WIKI - Flat MMO
922Articles

MediaWiki:Common.js: Difference between revisions

Coolrock (talk | contribs)
No edit summary
Coolrock (talk | contribs)
No edit summary
Line 6: Line 6:
   ============================================================ */
   ============================================================ */
(function() {
(function() {
    // Apply theme from localStorage BEFORE page renders (avoid flash)
     var saved = localStorage.getItem('flatmmo-theme') || 'dark';
     var saved = localStorage.getItem('flatmmo-theme') || 'dark';
     document.documentElement.className += ' ' + saved + '-theme';
     document.documentElement.className += ' ' + saved + '-theme';


    // Apply search bar mode BEFORE page renders (avoid flash)
     var searchMode = localStorage.getItem('flatmmo-search') || 'top';
     var searchMode = localStorage.getItem('flatmmo-search') || 'top';
     document.documentElement.className += ' search-' + searchMode;
     document.documentElement.className += ' search-' + searchMode;
Line 27: Line 25:
     var currentTheme = localStorage.getItem('flatmmo-theme') || 'dark';
     var currentTheme = localStorage.getItem('flatmmo-theme') || 'dark';


    // Ensure body has the right class
     document.body.classList.remove('dark-theme', 'light-theme');
     document.body.classList.remove('dark-theme', 'light-theme');
     document.body.classList.add(currentTheme + '-theme');
     document.body.classList.add(currentTheme + '-theme');


    // Create toggle button
     var btn = document.createElement('button');
     var btn = document.createElement('button');
     btn.className = 'theme-toggle-btn';
     btn.className = 'theme-toggle-btn';
Line 50: Line 46:
     });
     });


    // Insert into Cosmos header (next to wiki buttons) or fallback to content area
     var target = document.querySelector('.cosmos-header__wiki-buttons')
     var target = document.querySelector('.cosmos-header__wiki-buttons')
               || document.querySelector('.cosmos-actions')
               || document.querySelector('.cosmos-actions')
Line 57: Line 52:
     if (target) {
     if (target) {
         if (target.id === 'content') {
         if (target.id === 'content') {
            // Fallback: put it at the top of content
             target.insertBefore(btn, target.firstChild);
             target.insertBefore(btn, target.firstChild);
         } else {
         } else {
Line 70: Line 64:
     var searchMode = localStorage.getItem('flatmmo-search') || 'top';
     var searchMode = localStorage.getItem('flatmmo-search') || 'top';


    // Ensure body has the right class
     document.body.classList.remove('search-top', 'search-header');
     document.body.classList.remove('search-top', 'search-header');
     document.body.classList.add('search-' + searchMode);
     document.body.classList.add('search-' + searchMode);


    // Scroll to top in header mode (banner removal shifts content)
     if (searchMode === 'header') {
     if (searchMode === 'header') {
         window.scrollTo(0, 0);
         window.scrollTo(0, 0);
Line 82: Line 74:
     }
     }


    // Create toggle button
     var searchToggle = document.createElement('button');
     var searchToggle = document.createElement('button');
     searchToggle.className = 'search-toggle-btn';
     searchToggle.className = 'search-toggle-btn';
Line 101: Line 92:
     });
     });


    // Create compact header search bar
     var searchWrap = document.createElement('div');
     var searchWrap = document.createElement('div');
     searchWrap.className = 'header-search-wrap';
     searchWrap.className = 'header-search-wrap';
Line 131: Line 121:
     searchWrap.appendChild(searchBtn);
     searchWrap.appendChild(searchBtn);


    // Insert toggle button inline with other header buttons
     var target = document.querySelector('.cosmos-header__wiki-buttons')
     var target = document.querySelector('.cosmos-header__wiki-buttons')
               || document.querySelector('.cosmos-actions')
               || document.querySelector('.cosmos-actions')
Line 138: Line 127:
     if (target && target.id !== 'content') {
     if (target && target.id !== 'content') {
         target.appendChild(searchToggle);
         target.appendChild(searchToggle);
        // Make target the positioning anchor, append search bar inside
         target.style.position = 'relative';
         target.style.position = 'relative';
         target.appendChild(searchWrap);
         target.appendChild(searchWrap);


        // Relocate username from banner into header for header mode
         var bannerUser = document.querySelector('.cosmos-userButton-label')
         var bannerUser = document.querySelector('.cosmos-userButton-label')
                       || document.querySelector('#p-personal-label');
                       || document.querySelector('#p-personal-label');
Line 401: Line 388:
     document.addEventListener('DOMContentLoaded', function() {
     document.addEventListener('DOMContentLoaded', function() {
         var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body;
         var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body;
        // Remove all default browser tooltips from content links
        content.querySelectorAll('a[title]').forEach(function(a) { a.removeAttribute('title'); });


         content.addEventListener('mouseover', function(e) {
         content.addEventListener('mouseover', function(e) {
Line 411: Line 401:


             if (link.getAttribute('title')) {
             if (link.getAttribute('title')) {
                link.setAttribute('data-title', link.getAttribute('title'));
                 link.removeAttribute('title');
                 link.removeAttribute('title');
             }
             }
Line 425: Line 414:


             clearTimeout(showTimer);
             clearTimeout(showTimer);
            if (link.getAttribute('data-title')) {
                link.setAttribute('title', link.getAttribute('data-title'));
                link.removeAttribute('data-title');
            }


             hideTimer = setTimeout(function() {
             hideTimer = setTimeout(function() {

Revision as of 05:02, 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 });
254 
255 /* Page Preview Popup */
256 (function() {
257     var popup = null;
258     var hideTimer = null;
259     var showTimer = null;
260     var cache = {};
261     var currentRequest = null;
262 
263     function createPopup() {
264         popup = document.createElement('div');
265         popup.className = 'flatmmo-preview';
266         document.body.appendChild(popup);
267 
268         popup.addEventListener('mouseenter', function() {
269             clearTimeout(hideTimer);
270         });
271         popup.addEventListener('mouseleave', function() {
272             hideTimer = setTimeout(function() {
273                 popup.style.display = 'none';
274             }, 200);
275         });
276     }
277 
278     function positionPopup(e) {
279         var x = e.pageX + 15;
280         var y = e.pageY + 15;
281         var popupWidth = 340;
282         var popupHeight = 200;
283 
284         if (x + popupWidth > document.documentElement.scrollLeft + window.innerWidth) {
285             x = e.pageX - popupWidth - 15;
286         }
287         if (y + popupHeight > document.documentElement.scrollTop + window.innerHeight) {
288             y = e.pageY - popupHeight - 15;
289         }
290 
291         popup.style.left = x + 'px';
292         popup.style.top = y + 'px';
293     }
294 
295     function fetchPreview(title, callback) {
296         if (cache[title]) {
297             callback(cache[title]);
298             return;
299         }
300 
301         var url = '/api.php?action=parse&page=' + encodeURIComponent(title) + '&prop=text&format=json&redirects=1';
302 
303         var xhr = new XMLHttpRequest();
304         currentRequest = xhr;
305         xhr.open('GET', url);
306         xhr.onload = function() {
307             if (xhr !== currentRequest) return;
308             try {
309                 var data = JSON.parse(xhr.responseText);
310                 if (data.parse && data.parse.text) {
311                     var html = data.parse.text['*'];
312                     var temp = document.createElement('div');
313                     temp.innerHTML = html;
314 
315                     var img = null;
316                     var infoboxImg = temp.querySelector('.flatmmo-infobox-image img, .flatmmo-infobox img');
317                     if (infoboxImg) {
318                         img = infoboxImg.src;
319                     } else {
320                         var firstImg = temp.querySelector('img');
321                         if (firstImg && firstImg.width > 20) {
322                             img = firstImg.src;
323                         }
324                     }
325 
326                     var text = '';
327                     var paragraphs = temp.querySelectorAll('p');
328                     for (var i = 0; i < paragraphs.length; i++) {
329                         var t = paragraphs[i].textContent.trim();
330                         if (t.length > 10) {
331                             text = t;
332                             break;
333                         }
334                     }
335 
336                     if (text.length > 250) {
337                         text = text.substring(0, 247) + '...';
338                     }
339 
340                     var result = { image: img, text: text, title: title };
341                     cache[title] = result;
342                     callback(result);
343                 }
344             } catch(e) {
345                 console.log('Preview fetch error:', e);
346             }
347         };
348         xhr.onerror = function() {
349             console.log('Preview request failed for:', title);
350         };
351         xhr.send();
352     }
353 
354     function showPreview(link, e) {
355         if (!popup) createPopup();
356 
357         var href = link.getAttribute('href');
358         if (!href) return;
359 
360         var match = href.match(/\/index\.php\/(.+)/);
361         if (!match) return;
362 
363         var title = decodeURIComponent(match[1]).replace(/_/g, ' ');
364 
365         if (title.match(/^Special:|^Talk:|^User:|^Category:|^File:|^Template:|^MediaWiki:/i)) return;
366         if (href.indexOf('action=edit') !== -1) return;
367         if (link.classList.contains('new')) return;
368 
369         positionPopup(e);
370         popup.innerHTML = '<div class="flatmmo-preview-title">' + title + '</div><div class="flatmmo-preview-loading">Loading...</div>';
371         popup.style.display = 'block';
372 
373         fetchPreview(title, function(data) {
374             var html = '<div class="flatmmo-preview-title">' + data.title + '</div>';
375             if (data.image) {
376                 html += '<div class="flatmmo-preview-image"><img src="' + data.image + '"></div>';
377             }
378             if (data.text) {
379                 html += '<div class="flatmmo-preview-text">' + data.text + '</div>';
380             }
381             if (!data.image && !data.text) {
382                 html += '<div class="flatmmo-preview-text" style="color:#999;">No preview available.</div>';
383             }
384             popup.innerHTML = html;
385         });
386     }
387 
388     document.addEventListener('DOMContentLoaded', function() {
389         var content = document.getElementById('mw-content-text') || document.getElementById('bodyContent') || document.body;
390 
391         // Remove all default browser tooltips from content links
392         content.querySelectorAll('a[title]').forEach(function(a) { a.removeAttribute('title'); });
393 
394         content.addEventListener('mouseover', function(e) {
395             var link = e.target.closest('a');
396             if (!link) return;
397             if (link.closest('.flatmmo-preview')) return;
398 
399             clearTimeout(hideTimer);
400             clearTimeout(showTimer);
401 
402             if (link.getAttribute('title')) {
403                 link.removeAttribute('title');
404             }
405 
406             showTimer = setTimeout(function() {
407                 showPreview(link, e);
408             }, 300);
409         });
410 
411         content.addEventListener('mouseout', function(e) {
412             var link = e.target.closest('a');
413             if (!link) return;
414 
415             clearTimeout(showTimer);
416 
417             hideTimer = setTimeout(function() {
418                 if (popup) popup.style.display = 'none';
419             }, 200);
420         });
421     });
422 })();