참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.
- 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
- 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
- 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
- 오페라: Ctrl-F5를 입력.
/**
* MediaWiki 커스텀 펼치기/접기 애니메이션
*
* 틀 구조 수정 불필요.
*
* 지원 구조:
*
* <div id="mw-customcollapsible-XXX" class="mw-collapsible">
* <div class="mw-customtoggle-XXX mw-customtoggle">
* [ 펼치기 · 접기 ]
* </div>
*
* <table>...</table>
* </div>
*
* 토글 버튼은 항상 남겨두고
* 버튼 뒤의 내용만 슬라이드합니다.
*/
( function () {
'use strict';
var DURATION = 300;
function getToggleName( toggle ) {
var prefix = 'mw-customtoggle-';
var classes = toggle.classList;
var i;
for ( i = 0; i < classes.length; i++ ) {
if ( classes[ i ].indexOf( prefix ) === 0 ) {
return classes[ i ].substring( prefix.length );
}
}
return null;
}
function getTarget( toggle ) {
var name = getToggleName( toggle );
if ( !name ) {
return null;
}
return document.getElementById(
'mw-customcollapsible-' + name
);
}
/*
* 토글 버튼 다음에 있는 실제 내용들을 찾음.
*
* 여성 아나운서처럼 같은 div 안에 table이 있는 경우 대응.
*/
function getInternalContents( target, toggle ) {
var contents = [];
var node = toggle.nextElementSibling;
while ( node ) {
contents.push( node );
node = node.nextElementSibling;
}
return contents;
}
/*
* 남성 아나운서처럼 target 바깥 바로 다음에
* table이 있는 경우를 위한 처리.
*/
function getExternalContents( target ) {
var contents = [];
var node = target.nextElementSibling;
while ( node ) {
/*
* 다음 펼치기/접기 영역이 시작되면 종료
*/
if (
node.id &&
node.id.indexOf( 'mw-customcollapsible-' ) === 0
) {
break;
}
contents.push( node );
/*
* 현재 구조에서는 표 하나면 충분하므로
* 첫 실제 요소만 대상으로 함
*/
break;
}
return contents;
}
function getContents( target, toggle ) {
var internal = getInternalContents(
target,
toggle
);
if ( internal.length ) {
return internal;
}
return getExternalContents( target );
}
function isOpen( toggle, contents ) {
if (
toggle.getAttribute( 'aria-expanded' ) ===
'false'
) {
return false;
}
if ( !contents.length ) {
return false;
}
return (
window.getComputedStyle(
contents[ 0 ]
).display !== 'none'
);
}
/*
* 펼치기
*/
function openContents( toggle, contents ) {
toggle.setAttribute(
'aria-expanded',
'true'
);
contents.forEach( function ( element ) {
if ( element._collapseAnimation ) {
element._collapseAnimation.cancel();
}
/*
* 먼저 원래 display 복구
*/
element.style.display = '';
/*
* CSS 때문에 여전히 none인 경우
* 태그에 맞는 display 사용
*/
if (
window.getComputedStyle( element ).display ===
'none'
) {
if ( element.tagName === 'TABLE' ) {
element.style.display = 'table';
} else {
element.style.display = 'block';
}
}
var endHeight = element.scrollHeight;
element.style.overflow = 'hidden';
var animation = element.animate(
[
{
height: '0px'
},
{
height: endHeight + 'px'
}
],
{
duration: DURATION,
easing: 'ease',
fill: 'forwards'
}
);
element._collapseAnimation =
animation;
animation.onfinish = function () {
element.style.height = '';
element.style.overflow = '';
element.style.display = '';
element._collapseAnimation =
null;
animation.cancel();
};
} );
}
/*
* 접기
*/
function closeContents( toggle, contents ) {
toggle.setAttribute(
'aria-expanded',
'false'
);
contents.forEach( function ( element ) {
if ( element._collapseAnimation ) {
element._collapseAnimation.cancel();
}
var startHeight =
element.getBoundingClientRect().height;
if ( startHeight <= 0 ) {
element.style.display = 'none';
return;
}
element.style.overflow = 'hidden';
var animation = element.animate(
[
{
height:
startHeight + 'px'
},
{
height: '0px'
}
],
{
duration: DURATION,
easing: 'ease',
fill: 'forwards'
}
);
element._collapseAnimation =
animation;
animation.onfinish = function () {
element.style.display = 'none';
element.style.height = '';
element.style.overflow = '';
element._collapseAnimation =
null;
animation.cancel();
};
} );
}
function handleClick( event ) {
var toggle = event.currentTarget;
var target = getTarget( toggle );
if ( !target ) {
return;
}
var contents = getContents(
target,
toggle
);
/*
* 대상을 못 찾았다면 MediaWiki 기본 기능을
* 막지 않고 그대로 둔다.
*/
if ( !contents.length ) {
return;
}
/*
* 이제 대상이 확실하게 있을 때만
* MediaWiki 기본 즉시 접기/펼치기를 막음.
*/
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
if ( isOpen( toggle, contents ) ) {
closeContents(
toggle,
contents
);
} else {
openContents(
toggle,
contents
);
}
}
function handleKeydown( event ) {
if (
event.key !== 'Enter' &&
event.key !== ' '
) {
return;
}
handleClick( event );
}
function initialize() {
var toggles =
document.querySelectorAll(
'.mw-customtoggle'
);
toggles.forEach( function ( toggle ) {
if (
!getToggleName( toggle ) ||
toggle.dataset.collapseAnimationReady === '1'
) {
return;
}
toggle.dataset.collapseAnimationReady =
'1';
/*
* document capture가 아니라
* 실제 버튼 자체에 직접 등록
*/
toggle.addEventListener(
'click',
handleClick
);
toggle.addEventListener(
'keydown',
handleKeydown
);
} );
}
if ( document.readyState === 'loading' ) {
document.addEventListener(
'DOMContentLoaded',
initialize
);
} else {
initialize();
}
if ( window.mw && mw.hook ) {
mw.hook( 'wikipage.content' ).add(
function () {
initialize();
}
);
}
}() );