미디어위키:Gadget-Vector.js: 두 판 사이의 차이

식물 vs 좀비 위키
둘러보기로 이동 검색으로 이동
편집 요약 없음
편집 요약 없음
2번째 줄: 2번째 줄:
'use strict';
'use strict';


var animationDuration = 360;
var SPIN_CLASS = 'pvz-watch-spinning';
var animationEndTime = 0;
var WATCHED_CLASS = 'pvz-watch-watched';
var observer = null;
var NOT_WATCHED_CLASS = 'pvz-watch-not-watched';
var SPIN_TIME = 360;
var cleanupTimer = 0;


function getWatchButton() {
function getContainer() {
return document.querySelector('#ca-watch, #ca-unwatch');
return document.querySelector(
'#ca-watch, #ca-unwatch, li.mw-watchlink, a.mw-watchlink'
);
}
}


function startWatchAnimation() {
function getLink(container) {
var button = getWatchButton();
if (!container) {
return null;
}


animationEndTime = Date.now() + animationDuration;
return container.matches('a') ? container : container.querySelector('a');
}


if (button) {
function applyState(isWatched) {
button.classList.remove('pvz-watch-spinning');
var container = getContainer();


/* 같은 클래스를 연속으로 적용해도 애니메이션이 다시 시작되게 한다. */
if (!container) {
void button.offsetWidth;
return;
button.classList.add('pvz-watch-spinning');
}
}
container.classList.toggle(WATCHED_CLASS, !!isWatched);
container.classList.toggle(NOT_WATCHED_CLASS, !isWatched);
}
}


function continueAnimationAfterStateChange() {
function syncFromMarkup() {
var button;
var container = getContainer();
var remaining;
var link = getLink(container);
var href;


if (Date.now() >= animationEndTime) {
if (!container || !link) {
return;
return;
}
}


button = getWatchButton();
href = link.getAttribute('href') || '';
remaining = animationEndTime - Date.now();
 
applyState(
container.id === 'ca-unwatch' ||
href.indexOf('action=unwatch') !== -1
);
}
 
function spin() {
var container = getContainer();


if (!button || button.classList.contains('pvz-watch-spinning')) {
if (!container) {
return;
return;
}
}


button.classList.add('pvz-watch-spinning');
window.clearTimeout(cleanupTimer);
container.classList.remove(SPIN_CLASS);
void container.offsetWidth;
container.classList.add(SPIN_CLASS);


window.setTimeout(function () {
cleanupTimer = window.setTimeout(function () {
button.classList.remove('pvz-watch-spinning');
container.classList.remove(SPIN_CLASS);
}, remaining);
}, SPIN_TIME + 40);
}
}


function handleClick(event) {
function handleClick(event) {
var link = event.target.closest('#ca-watch > a, #ca-unwatch > a');
var link = event.target.closest(
'#ca-watch > a, #ca-unwatch > a, li.mw-watchlink > a, a.mw-watchlink'
);


if (!link) {
if (link) {
return;
spin();
}
}
startWatchAnimation();
}
}


function init() {
function init() {
var observer;
syncFromMarkup();
document.addEventListener('click', handleClick, true);
document.addEventListener('click', handleClick, true);


observer = new MutationObserver(function () {
observer = new MutationObserver(function () {
continueAnimationAfterStateChange();
syncFromMarkup();
});
});


observer.observe(document.body, {
observer.observe(document.body, {
subtree: true,
childList: true,
childList: true,
subtree: true,
attributes: true,
attributes: true,
attributeFilter: ['id']
attributeFilter: ['id', 'href']
});
});
if (window.mw && mw.hook) {
mw.hook('wikipage.watchlistChange').add(function (isWatched) {
applyState(isWatched);
spin();
});
}
}
}



2026년 7월 27일 (월) 22:44 판

(function () {
	'use strict';

	var SPIN_CLASS = 'pvz-watch-spinning';
	var WATCHED_CLASS = 'pvz-watch-watched';
	var NOT_WATCHED_CLASS = 'pvz-watch-not-watched';
	var SPIN_TIME = 360;
	var cleanupTimer = 0;

	function getContainer() {
		return document.querySelector(
			'#ca-watch, #ca-unwatch, li.mw-watchlink, a.mw-watchlink'
		);
	}

	function getLink(container) {
		if (!container) {
			return null;
		}

		return container.matches('a') ? container : container.querySelector('a');
	}

	function applyState(isWatched) {
		var container = getContainer();

		if (!container) {
			return;
		}

		container.classList.toggle(WATCHED_CLASS, !!isWatched);
		container.classList.toggle(NOT_WATCHED_CLASS, !isWatched);
	}

	function syncFromMarkup() {
		var container = getContainer();
		var link = getLink(container);
		var href;

		if (!container || !link) {
			return;
		}

		href = link.getAttribute('href') || '';

		applyState(
			container.id === 'ca-unwatch' ||
			href.indexOf('action=unwatch') !== -1
		);
	}

	function spin() {
		var container = getContainer();

		if (!container) {
			return;
		}

		window.clearTimeout(cleanupTimer);
		container.classList.remove(SPIN_CLASS);
		void container.offsetWidth;
		container.classList.add(SPIN_CLASS);

		cleanupTimer = window.setTimeout(function () {
			container.classList.remove(SPIN_CLASS);
		}, SPIN_TIME + 40);
	}

	function handleClick(event) {
		var link = event.target.closest(
			'#ca-watch > a, #ca-unwatch > a, li.mw-watchlink > a, a.mw-watchlink'
		);

		if (link) {
			spin();
		}
	}

	function init() {
		var observer;

		syncFromMarkup();
		document.addEventListener('click', handleClick, true);

		observer = new MutationObserver(function () {
			syncFromMarkup();
		});

		observer.observe(document.body, {
			subtree: true,
			childList: true,
			attributes: true,
			attributeFilter: ['id', 'href']
		});

		if (window.mw && mw.hook) {
			mw.hook('wikipage.watchlistChange').add(function (isWatched) {
				applyState(isWatched);
				spin();
			});
		}
	}

	if (document.readyState === 'loading') {
		document.addEventListener('DOMContentLoaded', init, { once: true });
	} else {
		init();
	}
}());