MediaWiki:Common.js: Difference between revisions

From Heroes 3 wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(26 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* Any JavaScript here will be loaded for all users on every page load. */
/* Any JavaScript here will be loaded for all users on every page load. */


console.log('v92');
console.log('v118');


(function () {
(function () {
Line 142: Line 142:
switchView2.addEventListener('click', toggleFunc);
switchView2.addEventListener('click', toggleFunc);
if (linkSelector=='switchDoR' || linkSelector=='switchExpansion') {
if (linkSelector=='switchDoR' || linkSelector=='switchExpansion') {
switchView2.style.display = 'none';
switchView.style.display = 'none';
switchView2.style.display = 'none';
}
}
mwpanelul.insertBefore(switchView2, null);
mwpanelul.insertBefore(switchView2, null);
Line 466: Line 467:
let fileName = 'File:' + mw.util.parseImageUrl(a.href).name;
let fileName = 'File:' + mw.util.parseImageUrl(a.href).name;
let fileLink = articlePath + '/' + fileName;
let fileLink = articlePath + '/' + fileName;
if (elems[i].dataset && elems[i].dataset.link) {
fileLink = articlePath + '/' + elems[i].dataset.link;
}
let video;
let video;
let videoTitle = 'Click anywhere on the page, then hover here and press shift to open ' + fileName;
let videoTitle = 'Click anywhere on the page, then hover here and press shift to open ' + fileName;
Line 565: Line 569:
if (video.tagName == 'IMG') {
if (video.tagName == 'IMG') {
var wrapA = document.createElement('a');
var wrapA = document.createElement('a');
if (elems[i].dataset && elems[i].dataset.hover) {
wrapA.title = elems[i].dataset.hover;
}
wrapA.href = fileLink;
wrapA.href = fileLink;
wrapA.appendChild(video);
wrapA.appendChild(video);
Line 590: Line 597:


function showAnonBanner() {
function showAnonBanner() {
if (mw.user.isAnon()) {
if (mw.user.isAnon() && location.href.replace(location.protocol, '').includes('Special:')) {
    var banner = document.createElement('div');
    var banner = document.createElement('div');
    banner.style.display = 'flex';
    banner.style.display = 'flex';
    banner.id = 'anonymous-banner';
    banner.id = 'anonymous-banner';
    banner.innerHTML = 'Wiki access is throttled for unauthenticated users. For a better experience, please log in.';
    banner.innerHTML = 'Access to special pages is throttled for unauthenticated users. For a better experience, please log in.';
    var content = document.getElementById('content');
    var content = document.getElementById('content');
    if (content) {
    if (content) {
Line 625: Line 632:
}
}


function displayWebp(parent, src) {
function displayWebp(parent, src, maxWidth, maxHeight) {
     var img = document.createElement('img');
     var img = document.createElement('img');
    if (maxWidth) {
    img.style.maxWidth = maxWidth + 'px';
    }
    if (maxHeight) {
    img.style.maxHeight = maxHeight + 'px';
    }
    img.classList.add('finishedFixingWebp');
     parent.appendChild(img);
     parent.appendChild(img);
     img.src = src;
     img.src = src;
Line 660: Line 674:
function fixWebpDisplay() {
function fixWebpDisplay() {
     var galleryBoxes = document.querySelectorAll('.gallerybox');
     var galleryBoxes = document.querySelectorAll('.gallerybox');
    for (const galleryBox of galleryBoxes) {
for (const galleryBox of galleryBoxes) {
        const elem = galleryBox.querySelector('a');
if (galleryBox.querySelector('.finishedFixingWebp')) {
        if (elem.href.endsWith('webp')) {
continue;
            const thumb = galleryBox.querySelector('.thumb');
}
            thumb.style.height = 'unset';
    const elem = galleryBox.querySelector('a');
            thumb.classList.remove('thumb');
    if (elem.href && elem.href.endsWith('webp')) {
            elem.innerHTML = '';
        elem.innerHTML = '';
            var fileName = getFileName(elem.href);
        var fileName = getFileName(elem.href);
            var fileHash = getFileNameHash(fileName);
        var fileHash = getFileNameHash(fileName);
            displayWebp(elem, siteUploadPath + fileHash[0] + '/' + fileHash.substr(0, 2) + '/' + fileName);
        displayWebp(elem, siteUploadPath + fileHash[0] + '/' + fileHash.substr(0, 2) + '/' + fileName, 150, 150);
        }
    }
    }
}
     var searchThumbnails = document.querySelectorAll('.searchResultImage-thumbnail');
     var searchThumbnails = document.querySelectorAll('.searchResultImage-thumbnail');
     for (const searchThumbnail of searchThumbnails) {
     for (const searchThumbnail of searchThumbnails) {
if (searchThumbnail.querySelector('.finishedFixingWebp')) {
continue;
}
         const elem = searchThumbnail.querySelector('a');
         const elem = searchThumbnail.querySelector('a');
         if (elem.href.endsWith('webp')) {
         if (elem.href && elem.href.endsWith('webp')) {
             elem.innerHTML = '';
             elem.innerHTML = '';
             var fileName = getFileName(elem.href);
             var fileName = getFileName(elem.href);
             var fileHash = getFileNameHash(fileName);
             var fileHash = getFileNameHash(fileName);
             displayWebp(elem, siteUploadPath + fileHash[0] + '/' + fileHash.substr(0, 2) + '/' + fileName);
             displayWebp(elem, siteUploadPath + fileHash[0] + '/' + fileHash.substr(0, 2) + '/' + fileName, 104, 90);
         }
         }
     }
     }
     var links = document.querySelectorAll('a');
     var links = document.querySelectorAll('a');
     for (const link of links) {
     for (const link of links) {
     if (!link.href || !link.href.split) {
     if (!link.href || !link.href.split || link.querySelector('.finishedFixingWebp')) {
     continue;
     continue;
     }
     }
Line 699: Line 716:
         }
         }
     }
     }
}
function verifyWebp() {
var links = document.querySelectorAll('a');
    for (const link of links) {
    if (!link.href || !link.href.split || link.querySelector('.finishedFixingWebp')) {
    continue;
    }
        var fileExt = link.href.split('/').at(-1).split('.').at(-1);
        if (fileExt == 'webp') {
            var images = link.querySelectorAll('img');
            for (const img of images) {
                var fileIcon = img.src.split('/').at(-1).split('.').at(-2);
                if (fileIcon == 'fileicon') {
                    window.setTimeout(initWebp, 0);
                    return;
                }
            }
        }
    }
}
function finalizeWebp() {
var links = document.querySelectorAll('a');
    for (const link of links) {
    if (!link.href || !link.href.split || !link.querySelector('.finishedFixingWebp')) {
    continue;
    }
        var images = link.querySelectorAll('img');
for (const img of images) {
if (!img.className.includes('finishedFixingWebp')) {
img.remove();
}
}
    }
}
function initWebp() {
try {
fixWebpDisplay();
verifyWebp();
finalizeWebp();
window.setTimeout(verifyWebp, 150);
window.setTimeout(verifyWebp, 1500);
return;
} catch (e) {
// console.log('fixWebpDisplay failed');
// console.error(e);
}
window.setTimeout(initWebp, 0);
}
}


Line 751: Line 818:
mw.loader.getScript(mw.config.values.wgScript + '?title=MediaWiki:Hashes.min.js&action=raw&ctype=text/javascript')
mw.loader.getScript(mw.config.values.wgScript + '?title=MediaWiki:Hashes.min.js&action=raw&ctype=text/javascript')
).done(function() {
).done(function() {
fixWebpDisplay();
initWebp();
}).fail(function (e) {
}).fail(function (e) {
console.log('mw.loader.getScript Hashes.min.js failed');
console.log('mw.loader.getScript Hashes.min.js failed');
console.error(e);
console.error(e);
});
});
try {
mw.config.set("wgMediaViewerOnClick", false);
} catch (e) {
// console.error(e);
}


})();
})();

Latest revision as of 03:31, 18 November 2025

/* Any JavaScript here will be loaded for all users on every page load. */

console.log('v118');

(function () {

const siteUploadPath = 'https://heroes.thelazy.net/images/';

function getCookie(cname) {
	var result = localStorage.getItem(cname);
	if (result) {
		return result;
	}
	return '';
}

function trimRE(str, charToTrim) {
	var escapedChar = charToTrim.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
	var regex = new RegExp(`^${escapedChar}+|${escapedChar}+$`, 'g');
	return str.replace(regex, '');
}

function showElements(desc, linkSelector) {
	var elems = document.querySelectorAll(desc);
	for (var i = 0; i < elems.length; i++) {
		elems[i].style.display = 'revert';
	}
	elems = document.querySelectorAll('.' + linkSelector + desc);
	for (i = 0; i < elems.length; i++) {
		elems[i].style = 'white-space: nowrap; user-select:none; cursor: pointer; color: rgb(102, 177, 250);';
	}
}

function hideElements(desc) {
	var elems = document.querySelectorAll(desc);
	for (var i = 0; i < elems.length; i++) {
		elems[i].style.display = 'none';
	}
	elems = document.querySelectorAll('.initialOnly');
	for (i = 0; i < elems.length; i++) {
		elems[i].style.display = 'none';
	}
}

function togglePreference(linkSelector, cookieName, cookie1, cookie2, link1, link2, prefName) {
	var preference = getCookie(cookieName);
	var switchView = document.querySelector('#' + linkSelector);
	var switchView2 = document.querySelector('#' + linkSelector + '2');
	if (preference == cookie2) {
		preference = cookie1;
		switchView.textContent = link2;
		switchView2.textContent = link2;
		hideElements('.only' + cookie2);
		showElements('.only' + cookie1, linkSelector);
	} else {
		preference = cookie2;
		switchView.textContent = link1;
		switchView2.textContent = link1;
		hideElements('.only' + cookie1);
		showElements('.only' + cookie2, linkSelector);
	}
	localStorage.setItem(cookieName, preference);
}

function setPreference(linkSelector, cookieName, cookie1, cookie2, link1, link2, prefName, preference) {
	var switchView = document.querySelector('#' + linkSelector);
	var switchView2 = document.querySelector('#' + linkSelector + '2');
	if (preference == cookie1) {
		switchView.textContent = link2;
		switchView2.textContent = link2;
		hideElements('.only' + cookie2);
		showElements('.only' + cookie1, linkSelector);
	} else {
		switchView.textContent = link1;
		switchView2.textContent = link1;
		hideElements('.only' + cookie1);
		showElements('.only' + cookie2, linkSelector);
	}
}

function togglePreferredExpansion() {
	togglePreference('switchExpansion', 'preferredExpansion', 'hota', 'sod', 'Enable HotA', 'Disable HotA', 'Horn of the Abyss');
}

function togglePreferredView() {
	togglePreference('switchView', 'preferredView', 'modern', 'legacy', 'Enable Modern', 'Enable Legacy', 'Legacy/Modern');
}

function toggleDoR() {
	togglePreference('switchDoR', 'preferredDoR', 'dor', 'nodor', 'Enable DoR', 'Disable DoR', 'Day of Reckoning');
}

function setHeroesStyle() {
	var	preference = getCookie('heroesStyle');
	if (preference == 'heroesStyleDisabled') {
		while (document.adoptedStyleSheets.pop());
	} else if (heroesStyleSheet) {
		document.adoptedStyleSheets.push(heroesStyleSheet);
	}
}

function toggleHeroesStyle() {
	togglePreference('switchHeroesStyle', 'heroesStyle', 'heroesStyleEnabled', 'heroesStyleDisabled', 'Enable H3CSS', 'Disable H3CSS', 'Heroes Style');
	setHeroesStyle();
}

function initPreference(linkSelector, cookieName, cookie1, cookie2, link1, link2, prefName, toggleFunc) {
	var userlink = document.querySelector('#pt-anonuserpage');
	if (!userlink) {
		userlink = document.querySelector('#pt-userpage');
	}
	var switchView = document.querySelector('#' + linkSelector);
	if (!switchView) {
		switchView = document.createElement('li');
		switchView.style = 'white-space: nowrap; user-select:none; cursor: pointer; color: rgb(102, 177, 250);';
		switchView.id = linkSelector;
		switchView.title = prefName + ' (toggle)';
		switchView.addEventListener('click', toggleFunc);
		userlink.parentElement.insertBefore(switchView, null);
		var elems = document.querySelectorAll('.' + linkSelector);
		for (var i = 0; i < elems.length; i++) {
			elems[i].addEventListener('click', toggleFunc);
			elems[i].style = 'white-space: nowrap; user-select:none; cursor: pointer; color: rgb(102, 177, 250);';
		}
	}
	if (getCookie(cookieName) == cookie2) {
		switchView.textContent = link1;
		hideElements('.only' + cookie1);
		showElements('.only' + cookie2);
	} else {
		switchView.textContent = link2;
		hideElements('.only' + cookie2);
		showElements('.only' + cookie1);
	}
	var mwpanelul = document.querySelector('#mw-panel ul');
	var switchView2 = document.querySelector('#' + linkSelector + '2');
	if (!switchView2) {
		switchView2 = document.createElement('li');
		switchView2.style = 'white-space: nowrap; user-select:none; cursor: pointer; color: rgb(102, 177, 250);';
		switchView2.id = linkSelector + '2';
		switchView2.title = prefName + ' (toggle)';
		switchView2.addEventListener('click', toggleFunc);
		if (linkSelector=='switchDoR' || linkSelector=='switchExpansion') {
			switchView.style.display = 'none';
			switchView2.style.display = 'none';
		}
		mwpanelul.insertBefore(switchView2, null);
		if (linkSelector=='switchDoR' || linkSelector=='switchExpansion') {
			var switchView3=document.createElement('li');
			var switchView3img=document.createElement('img');
			switchView3img.classList='only' + cookie1;
			var switchView3img2=document.createElement('img');
			switchView3img2.classList='only' + cookie2;
			switchView3.insertBefore(switchView3img, null);
			switchView3.insertBefore(switchView3img2, null);
			switchView3.id=linkSelector + '3';
			switchView3.classList=linkSelector;
			switchView3.title=prefName + ' (toggle)';
			switchView3.addEventListener('click', toggleFunc);
			mwpanelul.prepend(switchView3);
		}
	}
	if (getCookie(cookieName) == cookie2) {
		switchView2.textContent = link1;
		hideElements('.only' + cookie1);
		showElements('.only' + cookie2);
	} else {
		switchView2.textContent = link2;
		hideElements('.only' + cookie2);
		showElements('.only' + cookie1);
	}
}

function getCookieNumber(cookieName, cookieDefault) {
	var cookieVal = getCookie(cookieName);
	if (cookieVal == '') {
		cookieVal = cookieDefault;
	} else {
		cookieVal = Number(cookieVal);
	}
	return cookieVal;
}

function initPreferenceNumber(linkSelector, cookieName, cookieDefault, prefName, displayText, min, max, step, changeFunc) {
	var cookieVal = getCookieNumber(cookieName, 50);
	var mwpanelul = document.querySelector('#mw-panel ul');
	var switchView = document.querySelector('#' + linkSelector);
	if (!switchView) {
		switchView = document.createElement('li');
		switchView.style = 'user-select:none; padding-bottom:8px; color:rgb(102, 177, 250);';
		switchView.id = linkSelector;
		switchView.title = prefName;
		switchView.textContent = displayText;
		var switchViewInput = document.createElement('input');
		switchViewInput.type = 'number';
		switchViewInput.step = step;
		switchViewInput.min = min;
		switchViewInput.max = max;
		switchViewInput.value = cookieVal;
		switchViewInput.style.marginLeft = '3px';
		switchViewInput.style.fieldSizing = 'content';
		switchViewInput.style.minWidth = '34px';
		switchViewInput.addEventListener('change', changeFunc);
		switchView.insertBefore(switchViewInput, null);
		mwpanelul.insertBefore(switchView, null);
	}
}

function adjustVolume(e) {
	if (isNaN(Number(e.target.value))) {
		e.target.value = 50;
	} else if (e.target.value > 100) {
		e.target.value = 100;
	} else if (e.target.value < 0) {
		e.target.value = 0;
	}
	localStorage.setItem('volumeLoudness', e.target.value);
	
	var elems = document.querySelectorAll('audio,video');
	for (var i = 0; i < elems.length; i++) {
		elems[i].volume = e.target.value / 100;
	}
	
	for (i = 0; i < playables.length; i++) {
		playables[i].volume = e.target.value / 100;
	}
}

function removeTooltips() {
	var elems = document.querySelectorAll('.mainpage .tabs-content div div a');
	for (var i = 0; i < elems.length; i++) {
		elems[i].title = '';
	}
}

function removeUnwantedTitles() {
	var elems = document.querySelectorAll('#p-logo a');
	for (var i = 0; i < elems.length; i++) {
		elems[i].title = '';
	}
}

function getOffsetTop(e, top) {
	if (!e || e.id == 'bodyContent' || e.tagName == 'MAIN') {
		return top;
	}
	return getOffsetTop(e.offsetParent, top+e.offsetTop);
}

function getOffsetLeft(e, left) {
	if (!e || e.id == 'bodyContent' || e.tagName == 'MAIN') {
		return left;
	}
	return getOffsetLeft(e.offsetParent, left+e.offsetLeft);
}

function fixClassNames(selectors) {
	for (var h = 0; h < selectors.length; h++) {
		var elems = document.querySelectorAll(selectors[h]);
		for (var i = 0; i < elems.length; i++) {
			if (elems[i].className.includes(',')) {
				elems[i].className = elems[i].className.replaceAll(',','');
			}
			if (elems[i].className.includes('(')) {
				elems[i].className = elems[i].className.replaceAll('(','');
			}
			if (elems[i].className.includes(')')) {
				elems[i].className = elems[i].className.replaceAll(')','');
			}
		}
	}
}

function initHoverPopups() {
	var elems = document.querySelectorAll('.popupable');
	var bodyContent = document.querySelector('#bodyContent');
	var main = document.querySelector('main');
	for (var i = 0; i < elems.length; i++) {
		elems[i].parentElement.removeChild(elems[i]);
		if (bodyContent) {
			bodyContent.appendChild(elems[i]);
		} else if (main) {
			main.appendChild(elems[i]);
		}
	}
	elems = document.querySelectorAll('.hoverable a');
	for (i = 0; i < elems.length; i++) {
		elems[i].title = '';
	}
	elems = document.querySelectorAll('.hoverable');
	for (i = 0; i < elems.length; i++) {
		// var p = elems[i].parentElement;
		// if (p.tagName == 'P') {
		//     var span = document.createElement('span');
		//     p.parentElement.insertBefore(span, p);
		//     while (p.childNodes.length > 0) {
		//         span.appendChild(p.childNodes[0]);
		//     }
		//     p.parentElement.removeChild(p);
		// }
		for (var j = 0; j < elems[i].classList.length; j++) {
			var popupid = elems[i].classList[j];
			var re = /^popupid/i;
			var found = popupid.match(re);
			if (found) {
				let elem = document.querySelector('.popupable.' + popupid);
				if (elem) {
					let elem0 = elems[i];
					elems[i].addEventListener('mouseover', function () {
						let rect = elem0.getBoundingClientRect();
						elem.style.visibility = 'visible';
						elem.style.height = 'auto';
						elem.style.zIndex = 99;
						elem.style.top = getOffsetTop(elem0.offsetParent, elem0.offsetTop) + 23 + 'px';
						let left = getOffsetLeft(elem0.offsetParent, elem0.offsetLeft);
						if (rect.x > window.innerWidth / 2) {
							elem.style.left = (left - elem.offsetWidth + 20) + 'px';
						} else {
							elem.style.left = left + 20 + 'px';
						}
					});
					elems[i].addEventListener('mouseleave', function () {
						elem.style.visibility = 'hidden';
						elem.style.zIndex = -1;
					});
				}
			}
		}
	}
}

var playables = [];
function initPlayables() {
	var elems = document.querySelectorAll('.playable');
	var bodyContent = document.querySelector('#bodyContent');
	var main = document.querySelector('main');
	for (var i = 0; i < elems.length; i++) {
		elems[i].parentElement.removeChild(elems[i]);
		if (bodyContent) {
			bodyContent.appendChild(elems[i]);
		} else if (main) {
			main.appendChild(elems[i]);
		}
	}
	elems = document.querySelectorAll('.clickToPlay a');
	for (i = 0; i < elems.length; i++) {
		elems[i].title = '';
		elems[i].style.pointerEvents = 'none';
	}
	elems = document.querySelectorAll('.clickToPlay');
	for (i = 0; i < elems.length; i++) {
		for (var j = 0; j < elems[i].classList.length; j++) {
			var playid = elems[i].classList[j];
			var re = /^playid/i;
			var found = playid.match(re);
			if (found) {
				let elem = document.querySelector('.playable.' + playid + ' > a');
				if (elem) {
					let elem0 = elems[i];
					elem0.style.cursor = 'pointer';
					let audio = new Audio(elem.href);
					playables.push(audio);
					elems[i].addEventListener('click', function () {
						audio.volume = getCookieNumber('volumeLoudness', 50) / 100;
						if (audio.paused) {
							audio.play();
						} else {
							audio.pause();
						}
					});
				}
			}
		}
	}
}

function setVolumeTMH(cookieVolume, count) {
	if (count > 150) {
		return;
	}
	var elems = document.querySelectorAll('audio,video');
	for (var i = 0; i < elems.length; i++) {
		elems[i].volume = cookieVolume / 100;
	}
	window.setTimeout(function() { setVolumeTMH(cookieVolume, ++count); }, 0);
}

function handleTMH(elemid) {
	var elem = document.querySelector('#' + elemid);
	if (elem) {
		elem.parentElement.addEventListener('click', function() { var cookieVolume = getCookieNumber('volumeLoudness', 50); setVolumeTMH(cookieVolume, 0); });
	} else {
		window.setTimeout(function() { handleTMH(elemid); }, 0);
	}
}

function initTMH() {
	var elems = document.querySelectorAll('audio,video');
	for (var i = 0; i < elems.length; i++) {
		let elemid = elems[i].id;
		if (elemid.search('_placeholder') == -1) {
			elemid += '_placeholder';
		}
		window.setTimeout(function() { handleTMH(elemid); }, 0);
	}
}

function setPoster(e) {
	e.target.removeEventListener('seeked', setPoster);
	try {
		var canvas = document.createElement('canvas');
		var context = canvas.getContext('2d');
		canvas.width = e.target.videoWidth;
		canvas.height = e.target.videoHeight;
		context.drawImage(e.target, 0, 0, canvas.width, canvas.height);
	    canvas.toBlob(function(blob) { e.target.poster = URL.createObjectURL(blob); }, 'image/webp', 0.9);
		e.target.currentTime = 0;
		var src = e.target.src;
		e.target.src = '';
		e.target.src = src;
	} catch (error) {
		console.error(error);
	}
}

function initPoster(e) {
	e.target.removeEventListener('loadeddata', initPoster);
	var thumbtime = e.target.parentElement.dataset.thumbnail;
	var thumbtimeparts = trimRE(thumbtime, ':').split(':');
	if (thumbtimeparts.length == 1 && thumbtime != '') {
		thumbtime = parseFloat(thumbtime);
	} else if (thumbtimeparts.length == 2) {
		thumbtime = parseFloat(thumbtimeparts[1]) + parseFloat(thumbtimeparts[0]) * 60;
	} else if (thumbtimeparts.length == 3) {
		thumbtime = parseFloat(thumbtimeparts[2]) + parseFloat(thumbtimeparts[1]) * 60;
		thumbtime = thumbtime + parseFloat(thumbtimeparts[0]) * 60 * 60;
	} else {
		return;
	}
	if (thumbtime > 0) {
		e.target.addEventListener('seeked', setPoster);
		e.target.currentTime = thumbtime;
	}
}

var savedScrollPosition = window.scrollY;
function setSavedScrollPosition() {
    if (!document.fullscreenElement) {
        savedScrollPosition = window.scrollY;
    }
}

function fixFullscreen() {
	document.addEventListener('fullscreenchange', function() {
	    if (!document.fullscreenElement) {
	        window.scrollTo(0, savedScrollPosition);
	    }
	});
}

function setupWatchables() {
	var articlePath = mw.config.values.wgArticlePath.replace(/\/\$1/, '');
	var elems = document.querySelectorAll('.watchable');
	for (var i = 0; i < elems.length; i++) {
		var a = elems[i].querySelector('a');
		a.style.display = 'none';
		let fileName = 'File:' + mw.util.parseImageUrl(a.href).name;
		let fileLink = articlePath + '/' + fileName;
		if (elems[i].dataset && elems[i].dataset.link) {
			fileLink = articlePath + '/' + elems[i].dataset.link;
		}
		let video;
		let videoTitle = 'Click anywhere on the page, then hover here and press shift to open ' + fileName;
		if (elems[i].dataset && elems[i].dataset.audio) {
			video = document.createElement('audio');
			video.volume = getCookieNumber('volumeLoudness', 50) / 100;
			video.controls = true;
		} else if (a.href.toLowerCase().search('.gif') == -1 && a.href.toLowerCase().search('.png') == -1 && a.href.toLowerCase().search('.webp') == -1 && a.href.toLowerCase().search('.jpg') == -1) {
			video = document.createElement('video');
			video.volume = getCookieNumber('volumeLoudness', 50) / 100;
			let isFocused = false;
			video.addEventListener('play', function (e) {
				video.focus();
				video.title = '';
			});
			video.addEventListener('pause', function (e) {
				video.title = videoTitle;
			});
			video.addEventListener('mouseover', function (e) {
				window.setTimeout(setSavedScrollPosition, 0);
				e.target.controls = true;
				video.focus();
			});
			video.addEventListener('mouseleave', function (e) {
				e.target.controls = false;
			});
			video.addEventListener('focus', function (e) {
				isFocused = true;
			});
			video.addEventListener('blur', function (e) {
				isFocused = false;
			});
			video.addEventListener('keydown', function (e) {
				if (isFocused) {
					if (e.key == 'f' || e.key == 'F') {
						if (document.fullscreen) {
							document.exitFullscreen();
						} else {
							video.requestFullscreen();
						}
					}
				}
			});
			let clickTimer = null;
			video.addEventListener('click', function(e) {
				e.preventDefault();
				if (clickTimer == null) {
					clickTimer = setTimeout(function(){
						if (e.target.paused) {
							e.target.play();
						} else {
							e.target.pause();
						}
						clickTimer = null;
					}, 200);
				} else {
					clearTimeout(clickTimer);
					if (document.fullscreen) {
						document.exitFullscreen();
					} else {
						e.target.requestFullscreen();
					}
					clickTimer = null;
				}
			});
			if (!a.href.includes(window.location.hostname)) {
				video.crossOrigin = 'anonymous';
			}
		} else {
			video = document.createElement('img');
		}
		if (elems[i].dataset) {
			if (elems[i].dataset.width) {
				video.width = elems[i].dataset.width.replace('px', '');
			}
			if (elems[i].dataset.height) {
				video.height = elems[i].dataset.height.replace('px', '');
			}
			if (elems[i].dataset.thumbnail && elems[i].dataset.thumbnail != '') {
				video.addEventListener('loadeddata', initPoster);
			}
		}
		video.src = a.href;
		if (video.tagName == 'AUDIO' || video.tagName == 'VIDEO') {
			videoTitle = 'Click anywhere on the page, then hover here and press shift to open ' + fileName;
			video.title = videoTitle;
			function openOnShift(e) {
			    if (e.shiftKey) {
			        window.open(fileLink);
			    }
			}
			video.addEventListener('mouseover', function (e) {
			    document.addEventListener('keydown', openOnShift);
			});
			video.addEventListener('mouseleave', function (e) {
			    document.removeEventListener('keydown', openOnShift);
			});
		}
		if (video.tagName == 'IMG') {
			var wrapA = document.createElement('a');
			if (elems[i].dataset && elems[i].dataset.hover) {
				wrapA.title = elems[i].dataset.hover;
			}
			wrapA.href = fileLink;
			wrapA.appendChild(video);
			elems[i].insertBefore(wrapA, null);
		} else {
			elems[i].insertBefore(video, null);
		}
	}
}

function initWatchables() {
	var elems = document.querySelectorAll('audio,video');
	if (elems.length == 0) {
		setupWatchables();
		return;
	}
	for (var i = 0; i < elems.length; i++) {
		if (elems[i].id.search('_placeholder') != -1) {
			window.setTimeout(setupWatchables, 0);
			return;
		}
	}
	window.setTimeout(initWatchables, 0);
}

function showAnonBanner() {
	if (mw.user.isAnon() && location.href.replace(location.protocol, '').includes('Special:')) {
	    var banner = document.createElement('div');
	    banner.style.display = 'flex';
	    banner.id = 'anonymous-banner';
	    banner.innerHTML = 'Access to special pages is throttled for unauthenticated users. For a better experience, please log in.';
	    var content = document.getElementById('content');
	    if (content) {
	        content.append(banner, content.firstChild);
	    }
	}
}

function handleStorageChange(e) {
	if (event.storageArea == localStorage) {
		if (e.key == 'preferredExpansion') {
			setPreference('switchExpansion', 'preferredExpansion', 'hota', 'sod', 'Enable HotA', 'Disable HotA', 'Horn of the Abyss', e.newValue);
		} else if (e.key == 'preferredDoR') {
			setPreference('switchDoR', 'preferredDoR', 'dor', 'nodor', 'Enable DoR', 'Disable DoR', 'Day of Reckoning', e.newValue);
		} else if (e.key == 'preferredView') {
			var mainpage = document.querySelector('.mainpage.onlysod.onlyhota');
			if (mainpage) {
				setPreference('switchView', 'preferredView', 'modern', 'legacy', 'Enable Modern', 'Enable Legacy', 'Legacy/Modern', e.newValue);
			}
		} else if (e.key == 'volumeLoudness') {
			var volumeInput = document.querySelector('#adjustVolume input');
			if (volumeInput) {
				volumeInput.value = e.newValue;
			}
		} else if (e.key == 'heroesStyle') {
			setPreference('switchHeroesStyle', 'heroesStyle', 'heroesStyleEnabled', 'heroesStyleDisabled', 'Enable H3CSS', 'Disable H3CSS', 'Heroes Style', e.newValue);
			setHeroesStyle();
		}
	}
}

function displayWebp(parent, src, maxWidth, maxHeight) {
    var img = document.createElement('img');
    if (maxWidth) {
    	img.style.maxWidth = maxWidth + 'px';
    }
    if (maxHeight) {
    	img.style.maxHeight = maxHeight + 'px';
    }
    img.classList.add('finishedFixingWebp');
    parent.appendChild(img);
    img.src = src;
}

function escapeMediaWiki(fileName) {
  return fileName
    .replace(/ /g, '_')           // spaces to underscores
    .replace(/'/g, '%27')         // apostrophes
    .replace(/"/g, '%22')         // double quotes
    .replace(/\(/g, '%28')        // left parenthesis
    .replace(/\)/g, '%29')        // right parenthesis
    .replace(/:/g, '%3A')         // colon
    .replace(/;/g, '%3B')         // semicolon
    .replace(/@/g, '%40')         // at symbol
    .replace(/&/g, '%26')         // ampersand
    .replace(/\+/g, '%2B')        // plus
    .replace(/,/g, '%2C')         // comma
    .replace(/\?/g, '%3F')        // question mark
    .replace(/#/g, '%23')         // hash
    .replace(/\[/g, '%5B')        // left square bracket
    .replace(/\]/g, '%5D');       // right square bracket
}

function getFileName(href) {
	return escapeMediaWiki(href.split('/').at(-1).replace('File:', ''));
}

function getFileNameHash(fileName) {
	return new Hashes.MD5().hex(decodeURIComponent(fileName));
}

function fixWebpDisplay() {
    var galleryBoxes = document.querySelectorAll('.gallerybox');
	for (const galleryBox of galleryBoxes) {
		if (galleryBox.querySelector('.finishedFixingWebp')) {
			continue;
		}
	    const elem = galleryBox.querySelector('a');
	    if (elem.href && elem.href.endsWith('webp')) {
	        elem.innerHTML = '';
	        var fileName = getFileName(elem.href);
	        var fileHash = getFileNameHash(fileName);
	        displayWebp(elem, siteUploadPath + fileHash[0] + '/' + fileHash.substr(0, 2) + '/' + fileName, 150, 150);
	    }
	}
    var searchThumbnails = document.querySelectorAll('.searchResultImage-thumbnail');
    for (const searchThumbnail of searchThumbnails) {
		if (searchThumbnail.querySelector('.finishedFixingWebp')) {
			continue;
		}
        const elem = searchThumbnail.querySelector('a');
        if (elem.href && elem.href.endsWith('webp')) {
            elem.innerHTML = '';
            var fileName = getFileName(elem.href);
            var fileHash = getFileNameHash(fileName);
            displayWebp(elem, siteUploadPath + fileHash[0] + '/' + fileHash.substr(0, 2) + '/' + fileName, 104, 90);
        }
    }
    var links = document.querySelectorAll('a');
    for (const link of links) {
    	if (!link.href || !link.href.split || link.querySelector('.finishedFixingWebp')) {
    		continue;
    	}
        var fileExt = link.href.split('/').at(-1).split('.').at(-1);
        if (fileExt == 'webp') {
            var img = link.querySelector('img');
            if (img) {
                var fileIcon = img.src.split('/').at(-1).split('.').at(-2);
                if (fileIcon == 'fileicon') {
                    link.innerHTML = '';
                    displayWebp(link, link.href);
                }
            }
        }
    }
}

function verifyWebp() {
	var links = document.querySelectorAll('a');
    for (const link of links) {
    	if (!link.href || !link.href.split || link.querySelector('.finishedFixingWebp')) {
    		continue;
    	}
        var fileExt = link.href.split('/').at(-1).split('.').at(-1);
        if (fileExt == 'webp') {
            var images = link.querySelectorAll('img');
            for (const img of images) {
                var fileIcon = img.src.split('/').at(-1).split('.').at(-2);
                if (fileIcon == 'fileicon') {
                    window.setTimeout(initWebp, 0);
                    return;
                }
            }
        }
    }
}

function finalizeWebp() {
	var links = document.querySelectorAll('a');
    for (const link of links) {
    	if (!link.href || !link.href.split || !link.querySelector('.finishedFixingWebp')) {
    		continue;
    	}
        var images = link.querySelectorAll('img');
		for (const img of images) {
			if (!img.className.includes('finishedFixingWebp')) {
				img.remove();
			}
		}
    }
}

function initWebp() {
	try {
		fixWebpDisplay();
		verifyWebp();
		finalizeWebp();
		window.setTimeout(verifyWebp, 150);
		window.setTimeout(verifyWebp, 1500);
		return;
	} catch (e) {
		// console.log('fixWebpDisplay failed');
		// console.error(e);
	}
	window.setTimeout(initWebp, 0);
}

function initCommon() {
	showAnonBanner();
	initPreference('switchDoR', 'preferredDoR', 'dor', 'nodor', 'Enable DoR', 'Disable DoR', 'Day of Reckoning', toggleDoR);
	initPreference('switchExpansion', 'preferredExpansion', 'hota', 'sod', 'Enable HotA', 'Disable HotA', 'Horn of the Abyss', togglePreferredExpansion);
	var mainpage = document.querySelector('.mainpage.onlysod.onlyhota');
	if (mainpage) {
		initPreference('switchView', 'preferredView', 'modern', 'legacy', 'Enable Modern', 'Enable Legacy', 'Legacy/Modern', togglePreferredView);
		removeTooltips();
	}
	removeUnwantedTitles();
	initPreference('switchHeroesStyle', 'heroesStyle', 'heroesStyleEnabled', 'heroesStyleDisabled', 'Enable H3CSS', 'Disable H3CSS', 'Heroes Style', toggleHeroesStyle);
	fixClassNames(['.hoverable','.popupable','.clickToPlay','.playable']);
	initHoverPopups();
	initPlayables();
	initPreferenceNumber('adjustVolume', 'volumeLoudness', 50, 'Adjust Volume %', 'Volume', 0, 100, 5, adjustVolume);
	initWatchables();
	fixFullscreen();
	window.addEventListener('storage', handleStorageChange);
}

function beforeInitCommon() {
	var mwpanelul = document.querySelector('#mw-panel ul');
	if (mwpanelul) {
		try {
			initCommon();
			return;
		} catch (e) {
			// console.log('initCommon failed');
			// console.error(e);
		}
	}
	window.setTimeout(beforeInitCommon, 0);
}

// run immediately
initTMH();
window.setTimeout(beforeInitCommon, 0);

$.when(
	mw.loader.getScript(mw.config.values.wgScript + '?title=MediaWiki:H3CSS.min.js&action=raw&ctype=text/javascript')
).done(function() {
	setHeroesStyle();
}).fail(function (e) {
	console.log('mw.loader.getScript H3CSS.min.js failed');
	console.error(e);
});

$.when(
	mw.loader.getScript(mw.config.values.wgScript + '?title=MediaWiki:Hashes.min.js&action=raw&ctype=text/javascript')
).done(function() {
	initWebp();
}).fail(function (e) {
	console.log('mw.loader.getScript Hashes.min.js failed');
	console.error(e);
});

try {
	mw.config.set("wgMediaViewerOnClick", false);
} catch (e) {
	// console.error(e);
}

})();