미디어위키:Gadget-ArticleToc.js
식물 vs 좀비 위키
참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.
- 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
- 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
- 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
/* MediaWiki:Gadget-ArticleToc.js
* 데스크톱/모바일 공통 목차 위치 보정 및 자동 생성
*/
(function () {
'use strict';
function getHeadingText(heading) {
var copy = heading.cloneNode(true);
var editLinks = copy.querySelectorAll(
'.mw-editsection, .mw-editsection-like'
);
Array.prototype.forEach.call(editLinks, function (editLink) {
editLink.remove();
});
return copy.textContent.replace(/\s+/g, ' ').trim();
}
function getHeadings(output) {
var headings = output.querySelectorAll('h2, h3, h4, h5, h6');
return Array.prototype.filter.call(headings, function (heading) {
return !heading.closest(
'#toc, .toc, .mw-table-of-contents, .pvz-generated-toc'
);
});
}
function getHeadingBlock(heading) {
return heading.closest(
'.mw-heading, .mw-heading2, .mw-heading3, ' +
'.mw-heading4, .mw-heading5, .mw-heading6'
) || heading;
}
function moveNativeToc(output, firstHeading) {
var toc = output.querySelector(
'#toc, .toc, .mw-table-of-contents'
);
if (!toc) {
return null;
}
toc.classList.add('pvz-custom-toc');
if (firstHeading) {
firstHeading.parentNode.insertBefore(
toc,
getHeadingBlock(firstHeading)
);
}
return toc;
}
function createGeneratedToc(output, headings) {
var existing = output.querySelector('.pvz-generated-toc');
var toc;
var header;
var title;
var button;
var list;
var counters = [0, 0, 0, 0, 0, 0, 0];
var baseLevel;
if (existing || !headings.length) {
return existing;
}
baseLevel = headings.reduce(function (lowest, heading) {
var level = Number(heading.tagName.slice(1));
return Math.min(lowest, level);
}, 6);
toc = document.createElement('nav');
toc.id = 'pvz-generated-toc';
toc.className = 'toc pvz-custom-toc pvz-generated-toc';
toc.setAttribute('role', 'navigation');
toc.setAttribute('aria-labelledby', 'pvz-generated-toc-heading');
header = document.createElement('div');
header.className = 'toctitle pvz-toc-header';
title = document.createElement('h2');
title.id = 'pvz-generated-toc-heading';
title.textContent = '목차';
button = document.createElement('button');
button.type = 'button';
button.className = 'pvz-toc-toggle';
button.textContent = '접기';
button.setAttribute('aria-expanded', 'true');
button.setAttribute('aria-controls', 'pvz-generated-toc-list');
list = document.createElement('ul');
list.id = 'pvz-generated-toc-list';
list.className = 'pvz-toc-list';
headings.forEach(function (heading, index) {
var level = Number(heading.tagName.slice(1));
var text = getHeadingText(heading);
var item;
var link;
var number;
var label;
var numberText;
if (!text) {
return;
}
if (!heading.id) {
heading.id = 'pvz-section-' + (index + 1);
}
counters[level] += 1;
for (var deeper = level + 1; deeper <= 6; deeper += 1) {
counters[deeper] = 0;
}
numberText = counters
.slice(baseLevel, level + 1)
.filter(function (value) {
return value > 0;
})
.join('.');
item = document.createElement('li');
item.className = 'pvz-toc-item toclevel-' + level;
item.style.setProperty(
'--pvz-toc-depth',
String(Math.max(0, level - baseLevel))
);
link = document.createElement('a');
link.href = '#' + heading.id;
number = document.createElement('span');
number.className = 'tocnumber pvz-toc-number';
number.textContent = numberText;
label = document.createElement('span');
label.className = 'toctext pvz-toc-text';
label.textContent = text;
link.appendChild(number);
link.appendChild(label);
item.appendChild(link);
list.appendChild(item);
});
if (!list.children.length) {
return null;
}
button.addEventListener('click', function () {
var isOpen = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!isOpen));
button.textContent = isOpen ? '펼치기' : '접기';
list.hidden = isOpen;
});
header.appendChild(title);
header.appendChild(button);
toc.appendChild(header);
toc.appendChild(list);
getHeadingBlock(headings[0]).parentNode.insertBefore(
toc,
getHeadingBlock(headings[0])
);
return toc;
}
function installArticleToc(root) {
var scope = root && root.querySelector ? root : document;
var output = scope.matches && scope.matches('.mw-parser-output') ?
scope :
scope.querySelector('.mw-parser-output');
var headings;
var nativeToc;
if (!output) {
return;
}
headings = getHeadings(output);
if (!headings.length) {
return;
}
nativeToc = moveNativeToc(output, headings[0]);
if (!nativeToc) {
createGeneratedToc(output, headings);
}
}
function init() {
installArticleToc(document);
if (window.mw && mw.hook) {
mw.hook('wikipage.content').add(function ($content) {
var root = $content && $content[0] ?
$content[0] :
document;
installArticleToc(root);
});
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init, { once: true });
} else {
init();
}
}());
