미디어위키:Gadget-Vector.js: 두 판 사이의 차이
둘러보기로 이동
검색으로 이동
편집 요약 없음 태그: 되돌려진 기여 |
편집 요약 없음 태그: 되돌려진 기여 |
||
| 255번째 줄: | 255번째 줄: | ||
'use strict'; | 'use strict'; | ||
var | var MAX_RELATED = 5; | ||
var | var loaded = false; | ||
var | var loading = false; | ||
function | function clearV24Interface() { | ||
var | var ids = [ | ||
'pvz-right-panel', | |||
'pvz-left-panel-toggle', | |||
'pvz-right-panel-toggle' | |||
]; | |||
ids.forEach(function (id) { | |||
var element = document.getElementById(id); | |||
if (element) { | |||
element.remove(); | |||
} | |||
}); | }); | ||
document.documentElement.classList.remove( | |||
'pvz-font-small', | |||
'pvz-font-normal', | |||
'pvz-font-large', | |||
'pvz-width-narrow', | |||
'pvz-width-normal', | |||
'pvz-width-wide', | |||
'pvz-left-panel-open', | |||
'pvz-right-panel-open' | |||
); | ); | ||
} | } | ||
| 350번째 줄: | 305번째 줄: | ||
} | } | ||
function | function syncPanelTop() { | ||
var | 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 | function syncSearchTop() { | ||
var | var personal = document.querySelector('.skin-vector-legacy #p-personal'); | ||
var top; | |||
var | |||
if (!personal) { | |||
return; | |||
} | |||
} | |||
top = personal.getBoundingClientRect().bottom + window.scrollY + 5; | |||
document.documentElement.style.setProperty('--pvz-search-top', top + 'px'); | |||
} | } | ||
function | function makeRelatedInterface() { | ||
var | var button = document.getElementById('pvz-related-toggle'); | ||
var menu = document.getElementById('pvz-related-menu'); | |||
var lines; | |||
var title; | |||
var list; | |||
if (!document.body) { | if (!document.body) { | ||
| 394번째 줄: | 340번째 줄: | ||
} | } | ||
if (! | if (!button) { | ||
button = document.createElement('button'); | |||
button.id = 'pvz-related-toggle'; | |||
button.type = 'button'; | |||
document.body.appendChild( | button.setAttribute('aria-label', '관련 문서 열기'); | ||
button.setAttribute('title', '관련 문서'); | |||
button.setAttribute('aria-expanded', 'false'); | |||
lines = document.createElement('span'); | |||
lines.className = 'pvz-related-toggle-lines'; | |||
lines.setAttribute('aria-hidden', 'true'); | |||
button.appendChild(lines); | |||
document.body.appendChild(button); | |||
} | } | ||
if (!menu) { | |||
menu = document.createElement('aside'); | |||
menu.id = 'pvz-related-menu'; | |||
menu.setAttribute('aria-label', '관련 문서'); | |||
title = document.createElement('h2'); | |||
title.className = 'pvz-related-title'; | |||
title.textContent = '관련 문서'; | |||
list = document.createElement('ul'); | |||
list.className = 'pvz-related-list'; | |||
menu.appendChild(title); | |||
menu.appendChild(list); | |||
document.body.appendChild(menu); | |||
} | |||
if (button.getAttribute('data-pvz-ready') !== 'true') { | |||
button.setAttribute('data-pvz-ready', 'true'); | |||
button.addEventListener('click', function () { | |||
var willOpen = !menu.classList.contains('is-open'); | |||
menu.classList.toggle('is-open', willOpen); | |||
button.setAttribute('aria-expanded', willOpen ? 'true' : 'false'); | |||
button.setAttribute( | |||
'aria-label', | |||
willOpen ? '관련 문서 닫기' : '관련 문서 열기' | |||
); | |||
if (willOpen && !loaded && !loading) { | |||
loadRelatedPages(menu); | |||
} | |||
}); | |||
if ( | document.addEventListener('click', function (event) { | ||
if ( | |||
} | menu.classList.contains('is-open') && | ||
!menu.contains(event.target) && | |||
!button.contains(event.target) | |||
) { | |||
menu.classList.remove('is-open'); | |||
button.setAttribute('aria-expanded', 'false'); | |||
button.setAttribute('aria-label', '관련 문서 열기'); | |||
} | |||
}); | |||
} | |||
} | |||
function setRelatedMessage(menu, message) { | |||
var list = menu.querySelector('.pvz-related-list'); | |||
var item = document.createElement('li'); | |||
var text = document.createElement('span'); | |||
list.textContent = ''; | |||
text.className = 'pvz-related-empty'; | |||
text.textContent = message; | |||
item.appendChild(text); | |||
list.appendChild(item); | |||
} | } | ||
function | function renderRelatedPages(menu, titles) { | ||
var | var list = menu.querySelector('.pvz-related-list'); | ||
list.textContent = ''; | |||
titles.slice(0, MAX_RELATED).forEach(function (title) { | |||
var item = document.createElement('li'); | |||
var link = document.createElement('a'); | |||
link.href = mw.util.getUrl(title); | |||
link.textContent = title; | |||
item.appendChild(link); | |||
list.appendChild(item); | |||
}); | |||
if (!list.children.length) { | |||
setRelatedMessage(menu, '관련 문서가 없습니다.'); | |||
} | } | ||
loaded = true; | |||
loading = false; | |||
} | } | ||
function | function extractLinkedTitles(data) { | ||
var | var pages = data && data.query && data.query.pages; | ||
var currentTitle = mw.config.get('wgPageName').replace(/_/g, ' '); | |||
var titles = []; | |||
var seen = Object.create(null); | |||
var | |||
if (!pages) { | |||
return titles; | |||
} | |||
Object.keys(pages).some(function (pageId) { | |||
var links = pages[pageId].links || []; | |||
links.forEach(function (link) { | |||
var | var title = link.title; | ||
if ( | |||
title && | |||
title !== currentTitle && | |||
!seen[title] && | |||
titles.length < MAX_RELATED | |||
) { | |||
seen[title] = true; | |||
titles.push(title); | |||
} | |||
}); | }); | ||
return titles.length >= MAX_RELATED; | |||
}); | }); | ||
return titles; | |||
} | } | ||
function | function searchFallback(menu) { | ||
var | var pageTitle = mw.config.get('wgTitle') || ''; | ||
return new mw.Api().get({ | |||
var | action: 'query', | ||
var | list: 'search', | ||
var | srsearch: pageTitle, | ||
( | srnamespace: 0, | ||
( | srlimit: MAX_RELATED + 1, | ||
formatversion: 2 | |||
}).then(function (data) { | |||
var currentTitle = mw.config.get('wgPageName').replace(/_/g, ' '); | |||
var results = data && data.query && data.query.search | |||
? data.query.search | |||
: []; | |||
var titles = results | |||
.map(function (result) { | |||
return result.title; | |||
}) | |||
.filter(function (title) { | |||
return title && title !== currentTitle; | |||
}) | |||
.slice(0, MAX_RELATED); | |||
renderRelatedPages(menu, titles); | |||
}); | }); | ||
} | } | ||
function | function loadRelatedPages(menu) { | ||
var | var articleId = mw.config.get('wgArticleId'); | ||
loading = true; | |||
setRelatedMessage(menu, '관련 문서를 불러오는 중…'); | |||
if ( | if (!window.mw || !mw.Api || !mw.util) { | ||
setRelatedMessage(menu, '관련 문서를 불러올 수 없습니다.'); | |||
loading = false; | |||
return; | |||
} | } | ||
if (!articleId) { | |||
searchFallback(menu).catch(function () { | |||
setRelatedMessage(menu, '관련 문서가 없습니다.'); | |||
loading = false; | |||
}); | |||
return; | return; | ||
} | } | ||
new mw.Api().get({ | |||
action: 'query', | |||
prop: 'links', | |||
pageids: articleId, | |||
plnamespace: 0, | |||
pllimit: 20, | |||
formatversion: 2 | |||
}).then(function (data) { | |||
var titles = extractLinkedTitles(data); | |||
if (titles.length) { | |||
renderRelatedPages(menu, titles); | |||
return; | |||
} | |||
return searchFallback(menu); | |||
}).catch(function () { | |||
return searchFallback(menu); | |||
}).catch(function () { | |||
setRelatedMessage(menu, '관련 문서를 불러올 수 없습니다.'); | |||
loading = false; | |||
}); | |||
} | } | ||
function | function installV25Interface() { | ||
var panel = document.querySelector('.skin-vector-legacy #mw-panel'); | var panel = document.querySelector('.skin-vector-legacy #mw-panel'); | ||
if ( | clearV24Interface(); | ||
if (panel) { | |||
moveLogoOutsidePanel(panel); | |||
} | } | ||
makeRelatedInterface(); | |||
syncPanelTop(); | syncPanelTop(); | ||
syncSearchTop(); | |||
} | } | ||
function | function initV25Interface() { | ||
installV25Interface(); | |||
window.addEventListener('resize', function () { | window.addEventListener('resize', function () { | ||
syncPanelTop(); | syncPanelTop(); | ||
syncSearchTop(); | |||
}, { passive: true }); | }, { passive: true }); | ||
window.addEventListener('orientationchange', function () { | window.addEventListener('orientationchange', function () { | ||
syncPanelTop(); | syncPanelTop(); | ||
syncSearchTop(); | |||
}, { passive: true }); | }, { passive: true }); | ||
} | } | ||
if (document.readyState === 'loading') { | if (document.readyState === 'loading') { | ||
document.addEventListener('DOMContentLoaded', | document.addEventListener('DOMContentLoaded', initV25Interface, { once: true }); | ||
} else { | } else { | ||
initV25Interface(); | |||
} | } | ||
}()); | }()); | ||
2026년 7월 29일 (수) 23:38 판
(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 MAX_RELATED = 5;
var loaded = false;
var loading = false;
function clearV24Interface() {
var ids = [
'pvz-right-panel',
'pvz-left-panel-toggle',
'pvz-right-panel-toggle'
];
ids.forEach(function (id) {
var element = document.getElementById(id);
if (element) {
element.remove();
}
});
document.documentElement.classList.remove(
'pvz-font-small',
'pvz-font-normal',
'pvz-font-large',
'pvz-width-narrow',
'pvz-width-normal',
'pvz-width-wide',
'pvz-left-panel-open',
'pvz-right-panel-open'
);
}
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 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 syncSearchTop() {
var personal = document.querySelector('.skin-vector-legacy #p-personal');
var top;
if (!personal) {
return;
}
top = personal.getBoundingClientRect().bottom + window.scrollY + 5;
document.documentElement.style.setProperty('--pvz-search-top', top + 'px');
}
function makeRelatedInterface() {
var button = document.getElementById('pvz-related-toggle');
var menu = document.getElementById('pvz-related-menu');
var lines;
var title;
var list;
if (!document.body) {
return;
}
if (!button) {
button = document.createElement('button');
button.id = 'pvz-related-toggle';
button.type = 'button';
button.setAttribute('aria-label', '관련 문서 열기');
button.setAttribute('title', '관련 문서');
button.setAttribute('aria-expanded', 'false');
lines = document.createElement('span');
lines.className = 'pvz-related-toggle-lines';
lines.setAttribute('aria-hidden', 'true');
button.appendChild(lines);
document.body.appendChild(button);
}
if (!menu) {
menu = document.createElement('aside');
menu.id = 'pvz-related-menu';
menu.setAttribute('aria-label', '관련 문서');
title = document.createElement('h2');
title.className = 'pvz-related-title';
title.textContent = '관련 문서';
list = document.createElement('ul');
list.className = 'pvz-related-list';
menu.appendChild(title);
menu.appendChild(list);
document.body.appendChild(menu);
}
if (button.getAttribute('data-pvz-ready') !== 'true') {
button.setAttribute('data-pvz-ready', 'true');
button.addEventListener('click', function () {
var willOpen = !menu.classList.contains('is-open');
menu.classList.toggle('is-open', willOpen);
button.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
button.setAttribute(
'aria-label',
willOpen ? '관련 문서 닫기' : '관련 문서 열기'
);
if (willOpen && !loaded && !loading) {
loadRelatedPages(menu);
}
});
document.addEventListener('click', function (event) {
if (
menu.classList.contains('is-open') &&
!menu.contains(event.target) &&
!button.contains(event.target)
) {
menu.classList.remove('is-open');
button.setAttribute('aria-expanded', 'false');
button.setAttribute('aria-label', '관련 문서 열기');
}
});
}
}
function setRelatedMessage(menu, message) {
var list = menu.querySelector('.pvz-related-list');
var item = document.createElement('li');
var text = document.createElement('span');
list.textContent = '';
text.className = 'pvz-related-empty';
text.textContent = message;
item.appendChild(text);
list.appendChild(item);
}
function renderRelatedPages(menu, titles) {
var list = menu.querySelector('.pvz-related-list');
list.textContent = '';
titles.slice(0, MAX_RELATED).forEach(function (title) {
var item = document.createElement('li');
var link = document.createElement('a');
link.href = mw.util.getUrl(title);
link.textContent = title;
item.appendChild(link);
list.appendChild(item);
});
if (!list.children.length) {
setRelatedMessage(menu, '관련 문서가 없습니다.');
}
loaded = true;
loading = false;
}
function extractLinkedTitles(data) {
var pages = data && data.query && data.query.pages;
var currentTitle = mw.config.get('wgPageName').replace(/_/g, ' ');
var titles = [];
var seen = Object.create(null);
if (!pages) {
return titles;
}
Object.keys(pages).some(function (pageId) {
var links = pages[pageId].links || [];
links.forEach(function (link) {
var title = link.title;
if (
title &&
title !== currentTitle &&
!seen[title] &&
titles.length < MAX_RELATED
) {
seen[title] = true;
titles.push(title);
}
});
return titles.length >= MAX_RELATED;
});
return titles;
}
function searchFallback(menu) {
var pageTitle = mw.config.get('wgTitle') || '';
return new mw.Api().get({
action: 'query',
list: 'search',
srsearch: pageTitle,
srnamespace: 0,
srlimit: MAX_RELATED + 1,
formatversion: 2
}).then(function (data) {
var currentTitle = mw.config.get('wgPageName').replace(/_/g, ' ');
var results = data && data.query && data.query.search
? data.query.search
: [];
var titles = results
.map(function (result) {
return result.title;
})
.filter(function (title) {
return title && title !== currentTitle;
})
.slice(0, MAX_RELATED);
renderRelatedPages(menu, titles);
});
}
function loadRelatedPages(menu) {
var articleId = mw.config.get('wgArticleId');
loading = true;
setRelatedMessage(menu, '관련 문서를 불러오는 중…');
if (!window.mw || !mw.Api || !mw.util) {
setRelatedMessage(menu, '관련 문서를 불러올 수 없습니다.');
loading = false;
return;
}
if (!articleId) {
searchFallback(menu).catch(function () {
setRelatedMessage(menu, '관련 문서가 없습니다.');
loading = false;
});
return;
}
new mw.Api().get({
action: 'query',
prop: 'links',
pageids: articleId,
plnamespace: 0,
pllimit: 20,
formatversion: 2
}).then(function (data) {
var titles = extractLinkedTitles(data);
if (titles.length) {
renderRelatedPages(menu, titles);
return;
}
return searchFallback(menu);
}).catch(function () {
return searchFallback(menu);
}).catch(function () {
setRelatedMessage(menu, '관련 문서를 불러올 수 없습니다.');
loading = false;
});
}
function installV25Interface() {
var panel = document.querySelector('.skin-vector-legacy #mw-panel');
clearV24Interface();
if (panel) {
moveLogoOutsidePanel(panel);
}
makeRelatedInterface();
syncPanelTop();
syncSearchTop();
}
function initV25Interface() {
installV25Interface();
window.addEventListener('resize', function () {
syncPanelTop();
syncSearchTop();
}, { passive: true });
window.addEventListener('orientationchange', function () {
syncPanelTop();
syncSearchTop();
}, { passive: true });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initV25Interface, { once: true });
} else {
initV25Interface();
}
}());