편집 요약 없음 태그: 되돌려진 기여 |
편집 요약 없음 태그: 되돌려진 기여 |
||
| 1번째 줄: | 1번째 줄: | ||
/** | /** | ||
* MediaWiki | * MediaWiki customtoggle 펼치기/접기 애니메이션 | ||
* | * | ||
* | * 예: | ||
* .mw-customtoggle-KSC_LEADER | |||
* ↓ | |||
* #mw-customcollapsible-KSC_LEADER | |||
*/ | */ | ||
| 9번째 줄: | 12번째 줄: | ||
var DURATION = 300; | var DURATION = 300; | ||
/** | /** | ||
* | * customtoggle에서 식별자 추출 | ||
* | * | ||
* mw-customtoggle-KSC_LEADER | * mw-customtoggle-KSC_LEADER | ||
* → KSC_LEADER | * → KSC_LEADER | ||
*/ | */ | ||
function | function getToggleId( toggle ) { | ||
var classes = toggle. | var classes = toggle.className.split( /\\s+/ ); | ||
var i; | var i; | ||
for ( i = 0; i < classes.length; i++ ) { | for ( i = 0; i < classes.length; i++ ) { | ||
if ( classes[ i ].indexOf( | if ( | ||
return classes[ i ].substring( | classes[ i ].indexOf( 'mw-customtoggle-' ) === 0 | ||
) { | |||
return classes[ i ].substring( | |||
'mw-customtoggle-'.length | |||
); | |||
} | } | ||
} | } | ||
| 32번째 줄: | 37번째 줄: | ||
/** | /** | ||
* | * 연결된 collapsible 찾기 | ||
*/ | */ | ||
function getTarget( | function getTarget( id ) { | ||
if ( ! | if ( !id ) { | ||
return null; | return null; | ||
} | } | ||
/* | /* | ||
* | * 가장 일반적인 MediaWiki 형식 | ||
*/ | */ | ||
var target = document. | var target = document.getElementById( | ||
' | 'mw-customcollapsible-' + id | ||
); | ); | ||
| 71번째 줄: | 56번째 줄: | ||
/* | /* | ||
* | * 일부 틀에서 class 방식으로 만들어진 경우 대응 | ||
*/ | */ | ||
target = document. | target = document.querySelector( | ||
'mw-customcollapsible-' + | '.mw-customcollapsible-' + | ||
CSS.escape( id ) | |||
); | ); | ||
| 81번째 줄: | 67번째 줄: | ||
/** | /** | ||
* 실제 | * 실제 접히고 펼쳐지는 내용 찾기 | ||
*/ | */ | ||
function getContent( target ) { | function getContent( target ) { | ||
| 92번째 줄: | 78번째 줄: | ||
} | } | ||
/* | |||
* 별도의 mw-collapsible-content가 없으면 | |||
* target 자체를 애니메이션 | |||
*/ | |||
return target; | return target; | ||
} | } | ||
function isCollapsed( target, content ) { | function isCollapsed( target, content ) { | ||
return ( | |||
target.classList.contains( 'mw-collapsed' ) || | |||
window.getComputedStyle( content ).display === 'none' | |||
); | |||
} | } | ||
function expand( target, content, toggle ) { | function expand( target, content, toggle ) { | ||
if ( content.classList.contains( | if ( | ||
content.classList.contains( | |||
'mw-custom-collapse-animating' | |||
) | |||
) { | |||
return; | return; | ||
} | } | ||
target.classList.remove( 'mw-collapsed' ); | target.classList.remove( 'mw-collapsed' ); | ||
| 120번째 줄: | 105번째 줄: | ||
content.style.display = 'block'; | content.style.display = 'block'; | ||
content.style.height = 'auto'; | content.style.height = 'auto'; | ||
var targetHeight = content.scrollHeight; | var targetHeight = content.scrollHeight; | ||
content.style.height = '0px'; | content.style.height = '0px'; | ||
content.style.opacity = ''; | content.style.opacity = '0'; | ||
content.classList.add( | |||
'mw-custom-collapse-animating' | |||
); | |||
/* | /* reflow */ | ||
content.offsetHeight; | content.offsetHeight; | ||
| 136번째 줄: | 122번째 줄: | ||
{ | { | ||
height: '0px', | height: '0px', | ||
opacity: 0 | |||
}, | }, | ||
{ | { | ||
height: targetHeight + 'px', | height: targetHeight + 'px', | ||
opacity: 1 | |||
} | } | ||
], | ], | ||
| 149번째 줄: | 137번째 줄: | ||
animation.onfinish = function () { | animation.onfinish = function () { | ||
content.classList.remove( | content.classList.remove( | ||
'mw-custom-collapse-animating' | |||
); | |||
content.style.display = ''; | content.style.display = ''; | ||
content.style.height = ''; | content.style.height = ''; | ||
content.style.opacity = ''; | content.style.opacity = ''; | ||
toggle.setAttribute( | toggle.setAttribute( | ||
| 165번째 줄: | 154번째 줄: | ||
} | } | ||
function collapse( target, content, toggle ) { | function collapse( target, content, toggle ) { | ||
if ( content.classList.contains( | if ( | ||
content.classList.contains( | |||
'mw-custom-collapse-animating' | |||
) | |||
) { | |||
return; | return; | ||
} | } | ||
var startHeight = | var startHeight = | ||
| 179번째 줄: | 167번째 줄: | ||
content.style.display = 'block'; | content.style.display = 'block'; | ||
content. | |||
content.classList.add( | |||
'mw-custom-collapse-animating' | |||
); | |||
var animation = content.animate( | var animation = content.animate( | ||
| 202번째 줄: | 193번째 줄: | ||
target.classList.add( 'mw-collapsed' ); | target.classList.add( 'mw-collapsed' ); | ||
content.classList.remove( | content.classList.remove( | ||
'mw-custom-collapse-animating' | |||
); | |||
content.style.display = 'none'; | content.style.display = 'none'; | ||
content.style.height = ''; | content.style.height = ''; | ||
content.style.opacity = ''; | content.style.opacity = ''; | ||
toggle.setAttribute( | toggle.setAttribute( | ||
| 218번째 줄: | 210번째 줄: | ||
} | } | ||
function handleToggle( toggle ) { | |||
var id = getToggleId( toggle ); | |||
function | |||
var | |||
if ( ! | if ( !id ) { | ||
return | return; | ||
} | } | ||
var target = getTarget( | var target = getTarget( id ); | ||
if ( !target ) { | if ( !target ) { | ||
return | return; | ||
} | } | ||
| 237번째 줄: | 226번째 줄: | ||
if ( !content ) { | if ( !content ) { | ||
return | return; | ||
} | } | ||
| 253번째 줄: | 242번째 줄: | ||
); | ); | ||
} | } | ||
} | } | ||
/* | /* | ||
* MediaWiki 기본 customtoggle 동작보다 먼저 실행 | |||
* MediaWiki 기본 | |||
*/ | */ | ||
document.addEventListener( | document.addEventListener( | ||
| 274번째 줄: | 258번째 줄: | ||
} | } | ||
if ( ! | if ( !getToggleId( toggle ) ) { | ||
return; | return; | ||
} | } | ||
| 282번째 줄: | 266번째 줄: | ||
event.stopImmediatePropagation(); | event.stopImmediatePropagation(); | ||
handleToggle( toggle ); | |||
}, | }, | ||
true | true | ||
); | ); | ||
/ | /* | ||
* | * 키보드 접근 | ||
*/ | */ | ||
document.addEventListener( | document.addEventListener( | ||
| 305번째 줄: | 289번째 줄: | ||
if ( !toggle ) { | if ( !toggle ) { | ||
return; | return; | ||
} | } | ||
| 316번째 줄: | 296번째 줄: | ||
event.stopImmediatePropagation(); | event.stopImmediatePropagation(); | ||
handleToggle( toggle ); | |||
}, | }, | ||
true | true | ||
2026년 8월 20일 (목) 13:08 판
/**
* MediaWiki customtoggle 펼치기/접기 애니메이션
*
* 예:
* .mw-customtoggle-KSC_LEADER
* ↓
* #mw-customcollapsible-KSC_LEADER
*/
( function () {
'use strict';
var DURATION = 300;
/**
* customtoggle에서 식별자 추출
*
* mw-customtoggle-KSC_LEADER
* → KSC_LEADER
*/
function getToggleId( toggle ) {
var classes = toggle.className.split( /\\s+/ );
var i;
for ( i = 0; i < classes.length; i++ ) {
if (
classes[ i ].indexOf( 'mw-customtoggle-' ) === 0
) {
return classes[ i ].substring(
'mw-customtoggle-'.length
);
}
}
return null;
}
/**
* 연결된 collapsible 찾기
*/
function getTarget( id ) {
if ( !id ) {
return null;
}
/*
* 가장 일반적인 MediaWiki 형식
*/
var target = document.getElementById(
'mw-customcollapsible-' + id
);
if ( target ) {
return target;
}
/*
* 일부 틀에서 class 방식으로 만들어진 경우 대응
*/
target = document.querySelector(
'.mw-customcollapsible-' +
CSS.escape( id )
);
return target;
}
/**
* 실제 접히고 펼쳐지는 내용 찾기
*/
function getContent( target ) {
var content = target.querySelector(
'.mw-collapsible-content'
);
if ( content ) {
return content;
}
/*
* 별도의 mw-collapsible-content가 없으면
* target 자체를 애니메이션
*/
return target;
}
function isCollapsed( target, content ) {
return (
target.classList.contains( 'mw-collapsed' ) ||
window.getComputedStyle( content ).display === 'none'
);
}
function expand( target, content, toggle ) {
if (
content.classList.contains(
'mw-custom-collapse-animating'
)
) {
return;
}
target.classList.remove( 'mw-collapsed' );
content.style.display = 'block';
content.style.height = 'auto';
var targetHeight = content.scrollHeight;
content.style.height = '0px';
content.style.opacity = '0';
content.classList.add(
'mw-custom-collapse-animating'
);
/* reflow */
content.offsetHeight;
var animation = content.animate(
[
{
height: '0px',
opacity: 0
},
{
height: targetHeight + 'px',
opacity: 1
}
],
{
duration: DURATION,
easing: 'ease',
fill: 'forwards'
}
);
animation.onfinish = function () {
content.classList.remove(
'mw-custom-collapse-animating'
);
content.style.display = '';
content.style.height = '';
content.style.opacity = '';
toggle.setAttribute(
'aria-expanded',
'true'
);
animation.cancel();
};
}
function collapse( target, content, toggle ) {
if (
content.classList.contains(
'mw-custom-collapse-animating'
)
) {
return;
}
var startHeight =
content.getBoundingClientRect().height;
content.style.display = 'block';
content.classList.add(
'mw-custom-collapse-animating'
);
var animation = content.animate(
[
{
height: startHeight + 'px',
opacity: 1
},
{
height: '0px',
opacity: 0
}
],
{
duration: DURATION,
easing: 'ease',
fill: 'forwards'
}
);
animation.onfinish = function () {
target.classList.add( 'mw-collapsed' );
content.classList.remove(
'mw-custom-collapse-animating'
);
content.style.display = 'none';
content.style.height = '';
content.style.opacity = '';
toggle.setAttribute(
'aria-expanded',
'false'
);
animation.cancel();
};
}
function handleToggle( toggle ) {
var id = getToggleId( toggle );
if ( !id ) {
return;
}
var target = getTarget( id );
if ( !target ) {
return;
}
var content = getContent( target );
if ( !content ) {
return;
}
if ( isCollapsed( target, content ) ) {
expand(
target,
content,
toggle
);
} else {
collapse(
target,
content,
toggle
);
}
}
/*
* MediaWiki 기본 customtoggle 동작보다 먼저 실행
*/
document.addEventListener(
'click',
function ( event ) {
var toggle = event.target.closest(
'.mw-customtoggle'
);
if ( !toggle ) {
return;
}
if ( !getToggleId( toggle ) ) {
return;
}
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
handleToggle( toggle );
},
true
);
/*
* 키보드 접근
*/
document.addEventListener(
'keydown',
function ( event ) {
if (
event.key !== 'Enter' &&
event.key !== ' '
) {
return;
}
var toggle = event.target.closest(
'.mw-customtoggle'
);
if ( !toggle ) {
return;
}
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
handleToggle( toggle );
},
true
);
}() );