미디어위키:Gadget-Vector.js
식물 vs 좀비 위키
참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.
- 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
- 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
- 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
(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 shortenHistoryLabel() {
var historyLink = document.querySelector('#ca-history > a');
if (!historyLink) {
return;
}
Array.prototype.forEach.call(historyLink.childNodes, function (node) {
if (node.nodeType === Node.TEXT_NODE) {
node.nodeValue = node.nodeValue.replace(/역사 보기/g, '역사');
}
});
if (historyLink.textContent.trim() === '역사 보기') {
historyLink.textContent = '역사';
}
historyLink.setAttribute('title', '역사');
}
function init() {
var observer;
shortenHistoryLabel();
syncFromMarkup();
document.addEventListener('click', handleClick, true);
observer = new MutationObserver(function () {
shortenHistoryLabel();
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();
}
}());
(function () {
'use strict';
function installSearchButtonIcon(wrapper) {
var simpleSearch;
var searchButton;
var icon;
if (!wrapper) {
return;
}
simpleSearch = wrapper.querySelector('#simpleSearch');
if (!simpleSearch) {
return;
}
searchButton =
simpleSearch.querySelector('#searchButton') ||
simpleSearch.querySelector('.searchButton:not(#mw-searchButton)');
if (!searchButton) {
return;
}
searchButton.classList.add('pvz-primary-search-button');
icon = simpleSearch.querySelector('.pvz-search-button-icon');
if (!icon) {
icon = document.createElement('span');
icon.className = 'pvz-search-button-icon';
icon.setAttribute('aria-hidden', 'true');
simpleSearch.appendChild(icon);
}
}
function installTopSearch() {
var content = document.querySelector('.skin-vector-legacy #content');
var form = document.querySelector('#searchform');
var wrapper;
if (!content || !form || !document.body) {
return;
}
wrapper = document.getElementById('pvz-content-search');
if (!wrapper) {
wrapper = document.createElement('div');
wrapper.id = 'pvz-content-search';
wrapper.setAttribute('role', 'search');
wrapper.setAttribute('aria-label', '사이트 검색');
}
if (wrapper.parentNode !== document.body) {
document.body.insertBefore(wrapper, content);
}
if (form.parentNode !== wrapper) {
wrapper.appendChild(form);
}
installSearchButtonIcon(wrapper);
document.documentElement.classList.add('pvz-content-search-ready');
}
function initTopSearch() {
var observer;
installTopSearch();
observer = new MutationObserver(function () {
installTopSearch();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initTopSearch, { once: true });
} else {
initTopSearch();
}
}());
(function () {
'use strict';
function syncSearchLeft() {
var content = document.querySelector('.skin-vector-legacy #content');
var left;
if (!content) {
return;
}
left = content.getBoundingClientRect().left + window.scrollX;
document.documentElement.style.setProperty('--pvz-content-left', left + 'px');
}
function initSearchAlignment() {
syncSearchLeft();
window.addEventListener('resize', syncSearchLeft, { passive: true });
window.addEventListener('orientationchange', syncSearchLeft, { passive: true });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSearchAlignment, { once: true });
} else {
initSearchAlignment();
}
}());
(function () {
'use strict';
var FONT_VALUES = ['small', 'normal', 'large'];
var WIDTH_VALUES = ['narrow', 'normal', 'wide'];
var FONT_KEY = 'pvz-vector-font-size';
var WIDTH_KEY = 'pvz-vector-content-width';
function readPreference(key, allowed, fallback) {
var value;
try {
value = window.localStorage.getItem(key);
} catch (error) {
value = null;
}
return allowed.indexOf(value) !== -1 ? value : fallback;
}
function savePreference(key, value) {
try {
window.localStorage.setItem(key, value);
} catch (error) {
/* 저장소를 사용할 수 없는 환경에서는 현재 화면에만 적용한다. */
}
}
function replacePreferenceClass(prefix, allowed, value) {
var root = document.documentElement;
allowed.forEach(function (item) {
root.classList.remove(prefix + item);
});
root.classList.add(prefix + value);
}
function applyFontSize(value, shouldSave) {
replacePreferenceClass('pvz-font-', FONT_VALUES, value);
if (shouldSave) {
savePreference(FONT_KEY, value);
}
updateControlStates();
}
function applyContentWidth(value, shouldSave) {
replacePreferenceClass('pvz-width-', WIDTH_VALUES, value);
if (value !== 'wide') {
document.documentElement.classList.remove(
'pvz-left-panel-open',
'pvz-right-panel-open'
);
}
if (shouldSave) {
savePreference(WIDTH_KEY, value);
}
updateControlStates();
updateToggleStates();
window.requestAnimationFrame(syncPanelTop);
window.requestAnimationFrame(syncSearchLeft);
}
function applyStoredPreferences() {
applyFontSize(
readPreference(FONT_KEY, FONT_VALUES, 'normal'),
false
);
applyContentWidth(
readPreference(WIDTH_KEY, WIDTH_VALUES, 'normal'),
false
);
}
function moveLogoOutsidePanel(panel) {
var logo = panel && panel.querySelector('#p-logo');
var wrapper = document.getElementById('pvz-sidebar-logo');
if (!logo || !document.body) {
return;
}
if (!wrapper) {
wrapper = document.createElement('div');
wrapper.id = 'pvz-sidebar-logo';
document.body.appendChild(wrapper);
}
if (logo.parentNode !== wrapper) {
wrapper.appendChild(logo);
}
}
function makeOption(label, group, value) {
var button = document.createElement('button');
button.type = 'button';
button.className = 'pvz-settings-option';
button.textContent = label;
button.setAttribute('data-pvz-setting-group', group);
button.setAttribute('data-pvz-setting-value', value);
button.setAttribute('aria-pressed', 'false');
return button;
}
function makeSettingsSection(title, group, options) {
var section = document.createElement('section');
var heading = document.createElement('h3');
var optionList = document.createElement('div');
section.className = 'pvz-settings-section';
heading.className = 'pvz-settings-heading';
heading.textContent = title;
optionList.className = 'pvz-settings-options';
optionList.setAttribute('role', 'group');
optionList.setAttribute('aria-label', title);
options.forEach(function (option) {
optionList.appendChild(
makeOption(option.label, group, option.value)
);
});
section.appendChild(heading);
section.appendChild(optionList);
return section;
}
function buildRightPanel() {
var rightPanel = document.getElementById('pvz-right-panel');
if (!document.body) {
return;
}
if (!rightPanel) {
rightPanel = document.createElement('aside');
rightPanel.id = 'pvz-right-panel';
rightPanel.setAttribute('aria-label', '화면 설정');
document.body.appendChild(rightPanel);
}
rightPanel.textContent = '';
rightPanel.appendChild(
makeSettingsSection('글자 크기', 'font', [
{ label: '작게', value: 'small' },
{ label: '보통', value: 'normal' },
{ label: '크게', value: 'large' }
])
);
rightPanel.appendChild(
makeSettingsSection('화면 너비', 'width', [
{ label: '좁게', value: 'narrow' },
{ label: '보통', value: 'normal' },
{ label: '넓게', value: 'wide' }
])
);
rightPanel.addEventListener('click', function (event) {
var option = event.target.closest('.pvz-settings-option');
var group;
var value;
if (!option) {
return;
}
group = option.getAttribute('data-pvz-setting-group');
value = option.getAttribute('data-pvz-setting-value');
if (group === 'font' && FONT_VALUES.indexOf(value) !== -1) {
applyFontSize(value, true);
}
if (group === 'width' && WIDTH_VALUES.indexOf(value) !== -1) {
applyContentWidth(value, true);
}
});
updateControlStates();
}
function makePanelToggle(id, label, side) {
var button = document.getElementById(id);
var lines;
if (!button) {
button = document.createElement('button');
button.id = id;
button.type = 'button';
button.className = 'pvz-panel-toggle';
button.setAttribute('aria-label', label);
button.setAttribute('title', label);
button.setAttribute('aria-expanded', 'false');
button.setAttribute('data-pvz-panel-side', side);
lines = document.createElement('span');
lines.className = 'pvz-panel-toggle-lines';
lines.setAttribute('aria-hidden', 'true');
button.appendChild(lines);
document.body.appendChild(button);
}
return button;
}
function installPanelToggles() {
var leftToggle = makePanelToggle(
'pvz-left-panel-toggle',
'왼쪽 보조창 열기',
'left'
);
var rightToggle = makePanelToggle(
'pvz-right-panel-toggle',
'오른쪽 설정창 열기',
'right'
);
[leftToggle, rightToggle].forEach(function (button) {
if (button.getAttribute('data-pvz-toggle-ready') === 'true') {
return;
}
button.setAttribute('data-pvz-toggle-ready', 'true');
button.addEventListener('click', function () {
var root = document.documentElement;
var side = button.getAttribute('data-pvz-panel-side');
var targetClass =
side === 'left'
? 'pvz-left-panel-open'
: 'pvz-right-panel-open';
var otherClass =
side === 'left'
? 'pvz-right-panel-open'
: 'pvz-left-panel-open';
var willOpen = !root.classList.contains(targetClass);
root.classList.remove(otherClass);
root.classList.toggle(targetClass, willOpen);
updateToggleStates();
});
});
updateToggleStates();
}
function updateControlStates() {
var root = document.documentElement;
var options = document.querySelectorAll('.pvz-settings-option');
Array.prototype.forEach.call(options, function (option) {
var group = option.getAttribute('data-pvz-setting-group');
var value = option.getAttribute('data-pvz-setting-value');
var active =
(group === 'font' && root.classList.contains('pvz-font-' + value)) ||
(group === 'width' && root.classList.contains('pvz-width-' + value));
option.classList.toggle('is-active', active);
option.setAttribute('aria-pressed', active ? 'true' : 'false');
});
}
function updateToggleStates() {
var root = document.documentElement;
var leftToggle = document.getElementById('pvz-left-panel-toggle');
var rightToggle = document.getElementById('pvz-right-panel-toggle');
var leftOpen = root.classList.contains('pvz-left-panel-open');
var rightOpen = root.classList.contains('pvz-right-panel-open');
if (leftToggle) {
leftToggle.setAttribute('aria-expanded', leftOpen ? 'true' : 'false');
leftToggle.setAttribute(
'aria-label',
leftOpen ? '왼쪽 보조창 닫기' : '왼쪽 보조창 열기'
);
leftToggle.setAttribute(
'title',
leftOpen ? '왼쪽 보조창 닫기' : '왼쪽 보조창 열기'
);
}
if (rightToggle) {
rightToggle.setAttribute('aria-expanded', rightOpen ? 'true' : 'false');
rightToggle.setAttribute(
'aria-label',
rightOpen ? '오른쪽 설정창 닫기' : '오른쪽 설정창 열기'
);
rightToggle.setAttribute(
'title',
rightOpen ? '오른쪽 설정창 닫기' : '오른쪽 설정창 열기'
);
}
}
function syncPanelTop() {
var content = document.querySelector('.skin-vector-legacy #content');
var top;
if (!content) {
return;
}
top = content.getBoundingClientRect().top + window.scrollY;
document.documentElement.style.setProperty('--pvz-content-top', top + 'px');
}
function syncSearchLeft() {
var content = document.querySelector('.skin-vector-legacy #content');
var left;
if (!content) {
return;
}
left = content.getBoundingClientRect().left + window.scrollX;
document.documentElement.style.setProperty('--pvz-content-left', left + 'px');
}
function installSidePanels() {
var panel = document.querySelector('.skin-vector-legacy #mw-panel');
if (!panel || !document.body) {
return;
}
moveLogoOutsidePanel(panel);
buildRightPanel();
installPanelToggles();
syncPanelTop();
syncSearchLeft();
}
function initSidePanels() {
installSidePanels();
window.addEventListener('resize', function () {
syncPanelTop();
syncSearchLeft();
}, { passive: true });
window.addEventListener('orientationchange', function () {
syncPanelTop();
syncSearchLeft();
}, { passive: true });
}
applyStoredPreferences();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSidePanels, { once: true });
} else {
initSidePanels();
}
}());
