MediaWiki:Common.js: Difference between revisions
Appearance
Adiciona o seletor de habilidade das fichas de Campeao |
Barra de filtros das quests montada pelo JS: o sanitizador escapa input e select no wikitext |
||
| Line 1: | Line 1: | ||
(function () { | |||
function grupo(rotulo, conteudo) { | |||
var g = document.createElement('div'); | |||
g.className = 'pxgq-filter-group'; | |||
var l = document.createElement('label'); | |||
l.textContent = rotulo; | |||
g.appendChild(l); | |||
g.appendChild(conteudo); | |||
return g; | |||
} | |||
function montarFiltros(cards) { | |||
var regioes = []; | |||
var contas = []; | |||
var min = 9999; | |||
var max = 0; | |||
cards.forEach(function (c) { | |||
var r = c.getAttribute('data-region'); | |||
var a = c.getAttribute('data-account'); | |||
if (r && regioes.indexOf(r) === -1) { regioes.push(r); } | |||
if (a && contas.indexOf(a) === -1) { contas.push(a); } | |||
min = Math.min(min, parseInt(c.getAttribute('data-level-min') || '0', 10)); | |||
max = Math.max(max, parseInt(c.getAttribute('data-level-max') || '0', 10)); | |||
}); | |||
regioes.sort(); | |||
contas.sort(); | |||
var barra = document.createElement('div'); | |||
barra.className = 'pxgq-filters'; | |||
var busca = document.createElement('input'); | |||
busca.className = 'js-pxgq-search'; | |||
busca.type = 'search'; | |||
busca.placeholder = 'Nome, NPC, recompensa...'; | |||
barra.appendChild(grupo('Buscar', busca)); | |||
var sel = document.createElement('select'); | |||
sel.className = 'js-pxgq-region'; | |||
var todas = document.createElement('option'); | |||
todas.value = 'all'; | |||
todas.textContent = 'Todas as regioes'; | |||
sel.appendChild(todas); | |||
regioes.forEach(function (r) { | |||
var o = document.createElement('option'); | |||
o.value = r; | |||
o.textContent = r; | |||
sel.appendChild(o); | |||
}); | |||
barra.appendChild(grupo('Regiao', sel)); | |||
var linha = document.createElement('div'); | |||
linha.className = 'pxgq-level-row'; | |||
var de = document.createElement('input'); | |||
de.className = 'js-pxgq-min'; | |||
de.type = 'number'; | |||
de.placeholder = 'de ' + min; | |||
var ate = document.createElement('input'); | |||
ate.className = 'js-pxgq-max'; | |||
ate.type = 'number'; | |||
ate.placeholder = 'ate ' + max; | |||
linha.appendChild(de); | |||
linha.appendChild(ate); | |||
barra.appendChild(grupo('Nivel', linha)); | |||
var toggle = document.createElement('div'); | |||
toggle.className = 'pxgq-account-toggle'; | |||
[['all', 'Todas']].concat(contas.map(function (c) { return [c, c]; })) | |||
.forEach(function (par, i) { | |||
var b = document.createElement('span'); | |||
b.className = 'js-pxgq-account' + (i === 0 ? ' is-active' : ''); | |||
b.setAttribute('role', 'button'); | |||
b.setAttribute('tabindex', '0'); | |||
b.setAttribute('data-account', par[0]); | |||
b.textContent = par[1]; | |||
toggle.appendChild(b); | |||
}); | |||
barra.appendChild(grupo('Tipo de conta', toggle)); | |||
return barra; | |||
} | |||
window.montarFiltros = montarFiltros; | |||
}()); | |||
(function () { | (function () { | ||
function initQuestPage() { | function initQuestPage() { | ||
| Line 4: | Line 88: | ||
if (!cards.length) { | if (!cards.length) { | ||
return; | return; | ||
} | |||
// A barra de filtros e montada aqui, e nao escrita no wikitext, porque o | |||
// sanitizador do MediaWiki escapa <input>, <select> e <option>. Como ela | |||
// nasce dos data-* dos cards, as regioes e a faixa de nivel acompanham | |||
// sozinhas qualquer quest que for acrescentada a pagina. | |||
var grade = cards[0].parentNode; | |||
if (!document.querySelector('.js-pxgq-search')) { | |||
grade.parentNode.insertBefore(montarFiltros(cards), grade); | |||
} | } | ||
Revision as of 10:25, 14 September 2026
(function () {
function grupo(rotulo, conteudo) {
var g = document.createElement('div');
g.className = 'pxgq-filter-group';
var l = document.createElement('label');
l.textContent = rotulo;
g.appendChild(l);
g.appendChild(conteudo);
return g;
}
function montarFiltros(cards) {
var regioes = [];
var contas = [];
var min = 9999;
var max = 0;
cards.forEach(function (c) {
var r = c.getAttribute('data-region');
var a = c.getAttribute('data-account');
if (r && regioes.indexOf(r) === -1) { regioes.push(r); }
if (a && contas.indexOf(a) === -1) { contas.push(a); }
min = Math.min(min, parseInt(c.getAttribute('data-level-min') || '0', 10));
max = Math.max(max, parseInt(c.getAttribute('data-level-max') || '0', 10));
});
regioes.sort();
contas.sort();
var barra = document.createElement('div');
barra.className = 'pxgq-filters';
var busca = document.createElement('input');
busca.className = 'js-pxgq-search';
busca.type = 'search';
busca.placeholder = 'Nome, NPC, recompensa...';
barra.appendChild(grupo('Buscar', busca));
var sel = document.createElement('select');
sel.className = 'js-pxgq-region';
var todas = document.createElement('option');
todas.value = 'all';
todas.textContent = 'Todas as regioes';
sel.appendChild(todas);
regioes.forEach(function (r) {
var o = document.createElement('option');
o.value = r;
o.textContent = r;
sel.appendChild(o);
});
barra.appendChild(grupo('Regiao', sel));
var linha = document.createElement('div');
linha.className = 'pxgq-level-row';
var de = document.createElement('input');
de.className = 'js-pxgq-min';
de.type = 'number';
de.placeholder = 'de ' + min;
var ate = document.createElement('input');
ate.className = 'js-pxgq-max';
ate.type = 'number';
ate.placeholder = 'ate ' + max;
linha.appendChild(de);
linha.appendChild(ate);
barra.appendChild(grupo('Nivel', linha));
var toggle = document.createElement('div');
toggle.className = 'pxgq-account-toggle';
[['all', 'Todas']].concat(contas.map(function (c) { return [c, c]; }))
.forEach(function (par, i) {
var b = document.createElement('span');
b.className = 'js-pxgq-account' + (i === 0 ? ' is-active' : '');
b.setAttribute('role', 'button');
b.setAttribute('tabindex', '0');
b.setAttribute('data-account', par[0]);
b.textContent = par[1];
toggle.appendChild(b);
});
barra.appendChild(grupo('Tipo de conta', toggle));
return barra;
}
window.montarFiltros = montarFiltros;
}());
(function () {
function initQuestPage() {
var cards = Array.prototype.slice.call(document.querySelectorAll('.pxgq-card'));
if (!cards.length) {
return;
}
// A barra de filtros e montada aqui, e nao escrita no wikitext, porque o
// sanitizador do MediaWiki escapa <input>, <select> e <option>. Como ela
// nasce dos data-* dos cards, as regioes e a faixa de nivel acompanham
// sozinhas qualquer quest que for acrescentada a pagina.
var grade = cards[0].parentNode;
if (!document.querySelector('.js-pxgq-search')) {
grade.parentNode.insertBefore(montarFiltros(cards), grade);
}
var searchInput = document.querySelector('.js-pxgq-search');
var regionSelect = document.querySelector('.js-pxgq-region');
var minInput = document.querySelector('.js-pxgq-min');
var maxInput = document.querySelector('.js-pxgq-max');
var accountButtons = Array.prototype.slice.call(document.querySelectorAll('.js-pxgq-account'));
var currentAccount = 'all';
function normalize(value) {
return (value || '').toLowerCase().trim();
}
function applyFilters() {
var search = normalize(searchInput && searchInput.value);
var region = normalize(regionSelect && regionSelect.value);
var min = parseInt((minInput && minInput.value) || '0', 10);
var max = parseInt((maxInput && maxInput.value) || '9999', 10);
cards.forEach(function (card) {
var cardSearch = normalize(card.getAttribute('data-search'));
var cardRegion = normalize(card.getAttribute('data-region'));
var cardAccount = normalize(card.getAttribute('data-account'));
var cardMin = parseInt(card.getAttribute('data-level-min') || '0', 10);
var cardMax = parseInt(card.getAttribute('data-level-max') || '9999', 10);
var okSearch = !search || cardSearch.indexOf(search) !== -1;
var okRegion = region === 'all' || !region || cardRegion === region;
var okAccount = currentAccount === 'all' || cardAccount === currentAccount;
var okLevel = cardMax >= min && cardMin <= max;
card.classList.toggle('is-hidden', !(okSearch && okRegion && okAccount && okLevel));
});
}
if (searchInput) {
searchInput.addEventListener('input', applyFilters);
}
if (regionSelect) {
regionSelect.addEventListener('change', applyFilters);
}
if (minInput) {
minInput.addEventListener('input', applyFilters);
}
if (maxInput) {
maxInput.addEventListener('input', applyFilters);
}
accountButtons.forEach(function (button) {
button.addEventListener('click', function () {
accountButtons.forEach(function (btn) {
btn.classList.remove('is-active');
});
button.classList.add('is-active');
currentAccount = button.getAttribute('data-account') || 'all';
applyFilters();
});
});
document.querySelectorAll('.js-pxgq-spoiler').forEach(function (button) {
button.addEventListener('click', function () {
var card = button.closest('.pxgq-card');
if (!card) {
return;
}
var spoiler = card.querySelector('.pxgq-card-spoiler');
if (!spoiler) {
return;
}
var isHidden = spoiler.hasAttribute('hidden');
if (isHidden) {
spoiler.removeAttribute('hidden');
button.textContent = 'Ocultar spoiler';
} else {
spoiler.setAttribute('hidden', 'hidden');
button.textContent = 'Ver spoiler';
}
});
});
applyFilters();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initQuestPage);
} else {
initQuestPage();
}
}());
/* =========================================================================
Fichas de Campeao do Champion's Path (Module:Campeao)
Duas coisas: as abas de dificuldade e o alternador de tema.
Tudo degrada bem sem JS: sem script, a ficha mostra a dificuldade Normal
e o botao de tema permanece oculto.
========================================================================= */
(function () {
'use strict';
var CHAVE_TEMA = 'pst-cp-tema';
function trocarDificuldade(ficha, dif) {
var i;
var abas = ficha.querySelectorAll('.cp-tab');
for (i = 0; i < abas.length; i++) {
if (abas[i].getAttribute('data-dif') === dif) {
abas[i].classList.add('is-active');
} else {
abas[i].classList.remove('is-active');
}
}
var blocos = ficha.querySelectorAll('[data-dif]');
for (i = 0; i < blocos.length; i++) {
if (blocos[i].classList.contains('cp-tab')) continue;
if (blocos[i].getAttribute('data-dif') === dif) {
blocos[i].classList.remove('is-hidden');
} else {
blocos[i].classList.add('is-hidden');
}
}
}
function aplicarTema(ficha, tema) {
ficha.setAttribute('data-tema', tema);
var botao = ficha.querySelector('[data-cp-tema]');
if (botao) {
botao.textContent = tema === 'escuro' ? 'Modo claro' : 'Modo escuro';
}
}
// Seletor de habilidade: troca o detalhe exibido dentro de um grupo.
function ligarSeletorDeHabilidade(grupo) {
var picks = grupo.querySelectorAll('.cp-skill-pick');
for (var i = 0; i < picks.length; i++) {
picks[i].addEventListener('click', function () {
var alvo = this.getAttribute('data-skill');
var j;
for (j = 0; j < picks.length; j++) {
if (picks[j].getAttribute('data-skill') === alvo) {
picks[j].classList.add('is-active');
} else {
picks[j].classList.remove('is-active');
}
}
var dets = grupo.querySelectorAll('.cp-skill-detail');
for (j = 0; j < dets.length; j++) {
if (dets[j].getAttribute('data-skill') === alvo) {
dets[j].classList.remove('is-hidden');
} else {
dets[j].classList.add('is-hidden');
}
}
});
}
}
function iniciar(ficha) {
// Seletor de habilidade, um por dificuldade
var grupos = ficha.querySelectorAll('.cp-skills');
for (var g = 0; g < grupos.length; g++) {
ligarSeletorDeHabilidade(grupos[g]);
}
// Abas de dificuldade
var abas = ficha.querySelectorAll('.cp-tab');
for (var i = 0; i < abas.length; i++) {
abas[i].addEventListener('click', function () {
trocarDificuldade(ficha, this.getAttribute('data-dif'));
});
}
// Alternador de tema: so aparece se o JS rodou
var botao = ficha.querySelector('[data-cp-tema]');
if (botao) {
botao.style.display = '';
var salvo = 'claro';
try {
salvo = window.localStorage.getItem(CHAVE_TEMA) || 'claro';
} catch (e) {}
aplicarTema(ficha, salvo);
botao.addEventListener('click', function () {
var novo = ficha.getAttribute('data-tema') === 'escuro' ? 'claro' : 'escuro';
aplicarTema(ficha, novo);
try {
window.localStorage.setItem(CHAVE_TEMA, novo);
} catch (e) {}
});
}
}
function pronto() {
var fichas = document.querySelectorAll('.cp-boss');
for (var i = 0; i < fichas.length; i++) {
iniciar(fichas[i]);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', pronto);
} else {
pronto();
}
}());