MediaWiki:ShowFirstTabs.js
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 Tab Navigation Module
* Extracted from Common copy.js for modularity and customization
* Handles tab switching functionality with smooth scrolling support
* Enhanced to work with both MediaWiki tabs and nested tabs
*/
(function() {
'use strict';
const CONFIG = {
SELECTORS: {
TAB_CONTENT: '.tab-content',
NAV_TAB: '.nav-tab, .nav-tab-fgod',
NESTED_TAB: '.nested-tab',
NESTED_CONTENT: '.nested-content'
},
CLASSES: {
ACTIVE: 'active'
},
DELAYS: {
SCROLL_DELAY: 100
}
};
function safeGetElementById(id) {
try { return document.getElementById(id); } catch (e) { return null; }
}
function safeQuerySelectorAll(selector, context = document) {
try { return context.querySelectorAll(selector); } catch (e) { return []; }
}
function safeQuerySelector(selector, context = document) {
try { return context.querySelector(selector); } catch (e) { return null; }
}
const TabNavigation = {
showTab: function(tabId, tabElement) {
if (!tabId) return;
const allNested = document.querySelectorAll(CONFIG.SELECTORS.NESTED_CONTENT);
allNested.forEach(c => c.classList.remove(CONFIG.CLASSES.ACTIVE));
const contents = safeQuerySelectorAll(CONFIG.SELECTORS.TAB_CONTENT);
contents.forEach(c => c.classList.remove(CONFIG.CLASSES.ACTIVE));
const tabs = safeQuerySelectorAll(CONFIG.SELECTORS.NAV_TAB);
tabs.forEach(t => t.classList.remove(CONFIG.CLASSES.ACTIVE));
const target = safeGetElementById(tabId);
if (target) {
target.classList.add(CONFIG.CLASSES.ACTIVE);
setTimeout(() => {
const first = target.querySelector(CONFIG.SELECTORS.NESTED_TAB + '[data-tab]');
if (first) {
const nid = first.getAttribute('data-tab');
if (nid) TabNavigation.showNestedTab(nid, first);
}
}, 50);
}
if (tabElement) tabElement.classList.add(CONFIG.CLASSES.ACTIVE);
},
showNestedTab: function(tabId, tabElement) {
if (!tabId) return;
const container = tabElement
? (tabElement.closest('.nested-container, .token-card')
|| tabElement.closest('.tokens-section')
|| tabElement.closest('.tab-content')
|| document)
: document;
const nestedContents = container.querySelectorAll(CONFIG.SELECTORS.NESTED_CONTENT);
nestedContents.forEach(c => c.classList.remove(CONFIG.CLASSES.ACTIVE));
const nestedTabs = container.querySelectorAll(CONFIG.SELECTORS.NESTED_TAB);
nestedTabs.forEach(t => t.classList.remove(CONFIG.CLASSES.ACTIVE));
let target = null;
if (container && container.querySelector) target = container.querySelector('#' + tabId);
if (!target) target = safeGetElementById(tabId);
if (target) target.classList.add(CONFIG.CLASSES.ACTIVE);
if (tabElement) tabElement.classList.add(CONFIG.CLASSES.ACTIVE);
},
handleTabClick: function(event) {
const tab = event.target.closest('.nav-tab[data-tab], .nav-tab-fgod[data-tab]');
if (!tab) return;
event.preventDefault();
const targetId = tab.getAttribute('data-tab');
if (targetId) TabNavigation.showTab(targetId, tab);
},
handleNestedTabClick: function(event) {
const nestedTab = event.target.closest('.nested-tab[data-tab]');
if (!nestedTab) return;
event.preventDefault();
const targetId = nestedTab.getAttribute('data-tab');
if (targetId) TabNavigation.showNestedTab(targetId, nestedTab);
},
handleSpecialTabNavigation: function(event) {
const trigger = event.target.closest('[data-tab-trigger]');
if (!trigger) return;
event.preventDefault();
const tabData = trigger.getAttribute('data-tab-trigger');
const buttonId = trigger.getAttribute('data-tab-button');
const href = trigger.getAttribute('href');
const scrollToAttr = trigger.getAttribute('data-scroll-to');
let scrollTargetSelector = null;
if (scrollToAttr && scrollToAttr.trim()) scrollTargetSelector = '#' + scrollToAttr.replace(/^#/, '');
else if (href && href.charAt(0) === '#') scrollTargetSelector = href;
if (tabData && buttonId) {
const btn = safeGetElementById(buttonId);
if (btn) {
TabNavigation.showTab(tabData, btn);
if (scrollTargetSelector) {
const target = safeQuerySelector(scrollTargetSelector);
if (target) setTimeout(() => target.scrollIntoView({ behavior: 'smooth' }), CONFIG.DELAYS.SCROLL_DELAY);
}
}
}
},
init: function() {
document.addEventListener('click', this.handleTabClick, false);
document.addEventListener('click', this.handleNestedTabClick, false);
document.addEventListener('click', this.handleSpecialTabNavigation, false);
window.showTab = this.showTab;
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => TabNavigation.init());
} else {
TabNavigation.init();
}
})();