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.
/* Any JavaScript here will be loaded for all users on every page load. */
/* DRUID */
$(function () {
$(".druid-main-images-label").off("click");
$(".druid-main-images-label").click(function () {
var $parent = $(this).closest(".druid-container");
$parent.find(".druid-toggleable").removeClass("focused");
var i = $(this).attr("data-druid");
$parent.find(".druid-toggleable[data-druid=" + i + "]").addClass("focused");
});
$(".druid-collapsible").off("click");
$(".druid-collapsible").click(function () {
var kind = $(this).attr("data-druid-section");
$(this).toggleClass("druid-collapsible-collapsed");
$(this)
.closest(".druid-container")
.find("[data-druid-section-row=" + kind + "]")
.toggleClass("druid-collapsed");
});
});
/* End DRUID */
/* [[Template:Spoiler]] */
$(function () {
$('.spoiler-content')
.off('click') // in case this code is loaded twice
.on('click', function(e){
$(this).toggleClass('show');
}).find('a').on('click', function(e){
e.stopPropagation();
});
});
/* End Template:Spoiler */
/* Link to imported modules from Lua code */
$(function() {
var config = mw.config.get([
'wgCanonicalNamespace',
'wgFormattedNamespaces'
]);
if (config.wgCanonicalNamespace !== 'Module') {
return;
}
var localizedNamespace = config.wgFormattedNamespaces[828];
$('.s1, .s2, .s').each(function() {
var $this = $(this);
var html = $this.html();
var quote = html[0];
var isLongStringQuote = quote === '[';
var quoteRE = new RegExp('^\\' + quote + '|\\' + quote + '$', 'g');
if (isLongStringQuote) {
quoteRE = /^\[\[|\]\]$/g;
}
var name = html.replace(quoteRE, '');
var isEnglishPrefix = name.startsWith('Module:');
var isLocalizedPrefix = name.startsWith(localizedNamespace + ':');
var isDevPrefix = name.startsWith('Dev:');
if (isEnglishPrefix || isLocalizedPrefix || isDevPrefix) {
var attrs = {
href: mw.util.getUrl(name)
};
if (isDevPrefix) {
attrs.href = 'https://commons.wiki.gg/wiki/Module:' + mw.util.wikiUrlencode(name.replace('Dev:', ''));
attrs.target = '_blank';
attrs.rel = 'noopener';
}
var link = mw.html.element('a', attrs, name);
var str = quote + link + quote;
if (isLongStringQuote) {
str = '[[' + link + ']]';
}
$this.html(str);
}
});
});
/* dynamic gif displayer ONLY TOUCH IF YOU KNOW WHAT YOU ARE DOING */
(function() {
'use strict';
console.log('Dynamic GIF Displayer: Script loading...');
// Configuration
const CONFIG = {
containerClass: 'dynamic-gif-container',
displayClass: 'gif-display-area',
autoExpand: true,
expandDelay: 200,
collapseDelay: 1000
};
let expandTimer = null;
let collapseTimer = null;
let currentGif = null;
function safeCreateError(message) {
const div = document.createElement('div');
div.className = 'gif-error';
div.textContent = message;
return div;
}
function safeCreatePlaceholder(message) {
const div = document.createElement('div');
div.className = 'gif-placeholder';
div.textContent = message;
return div;
}
function init() {
console.log('Dynamic GIF Displayer: Initializing...');
const containers = document.querySelectorAll('.' + CONFIG.containerClass);
console.log('Dynamic GIF Displayer: Found', containers.length, 'containers');
containers.forEach(container => {
console.log('Dynamic GIF Displayer: Setting up container', container.id);
setupContainer(container);
attachTooltipListeners(container);
});
}
function setupContainer(container) {
const displayArea = container.querySelector('.' + CONFIG.displayClass);
if (!displayArea) {
console.error('Dynamic GIF Displayer: No display area found');
return;
}
displayArea.addEventListener('mouseenter', () => {
clearTimeout(collapseTimer);
});
displayArea.addEventListener('mouseleave', () => {
scheduleCollapse(container);
});
}
function attachTooltipListeners(container) {
console.log('Dynamic GIF Displayer: Attaching tooltip listeners...');
const gifMap = buildGifMap(container);
console.log('Dynamic GIF Displayer: GIF map', gifMap);
const tooltips = document.querySelectorAll('.advanced-tooltip');
console.log('Dynamic GIF Displayer: Found', tooltips.length, 'tooltips');
tooltips.forEach((tooltip) => {
const skillTitle = tooltip.querySelector('.skill-title');
if (!skillTitle) return;
const skillName = skillTitle.textContent.trim();
const gifUrl = gifMap[skillName];
console.log('Dynamic GIF Displayer: Processing tooltip:', skillName, 'GIF:', gifUrl);
if (gifUrl) {
tooltip.removeEventListener('mouseenter', tooltip._gifHoverHandler);
tooltip.removeEventListener('mouseleave', tooltip._gifLeaveHandler);
tooltip._gifHoverHandler = () => handleTooltipHover(container, gifUrl, skillName);
tooltip._gifLeaveHandler = () => scheduleCollapse(container);
tooltip.addEventListener('mouseenter', tooltip._gifHoverHandler);
tooltip.addEventListener('mouseleave', tooltip._gifLeaveHandler);
console.log('Dynamic GIF Displayer: Attached listeners to', skillName);
}
});
}
function buildGifMap(container) {
const gifMap = {};
const listData = container.getAttribute('data-gif-list');
if (!listData) {
console.error('Dynamic GIF Displayer: No data-gif-list attribute found');
return gifMap;
}
console.log('Dynamic GIF Displayer: Raw list data:', listData);
const entries = listData.split(';').filter(e => e.trim());
console.log('Dynamic GIF Displayer: Found', entries.length, 'entries');
entries.forEach(entry => {
const parts = entry.split(':');
if (parts.length >= 2) {
const skillName = parts[0].trim();
const gifFile = parts.slice(1).join(':').trim();
if (skillName && gifFile) {
let gifUrl;
if (typeof mw !== 'undefined' && mw.config) {
const scriptPath = mw.config.get('wgScriptPath') || '';
gifUrl = scriptPath + '/index.php?title=Special:Redirect/file/' + encodeURIComponent(gifFile);
} else {
gifUrl = '/index.php?title=Special:Redirect/file/' + encodeURIComponent(gifFile);
}
gifMap[skillName] = gifUrl;
console.log('Dynamic GIF Displayer: Mapped "' + skillName + '" to', gifUrl);
}
}
});
return gifMap;
}
function handleTooltipHover(container, gifUrl, skillName) {
console.log('Dynamic GIF Displayer: Hovering', skillName);
clearTimeout(collapseTimer);
clearTimeout(expandTimer);
expandTimer = setTimeout(() => {
showGif(container, gifUrl, skillName);
}, CONFIG.expandDelay);
}
function showGif(container, gifUrl, skillName) {
console.log('Dynamic GIF Displayer: Showing GIF for', skillName, gifUrl);
const displayArea = container.querySelector('.' + CONFIG.displayClass);
if (!displayArea) return;
const gifSize = container.getAttribute('data-gif-size') || '400';
if (!container.classList.contains('expanded')) {
container.classList.add('expanded');
console.log('Dynamic GIF Displayer: Expanded container');
}
if (currentGif !== gifUrl) {
const imgContainer = displayArea.querySelector('.gif-image-container');
const caption = displayArea.querySelector('.gif-caption');
if (imgContainer) {
const placeholder = imgContainer.querySelector('.gif-placeholder');
if (placeholder) {
placeholder.remove();
}
imgContainer.style.height = gifSize + 'px';
imgContainer.style.minHeight = gifSize + 'px';
const gifFilename = gifUrl.split('/').pop();
if (gifFilename.toLowerCase() === 'blank' || gifFilename.toLowerCase() === 'blank.gif') {
imgContainer.innerHTML = '';
imgContainer.appendChild(safeCreatePlaceholder('This node does not require a GIF due to its simplicity.'));
imgContainer.classList.remove('loading');
} else {
imgContainer.classList.add('loading');
const img = document.createElement('img');
img.src = gifUrl;
img.alt = skillName;
img.style.maxHeight = gifSize + 'px';
img.onload = () => {
imgContainer.innerHTML = '';
imgContainer.appendChild(img);
imgContainer.classList.remove('loading');
console.log('Dynamic GIF Displayer: GIF loaded successfully');
};
img.onerror = () => {
imgContainer.innerHTML = '';
imgContainer.appendChild(safeCreateError('GIF not found: ' + gifUrl));
imgContainer.classList.remove('loading');
console.error('Dynamic GIF Displayer: Failed to load GIF', gifUrl);
};
}
}
if (caption) {
caption.textContent = skillName;
caption.style.display = 'block';
}
currentGif = gifUrl;
}
}
function scheduleCollapse(container) {
// Keep the most recent GIF displayed instead of clearing it
// GIF will only change when a different skill node is hovered
clearTimeout(collapseTimer);
console.log('Dynamic GIF Displayer: Keeping current GIF displayed');
}
window.toggleGifDisplay = function(containerId) {
console.log('Dynamic GIF Displayer: Toggle clicked for', containerId);
const container = document.getElementById(containerId);
if (!container) {
console.error('Dynamic GIF Displayer: Container not found', containerId);
return;
}
clearTimeout(collapseTimer);
if (container.style.display === 'none') {
container.style.display = 'block';
} else {
container.style.display = 'none';
}
// Only clear the GIF when manually toggling the display off
if (container.style.display === 'none') {
const displayArea = container.querySelector('.' + CONFIG.displayClass);
if (displayArea) {
const imgContainer = displayArea.querySelector('.gif-image-container');
const caption = displayArea.querySelector('.gif-caption');
if (imgContainer) {
imgContainer.innerHTML = '';
imgContainer.appendChild(safeCreatePlaceholder('Hover over a skill node to see its demonstration'));
imgContainer.style.height = '';
imgContainer.style.minHeight = '';
}
if (caption) {
caption.textContent = '';
caption.style.display = 'none';
}
}
container.classList.remove('expanded');
currentGif = null;
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.addEventListener('load', init);
if (typeof mw !== 'undefined' && mw.hook) {
mw.hook('wikipage.content').add(init);
}
const observer = new MutationObserver(function(mutations) {
let shouldReinit = false;
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1 && (
node.classList && node.classList.contains('advanced-tooltip') ||
node.querySelector && node.querySelector('.advanced-tooltip')
)) {
shouldReinit = true;
}
});
}
});
if (shouldReinit) {
console.log('Dynamic GIF Displayer: Content changed, reinitializing...');
setTimeout(init, 100);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('Dynamic GIF Displayer: Script loaded');
})();
/**
* Tab-Based GIF Display for Telos Realms Wiki
* Displays GIFs using clickable tabs instead of tooltip hover
* FIXED VERSION - Better initialization and error handling
*/
(function() {
'use strict';
console.log('Tab GIF Display: Script loading...');
// Configuration
const CONFIG = {
containerClass: 'tab-gif-container',
displayClass: 'tab-gif-display-area',
tabsClass: 'tab-gif-tabs',
tabClass: 'tab-gif-tab',
activeTabClass: 'tab-gif-active'
};
let currentContainers = new Map();
let initAttempts = 0;
const MAX_INIT_ATTEMPTS = 5;
function safeCreateError(message) {
const div = document.createElement('div');
div.className = 'gif-error';
div.textContent = message;
return div;
}
function safeCreatePlaceholder(message) {
const div = document.createElement('div');
div.className = 'gif-placeholder';
div.textContent = message;
return div;
}
function init() {
initAttempts++;
console.log('Tab GIF Display: Initializing... (attempt ' + initAttempts + ')');
const containers = document.querySelectorAll('.' + CONFIG.containerClass);
console.log('Tab GIF Display: Found', containers.length, 'containers');
if (containers.length === 0 && initAttempts < MAX_INIT_ATTEMPTS) {
console.log('Tab GIF Display: No containers found yet, will retry...');
setTimeout(init, 500);
return;
}
let setupCount = 0;
containers.forEach(container => {
const containerId = container.id;
console.log('Tab GIF Display: Checking container', containerId);
if (!currentContainers.has(containerId)) {
console.log('Tab GIF Display: Setting up NEW container', containerId);
const success = setupContainer(container);
if (success) {
currentContainers.set(containerId, container);
setupCount++;
}
} else {
console.log('Tab GIF Display: Container already initialized', containerId);
}
});
console.log('Tab GIF Display: Successfully set up', setupCount, 'containers');
}
function setupContainer(container) {
console.log('Tab GIF Display: setupContainer called for', container.id);
const gifMap = buildGifMap(container);
console.log('Tab GIF Display: GIF map built', gifMap);
if (Object.keys(gifMap).length === 0) {
console.error('Tab GIF Display: No GIFs found for container', container.id);
const displayArea = container.querySelector('.' + CONFIG.displayClass);
if (displayArea) {
const imgContainer = displayArea.querySelector('.gif-image-container');
if (imgContainer) {
imgContainer.innerHTML = '';
imgContainer.appendChild(safeCreateError('No GIFs configured. Check your list parameter.'));
}
}
return false;
}
createTabs(container, gifMap);
const firstTabName = Object.keys(gifMap)[0];
console.log('Tab GIF Display: Showing first tab:', firstTabName);
showGif(container, gifMap[firstTabName], firstTabName);
return true;
}
function buildGifMap(container) {
const gifMap = {};
const listData = container.getAttribute('data-gif-list');
console.log('Tab GIF Display: Building map for container', container.id);
console.log('Tab GIF Display: data-gif-list attribute:', listData);
if (!listData) {
console.error('Tab GIF Display: No data-gif-list attribute found on', container.id);
return gifMap;
}
if (listData.trim() === '') {
console.error('Tab GIF Display: data-gif-list is empty on', container.id);
return gifMap;
}
const entries = listData.split(';').filter(e => e.trim());
console.log('Tab GIF Display: Found', entries.length, 'entries in list');
entries.forEach((entry, index) => {
console.log('Tab GIF Display: Processing entry', index, ':', entry);
const parts = entry.split(':');
if (parts.length < 2) {
console.warn('Tab GIF Display: Invalid entry format (no colon):', entry);
return;
}
const tabName = parts[0].trim();
const gifFile = parts.slice(1).join(':').trim();
console.log('Tab GIF Display: Parsed - Tab:', tabName, 'File:', gifFile);
if (!tabName) {
console.warn('Tab GIF Display: Empty tab name in entry:', entry);
return;
}
if (!gifFile) {
console.warn('Tab GIF Display: Empty gif file in entry:', entry);
return;
}
let gifUrl;
if (typeof mw !== 'undefined' && mw.config) {
const scriptPath = mw.config.get('wgScriptPath') || '';
gifUrl = scriptPath + '/index.php?title=Special:Redirect/file/' + encodeURIComponent(gifFile);
} else {
gifUrl = '/index.php?title=Special:Redirect/file/' + encodeURIComponent(gifFile);
}
gifMap[tabName] = gifUrl;
console.log('Tab GIF Display: Mapped "' + tabName + '" to', gifUrl);
});
console.log('Tab GIF Display: Final map has', Object.keys(gifMap).length, 'entries');
return gifMap;
}
function createTabs(container, gifMap) {
const tabsContainer = container.querySelector('.' + CONFIG.tabsClass);
if (!tabsContainer) {
console.error('Tab GIF Display: No tabs container found in', container.id);
return;
}
console.log('Tab GIF Display: Creating tabs in', container.id);
tabsContainer.innerHTML = '';
let isFirst = true;
let tabCount = 0;
Object.keys(gifMap).forEach(tabName => {
const tab = document.createElement('button');
tab.className = CONFIG.tabClass;
tab.textContent = tabName;
tab.setAttribute('data-tab-name', tabName);
tab.type = 'button';
if (isFirst) {
tab.classList.add(CONFIG.activeTabClass);
isFirst = false;
}
tab.addEventListener('click', () => {
console.log('Tab GIF Display: Tab clicked:', tabName);
handleTabClick(container, gifMap, tabName);
});
tabsContainer.appendChild(tab);
tabCount++;
console.log('Tab GIF Display: Created tab button for', tabName);
});
console.log('Tab GIF Display: Created', tabCount, 'tabs total');
}
function handleTabClick(container, gifMap, tabName) {
console.log('Tab GIF Display: Handling tab click for', tabName);
const tabs = container.querySelectorAll('.' + CONFIG.tabClass);
tabs.forEach(tab => {
if (tab.getAttribute('data-tab-name') === tabName) {
tab.classList.add(CONFIG.activeTabClass);
} else {
tab.classList.remove(CONFIG.activeTabClass);
}
});
const gifUrl = gifMap[tabName];
showGif(container, gifUrl, tabName);
}
function showGif(container, gifUrl, tabName) {
console.log('Tab GIF Display: Showing GIF for', tabName, '-', gifUrl);
const displayArea = container.querySelector('.' + CONFIG.displayClass);
if (!displayArea) {
console.error('Tab GIF Display: No display area found');
return;
}
const rawSize = container.getAttribute('data-gif-size') || '400';
const gifSize = rawSize.replace(/[^0-9]/g, '') || '400';
const imgContainer = displayArea.querySelector('.gif-image-container');
const caption = displayArea.querySelector('.gif-caption');
if (imgContainer) {
const placeholder = imgContainer.querySelector('.gif-placeholder');
if (placeholder) {
placeholder.remove();
}
imgContainer.style.height = gifSize + 'px';
imgContainer.style.minHeight = gifSize + 'px';
const gifFilename = gifUrl.split('/').pop();
const decodedFilename = decodeURIComponent(gifFilename);
if (decodedFilename.toLowerCase() === 'blank' || decodedFilename.toLowerCase() === 'blank.gif') {
imgContainer.innerHTML = '';
imgContainer.appendChild(safeCreatePlaceholder('No GIF available for this tab.'));
imgContainer.classList.remove('loading');
} else {
imgContainer.classList.add('loading');
imgContainer.innerHTML = '';
const img = document.createElement('img');
img.src = gifUrl;
img.alt = tabName;
img.style.maxHeight = gifSize + 'px';
img.onload = () => {
imgContainer.innerHTML = '';
imgContainer.appendChild(img);
imgContainer.classList.remove('loading');
console.log('Tab GIF Display: GIF loaded successfully');
};
img.onerror = () => {
imgContainer.innerHTML = '';
imgContainer.appendChild(safeCreateError('GIF not found: ' + decodedFilename));
imgContainer.classList.remove('loading');
console.error('Tab GIF Display: Failed to load GIF', gifUrl);
};
}
}
if (caption) {
caption.textContent = tabName;
caption.style.display = 'block';
}
}
window.toggleTabGifDisplay = function(containerId) {
console.log('Tab GIF Display: Toggle clicked for', containerId);
const container = document.getElementById(containerId);
if (!container) {
console.error('Tab GIF Display: Container not found', containerId);
return;
}
if (container.style.display === 'none') {
container.style.display = 'block';
} else {
container.style.display = 'none';
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.addEventListener('load', init);
if (typeof mw !== 'undefined' && mw.hook) {
mw.hook('wikipage.content').add(init);
}
const observer = new MutationObserver(function(mutations) {
let shouldReinit = false;
mutations.forEach(function(mutation) {
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1 && (
node.classList && node.classList.contains(CONFIG.containerClass) ||
node.querySelector && node.querySelector('.' + CONFIG.containerClass)
)) {
shouldReinit = true;
}
});
}
});
if (shouldReinit) {
console.log('Tab GIF Display: Content changed, reinitializing...');
setTimeout(init, 100);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('Tab GIF Display: Script loaded and ready');
})();