미디어위키:Gadget-Vector.js: 두 판 사이의 차이
식물 vs 좀비 위키
편집 요약 없음 태그: 되돌려진 기여 |
편집 요약 없음 태그: 되돌려진 기여 |
||
| 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(); | |||
} | } | ||
}()); | }()); | ||
