MediaWiki:Timeless.js: Difference between revisions
From Game Wiki - VortanMU
No edit summary Tag: Reverted |
No edit summary Tag: Reverted |
||
| Line 1: | Line 1: | ||
/* | |||
VortanMU - Timeless sidebar behavior (v3) | |||
- Hover to open (desktop) + click to toggle (touch/keyboard) | |||
- Keeps original Timeless structure (portlets) | |||
- Avoids conflicts with any previously-injected mega-menu nodes | |||
Install: paste into MediaWiki:Timeless.js (replace your current sidebar script). | |||
*/ | |||
(function () { | |||
'use strict'; | |||
if (window.VM_TIMELESS_SIDEBAR_V3) return; | |||
window.VM_TIMELESS_SIDEBAR_V3 = true; | |||
function enhanceSidebar() { | |||
var nav = document.getElementById('mw-site-navigation'); | |||
if (!nav) return; | |||
nav.classList.add('vm-nav'); | |||
// Remove any old injected mega-menu nodes (common source of “applies then reverts”) | |||
Array.prototype.forEach.call(nav.querySelectorAll('ul.submenu'), function (el) { | |||
el.parentNode && el.parentNode.removeChild(el); | |||
}); | |||
var portlets = Array.prototype.slice.call( | |||
nav.querySelectorAll('.mw-portlet[role="navigation"]') | |||
); | |||
var hoverCapable = !!(window.matchMedia && window.matchMedia('(hover:hover) and (pointer:fine)').matches); | |||
function setExpanded(p, expanded) { | |||
var h = p.querySelector('h3.vm-portlet__header') || p.querySelector('h3'); | |||
if (h) h.setAttribute('aria-expanded', expanded ? 'true' : 'false'); | |||
} | |||
function closePortlet(p) { | |||
p.classList.remove('is-open'); | |||
setExpanded(p, false); | |||
} | |||
function openPortlet(p) { | |||
// close others (keeps sidebar clean), but never close Wiki tools | |||
portlets.forEach(function (other) { | |||
if (other !== p && other.id !== 'p-tb') closePortlet(other); | |||
}); | |||
p.classList.add('is-open'); | |||
setExpanded(p, true); | |||
} | |||
portlets.forEach(function (p) { | |||
var h3 = p.querySelector('h3'); | |||
var body = p.querySelector('.mw-portlet-body'); | |||
if (!h3 || !body) return; | |||
h3.classList.add('vm-portlet__header'); | |||
body.classList.add('vm-portlet__body'); | |||
// If something hid the original <ul> inline, bring it back | |||
var ul = body.querySelector('ul'); | |||
if (ul && ul.style && ul.style.display === 'none') ul.style.display = ''; | |||
// Wiki tools: always visible | |||
if (p.id === 'p-tb') { | |||
p.classList.add('is-open'); | |||
h3.setAttribute('aria-expanded', 'true'); | |||
return; | |||
} | |||
// default closed | |||
closePortlet(p); | |||
// accessibility + click toggle | |||
h3.setAttribute('role', 'button'); | |||
h3.setAttribute('tabindex', '0'); | |||
h3.setAttribute('aria-expanded', 'false'); | |||
function toggle() { | |||
if (p.classList.contains('is-open')) closePortlet(p); | |||
else openPortlet(p); | |||
} | |||
h3.addEventListener('click', function (e) { | |||
e.preventDefault(); | |||
toggle(); | |||
}); | |||
h3.addEventListener('keydown', function (e) { | |||
if (e.key === 'Enter' || e.key === ' ') { | |||
e.preventDefault(); | |||
toggle(); | |||
} | |||
}); | |||
// Hover open (desktop) | |||
if (hoverCapable) { | |||
var t; | |||
p.addEventListener('mouseenter', function () { | |||
if (t) clearTimeout(t); | |||
openPortlet(p); | |||
}); | |||
p.addEventListener('mouseleave', function () { | |||
if (t) clearTimeout(t); | |||
t = setTimeout(function () { closePortlet(p); }, 180); | |||
}); | |||
} | |||
}); | |||
} | |||
// Run on normal loads + after purge/navigation | |||
if (window.mw && mw.hook) { | |||
mw.hook('wikipage.content').add(enhanceSidebar); | |||
} else if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', enhanceSidebar); | |||
} else { | |||
enhanceSidebar(); | |||
} | |||
})(); | |||
/* ============================== | /* ============================== | ||
VortanMU - Mega flyout (hover + colunas) | VortanMU - Mega flyout (hover + colunas) | ||
Revision as of 09:05, 16 January 2026
/*
VortanMU - Timeless sidebar behavior (v3)
- Hover to open (desktop) + click to toggle (touch/keyboard)
- Keeps original Timeless structure (portlets)
- Avoids conflicts with any previously-injected mega-menu nodes
Install: paste into MediaWiki:Timeless.js (replace your current sidebar script).
*/
(function () {
'use strict';
if (window.VM_TIMELESS_SIDEBAR_V3) return;
window.VM_TIMELESS_SIDEBAR_V3 = true;
function enhanceSidebar() {
var nav = document.getElementById('mw-site-navigation');
if (!nav) return;
nav.classList.add('vm-nav');
// Remove any old injected mega-menu nodes (common source of “applies then reverts”)
Array.prototype.forEach.call(nav.querySelectorAll('ul.submenu'), function (el) {
el.parentNode && el.parentNode.removeChild(el);
});
var portlets = Array.prototype.slice.call(
nav.querySelectorAll('.mw-portlet[role="navigation"]')
);
var hoverCapable = !!(window.matchMedia && window.matchMedia('(hover:hover) and (pointer:fine)').matches);
function setExpanded(p, expanded) {
var h = p.querySelector('h3.vm-portlet__header') || p.querySelector('h3');
if (h) h.setAttribute('aria-expanded', expanded ? 'true' : 'false');
}
function closePortlet(p) {
p.classList.remove('is-open');
setExpanded(p, false);
}
function openPortlet(p) {
// close others (keeps sidebar clean), but never close Wiki tools
portlets.forEach(function (other) {
if (other !== p && other.id !== 'p-tb') closePortlet(other);
});
p.classList.add('is-open');
setExpanded(p, true);
}
portlets.forEach(function (p) {
var h3 = p.querySelector('h3');
var body = p.querySelector('.mw-portlet-body');
if (!h3 || !body) return;
h3.classList.add('vm-portlet__header');
body.classList.add('vm-portlet__body');
// If something hid the original <ul> inline, bring it back
var ul = body.querySelector('ul');
if (ul && ul.style && ul.style.display === 'none') ul.style.display = '';
// Wiki tools: always visible
if (p.id === 'p-tb') {
p.classList.add('is-open');
h3.setAttribute('aria-expanded', 'true');
return;
}
// default closed
closePortlet(p);
// accessibility + click toggle
h3.setAttribute('role', 'button');
h3.setAttribute('tabindex', '0');
h3.setAttribute('aria-expanded', 'false');
function toggle() {
if (p.classList.contains('is-open')) closePortlet(p);
else openPortlet(p);
}
h3.addEventListener('click', function (e) {
e.preventDefault();
toggle();
});
h3.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
toggle();
}
});
// Hover open (desktop)
if (hoverCapable) {
var t;
p.addEventListener('mouseenter', function () {
if (t) clearTimeout(t);
openPortlet(p);
});
p.addEventListener('mouseleave', function () {
if (t) clearTimeout(t);
t = setTimeout(function () { closePortlet(p); }, 180);
});
}
});
}
// Run on normal loads + after purge/navigation
if (window.mw && mw.hook) {
mw.hook('wikipage.content').add(enhanceSidebar);
} else if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', enhanceSidebar);
} else {
enhanceSidebar();
}
})();
/* ==============================
VortanMU - Mega flyout (hover + colunas)
Cole no FINAL do MediaWiki:Timeless.js
============================== */
(function () {
function onReady(fn) {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", fn);
} else {
fn();
}
}
function clamp(n, min, max) {
return Math.max(min, Math.min(max, n));
}
function calcColumns(portletId, itemCount) {
// Regra principal: ~6 itens por coluna
// Mapas é exceção: aceita mais por coluna pra não virar 5+ colunas
var perCol = 6;
if (portletId === "p-Mapas") perCol = 10;
var cols = Math.ceil(itemCount / perCol);
return clamp(cols, 1, 4);
}
onReady(function () {
var nav = document.getElementById("site-navigation");
if (!nav) return;
var portlets = nav.querySelectorAll(".mw-portlet");
portlets.forEach(function (portlet) {
var h3 = portlet.querySelector("h3");
var body = portlet.querySelector(".mw-portlet-body");
if (!h3 || !body) return;
var ul = body.querySelector("ul");
if (!ul) return;
var lis = Array.from(ul.querySelectorAll("li"));
if (!lis.length) return;
// Marca como “mega”
h3.classList.add("has-mega");
// Cria o submenu (se ainda não existe)
var submenu = portlet.querySelector("ul.submenu");
if (!submenu) {
submenu = document.createElement("ul");
submenu.className = "submenu";
portlet.appendChild(submenu);
}
// Reconstrói os itens do flyout (mantém sempre consistente)
submenu.innerHTML = "";
lis.forEach(function (li) {
var a = li.querySelector("a");
if (!a) return;
var li2 = document.createElement("li");
li2.appendChild(a.cloneNode(true));
submenu.appendChild(li2);
});
// Define quantidade de colunas por regra
var count = submenu.querySelectorAll("li").length;
var cols = calcColumns(portlet.id || "", count);
submenu.classList.remove(
"submenu-1-columns",
"submenu-2-columns",
"submenu-3-columns",
"submenu-4-columns"
);
submenu.classList.add("submenu-" + cols + "-columns");
// Esconde UL original (menu vira “botão” + flyout)
ul.style.display = "none";
body.style.display = "none";
// Hover abre/fecha com pequeno delay (pra dar tempo de mover o mouse)
var hideTimer = null;
function show() {
if (hideTimer) clearTimeout(hideTimer);
submenu.style.display = "grid";
}
function hide() {
hideTimer = setTimeout(function () {
submenu.style.display = "none";
}, 140);
}
// Hover desktop
h3.addEventListener("mouseenter", show);
portlet.addEventListener("mouseenter", show);
portlet.addEventListener("mouseleave", hide);
submenu.addEventListener("mouseenter", show);
submenu.addEventListener("mouseleave", hide);
// Clique (fallback)
h3.addEventListener("click", function (e) {
// em desktop isso não atrapalha, e em touch ajuda
e.preventDefault();
var isOpen = submenu.style.display === "grid";
submenu.style.display = isOpen ? "none" : "grid";
});
});
});
})();