MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| Line 42: | Line 42: | ||
} | } | ||
}); | }); | ||
} | |||
function toNumber(value, fallback) { | |||
var n = parseFloat(value); | |||
return isNaN(n) ? fallback : n; | |||
} | |||
function clamp(value, min, max) { | |||
return Math.max(min, Math.min(max, value)); | |||
} | } | ||
| Line 52: | Line 61: | ||
var html = document.documentElement; | var html = document.documentElement; | ||
var body = document.body; | var body = document.body; | ||
var hasGuideRoot = | |||
document.getElementById('farming-guide-root') || | |||
document.getElementById('mvp-guide-root') || | |||
document.getElementById('leveling-guide-root') || | |||
document.querySelector('.timero-wiki-root'); | |||
if (!html || !body) return; | if (!html || !body) return; | ||
| Line 67: | Line 81: | ||
}); | }); | ||
if (/^Guia_de_/.test(page)) { | if (/^Guia_de_/.test(page) || hasGuideRoot) { | ||
var safePageClass = 'guide-page-' + page.replace(/[^A-Za-z0-9_-]/g, '-'); | var safePageClass = 'guide-page-' + String(page || 'custom-guide').replace(/[^A-Za-z0-9_-]/g, '-'); | ||
html.classList.add('timero-guide-skin'); | html.classList.add('timero-guide-skin'); | ||
body.classList.add('timero-guide-skin'); | body.classList.add('timero-guide-skin'); | ||
| Line 275: | Line 289: | ||
} | } | ||
if (rounded >= 1) { | |||
return | return rounded.toString().replace('.0', '').replace('.', ',') + 'M z'; | ||
} | |||
return Math.round(rounded * 1000) + 'k z'; | |||
} | } | ||
| Line 309: | Line 326: | ||
if (menuEl) { | if (menuEl) { | ||
menuEl.style.display = section.getAttribute('data-method-menu-open') === '1' ? 'block' : 'none'; | menuEl.style.display = section.getAttribute('data-method-menu-open') === '1' ? 'block' : 'none'; | ||
} | |||
} | |||
function syncCalcStateFromNativeSelect(section) { | |||
if (!section) return; | |||
var select = section.querySelector('#calc-method'); | |||
if (!select) return; | |||
calcState.rate = toNumber(select.value, calcState.rate); | |||
if (select.options && select.selectedIndex >= 0) { | |||
calcState.label = select.options[select.selectedIndex].text; | |||
} | } | ||
} | } | ||
| Line 315: | Line 345: | ||
if (field !== 'hours') return; | if (field !== 'hours') return; | ||
calcState.hours = | calcState.hours = clamp(calcState.hours + delta, 0.5, 24); | ||
updateCalc(); | updateCalc(); | ||
}; | }; | ||
| Line 325: | Line 355: | ||
window.setCalcMethod = function (rate, label) { | window.setCalcMethod = function (rate, label) { | ||
calcState.rate = | calcState.rate = toNumber(rate, calcState.rate); | ||
calcState.label = label || | calcState.label = label || calcState.label; | ||
var section = document.getElementById('calculator-section'); | var section = document.getElementById('calculator-section'); | ||
if (section) { | if (section) { | ||
section.setAttribute('data-method-menu-open', '0'); | section.setAttribute('data-method-menu-open', '0'); | ||
var select = section.querySelector('#calc-method'); | |||
if (select) { | |||
select.value = String(calcState.rate); | |||
} | |||
} | } | ||
| Line 356: | Line 391: | ||
var section = document.getElementById('calculator-section'); | var section = document.getElementById('calculator-section'); | ||
if (!section) return; | if (!section) return; | ||
syncCalcStateFromNativeSelect(section); | |||
var hoursEl = document.getElementById('calc-hours'); | var hoursEl = document.getElementById('calc-hours'); | ||
| Line 418: | Line 455: | ||
bindActionButton(adjuster, function (e) { | bindActionButton(adjuster, function (e) { | ||
e.stopPropagation(); | e.stopPropagation(); | ||
adjustCalc(this.getAttribute('data-calc-adjust'), | adjustCalc(this.getAttribute('data-calc-adjust'), toNumber(this.getAttribute('data-delta'), 0)); | ||
}); | }); | ||
})(adjusters[i]); | })(adjusters[i]); | ||
| Line 449: | Line 486: | ||
}); | }); | ||
})(options[k]); | })(options[k]); | ||
} | |||
var nativeSelect = section.querySelector('#calc-method'); | |||
if (nativeSelect && nativeSelect.dataset.timeroBound !== '1') { | |||
nativeSelect.dataset.timeroBound = '1'; | |||
nativeSelect.addEventListener('change', function () { | |||
updateCalc(); | |||
}); | |||
} | } | ||
| Line 514: | Line 559: | ||
for (var i = 0; i < items.length; i++) { | for (var i = 0; i < items.length; i++) { | ||
if (items[i].classList.contains('is-active')) { | if (items[i].classList.contains('is-active')) { | ||
total += | total += toNumber(items[i].getAttribute('data-cost'), 0); | ||
count += 1; | count += 1; | ||
} | } | ||
| Line 570: | Line 615: | ||
updateLoadoutSummary(); | updateLoadoutSummary(); | ||
} | |||
/* ========================================================= | |||
TIMERO CLICKABLE CARDS | |||
========================================================= */ | |||
function bindTimeroNavCards(context) { | |||
var scope = context && context.querySelector ? context : document; | |||
var cards = scope.querySelectorAll('.timero-nav-card[data-href]'); | |||
for (var i = 0; i < cards.length; i++) { | |||
(function (card) { | |||
if (card.dataset.timeroNavBound === '1') return; | |||
card.dataset.timeroNavBound = '1'; | |||
card.setAttribute('role', 'button'); | |||
card.setAttribute('tabindex', '0'); | |||
card.style.cursor = 'pointer'; | |||
card.addEventListener('click', function (e) { | |||
if (e.target.closest('a, button, input, select, textarea')) return; | |||
var href = this.getAttribute('data-href'); | |||
var target = this.getAttribute('data-target') || ''; | |||
if (!href) return; | |||
if (target === '_blank') { | |||
window.open(href, '_blank', 'noopener'); | |||
} else { | |||
window.location.href = href; | |||
} | |||
}); | |||
card.addEventListener('keydown', function (e) { | |||
if (e.key === 'Enter' || e.key === ' ') { | |||
e.preventDefault(); | |||
this.click(); | |||
} | |||
}); | |||
})(cards[i]); | |||
} | |||
} | |||
/* ========================================================= | |||
MVP GUIDE | |||
========================================================= */ | |||
var MVP_TIMER_STORAGE_KEY = 'timero_mvp_timers_v1'; | |||
function readStoredMvpTimers() { | |||
try { | |||
var raw = window.localStorage.getItem(MVP_TIMER_STORAGE_KEY); | |||
if (!raw) return []; | |||
var parsed = JSON.parse(raw); | |||
return Array.isArray(parsed) ? parsed : []; | |||
} catch (err) { | |||
return []; | |||
} | |||
} | |||
function writeStoredMvpTimers(list) { | |||
try { | |||
window.localStorage.setItem(MVP_TIMER_STORAGE_KEY, JSON.stringify(list)); | |||
} catch (err) { | |||
/* ignore */ | |||
} | |||
} | |||
function getRemainingTimerMs(timerObj) { | |||
var now = Date.now(); | |||
var endAt = timerObj.killTime + timerObj.respawnMs; | |||
return Math.max(0, endAt - now); | |||
} | |||
function formatTimerMs(ms) { | |||
var totalSec = Math.max(0, Math.floor(ms / 1000)); | |||
var hours = Math.floor(totalSec / 3600); | |||
var mins = Math.floor((totalSec % 3600) / 60); | |||
var secs = totalSec % 60; | |||
if (hours > 0) { | |||
return String(hours).padStart(2, '0') + ':' + String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0'); | |||
} | |||
return String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0'); | |||
} | |||
function removeTimerById(timerId) { | |||
var list = readStoredMvpTimers().filter(function (item) { | |||
return item.id !== timerId; | |||
}); | |||
writeStoredMvpTimers(list); | |||
var row = document.getElementById(timerId); | |||
if (row && row.parentNode) { | |||
row.parentNode.removeChild(row); | |||
} | |||
var timerList = document.getElementById('timer-list'); | |||
var empty = document.getElementById('timer-empty'); | |||
if (timerList && empty && timerList.children.length === 0) { | |||
empty.style.display = ''; | |||
} | |||
} | |||
function createTimerRow(timerObj) { | |||
var list = document.getElementById('timer-list'); | |||
if (!list) return null; | |||
var existing = document.getElementById(timerObj.id); | |||
if (existing) return existing; | |||
var empty = document.getElementById('timer-empty'); | |||
if (empty) empty.style.display = 'none'; | |||
var row = document.createElement('div'); | |||
row.id = timerObj.id; | |||
row.className = 'mvp-timer-row'; | |||
row.style.cssText = 'display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center;padding:13px 16px;border-radius:12px;background:rgba(0,212,255,0.05);border:1px solid rgba(0,212,255,0.14);'; | |||
var killTs = new Date(timerObj.killTime); | |||
var h = killTs.getHours().toString().padStart(2, '0'); | |||
var m = killTs.getMinutes().toString().padStart(2, '0'); | |||
row.innerHTML = | |||
'<div>' + | |||
'<div style="font-size:0.90rem;font-weight:800;color:#fff;margin-bottom:2px;">💀 ' + timerObj.name + '</div>' + | |||
'<div style="font-size:0.70rem;color:rgba(122,144,176,0.55);">Kill registrada às ' + h + ':' + m + ' · Respawn ' + timerObj.respawnMins + 'min</div>' + | |||
'</div>' + | |||
'<div class="mvp-timer-countdown" style="font-size:0.86rem;font-weight:900;color:#00d4ff;min-width:78px;text-align:right;">--:--</div>' + | |||
'<button type="button" class="mvp-timer-remove" style="padding:8px 12px;border-radius:8px;background:rgba(255,61,90,0.10);border:1px solid rgba(255,61,90,0.22);color:#ff3d5a;font-size:0.75rem;font-weight:800;cursor:pointer;font-family:inherit;">Remover</button>'; | |||
var removeBtn = row.querySelector('.mvp-timer-remove'); | |||
if (removeBtn) { | |||
removeBtn.addEventListener('click', function () { | |||
removeTimerById(timerObj.id); | |||
}); | |||
} | |||
list.appendChild(row); | |||
return row; | |||
} | |||
function refreshSingleTimerRow(timerObj) { | |||
var row = document.getElementById(timerObj.id); | |||
if (!row) { | |||
row = createTimerRow(timerObj); | |||
} | |||
if (!row) return; | |||
var countdown = row.querySelector('.mvp-timer-countdown'); | |||
var remaining = getRemainingTimerMs(timerObj); | |||
if (countdown) { | |||
if (remaining <= 0) { | |||
countdown.textContent = 'Respawn'; | |||
countdown.style.color = '#00ff88'; | |||
row.style.borderColor = 'rgba(0,255,136,0.22)'; | |||
row.style.background = 'rgba(0,255,136,0.05)'; | |||
} else { | |||
countdown.textContent = formatTimerMs(remaining); | |||
countdown.style.color = '#00d4ff'; | |||
row.style.borderColor = 'rgba(0,212,255,0.14)'; | |||
row.style.background = 'rgba(0,212,255,0.05)'; | |||
} | |||
} | |||
} | |||
function refreshAllMvpTimers() { | |||
var list = readStoredMvpTimers(); | |||
for (var i = 0; i < list.length; i++) { | |||
refreshSingleTimerRow(list[i]); | |||
} | |||
} | |||
window.toggleBoss = function (card) { | |||
if (!card) return; | |||
var dossier = card.querySelector('.boss-dossier'); | |||
var chevron = card.querySelector('.boss-chevron'); | |||
if (!dossier) return; | |||
var isOpen = dossier.style.display !== 'none'; | |||
dossier.style.display = isOpen ? 'none' : 'block'; | |||
if (chevron) { | |||
chevron.textContent = isOpen ? '▼ Dossiê' : '▲ Fechar'; | |||
} | |||
card.style.boxShadow = isOpen ? '' : '0 0 32px rgba(255,61,90,0.12)'; | |||
}; | |||
window.filterTier = function (tier) { | |||
var btns = document.querySelectorAll('.tf-btn'); | |||
for (var i = 0; i < btns.length; i++) { | |||
btns[i].style.opacity = '0.45'; | |||
btns[i].style.fontWeight = '700'; | |||
} | |||
var active = document.getElementById('tf-' + tier); | |||
if (active) { | |||
active.style.opacity = '1'; | |||
active.style.fontWeight = '900'; | |||
} | |||
var cards = document.querySelectorAll('.boss-card'); | |||
var shown = 0; | |||
for (var j = 0; j < cards.length; j++) { | |||
var t = cards[j].dataset.tier; | |||
var show = tier === 'all' || t === tier; | |||
cards[j].style.display = show ? '' : 'none'; | |||
if (show) shown++; | |||
} | |||
var label = document.getElementById('boss-count-label'); | |||
if (label) { | |||
label.textContent = shown + (shown === 1 ? ' MVP exibido' : ' MVPs exibidos'); | |||
} | |||
}; | |||
window.sortBosses = function (by) { | |||
var btns = document.querySelectorAll('.sort-btn'); | |||
for (var i = 0; i < btns.length; i++) { | |||
btns[i].style.background = 'rgba(255,255,255,0.06)'; | |||
btns[i].style.borderColor = 'rgba(255,255,255,0.10)'; | |||
btns[i].style.color = 'rgba(232,238,248,0.65)'; | |||
} | |||
var active = document.getElementById('sort-' + by); | |||
if (active) { | |||
active.style.background = 'rgba(255,61,90,0.12)'; | |||
active.style.borderColor = 'rgba(255,61,90,0.30)'; | |||
active.style.color = '#ff3d5a'; | |||
} | |||
var grid = document.getElementById('boss-grid'); | |||
if (!grid) return; | |||
var cards = Array.prototype.slice.call(grid.querySelectorAll('.boss-card')); | |||
cards.sort(function (a, b) { | |||
if (by === 'danger') return parseInt(b.dataset.danger || '0', 10) - parseInt(a.dataset.danger || '0', 10); | |||
if (by === 'exp') return parseInt(b.dataset.exp || '0', 10) - parseInt(a.dataset.exp || '0', 10); | |||
if (by === 'respawn') return parseInt(a.dataset.respawn || '0', 10) - parseInt(b.dataset.respawn || '0', 10); | |||
return 0; | |||
}); | |||
for (var j = 0; j < cards.length; j++) { | |||
grid.appendChild(cards[j]); | |||
} | |||
}; | |||
window.toggleClassMvp = function (row) { | |||
if (!row) return; | |||
var detail = row.querySelector('.class-mvp-detail'); | |||
var chevron = row.querySelector('.class-chevron'); | |||
if (!detail) return; | |||
var open = detail.style.display !== 'none'; | |||
detail.style.display = open ? 'none' : 'block'; | |||
if (chevron) { | |||
chevron.style.transform = open ? 'rotate(0deg)' : 'rotate(180deg)'; | |||
} | |||
}; | |||
window.logKill = function (btn, name, respawnMins) { | |||
var killTime = Date.now(); | |||
var respawnMs = toNumber(respawnMins, 0) * 60 * 1000; | |||
var timerObj = { | |||
id: 'timer-' + killTime, | |||
name: name || 'MVP', | |||
respawnMins: toNumber(respawnMins, 0), | |||
respawnMs: respawnMs, | |||
killTime: killTime | |||
}; | |||
var list = readStoredMvpTimers(); | |||
list.unshift(timerObj); | |||
writeStoredMvpTimers(list); | |||
createTimerRow(timerObj); | |||
refreshSingleTimerRow(timerObj); | |||
if (btn) { | |||
btn.style.filter = 'brightness(1.08)'; | |||
setTimeout(function () { | |||
btn.style.filter = ''; | |||
}, 450); | |||
} | |||
}; | |||
function bindMvpGuide(context) { | |||
var scope = context && context.querySelector ? context : document; | |||
var root = scope.querySelector('#mvp-guide-root') || document.getElementById('mvp-guide-root'); | |||
if (!root) return; | |||
var tierButtons = root.querySelectorAll('.tf-btn[data-tier]'); | |||
for (var i = 0; i < tierButtons.length; i++) { | |||
(function (btn) { | |||
bindActionButton(btn, function () { | |||
filterTier(this.getAttribute('data-tier')); | |||
}); | |||
})(tierButtons[i]); | |||
} | |||
var sortButtons = root.querySelectorAll('.sort-btn[data-sort]'); | |||
for (var j = 0; j < sortButtons.length; j++) { | |||
(function (btn) { | |||
bindActionButton(btn, function () { | |||
sortBosses(this.getAttribute('data-sort')); | |||
}); | |||
})(sortButtons[j]); | |||
} | |||
if (!window.__timeroMvpTimerInterval) { | |||
window.__timeroMvpTimerInterval = window.setInterval(refreshAllMvpTimers, 1000); | |||
} | |||
refreshAllMvpTimers(); | |||
var label = document.getElementById('boss-count-label'); | |||
if (label && label.textContent.replace(/\s+/g, '') === '') { | |||
filterTier('all'); | |||
} | |||
} | |||
/* ========================================================= | |||
OPTIONAL GUIDE HELPERS | |||
========================================================= */ | |||
function bindPhaseNav(context) { | |||
var scope = context && context.querySelector ? context : document; | |||
var nav = scope.querySelector('#phase-nav'); | |||
if (!nav) return; | |||
var links = nav.querySelectorAll('a[href^="#"], a[data-target]'); | |||
for (var i = 0; i < links.length; i++) { | |||
(function (link) { | |||
if (link.dataset.timeroPhaseBound === '1') return; | |||
link.dataset.timeroPhaseBound = '1'; | |||
link.addEventListener('click', function (e) { | |||
var targetSelector = this.getAttribute('href'); | |||
if (!targetSelector || targetSelector === '#') { | |||
targetSelector = this.getAttribute('data-target'); | |||
} | |||
if (!targetSelector) return; | |||
var target = document.querySelector(targetSelector); | |||
if (!target) return; | |||
e.preventDefault(); | |||
target.scrollIntoView({ | |||
behavior: 'smooth', | |||
block: 'start' | |||
}); | |||
}); | |||
})(links[i]); | |||
} | |||
} | } | ||
| Line 584: | Line 989: | ||
bindCalculator(context || document); | bindCalculator(context || document); | ||
bindLoadout(context || document); | bindLoadout(context || document); | ||
bindTimeroNavCards(context || document); | |||
bindMvpGuide(context || document); | |||
bindPhaseNav(context || document); | |||
} | } | ||
Revision as of 22:25, 13 April 2026
/* Any JavaScript here will be loaded for all users on every page load. */
(function ($, mw) {
'use strict';
/* =========================================================
GLOBAL BASICS
========================================================= */
function setLogoHref() {
var logoLink = document.querySelector('#p-logo a');
if (logoLink) {
logoLink.setAttribute('href', 'https://timero.com.br/');
}
}
function ensureFontAwesome() {
if (document.querySelector('link[data-timero-fa]')) return;
var fa = document.createElement('link');
fa.rel = 'stylesheet';
fa.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css';
fa.setAttribute('data-timero-fa', '1');
document.head.appendChild(fa);
}
function bindActionButton(el, handler) {
if (!el || el.dataset.timeroBound === '1') return;
el.dataset.timeroBound = '1';
el.setAttribute('role', 'button');
el.setAttribute('tabindex', '0');
el.addEventListener('click', function (e) {
e.preventDefault();
handler.call(this, e);
});
el.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handler.call(this, e);
}
});
}
function toNumber(value, fallback) {
var n = parseFloat(value);
return isNaN(n) ? fallback : n;
}
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
/* =========================================================
GUIDE PAGE SKIN SWITCH
========================================================= */
function applyTimeroGuideSkin() {
var page = mw.config.get('wgPageName') || '';
var html = document.documentElement;
var body = document.body;
var hasGuideRoot =
document.getElementById('farming-guide-root') ||
document.getElementById('mvp-guide-root') ||
document.getElementById('leveling-guide-root') ||
document.querySelector('.timero-wiki-root');
if (!html || !body) return;
Array.prototype.slice.call(html.classList).forEach(function (cls) {
if (cls === 'timero-guide-skin' || cls.indexOf('guide-page-') === 0) {
html.classList.remove(cls);
}
});
Array.prototype.slice.call(body.classList).forEach(function (cls) {
if (cls === 'timero-guide-skin' || cls.indexOf('guide-page-') === 0) {
body.classList.remove(cls);
}
});
if (/^Guia_de_/.test(page) || hasGuideRoot) {
var safePageClass = 'guide-page-' + String(page || 'custom-guide').replace(/[^A-Za-z0-9_-]/g, '-');
html.classList.add('timero-guide-skin');
body.classList.add('timero-guide-skin');
html.classList.add(safePageClass);
body.classList.add(safePageClass);
}
}
/* =========================================================
ROUTES
========================================================= */
function resetRoutePill(pill) {
if (!pill) return;
pill.style.transform = '';
pill.style.fontWeight = '800';
pill.style.boxShadow = 'none';
pill.style.filter = 'none';
}
function activateRoutePill(pill) {
if (!pill) return;
pill.style.transform = 'translateY(-1px)';
pill.style.fontWeight = '900';
pill.style.boxShadow = '0 0 0 1px rgba(255,255,255,0.05) inset, 0 0 22px rgba(255,255,255,0.05)';
pill.style.filter = 'brightness(1.08)';
}
function closeAllRoutes(section) {
if (!section) return;
var details = section.querySelectorAll('.route-detail');
var pills = section.querySelectorAll('.route-pill[data-route]');
for (var i = 0; i < details.length; i++) {
details[i].style.display = 'none';
}
for (var j = 0; j < pills.length; j++) {
resetRoutePill(pills[j]);
}
section.setAttribute('data-open-route', '');
}
window.expandRoute = function (routeId) {
var section = document.getElementById('routes-section');
if (!section) return;
var target = document.getElementById(routeId);
if (!target) return;
var currentOpen = section.getAttribute('data-open-route');
if (currentOpen === routeId) {
closeAllRoutes(section);
return;
}
closeAllRoutes(section);
target.style.display = 'block';
target.style.animation = 'route-in 0.3s ease both';
section.setAttribute('data-open-route', routeId);
var activePill = document.getElementById('pill-' + routeId);
activateRoutePill(activePill);
if (typeof target.scrollIntoView === 'function') {
setTimeout(function () {
target.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
});
}, 80);
}
};
function bindRouteViewer(context) {
var scope = context && context.querySelector ? context : document;
var section = scope.querySelector('#routes-section') || document.getElementById('routes-section');
if (!section) return;
var pills = section.querySelectorAll('.route-pill[data-route]');
for (var i = 0; i < pills.length; i++) {
(function (pill) {
bindActionButton(pill, function () {
expandRoute(this.getAttribute('data-route'));
});
})(pills[i]);
}
var closeButtons = section.querySelectorAll('.route-close[data-route]');
for (var j = 0; j < closeButtons.length; j++) {
(function (closeBtn) {
bindActionButton(closeBtn, function () {
expandRoute(this.getAttribute('data-route'));
});
})(closeButtons[j]);
}
}
/* =========================================================
METHODS
========================================================= */
function resetMethodTab(tab, type) {
if (!tab) return;
tab.style.background = 'transparent';
tab.style.fontWeight = '700';
if (type === 'grind') tab.style.color = 'rgba(249,197,0,0.60)';
if (type === 'market') tab.style.color = 'rgba(0,212,255,0.60)';
if (type === 'passive') tab.style.color = 'rgba(176,108,255,0.60)';
}
function activateMethodTab(tab, type) {
if (!tab) return;
tab.style.fontWeight = '900';
if (type === 'grind') {
tab.style.background = 'linear-gradient(135deg,rgba(249,197,0,0.18),rgba(249,197,0,0.07))';
tab.style.color = '#f9c500';
}
if (type === 'market') {
tab.style.background = 'linear-gradient(135deg,rgba(0,212,255,0.14),rgba(0,212,255,0.05))';
tab.style.color = '#00d4ff';
}
if (type === 'passive') {
tab.style.background = 'linear-gradient(135deg,rgba(176,108,255,0.14),rgba(176,108,255,0.05))';
tab.style.color = '#b06cff';
}
}
window.switchMethod = function (methodId) {
var section = document.getElementById('methods-section');
if (!section) return;
var panels = section.querySelectorAll('.method-panel');
var tabs = section.querySelectorAll('.method-tab[data-method]');
for (var i = 0; i < panels.length; i++) {
panels[i].style.display = 'none';
}
for (var j = 0; j < tabs.length; j++) {
resetMethodTab(tabs[j], tabs[j].getAttribute('data-method'));
}
var activePanel = document.getElementById('method-' + methodId);
if (activePanel) {
activePanel.style.display = 'grid';
activePanel.style.animation = 'method-in 0.3s ease both';
}
var activeTab = document.getElementById('mtab-' + methodId);
activateMethodTab(activeTab, methodId);
section.setAttribute('data-open-method', methodId);
};
function bindMethodViewer(context) {
var scope = context && context.querySelector ? context : document;
var section = scope.querySelector('#methods-section') || document.getElementById('methods-section');
if (!section) return;
var tabs = section.querySelectorAll('.method-tab[data-method]');
for (var i = 0; i < tabs.length; i++) {
(function (tab) {
bindActionButton(tab, function () {
switchMethod(this.getAttribute('data-method'));
});
})(tabs[i]);
}
if (!section.getAttribute('data-open-method')) {
switchMethod('grind');
} else {
switchMethod(section.getAttribute('data-open-method'));
}
}
/* =========================================================
CALCULATOR
========================================================= */
var calcState = {
hours: 2,
booster: false,
rate: 70,
label: 'Rota Mid-Game (70M/hr)',
weeklyTarget: 12000
};
function formatMillions(value) {
var rounded = Math.round(value * 10) / 10;
if (rounded >= 1000) {
var billions = rounded / 1000;
var bText = (Math.round(billions * 10) / 10).toString().replace('.0', '').replace('.', ',');
return bText + 'B z';
}
if (rounded >= 1) {
return rounded.toString().replace('.0', '').replace('.', ',') + 'M z';
}
return Math.round(rounded * 1000) + 'k z';
}
function refreshCalcMethodUI(section) {
if (!section) return;
var labelEl = section.querySelector('#calc-method-label');
var menuEl = section.querySelector('#calc-method-menu');
var options = section.querySelectorAll('.calc-method-option');
if (labelEl) {
labelEl.textContent = calcState.label;
}
for (var i = 0; i < options.length; i++) {
var opt = options[i];
var isActive = String(opt.getAttribute('data-rate')) === String(calcState.rate);
if (isActive) {
opt.style.background = 'rgba(0,212,255,0.12)';
opt.style.borderColor = 'rgba(0,212,255,0.25)';
opt.style.color = '#00d4ff';
opt.style.fontWeight = '800';
} else {
opt.style.background = 'rgba(255,255,255,0.03)';
opt.style.borderColor = 'rgba(255,255,255,0.06)';
opt.style.color = 'rgba(232,238,248,0.82)';
opt.style.fontWeight = '700';
}
}
if (menuEl) {
menuEl.style.display = section.getAttribute('data-method-menu-open') === '1' ? 'block' : 'none';
}
}
function syncCalcStateFromNativeSelect(section) {
if (!section) return;
var select = section.querySelector('#calc-method');
if (!select) return;
calcState.rate = toNumber(select.value, calcState.rate);
if (select.options && select.selectedIndex >= 0) {
calcState.label = select.options[select.selectedIndex].text;
}
}
window.adjustCalc = function (field, delta) {
if (field !== 'hours') return;
calcState.hours = clamp(calcState.hours + delta, 0.5, 24);
updateCalc();
};
window.setBooster = function (enabled) {
calcState.booster = !!enabled;
updateCalc();
};
window.setCalcMethod = function (rate, label) {
calcState.rate = toNumber(rate, calcState.rate);
calcState.label = label || calcState.label;
var section = document.getElementById('calculator-section');
if (section) {
section.setAttribute('data-method-menu-open', '0');
var select = section.querySelector('#calc-method');
if (select) {
select.value = String(calcState.rate);
}
}
updateCalc();
};
window.toggleCalcMethodMenu = function () {
var section = document.getElementById('calculator-section');
if (!section) return;
var isOpen = section.getAttribute('data-method-menu-open') === '1';
section.setAttribute('data-method-menu-open', isOpen ? '0' : '1');
refreshCalcMethodUI(section);
};
window.closeCalcMethodMenu = function () {
var section = document.getElementById('calculator-section');
if (!section) return;
section.setAttribute('data-method-menu-open', '0');
refreshCalcMethodUI(section);
};
window.updateCalc = function () {
var section = document.getElementById('calculator-section');
if (!section) return;
syncCalcStateFromNativeSelect(section);
var hoursEl = document.getElementById('calc-hours');
var resultSession = document.getElementById('result-session');
var resultDay = document.getElementById('result-day');
var resultWeek = document.getElementById('result-week');
var resultPct = document.getElementById('result-pct');
var resultBar = document.getElementById('result-bar');
var boostNo = document.getElementById('boost-no');
var boostYes = document.getElementById('boost-yes');
var effectiveRate = calcState.booster ? calcState.rate * 1.5 : calcState.rate;
var session = calcState.hours * effectiveRate;
var day = session;
var week = day * 7;
var pct = Math.max(0, Math.min(100, Math.round((week / calcState.weeklyTarget) * 100)));
if (hoursEl) {
hoursEl.textContent = calcState.hours % 1 === 0 ? String(calcState.hours) : String(calcState.hours).replace('.', ',');
}
if (resultSession) resultSession.textContent = formatMillions(session);
if (resultDay) resultDay.textContent = formatMillions(day);
if (resultWeek) resultWeek.textContent = formatMillions(week);
if (resultPct) resultPct.textContent = pct + '%';
if (resultBar) resultBar.style.width = pct + '%';
if (boostNo && boostYes) {
if (calcState.booster) {
boostNo.style.background = 'rgba(255,255,255,0.04)';
boostNo.style.borderColor = 'rgba(255,255,255,0.09)';
boostNo.style.color = 'rgba(122,144,176,0.60)';
boostNo.style.fontWeight = '700';
boostYes.style.background = 'rgba(0,212,255,0.15)';
boostYes.style.borderColor = 'rgba(0,212,255,0.30)';
boostYes.style.color = '#00d4ff';
boostYes.style.fontWeight = '800';
} else {
boostNo.style.background = 'rgba(255,61,90,0.15)';
boostNo.style.borderColor = 'rgba(255,61,90,0.30)';
boostNo.style.color = '#ff3d5a';
boostNo.style.fontWeight = '800';
boostYes.style.background = 'rgba(255,255,255,0.04)';
boostYes.style.borderColor = 'rgba(255,255,255,0.09)';
boostYes.style.color = 'rgba(122,144,176,0.60)';
boostYes.style.fontWeight = '700';
}
}
refreshCalcMethodUI(section);
};
function bindCalculator(context) {
var scope = context && context.querySelector ? context : document;
var section = scope.querySelector('#calculator-section') || document.getElementById('calculator-section');
if (!section) return;
var adjusters = section.querySelectorAll('[data-calc-adjust]');
for (var i = 0; i < adjusters.length; i++) {
(function (adjuster) {
bindActionButton(adjuster, function (e) {
e.stopPropagation();
adjustCalc(this.getAttribute('data-calc-adjust'), toNumber(this.getAttribute('data-delta'), 0));
});
})(adjusters[i]);
}
var boosters = section.querySelectorAll('[data-booster]');
for (var j = 0; j < boosters.length; j++) {
(function (booster) {
bindActionButton(booster, function (e) {
e.stopPropagation();
setBooster(this.getAttribute('data-booster') === '1');
});
})(boosters[j]);
}
var methodDisplay = section.querySelector('#calc-method-display');
if (methodDisplay) {
bindActionButton(methodDisplay, function (e) {
e.stopPropagation();
toggleCalcMethodMenu();
});
}
var options = section.querySelectorAll('.calc-method-option');
for (var k = 0; k < options.length; k++) {
(function (option) {
bindActionButton(option, function (e) {
e.stopPropagation();
setCalcMethod(this.getAttribute('data-rate'), this.getAttribute('data-label'));
});
})(options[k]);
}
var nativeSelect = section.querySelector('#calc-method');
if (nativeSelect && nativeSelect.dataset.timeroBound !== '1') {
nativeSelect.dataset.timeroBound = '1';
nativeSelect.addEventListener('change', function () {
updateCalc();
});
}
if (!window.__timeroCalcDocBound) {
window.__timeroCalcDocBound = true;
document.addEventListener('click', function (e) {
var liveSection = document.getElementById('calculator-section');
if (!liveSection) return;
if (!liveSection.contains(e.target)) {
closeCalcMethodMenu();
}
});
}
if (!section.getAttribute('data-method-menu-open')) {
section.setAttribute('data-method-menu-open', '0');
}
updateCalc();
}
/* =========================================================
LOADOUT
========================================================= */
function setLoadoutItemState(item, active) {
if (!item) return;
var check = item.querySelector('.li-check');
if (!check) return;
if (active) {
item.classList.add('is-active');
item.style.background = 'rgba(176,108,255,0.08)';
item.style.borderColor = 'rgba(176,108,255,0.24)';
item.style.boxShadow = '0 0 0 1px rgba(176,108,255,0.05) inset';
check.style.background = 'rgba(176,108,255,0.16)';
check.style.borderColor = 'rgba(176,108,255,0.45)';
check.style.color = '#b06cff';
check.innerHTML = '✓';
} else {
item.classList.remove('is-active');
item.style.background = 'rgba(255,255,255,0.03)';
item.style.borderColor = 'rgba(255,255,255,0.07)';
item.style.boxShadow = 'none';
check.style.background = 'rgba(176,108,255,0.04)';
check.style.borderColor = 'rgba(176,108,255,0.30)';
check.style.color = 'transparent';
check.innerHTML = '';
}
}
function updateLoadoutSummary() {
var section = document.getElementById('loadout-section');
if (!section) return;
var items = section.querySelectorAll('.loadout-item');
var total = 0;
var count = 0;
for (var i = 0; i < items.length; i++) {
if (items[i].classList.contains('is-active')) {
total += toNumber(items[i].getAttribute('data-cost'), 0);
count += 1;
}
}
var totalEl = document.getElementById('loadout-total');
var countEl = document.getElementById('loadout-count');
if (totalEl) totalEl.textContent = total + 'k z';
if (countEl) countEl.textContent = String(count);
}
window.toggleLoadout = function (element) {
if (!element) return;
var active = !element.classList.contains('is-active');
setLoadoutItemState(element, active);
updateLoadoutSummary();
};
window.clearLoadout = function () {
var section = document.getElementById('loadout-section');
if (!section) return;
var items = section.querySelectorAll('.loadout-item');
for (var i = 0; i < items.length; i++) {
setLoadoutItemState(items[i], false);
}
updateLoadoutSummary();
};
function bindLoadout(context) {
var scope = context && context.querySelector ? context : document;
var section = scope.querySelector('#loadout-section') || document.getElementById('loadout-section');
if (!section) return;
var items = section.querySelectorAll('.loadout-item');
for (var i = 0; i < items.length; i++) {
(function (item) {
setLoadoutItemState(item, item.classList.contains('is-active'));
bindActionButton(item, function () {
toggleLoadout(this);
});
})(items[i]);
}
var clearBtn = section.querySelector('.loadout-clear');
if (clearBtn) {
bindActionButton(clearBtn, function () {
clearLoadout();
});
}
updateLoadoutSummary();
}
/* =========================================================
TIMERO CLICKABLE CARDS
========================================================= */
function bindTimeroNavCards(context) {
var scope = context && context.querySelector ? context : document;
var cards = scope.querySelectorAll('.timero-nav-card[data-href]');
for (var i = 0; i < cards.length; i++) {
(function (card) {
if (card.dataset.timeroNavBound === '1') return;
card.dataset.timeroNavBound = '1';
card.setAttribute('role', 'button');
card.setAttribute('tabindex', '0');
card.style.cursor = 'pointer';
card.addEventListener('click', function (e) {
if (e.target.closest('a, button, input, select, textarea')) return;
var href = this.getAttribute('data-href');
var target = this.getAttribute('data-target') || '';
if (!href) return;
if (target === '_blank') {
window.open(href, '_blank', 'noopener');
} else {
window.location.href = href;
}
});
card.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.click();
}
});
})(cards[i]);
}
}
/* =========================================================
MVP GUIDE
========================================================= */
var MVP_TIMER_STORAGE_KEY = 'timero_mvp_timers_v1';
function readStoredMvpTimers() {
try {
var raw = window.localStorage.getItem(MVP_TIMER_STORAGE_KEY);
if (!raw) return [];
var parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : [];
} catch (err) {
return [];
}
}
function writeStoredMvpTimers(list) {
try {
window.localStorage.setItem(MVP_TIMER_STORAGE_KEY, JSON.stringify(list));
} catch (err) {
/* ignore */
}
}
function getRemainingTimerMs(timerObj) {
var now = Date.now();
var endAt = timerObj.killTime + timerObj.respawnMs;
return Math.max(0, endAt - now);
}
function formatTimerMs(ms) {
var totalSec = Math.max(0, Math.floor(ms / 1000));
var hours = Math.floor(totalSec / 3600);
var mins = Math.floor((totalSec % 3600) / 60);
var secs = totalSec % 60;
if (hours > 0) {
return String(hours).padStart(2, '0') + ':' + String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0');
}
return String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0');
}
function removeTimerById(timerId) {
var list = readStoredMvpTimers().filter(function (item) {
return item.id !== timerId;
});
writeStoredMvpTimers(list);
var row = document.getElementById(timerId);
if (row && row.parentNode) {
row.parentNode.removeChild(row);
}
var timerList = document.getElementById('timer-list');
var empty = document.getElementById('timer-empty');
if (timerList && empty && timerList.children.length === 0) {
empty.style.display = '';
}
}
function createTimerRow(timerObj) {
var list = document.getElementById('timer-list');
if (!list) return null;
var existing = document.getElementById(timerObj.id);
if (existing) return existing;
var empty = document.getElementById('timer-empty');
if (empty) empty.style.display = 'none';
var row = document.createElement('div');
row.id = timerObj.id;
row.className = 'mvp-timer-row';
row.style.cssText = 'display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center;padding:13px 16px;border-radius:12px;background:rgba(0,212,255,0.05);border:1px solid rgba(0,212,255,0.14);';
var killTs = new Date(timerObj.killTime);
var h = killTs.getHours().toString().padStart(2, '0');
var m = killTs.getMinutes().toString().padStart(2, '0');
row.innerHTML =
'<div>' +
'<div style="font-size:0.90rem;font-weight:800;color:#fff;margin-bottom:2px;">💀 ' + timerObj.name + '</div>' +
'<div style="font-size:0.70rem;color:rgba(122,144,176,0.55);">Kill registrada às ' + h + ':' + m + ' · Respawn ' + timerObj.respawnMins + 'min</div>' +
'</div>' +
'<div class="mvp-timer-countdown" style="font-size:0.86rem;font-weight:900;color:#00d4ff;min-width:78px;text-align:right;">--:--</div>' +
'<button type="button" class="mvp-timer-remove" style="padding:8px 12px;border-radius:8px;background:rgba(255,61,90,0.10);border:1px solid rgba(255,61,90,0.22);color:#ff3d5a;font-size:0.75rem;font-weight:800;cursor:pointer;font-family:inherit;">Remover</button>';
var removeBtn = row.querySelector('.mvp-timer-remove');
if (removeBtn) {
removeBtn.addEventListener('click', function () {
removeTimerById(timerObj.id);
});
}
list.appendChild(row);
return row;
}
function refreshSingleTimerRow(timerObj) {
var row = document.getElementById(timerObj.id);
if (!row) {
row = createTimerRow(timerObj);
}
if (!row) return;
var countdown = row.querySelector('.mvp-timer-countdown');
var remaining = getRemainingTimerMs(timerObj);
if (countdown) {
if (remaining <= 0) {
countdown.textContent = 'Respawn';
countdown.style.color = '#00ff88';
row.style.borderColor = 'rgba(0,255,136,0.22)';
row.style.background = 'rgba(0,255,136,0.05)';
} else {
countdown.textContent = formatTimerMs(remaining);
countdown.style.color = '#00d4ff';
row.style.borderColor = 'rgba(0,212,255,0.14)';
row.style.background = 'rgba(0,212,255,0.05)';
}
}
}
function refreshAllMvpTimers() {
var list = readStoredMvpTimers();
for (var i = 0; i < list.length; i++) {
refreshSingleTimerRow(list[i]);
}
}
window.toggleBoss = function (card) {
if (!card) return;
var dossier = card.querySelector('.boss-dossier');
var chevron = card.querySelector('.boss-chevron');
if (!dossier) return;
var isOpen = dossier.style.display !== 'none';
dossier.style.display = isOpen ? 'none' : 'block';
if (chevron) {
chevron.textContent = isOpen ? '▼ Dossiê' : '▲ Fechar';
}
card.style.boxShadow = isOpen ? '' : '0 0 32px rgba(255,61,90,0.12)';
};
window.filterTier = function (tier) {
var btns = document.querySelectorAll('.tf-btn');
for (var i = 0; i < btns.length; i++) {
btns[i].style.opacity = '0.45';
btns[i].style.fontWeight = '700';
}
var active = document.getElementById('tf-' + tier);
if (active) {
active.style.opacity = '1';
active.style.fontWeight = '900';
}
var cards = document.querySelectorAll('.boss-card');
var shown = 0;
for (var j = 0; j < cards.length; j++) {
var t = cards[j].dataset.tier;
var show = tier === 'all' || t === tier;
cards[j].style.display = show ? '' : 'none';
if (show) shown++;
}
var label = document.getElementById('boss-count-label');
if (label) {
label.textContent = shown + (shown === 1 ? ' MVP exibido' : ' MVPs exibidos');
}
};
window.sortBosses = function (by) {
var btns = document.querySelectorAll('.sort-btn');
for (var i = 0; i < btns.length; i++) {
btns[i].style.background = 'rgba(255,255,255,0.06)';
btns[i].style.borderColor = 'rgba(255,255,255,0.10)';
btns[i].style.color = 'rgba(232,238,248,0.65)';
}
var active = document.getElementById('sort-' + by);
if (active) {
active.style.background = 'rgba(255,61,90,0.12)';
active.style.borderColor = 'rgba(255,61,90,0.30)';
active.style.color = '#ff3d5a';
}
var grid = document.getElementById('boss-grid');
if (!grid) return;
var cards = Array.prototype.slice.call(grid.querySelectorAll('.boss-card'));
cards.sort(function (a, b) {
if (by === 'danger') return parseInt(b.dataset.danger || '0', 10) - parseInt(a.dataset.danger || '0', 10);
if (by === 'exp') return parseInt(b.dataset.exp || '0', 10) - parseInt(a.dataset.exp || '0', 10);
if (by === 'respawn') return parseInt(a.dataset.respawn || '0', 10) - parseInt(b.dataset.respawn || '0', 10);
return 0;
});
for (var j = 0; j < cards.length; j++) {
grid.appendChild(cards[j]);
}
};
window.toggleClassMvp = function (row) {
if (!row) return;
var detail = row.querySelector('.class-mvp-detail');
var chevron = row.querySelector('.class-chevron');
if (!detail) return;
var open = detail.style.display !== 'none';
detail.style.display = open ? 'none' : 'block';
if (chevron) {
chevron.style.transform = open ? 'rotate(0deg)' : 'rotate(180deg)';
}
};
window.logKill = function (btn, name, respawnMins) {
var killTime = Date.now();
var respawnMs = toNumber(respawnMins, 0) * 60 * 1000;
var timerObj = {
id: 'timer-' + killTime,
name: name || 'MVP',
respawnMins: toNumber(respawnMins, 0),
respawnMs: respawnMs,
killTime: killTime
};
var list = readStoredMvpTimers();
list.unshift(timerObj);
writeStoredMvpTimers(list);
createTimerRow(timerObj);
refreshSingleTimerRow(timerObj);
if (btn) {
btn.style.filter = 'brightness(1.08)';
setTimeout(function () {
btn.style.filter = '';
}, 450);
}
};
function bindMvpGuide(context) {
var scope = context && context.querySelector ? context : document;
var root = scope.querySelector('#mvp-guide-root') || document.getElementById('mvp-guide-root');
if (!root) return;
var tierButtons = root.querySelectorAll('.tf-btn[data-tier]');
for (var i = 0; i < tierButtons.length; i++) {
(function (btn) {
bindActionButton(btn, function () {
filterTier(this.getAttribute('data-tier'));
});
})(tierButtons[i]);
}
var sortButtons = root.querySelectorAll('.sort-btn[data-sort]');
for (var j = 0; j < sortButtons.length; j++) {
(function (btn) {
bindActionButton(btn, function () {
sortBosses(this.getAttribute('data-sort'));
});
})(sortButtons[j]);
}
if (!window.__timeroMvpTimerInterval) {
window.__timeroMvpTimerInterval = window.setInterval(refreshAllMvpTimers, 1000);
}
refreshAllMvpTimers();
var label = document.getElementById('boss-count-label');
if (label && label.textContent.replace(/\s+/g, '') === '') {
filterTier('all');
}
}
/* =========================================================
OPTIONAL GUIDE HELPERS
========================================================= */
function bindPhaseNav(context) {
var scope = context && context.querySelector ? context : document;
var nav = scope.querySelector('#phase-nav');
if (!nav) return;
var links = nav.querySelectorAll('a[href^="#"], a[data-target]');
for (var i = 0; i < links.length; i++) {
(function (link) {
if (link.dataset.timeroPhaseBound === '1') return;
link.dataset.timeroPhaseBound = '1';
link.addEventListener('click', function (e) {
var targetSelector = this.getAttribute('href');
if (!targetSelector || targetSelector === '#') {
targetSelector = this.getAttribute('data-target');
}
if (!targetSelector) return;
var target = document.querySelector(targetSelector);
if (!target) return;
e.preventDefault();
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
});
})(links[i]);
}
}
/* =========================================================
INIT
========================================================= */
function init(context) {
setLogoHref();
ensureFontAwesome();
applyTimeroGuideSkin();
bindMethodViewer(context || document);
bindRouteViewer(context || document);
bindCalculator(context || document);
bindLoadout(context || document);
bindTimeroNavCards(context || document);
bindMvpGuide(context || document);
bindPhaseNav(context || document);
}
$(function () {
init(document);
});
if (mw && mw.hook) {
mw.hook('wikipage.content').add(function ($content) {
init(($content && $content[0]) || document);
});
}
})(jQuery, mediaWiki);