편집 요약 없음 |
편집 요약 없음 |
||
| 4번째 줄: | 4번째 줄: | ||
* 지원: | * 지원: | ||
* | * | ||
* 1. 일반 구조 | * 1. 일반 MediaWiki 구조 | ||
* | * | ||
* .mw-customtoggle-XXX | * .mw-customtoggle-XXX | ||
| 27번째 줄: | 27번째 줄: | ||
* TWICE_ETC | * TWICE_ETC | ||
* TWICE_REL | * TWICE_REL | ||
* | |||
* | |||
* 4. 정보상자 / table / rowspan 내부 지원 | |||
* | |||
* mw-collapsible 자체의 height를 직접 변경하지 않고 | |||
* 내부 wrapper만 slide 처리하여 | |||
* table 레이아웃 재계산 문제를 줄임. | |||
* | * | ||
* | * | ||
| 42번째 줄: | 49번째 줄: | ||
var DATA_DISPLAY = | var DATA_DISPLAY = | ||
'mwCustomCollapseDisplay'; | 'mwCustomCollapseDisplay'; | ||
var INNER_CLASS = | |||
'mw-custom-collapse-inner'; | |||
var DATA_WRAPPED = | |||
'mwCustomCollapseWrapped'; | |||
| 97번째 줄: | 110번째 줄: | ||
/** | /** | ||
* 같은 | * 같은 name을 가진 모든 target 검색 | ||
*/ | */ | ||
function getTargets( name ) { | function getTargets( name ) { | ||
| 122번째 줄: | 133번째 줄: | ||
* .mw-collapsible-content 검색 | * .mw-collapsible-content 검색 | ||
* | * | ||
* | * 중첩 collapsible 오선택 방지. | ||
*/ | */ | ||
function getDirectContent( target ) { | function getDirectContent( target ) { | ||
| 137번째 줄: | 147번째 줄: | ||
) { | ) { | ||
if ( | if ( | ||
children[ i ] | children[ i ].classList && | ||
children[ i ].classList.contains( | |||
'mw-collapsible-content' | |||
) | |||
) | ) { | ||
return children[ i ]; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* 기존에 만든 내부 wrapper 검색 | |||
*/ | |||
function getDirectInnerWrapper( target ) { | |||
var children = | |||
target.children; | |||
var i; | |||
for ( | |||
i = 0; | |||
i < children.length; | |||
i++ | |||
) { | |||
if ( | |||
children[ i ].classList && | |||
children[ i ].classList.contains( | |||
INNER_CLASS | |||
) | |||
) { | ) { | ||
return children[ i ]; | return children[ i ]; | ||
| 152번째 줄: | 189번째 줄: | ||
/** | /** | ||
* 실제 | * target 내부에 애니메이션용 wrapper 생성 | ||
* | |||
* .mw-collapsible-content가 없는 구조에서 사용. | |||
* | |||
* target 자체 height를 변경하지 않고 | |||
* 내부 wrapper만 slide 처리. | |||
*/ | |||
function createInnerWrapper( target ) { | |||
var existing = | |||
getDirectInnerWrapper( | |||
target | |||
); | |||
if ( existing ) { | |||
return existing; | |||
} | |||
var wrapper = | |||
document.createElement( | |||
'div' | |||
); | |||
wrapper.className = | |||
INNER_CLASS; | |||
/* | |||
* 기존 자식 전부 wrapper 안으로 이동 | |||
*/ | |||
while ( | |||
target.firstChild | |||
) { | |||
wrapper.appendChild( | |||
target.firstChild | |||
); | |||
} | |||
target.appendChild( | |||
wrapper | |||
); | |||
$( target ).data( | |||
DATA_WRAPPED, | |||
true | |||
); | |||
return wrapper; | |||
} | |||
/** | |||
* 실제 애니메이션 요소 결정 | |||
* | * | ||
* | * 1순위: | ||
* .mw-collapsible-content | * .mw-collapsible-content | ||
* | * | ||
* | * 2순위: | ||
* | * 자동 생성 inner wrapper | ||
*/ | */ | ||
function getAnimatedElement( target ) { | function getAnimatedElement( target ) { | ||
| 170번째 줄: | 262번째 줄: | ||
} | } | ||
return target; | |||
return createInnerWrapper( | |||
target | |||
); | |||
} | } | ||
/** | /** | ||
* target 자신의 직계 | * target 자신의 직계 토글 검색 | ||
* | * | ||
* | * inner wrapper가 생성된 뒤에는 | ||
* | * 토글이 wrapper 안으로 들어가므로 | ||
* wrapper 내부도 확인. | |||
*/ | */ | ||
function getOwnToggle( | function getOwnToggle( | ||
| 193번째 줄: | 288번째 줄: | ||
var i; | var i; | ||
for ( | for ( | ||
| 208번째 줄: | 304번째 줄: | ||
} | } | ||
} | } | ||
var wrapper = | |||
getDirectInnerWrapper( | |||
target | |||
); | |||
if ( wrapper ) { | |||
children = | |||
wrapper.children; | |||
for ( | |||
i = 0; | |||
i < children.length; | |||
i++ | |||
) { | |||
if ( | |||
children[ i ].classList && | |||
children[ i ].classList.contains( | |||
className | |||
) | |||
) { | |||
return children[ i ]; | |||
} | |||
} | |||
} | |||
return null; | return null; | ||
| 227번째 줄: | 351번째 줄: | ||
return true; | return true; | ||
} | } | ||
if ( | |||
window | |||
.getComputedStyle( | |||
target | |||
) | |||
.display === 'none' | |||
) { | |||
return true; | |||
} | |||
return ( | return ( | ||
| 239번째 줄: | 375번째 줄: | ||
/** | /** | ||
* | * display 값 기억 | ||
*/ | */ | ||
function rememberDisplay( element ) { | function rememberDisplay( element ) { | ||
| 256번째 줄: | 390번째 줄: | ||
) { | ) { | ||
$( element ).data( | $( element ).data( | ||
DATA_DISPLAY, | |||
display | |||
); | |||
} | |||
} | |||
/** | |||
* target 자체 display 기억 | |||
*/ | |||
function rememberTargetDisplay( | |||
target | |||
) { | |||
var display = | |||
window | |||
.getComputedStyle( | |||
target | |||
) | |||
.display; | |||
if ( | |||
display && | |||
display !== 'none' | |||
) { | |||
$( target ).data( | |||
DATA_DISPLAY, | DATA_DISPLAY, | ||
display | display | ||
| 267번째 줄: | 426번째 줄: | ||
*/ | */ | ||
function getOpenDisplay( element ) { | function getOpenDisplay( element ) { | ||
var stored = | var stored = | ||
$( element ).data( | $( element ).data( | ||
| 278번째 줄: | 436번째 줄: | ||
if ( | if ( | ||
element.style.display && | element.style.display && | ||
| 340번째 줄: | 495번째 줄: | ||
if ( | if ( | ||
element.classList.contains( | element.classList.contains( | ||
| 351번째 줄: | 500번째 줄: | ||
) | ) | ||
) { | ) { | ||
if ( | if ( | ||
element.style.width === '100%' || | element.style.width === '100%' || | ||
| 368번째 줄: | 516번째 줄: | ||
/** | /** | ||
* aria-expanded 갱신 | |||
* aria-expanded | |||
*/ | */ | ||
function updateAria( | function updateAria( | ||
| 403번째 줄: | 550번째 줄: | ||
/** | /** | ||
* 펼치기 | * 펼치기 | ||
*/ | */ | ||
function expand( | function expand( | ||
| 417번째 줄: | 557번째 줄: | ||
hideOwnToggle | hideOwnToggle | ||
) { | ) { | ||
var $target = | |||
$( target ); | |||
var $element = | var $element = | ||
$( element ); | $( element ); | ||
| 424번째 줄: | 567번째 줄: | ||
/* | |||
* 교대형 구조: | |||
* 새로 나타나는 쪽 토글 글자를 | |||
) { | * 애니메이션이 끝날 때까지 숨김. | ||
*/ | |||
if ( hideOwnToggle ) { | |||
ownToggle = | ownToggle = | ||
getOwnToggle( | getOwnToggle( | ||
| 447번째 줄: | 592번째 줄: | ||
/* | |||
* target 자체가 display:none 상태라면 | |||
* 먼저 바깥 컨테이너를 복원. | |||
/ | |||
* target | |||
* | |||
*/ | */ | ||
if ( | if ( | ||
window | |||
.getComputedStyle( | |||
target | |||
) | |||
.display === 'none' | |||
) { | ) { | ||
$target.css( | |||
$ | 'display', | ||
getOpenDisplay( | |||
target | |||
) | ) | ||
); | |||
} | } | ||
target.classList.remove( | |||
'mw-collapsed' | |||
); | ); | ||
/* | /* | ||
* | * 내부 요소만 slideDown. | ||
* | |||
* target 자체 height는 건드리지 않음. | |||
*/ | */ | ||
$element | |||
.stop( | |||
true, | |||
false | |||
) | |||
.slideDown( | |||
{ | |||
duration: | |||
DURATION, | |||
easing: | |||
EASING, | |||
complete: | |||
function () { | |||
$element.css( | |||
{ | |||
height: | |||
'', | |||
overflow: | |||
'' | |||
} | |||
); | |||
if ( | |||
'' | ownToggle | ||
) { | |||
ownToggle.style.visibility = | |||
''; | |||
} | } | ||
} | } | ||
} | |||
); | |||
} | } | ||
| 593번째 줄: | 668번째 줄: | ||
element | element | ||
) { | ) { | ||
var $target = | |||
$( target ); | |||
var $element = | var $element = | ||
$( element ); | $( element ); | ||
| 602번째 줄: | 680번째 줄: | ||
); | ); | ||
rememberTargetDisplay( | |||
target | |||
); | |||
rememberDisplay( | rememberDisplay( | ||
| 608번째 줄: | 690번째 줄: | ||
/* | /* | ||
* 내부 요소만 slideUp. | |||
* | |||
*/ | */ | ||
$element.slideUp( | |||
$element. | |||
{ | { | ||
duration: | duration: | ||
| 692번째 줄: | 709번째 줄: | ||
/* | |||
* 자동 wrapper 구조에서는 | |||
* 바깥 target도 최종적으로 숨김. | |||
* | |||
* LACTEA 같은 display:none 교대형 | |||
* 구조 대응. | |||
*/ | |||
if ( | |||
$( target ).data( | |||
DATA_WRAPPED | |||
) | |||
) { | |||
$target.css( | |||
'display', | |||
'none' | |||
); | |||
} | |||
/* | |||
* 다음에 다시 slideDown할 수 있도록 | |||
* 내부 wrapper의 display만 정리. | |||
*/ | |||
$element.css( | $element.css( | ||
{ | { | ||
height: | height: | ||
'', | '', | ||
| 712번째 줄: | 749번째 줄: | ||
/** | /** | ||
* 그룹 전체 토글 | * 그룹 전체 토글 | ||
*/ | */ | ||
function toggleGroup( | function toggleGroup( | ||
| 765번째 줄: | 782번째 줄: | ||
var openedAny = | var openedAny = | ||
false; | false; | ||
var i; | |||
| 775번째 줄: | 793번째 줄: | ||
i++ | i++ | ||
) { | ) { | ||
var target = | var target = | ||
targets[ i ]; | targets[ i ]; | ||
| 795번째 줄: | 812번째 줄: | ||
if ( collapsed ) { | if ( collapsed ) { | ||
expand( | expand( | ||
target, | target, | ||
| 813번째 줄: | 818번째 줄: | ||
multipleTargets | multipleTargets | ||
); | ); | ||
openedAny = | openedAny = | ||
| 828번째 줄: | 832번째 줄: | ||
if ( | if ( | ||
targets.length === 1 | targets.length === 1 | ||
) { | ) { | ||
updateAria( | updateAria( | ||
name, | name, | ||
| 851번째 줄: | 847번째 줄: | ||
/** | /** | ||
* 클릭 | * 클릭 처리 | ||
*/ | */ | ||
document.addEventListener( | document.addEventListener( | ||
'click', | 'click', | ||
function ( event ) { | function ( event ) { | ||
var toggle = | var toggle = | ||
event.target.closest( | event.target.closest( | ||
| 902번째 줄: | 893번째 줄: | ||
'keydown', | 'keydown', | ||
function ( event ) { | function ( event ) { | ||
if ( | if ( | ||
event.key !== 'Enter' && | event.key !== 'Enter' && | ||
| 947번째 줄: | 937번째 줄: | ||
/** | /** | ||
* | * 초기 상태 저장 | ||
*/ | */ | ||
function initializeDisplays( | function initializeDisplays( | ||
| 968번째 줄: | 955번째 줄: | ||
i++ | i++ | ||
) { | ) { | ||
var element = | var element = | ||
collapsibles[ i ]; | collapsibles[ i ]; | ||
| 985번째 줄: | 971번째 줄: | ||
display !== 'none' | display !== 'none' | ||
) { | ) { | ||
$( element ).data( | $( element ).data( | ||
DATA_DISPLAY, | DATA_DISPLAY, | ||
| 991번째 줄: | 976번째 줄: | ||
); | ); | ||
} | } | ||
/* | |||
* 이미 mw-collapsible-content가 없는 구조는 | |||
* 초기화 시 wrapper를 미리 만들지 않음. | |||
* | |||
* 실제 클릭할 때 필요한 target만 생성해서 | |||
* 불필요한 DOM 변경을 줄임. | |||
*/ | |||
} | } | ||
} | } | ||
| 996번째 줄: | 990번째 줄: | ||
/** | /** | ||
* 최초 | * 최초 로드 | ||
*/ | */ | ||
$( function () { | $( function () { | ||
initializeDisplays( | initializeDisplays( | ||
document | document | ||
); | ); | ||
} ); | } ); | ||
| 1,009번째 줄: | 1,001번째 줄: | ||
/** | /** | ||
* MediaWiki 동적 콘텐츠 대응 | * MediaWiki 동적 콘텐츠 대응 | ||
*/ | */ | ||
if ( | if ( | ||
| 1,017번째 줄: | 1,006번째 줄: | ||
mw.hook | mw.hook | ||
) { | ) { | ||
mw.hook( | mw.hook( | ||
'wikipage.content' | 'wikipage.content' | ||
).add( | ).add( | ||
function ( $content ) { | function ( $content ) { | ||
if ( | if ( | ||
$content && | $content && | ||
$content[ 0 ] | $content[ 0 ] | ||
) { | ) { | ||
initializeDisplays( | initializeDisplays( | ||
$content[ 0 ] | $content[ 0 ] | ||
2026년 8월 20일 (목) 14:19 판
/**
* MediaWiki 커스텀 펼치기 / 접기 애니메이션
*
* 지원:
*
* 1. 일반 MediaWiki 구조
*
* .mw-customtoggle-XXX
* #mw-customcollapsible-XXX
* └─ .mw-collapsible-content
*
*
* 2. 동일 ID 2개를 사용하는 교대형 구조
*
* #mw-customcollapsible-XXX
* └─ [ 버튼 ]
*
* #mw-customcollapsible-XXX.mw-collapsed
* ├─ [ 버튼 ]
* └─ 실제 내용
*
*
* 3. 여러 독립 토글
*
* TWICE_KOR
* TWICE_OVS
* TWICE_ETC
* TWICE_REL
*
*
* 4. 정보상자 / table / rowspan 내부 지원
*
* mw-collapsible 자체의 height를 직접 변경하지 않고
* 내부 wrapper만 slide 처리하여
* table 레이아웃 재계산 문제를 줄임.
*
*
* 애니메이션:
* height만 사용
* opacity 사용하지 않음
*/
( function ( $, mw ) {
'use strict';
var DURATION = 200;
var EASING = 'swing';
var DATA_DISPLAY =
'mwCustomCollapseDisplay';
var INNER_CLASS =
'mw-custom-collapse-inner';
var DATA_WRAPPED =
'mwCustomCollapseWrapped';
/**
* 토글 클래스에서 식별자 추출
*
* mw-customtoggle-Flora_LACTEA_01
* →
* Flora_LACTEA_01
*/
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;
}
/**
* attribute selector escape
*/
function escapeAttribute( value ) {
return String( value )
.replace(
/\\/g,
'\\\\'
)
.replace(
/"/g,
'\\"'
);
}
/**
* 같은 name을 가진 모든 target 검색
*/
function getTargets( name ) {
if ( !name ) {
return [];
}
var id =
'mw-customcollapsible-' +
name;
return document.querySelectorAll(
'[id="' +
escapeAttribute( id ) +
'"]'
);
}
/**
* target의 직계
* .mw-collapsible-content 검색
*
* 중첩 collapsible 오선택 방지.
*/
function getDirectContent( target ) {
var children =
target.children;
var i;
for (
i = 0;
i < children.length;
i++
) {
if (
children[ i ].classList &&
children[ i ].classList.contains(
'mw-collapsible-content'
)
) {
return children[ i ];
}
}
return null;
}
/**
* 기존에 만든 내부 wrapper 검색
*/
function getDirectInnerWrapper( target ) {
var children =
target.children;
var i;
for (
i = 0;
i < children.length;
i++
) {
if (
children[ i ].classList &&
children[ i ].classList.contains(
INNER_CLASS
)
) {
return children[ i ];
}
}
return null;
}
/**
* target 내부에 애니메이션용 wrapper 생성
*
* .mw-collapsible-content가 없는 구조에서 사용.
*
* target 자체 height를 변경하지 않고
* 내부 wrapper만 slide 처리.
*/
function createInnerWrapper( target ) {
var existing =
getDirectInnerWrapper(
target
);
if ( existing ) {
return existing;
}
var wrapper =
document.createElement(
'div'
);
wrapper.className =
INNER_CLASS;
/*
* 기존 자식 전부 wrapper 안으로 이동
*/
while (
target.firstChild
) {
wrapper.appendChild(
target.firstChild
);
}
target.appendChild(
wrapper
);
$( target ).data(
DATA_WRAPPED,
true
);
return wrapper;
}
/**
* 실제 애니메이션 요소 결정
*
* 1순위:
* .mw-collapsible-content
*
* 2순위:
* 자동 생성 inner wrapper
*/
function getAnimatedElement( target ) {
var content =
getDirectContent(
target
);
if ( content ) {
return content;
}
return createInnerWrapper(
target
);
}
/**
* target 자신의 직계 토글 검색
*
* inner wrapper가 생성된 뒤에는
* 토글이 wrapper 안으로 들어가므로
* wrapper 내부도 확인.
*/
function getOwnToggle(
target,
name
) {
var className =
'mw-customtoggle-' +
name;
var children =
target.children;
var i;
for (
i = 0;
i < children.length;
i++
) {
if (
children[ i ].classList &&
children[ i ].classList.contains(
className
)
) {
return children[ i ];
}
}
var wrapper =
getDirectInnerWrapper(
target
);
if ( wrapper ) {
children =
wrapper.children;
for (
i = 0;
i < children.length;
i++
) {
if (
children[ i ].classList &&
children[ i ].classList.contains(
className
)
) {
return children[ i ];
}
}
}
return null;
}
/**
* 현재 접힌 상태인지 확인
*/
function isCollapsed(
target,
element
) {
if (
target.classList.contains(
'mw-collapsed'
)
) {
return true;
}
if (
window
.getComputedStyle(
target
)
.display === 'none'
) {
return true;
}
return (
window
.getComputedStyle(
element
)
.display === 'none'
);
}
/**
* display 값 기억
*/
function rememberDisplay( element ) {
var display =
window
.getComputedStyle(
element
)
.display;
if (
display &&
display !== 'none'
) {
$( element ).data(
DATA_DISPLAY,
display
);
}
}
/**
* target 자체 display 기억
*/
function rememberTargetDisplay(
target
) {
var display =
window
.getComputedStyle(
target
)
.display;
if (
display &&
display !== 'none'
) {
$( target ).data(
DATA_DISPLAY,
display
);
}
}
/**
* 펼칠 때 사용할 display 계산
*/
function getOpenDisplay( element ) {
var stored =
$( element ).data(
DATA_DISPLAY
);
if ( stored ) {
return stored;
}
if (
element.style.display &&
element.style.display !== 'none'
) {
return element.style.display;
}
var computed =
window
.getComputedStyle(
element
)
.display;
if (
computed &&
computed !== 'none'
) {
return computed;
}
switch ( element.tagName ) {
case 'TABLE':
return 'table';
case 'TBODY':
return 'table-row-group';
case 'THEAD':
return 'table-header-group';
case 'TFOOT':
return 'table-footer-group';
case 'TR':
return 'table-row';
case 'TD':
case 'TH':
return 'table-cell';
case 'COLGROUP':
return 'table-column-group';
case 'COL':
return 'table-column';
case 'CAPTION':
return 'table-caption';
case 'LI':
return 'list-item';
}
if (
element.classList.contains(
'mw-collapsible'
)
) {
if (
element.style.width === '100%' ||
element.style.width === '100.0%'
) {
return 'block';
}
return 'inline-block';
}
return 'block';
}
/**
* aria-expanded 갱신
*/
function updateAria(
name,
expanded
) {
var className =
'mw-customtoggle-' +
name;
var toggles =
document.getElementsByClassName(
className
);
var i;
for (
i = 0;
i < toggles.length;
i++
) {
toggles[ i ].setAttribute(
'aria-expanded',
expanded ?
'true' :
'false'
);
}
}
/**
* 펼치기
*/
function expand(
target,
element,
name,
hideOwnToggle
) {
var $target =
$( target );
var $element =
$( element );
var ownToggle =
null;
/*
* 교대형 구조:
* 새로 나타나는 쪽 토글 글자를
* 애니메이션이 끝날 때까지 숨김.
*/
if ( hideOwnToggle ) {
ownToggle =
getOwnToggle(
target,
name
);
if ( ownToggle ) {
ownToggle.style.visibility =
'hidden';
}
}
$element.stop(
true,
false
);
/*
* target 자체가 display:none 상태라면
* 먼저 바깥 컨테이너를 복원.
*/
if (
window
.getComputedStyle(
target
)
.display === 'none'
) {
$target.css(
'display',
getOpenDisplay(
target
)
);
}
target.classList.remove(
'mw-collapsed'
);
/*
* 내부 요소만 slideDown.
*
* target 자체 height는 건드리지 않음.
*/
$element
.stop(
true,
false
)
.slideDown(
{
duration:
DURATION,
easing:
EASING,
complete:
function () {
$element.css(
{
height:
'',
overflow:
''
}
);
if (
ownToggle
) {
ownToggle.style.visibility =
'';
}
}
}
);
}
/**
* 접기
*/
function collapse(
target,
element
) {
var $target =
$( target );
var $element =
$( element );
$element.stop(
true,
false
);
rememberTargetDisplay(
target
);
rememberDisplay(
element
);
/*
* 내부 요소만 slideUp.
*/
$element.slideUp(
{
duration:
DURATION,
easing:
EASING,
complete:
function () {
target.classList.add(
'mw-collapsed'
);
/*
* 자동 wrapper 구조에서는
* 바깥 target도 최종적으로 숨김.
*
* LACTEA 같은 display:none 교대형
* 구조 대응.
*/
if (
$( target ).data(
DATA_WRAPPED
)
) {
$target.css(
'display',
'none'
);
}
/*
* 다음에 다시 slideDown할 수 있도록
* 내부 wrapper의 display만 정리.
*/
$element.css(
{
height:
'',
overflow:
''
}
);
}
}
);
}
/**
* 그룹 전체 토글
*/
function toggleGroup(
toggle
) {
var name =
getToggleName(
toggle
);
if ( !name ) {
return false;
}
var targets =
getTargets(
name
);
if (
!targets ||
!targets.length
) {
return false;
}
var multipleTargets =
targets.length > 1;
var openedAny =
false;
var i;
for (
i = 0;
i < targets.length;
i++
) {
var target =
targets[ i ];
var element =
getAnimatedElement(
target
);
var collapsed =
isCollapsed(
target,
element
);
if ( collapsed ) {
expand(
target,
element,
name,
multipleTargets
);
openedAny =
true;
} else {
collapse(
target,
element
);
}
}
if (
targets.length === 1
) {
updateAria(
name,
openedAny
);
}
return true;
}
/**
* 클릭 처리
*/
document.addEventListener(
'click',
function ( event ) {
var toggle =
event.target.closest(
'.mw-customtoggle'
);
if ( !toggle ) {
return;
}
if (
!getToggleName(
toggle
)
) {
return;
}
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
toggleGroup(
toggle
);
},
true
);
/**
* Enter / Space
*/
document.addEventListener(
'keydown',
function ( event ) {
if (
event.key !== 'Enter' &&
event.key !== ' '
) {
return;
}
var toggle =
event.target.closest(
'.mw-customtoggle'
);
if ( !toggle ) {
return;
}
if (
!getToggleName(
toggle
)
) {
return;
}
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
toggleGroup(
toggle
);
},
true
);
/**
* 초기 상태 저장
*/
function initializeDisplays(
root
) {
var collapsibles =
root.querySelectorAll(
'.mw-collapsible'
);
var i;
for (
i = 0;
i < collapsibles.length;
i++
) {
var element =
collapsibles[ i ];
var display =
window
.getComputedStyle(
element
)
.display;
if (
display &&
display !== 'none'
) {
$( element ).data(
DATA_DISPLAY,
display
);
}
/*
* 이미 mw-collapsible-content가 없는 구조는
* 초기화 시 wrapper를 미리 만들지 않음.
*
* 실제 클릭할 때 필요한 target만 생성해서
* 불필요한 DOM 변경을 줄임.
*/
}
}
/**
* 최초 로드
*/
$( function () {
initializeDisplays(
document
);
} );
/**
* MediaWiki 동적 콘텐츠 대응
*/
if (
mw &&
mw.hook
) {
mw.hook(
'wikipage.content'
).add(
function ( $content ) {
if (
$content &&
$content[ 0 ]
) {
initializeDisplays(
$content[ 0 ]
);
}
}
);
}
}( jQuery, mediaWiki ) );