MediaWiki:Common.js: Difference between revisions

From Heroes 3 wiki
Jump to navigation Jump to search
No edit summary
No edit summary
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('v81');
console.log('v82');


(function () {
(function () {
Line 660: Line 660:
console.error(e);
console.error(e);
});
});
} else {
console.log('HSS already available');
}
}


})();
})();

Revision as of 08:48, 4 October 2025

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

console.log('v82');

(function () {

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') {
			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;
		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');
			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()) {
	    var banner = document.createElement('div');
	    banner.style.display = 'flex';
	    banner.id = 'anonymous-banner';
	    banner.innerHTML = 'Wiki access 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 initCommon() {
	initTMH();
	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);
}

try {
	initCommon();
} catch (error) {
	console.log('...waiting 2 seconds before trying initCommon again...');
	window.setTimeout(initCommon, 2000);
}

if (!heroesStyleSheet) {
	$.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.error('mw.loader.getScript failed');
		console.error(e);
	});
} else {
	console.log('HSS already available');
}

})();