MediaWiki:Common.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* MediaWiki:Common.js
* Once Human Guide
*/
mw.loader.using(['mediawiki.util']).then(function () {
$(function () {
/* ============================================================
* TAB SYSTEM
* Wires up .mw-tab-buttons groups so each .mw-tab-btn shows its
* matching .mw-tab-content sibling.
* ============================================================ */
function initTabs() {
document.querySelectorAll('.mw-tab-buttons').forEach(group => {
const buttons = group.querySelectorAll('.mw-tab-btn');
buttons.forEach(btn => {
btn.addEventListener('click', function () {
const tabId = this.getAttribute('data-tab');
// Deactivate buttons in this group only
buttons.forEach(b => b.classList.remove('active'));
this.classList.add('active');
// Hide only the direct-child tab panels
const container = group.parentElement;
container.querySelectorAll(':scope > .mw-tab-content').forEach(c => {
c.classList.remove('active');
});
// Show the target panel and init any dropdowns inside it
const target = container.querySelector('#' + tabId);
if (target) {
target.classList.add('active');
initDropdowns(target);
}
});
});
});
// Auto-click the first tab in each group on load
document.querySelectorAll('.mw-tab-buttons').forEach(group => {
const first = group.querySelector('.mw-tab-btn');
if (first) first.click();
});
}
/* ============================================================
* JSON-DRIVEN DROPDOWN UI
* Renders .mw-dropdown-ui[data-options] containers as a
* label button, sorted list, and detail output panel.
* Supports both the new "lines" array format and the old
* semicolon-separated "content" string format.
* ============================================================ */
function initDropdowns(scope) {
scope.querySelectorAll('.mw-dropdown-ui[data-options]').forEach(container => {
if (container.dataset.rendered === 'true') return;
let data;
try {
data = JSON.parse(container.dataset.options);
} catch (e) {
console.error('Bad dropdown JSON:', e);
return;
}
container.innerHTML = '';
const btn = document.createElement('div');
btn.className = 'mod-dropdown-btn';
btn.textContent = container.dataset.label || 'Select One';
const list = document.createElement('div');
list.className = 'mod-dropdown-list';
const output = document.createElement('div');
output.className = 'mw-dropdown-output';
output.innerHTML = '<div class="mw-ui-placeholder">Select something to see details</div>';
Object.values(data)
.sort((a, b) => a.label.localeCompare(b.label))
.forEach(item => {
const option = document.createElement('div');
option.className = 'mod-dropdown-item';
option.textContent = item.label;
option.onclick = () => {
btn.textContent = item.label;
list.style.display = 'none';
let lines = [];
if (item.lines && Array.isArray(item.lines)) {
lines = item.lines;
} else if (item.content) {
lines = item.content.split(';').map(s => s.trim()).filter(Boolean);
}
output.innerHTML =
`<div class="mw-ui-title">${item.label}</div>` +
lines.map(line => `<div class="mw-ui-line">${line}</div>`).join('');
};
list.appendChild(option);
});
// Toggle list open/closed
btn.onclick = (e) => {
e.stopPropagation();
list.style.display = list.style.display === 'block' ? 'none' : 'block';
};
// Close when clicking outside
document.addEventListener('click', () => {
list.style.display = 'none';
});
container.appendChild(btn);
container.appendChild(list);
container.appendChild(output);
container.dataset.rendered = 'true';
});
}
/* ============================================================
* EXCLUSIVE COLLAPSIBLE DROPDOWNS (Loot Crate pages)
* When one item's image is opened, all others in the group
* are forced to collapse so only one is visible at a time.
* ============================================================ */
function initExclusiveCollapsibles() {
const crateKeys = [
'astralnexus', 'bloomingvows', 'celestialreverie', 'crimsonascent',
'echovesperine', 'eclipsecinder', 'etherealtide', 'goldensurge',
'luminoadventure', 'phazeblitz', 'thunderoverlord', 'wishland', 'zerooverture'
];
const outerKey = 'lootcrate';
const selector = crateKeys.map(k => '.mw-customtoggle-' + k).join(', ');
let suppress = false;
$(selector).on('click', function () {
if (suppress) return;
const match = this.className.match(/mw-customtoggle-(\S+)/);
if (!match) return;
const clickedKey = match[1];
// Let MediaWiki's own toggle handler finish, then trigger
// clicks on the other toggles so MW collapses them itself.
setTimeout(() => {
suppress = true;
// Close other item images
crateKeys.forEach(k => {
if (k === clickedKey) return;
const $el = $('#mw-customcollapsible-' + k);
if ($el.length && !$el.hasClass('mw-collapsed')) {
$('.mw-customtoggle-' + k).first().trigger('click');
}
});
// Auto-close the outer dropdown after a pick
const $outer = $('#mw-customcollapsible-' + outerKey);
if ($outer.length && !$outer.hasClass('mw-collapsed')) {
$('.mw-customtoggle-' + outerKey).first().trigger('click');
}
suppress = false;
}, 50);
});
}
/* ============================================================
* DISCORD TAB OVERRIDE
* Repurposes the page's "Discussion" tab as a Discord invite.
* ============================================================ */
function initDiscordTab() {
const discussionTab = document.querySelector('#ca-talk a');
if (discussionTab) {
discussionTab.href = 'https://discord.com/invite/FZtkXeGeUA';
discussionTab.target = '_blank';
discussionTab.textContent = 'Discord';
}
}
/* ============================================================
* BOOT
* ============================================================ */
initTabs();
initExclusiveCollapsibles();
initDiscordTab();
});
});