No edit summary |
No edit summary |
||
| Line 73: | Line 73: | ||
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); | ||
// Directly shrink/restore the header via JS (CSS can't override Cosmos inline styles) | |||
function applyHeaderShrink(mode) { | |||
// Find every element inside .cosmos-header that might have height/padding | |||
var header = document.querySelector('.cosmos-header'); | |||
if (!header) return; | |||
var els = header.querySelectorAll('*'); | |||
if (mode === 'header') { | |||
// Store original styles and shrink | |||
header.setAttribute('data-orig-pt', header.style.paddingTop || ''); | |||
header.setAttribute('data-orig-mh', header.style.minHeight || ''); | |||
header.style.paddingTop = '0px'; | |||
header.style.minHeight = '0px'; | |||
for (var i = 0; i < els.length; i++) { | |||
var el = els[i]; | |||
var tag = el.tagName.toLowerCase(); | |||
var cs = window.getComputedStyle(el); | |||
// Shrink any element with large padding-top or min-height | |||
if (parseInt(cs.paddingTop) > 20) { | |||
el.setAttribute('data-orig-pt', el.style.paddingTop || ''); | |||
el.style.paddingTop = '0px'; | |||
} | |||
if (parseInt(cs.minHeight) > 50) { | |||
el.setAttribute('data-orig-mh', el.style.minHeight || ''); | |||
el.style.minHeight = '0px'; | |||
} | |||
if (parseInt(cs.height) > 100 && cs.backgroundImage && cs.backgroundImage !== 'none') { | |||
el.setAttribute('data-orig-h', el.style.height || ''); | |||
el.style.height = 'auto'; | |||
} | |||
} | |||
} else { | |||
// Restore originals | |||
header.style.paddingTop = header.getAttribute('data-orig-pt') || ''; | |||
header.style.minHeight = header.getAttribute('data-orig-mh') || ''; | |||
for (var j = 0; j < els.length; j++) { | |||
var el2 = els[j]; | |||
if (el2.hasAttribute('data-orig-pt')) { | |||
el2.style.paddingTop = el2.getAttribute('data-orig-pt'); | |||
} | |||
if (el2.hasAttribute('data-orig-mh')) { | |||
el2.style.minHeight = el2.getAttribute('data-orig-mh'); | |||
} | |||
if (el2.hasAttribute('data-orig-h')) { | |||
el2.style.height = el2.getAttribute('data-orig-h'); | |||
} | |||
} | |||
} | |||
} | |||
// Apply on load | |||
applyHeaderShrink(searchMode); | |||
// Create toggle button | // Create toggle button | ||
| Line 91: | Line 143: | ||
localStorage.setItem('flatmmo-search', newMode); | localStorage.setItem('flatmmo-search', newMode); | ||
searchToggle.textContent = newMode === 'top' ? '🔍' : '🔎'; | searchToggle.textContent = newMode === 'top' ? '🔍' : '🔎'; | ||
applyHeaderShrink(newMode); | |||
}); | }); | ||
Revision as of 20:36, 15 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 // Apply theme from localStorage BEFORE page renders (avoid flash)
9 var saved = localStorage.getItem('flatmmo-theme') || 'dark';
10 document.documentElement.className += ' ' + saved + '-theme';
11
12 // Apply search bar mode BEFORE page renders (avoid flash)
13 var searchMode = localStorage.getItem('flatmmo-search') || 'top';
14 document.documentElement.className += ' search-' + searchMode;
15
16 document.addEventListener('DOMContentLoaded', function() {
17 document.body.classList.add(saved + '-theme');
18 document.body.classList.add('search-' + searchMode);
19 });
20 })();
21
22 $(document).ready(function () {
23 console.log("loaded");
24
25 // --- Theme toggle button ---
26 (function() {
27 var currentTheme = localStorage.getItem('flatmmo-theme') || 'dark';
28
29 // Ensure body has the right class
30 document.body.classList.remove('dark-theme', 'light-theme');
31 document.body.classList.add(currentTheme + '-theme');
32
33 // Create toggle button
34 var btn = document.createElement('button');
35 btn.className = 'theme-toggle-btn';
36 btn.title = 'Toggle light/dark mode';
37 btn.textContent = currentTheme === 'dark' ? '☀️' : '🌙';
38
39 btn.addEventListener('click', function() {
40 var isDark = document.body.classList.contains('dark-theme');
41 var newTheme = isDark ? 'light' : 'dark';
42
43 document.body.classList.remove('dark-theme', 'light-theme');
44 document.body.classList.add(newTheme + '-theme');
45 document.documentElement.classList.remove('dark-theme', 'light-theme');
46 document.documentElement.classList.add(newTheme + '-theme');
47
48 localStorage.setItem('flatmmo-theme', newTheme);
49 btn.textContent = newTheme === 'dark' ? '☀️' : '🌙';
50 });
51
52 // Insert into Cosmos header (next to wiki buttons) or fallback to content area
53 var target = document.querySelector('.cosmos-header__wiki-buttons')
54 || document.querySelector('.cosmos-actions')
55 || document.querySelector('.wds-button-group')
56 || document.querySelector('#content');
57 if (target) {
58 if (target.id === 'content') {
59 // Fallback: put it at the top of content
60 target.insertBefore(btn, target.firstChild);
61 } else {
62 target.appendChild(btn);
63 }
64 }
65
66 })();
67
68 // --- Search bar toggle + compact header search bar ---
69 (function() {
70 var searchMode = localStorage.getItem('flatmmo-search') || 'top';
71
72 // Ensure body has the right class
73 document.body.classList.remove('search-top', 'search-header');
74 document.body.classList.add('search-' + searchMode);
75
76 // Directly shrink/restore the header via JS (CSS can't override Cosmos inline styles)
77 function applyHeaderShrink(mode) {
78 // Find every element inside .cosmos-header that might have height/padding
79 var header = document.querySelector('.cosmos-header');
80 if (!header) return;
81 var els = header.querySelectorAll('*');
82 if (mode === 'header') {
83 // Store original styles and shrink
84 header.setAttribute('data-orig-pt', header.style.paddingTop || '');
85 header.setAttribute('data-orig-mh', header.style.minHeight || '');
86 header.style.paddingTop = '0px';
87 header.style.minHeight = '0px';
88 for (var i = 0; i < els.length; i++) {
89 var el = els[i];
90 var tag = el.tagName.toLowerCase();
91 var cs = window.getComputedStyle(el);
92 // Shrink any element with large padding-top or min-height
93 if (parseInt(cs.paddingTop) > 20) {
94 el.setAttribute('data-orig-pt', el.style.paddingTop || '');
95 el.style.paddingTop = '0px';
96 }
97 if (parseInt(cs.minHeight) > 50) {
98 el.setAttribute('data-orig-mh', el.style.minHeight || '');
99 el.style.minHeight = '0px';
100 }
101 if (parseInt(cs.height) > 100 && cs.backgroundImage && cs.backgroundImage !== 'none') {
102 el.setAttribute('data-orig-h', el.style.height || '');
103 el.style.height = 'auto';
104 }
105 }
106 } else {
107 // Restore originals
108 header.style.paddingTop = header.getAttribute('data-orig-pt') || '';
109 header.style.minHeight = header.getAttribute('data-orig-mh') || '';
110 for (var j = 0; j < els.length; j++) {
111 var el2 = els[j];
112 if (el2.hasAttribute('data-orig-pt')) {
113 el2.style.paddingTop = el2.getAttribute('data-orig-pt');
114 }
115 if (el2.hasAttribute('data-orig-mh')) {
116 el2.style.minHeight = el2.getAttribute('data-orig-mh');
117 }
118 if (el2.hasAttribute('data-orig-h')) {
119 el2.style.height = el2.getAttribute('data-orig-h');
120 }
121 }
122 }
123 }
124
125 // Apply on load
126 applyHeaderShrink(searchMode);
127
128 // Create toggle button
129 var searchToggle = document.createElement('button');
130 searchToggle.className = 'search-toggle-btn';
131 searchToggle.title = 'Toggle search bar position';
132 searchToggle.textContent = searchMode === 'top' ? '🔍' : '🔎';
133
134 searchToggle.addEventListener('click', function() {
135 var isTop = document.body.classList.contains('search-top');
136 var newMode = isTop ? 'header' : 'top';
137
138 document.body.classList.remove('search-top', 'search-header');
139 document.body.classList.add('search-' + newMode);
140 document.documentElement.classList.remove('search-top', 'search-header');
141 document.documentElement.classList.add('search-' + newMode);
142
143 localStorage.setItem('flatmmo-search', newMode);
144 searchToggle.textContent = newMode === 'top' ? '🔍' : '🔎';
145
146 applyHeaderShrink(newMode);
147 });
148
149 // Create compact header search bar
150 var searchWrap = document.createElement('div');
151 searchWrap.className = 'header-search-wrap';
152
153 var searchInput = document.createElement('input');
154 searchInput.type = 'text';
155 searchInput.className = 'header-search-input';
156 searchInput.placeholder = 'Search wiki...';
157 searchInput.setAttribute('autocomplete', 'off');
158
159 var searchBtn = document.createElement('button');
160 searchBtn.className = 'header-search-btn';
161 searchBtn.innerHTML = '🔍';
162 searchBtn.title = 'Search';
163
164 function doSearch() {
165 var q = searchInput.value.trim();
166 if (q) {
167 window.location.href = mw.util.getUrl('Special:Search') + '?search=' + encodeURIComponent(q);
168 }
169 }
170
171 searchBtn.addEventListener('click', doSearch);
172 searchInput.addEventListener('keydown', function(e) {
173 if (e.key === 'Enter') doSearch();
174 });
175
176 searchWrap.appendChild(searchInput);
177 searchWrap.appendChild(searchBtn);
178
179 // Insert toggle button inline with other header buttons
180 var target = document.querySelector('.cosmos-header__wiki-buttons')
181 || document.querySelector('.cosmos-actions')
182 || document.querySelector('.wds-button-group')
183 || document.querySelector('#content');
184 if (target && target.id !== 'content') {
185 target.appendChild(searchToggle);
186 // Make target the positioning anchor, append search bar inside
187 target.style.position = 'relative';
188 target.appendChild(searchWrap);
189
190 // Relocate username from banner into header for header mode
191 var bannerUser = document.querySelector('.cosmos-userButton-label')
192 || document.querySelector('#p-personal-label');
193 var userName = bannerUser ? bannerUser.textContent.trim() : '';
194 if (userName) {
195 var userLink = document.createElement('a');
196 userLink.className = 'relocated-user';
197 userLink.href = mw.util.getUrl('User:' + userName);
198 userLink.title = userName;
199
200 var userIcon = document.createElement('span');
201 userIcon.className = 'relocated-user-icon';
202 userIcon.innerHTML = '👤';
203
204 var userText = document.createElement('span');
205 userText.className = 'relocated-user-name';
206 userText.textContent = userName;
207
208 userLink.appendChild(userIcon);
209 userLink.appendChild(userText);
210 target.appendChild(userLink);
211 }
212 }
213 })();
214
215 $.getScript(mw.util.getUrl("MediaWiki:ProfileTags.js") + "?action=raw&ctype=text/javascript");
216 if (document.getElementById("interactiveMap")) {
217 console.log("map loaded")
218 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() {
219 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() {
220 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() {
221 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap.js") + "?action=raw&ctype=text/javascript", function() {
222 });
223 });
224 });
225 });
226 }
227
228 if (document.getElementById("wardrobe")) {
229 $.getScript(mw.util.getUrl("MediaWiki:Wardrobe.js") + "?action=raw&ctype=text/javascript");
230 console.log("wardrobe loaded")
231 }
232
233 if (document.getElementById("mapEditor")) {
234 $.getScript("https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js", function() {
235 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Objects.js") + "?action=raw&ctype=text/javascript", function() {
236 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/NPCs.js") + "?action=raw&ctype=text/javascript", function() {
237 $.getScript(mw.util.getUrl("MediaWiki:InteractiveMap/Maps.js") + "?action=raw&ctype=text/javascript", function() {
238 $.getScript(mw.util.getUrl("MediaWiki:MapEditor.js") + "?action=raw&ctype=text/javascript", function() {
239 });
240 });
241 });
242 });
243 });
244 }
245 if (document.querySelector(".code")) {
246 $.getScript("../custom/highlight.min.js", ()=>{
247 document.querySelectorAll(".code").forEach(el=>hljs.highlightElement(el))
248 console.log('Code highlighted');
249 });
250 }
251
252 if (document.querySelector('[class*="Tracker"]') && !document.querySelector('[class*="page-MediaWiki"]')) {
253 $.getScript(mw.util.getUrl("MediaWiki:Trackers.js") + "?action=raw&ctype=text/javascript");
254 console.log("Tracker loaded");
255 }
256
257 if (document.getElementById("enemiesDB")) {
258 $.getScript(mw.util.getUrl("MediaWiki:Update_DB.js") + "?action=raw&ctype=text/javascript");
259 console.log("DB Updater Loaded")
260 }
261 function hitChance(accuracy, defence) {
262 accuracy = parseInt(accuracy);
263 defence = parseInt(defence);
264 let hitChance = 0;
265 if(accuracy >= defence) {
266 hitChance = 1;
267 } else {
268 hitChance = 1 / (1 + defence - accuracy)
269 }
270 return (hitChance * 100).toFixed(2);
271 }
272 if (document.querySelector('.hitChance')) {
273 document.querySelectorAll(".hitChance").forEach(el => {
274 let [acc, def] = el.innerText.split(",")
275 el.innerText = "";
276 const accSpan = document.createElement("span");
277 const defSpan = document.createElement("span");
278 const hitSpan = document.createElement("span");
279 const accInput = document.createElement("input");
280 const defInput = document.createElement("input");
281 const hitValueSpan = document.createElement("span");
282
283 accSpan.innerText = "Accuracy:";
284 defSpan.innerText = "Defence:";
285 hitSpan.innerText = "Hit Chance:";
286
287 accInput.type = "number";
288 defInput.type = "number";
289 accInput.min = 0;
290 defInput.min = 0;
291 if(acc !== "0") {
292 accInput.disabled = true;
293 }
294 if(def !== "0") {
295 defInput.disabled = true
296 }
297 def = def < 0 ? 0 : def;
298 acc = acc < 0 ? 0 : acc;
299 accInput.defaultValue = acc;
300 defInput.defaultValue = def;
301 accInput.onchange = function(){
302 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
303 }
304 defInput.onchange = function(){
305 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
306 }
307 el.append(accSpan, accInput, defSpan, defInput, hitSpan, hitValueSpan);
308 hitValueSpan.innerText = hitChance(accInput.value, defInput.value) + "%";
309 })
310 }
311
312 });
