편집 요약 없음 |
편집 요약 없음 |
||
| 23번째 줄: | 23번째 줄: | ||
/* | /* | ||
* | * ID 중복 가능성을 고려해서 attribute selector 사용 | ||
*/ | */ | ||
var $ | var $targets = $content.find('[id="' + targetId + '"]'); | ||
if (!$targets.length) { | |||
return; | |||
} | |||
/* | /* | ||
* wikitable을 | * ===================================================== | ||
* 1. 아나운서형 특수 구조 | |||
* | |||
* 같은 ID가 여러 개 있고, | |||
* 그중 하나가 wikitable을 포함하는 경우 | |||
* ===================================================== | |||
*/ | */ | ||
if ( | |||
$targets.length > 1 && | |||
$targets.filter(function () { | |||
return $(this).find('table.wikitable').length > 0; | |||
}).length | |||
) { | |||
initStackedCollapsible( | |||
$content, | |||
cls, | |||
$targets | |||
); | |||
return; | return; | ||
} | } | ||
/* | /* | ||
* | * ===================================================== | ||
* 2. 일반 MediaWiki collapsible | |||
* ===================================================== | |||
*/ | */ | ||
initNormalCollapsible( | |||
$content, | |||
cls, | |||
$targets.first() | |||
); | |||
}); | |||
}); | |||
/* | |||
* ----------------------------------------------------- | |||
* 일반 펼치기 · 접기 | |||
* ----------------------------------------------------- | |||
*/ | |||
function initNormalCollapsible($content, cls, $target) { | |||
var $toggles = $content.find('.' + cls); | |||
/* | |||
* 실제로 애니메이션할 부분 | |||
*/ | |||
var $contentTarget = $target.children('.mw-collapsible-content'); | |||
if (!$contentTarget.length) { | |||
$contentTarget = $target.find('.mw-collapsible-content').first(); | |||
} | |||
/* | |||
* mw-collapsible-content가 없다면 | |||
* target 자체를 애니메이션 | |||
*/ | |||
var $animTarget = $contentTarget.length | |||
? $contentTarget | |||
: $target; | |||
$toggles | |||
.off('click.smoothSlide') | |||
.on('click.smoothSlide', function (e) { | |||
/* | |||
* MediaWiki 기본 이벤트까지 완전히 죽이지 않고 | |||
* 우리가 애니메이션만 담당 | |||
*/ | |||
e.preventDefault(); | |||
e.stopImmediatePropagation(); | |||
. | |||
. | |||
var opening = !$animTarget.is(':visible'); | |||
if (opening) { | |||
/* | /* | ||
* | * 먼저 collapsed 해제 | ||
*/ | */ | ||
$ | $target.removeClass('mw-collapsed'); | ||
$animTarget | |||
.stop(true, false) | |||
.slideDown(200, function () { | |||
$(this).css({ | |||
height: '', | |||
overflow: '', | |||
paddingTop: '', | |||
paddingBottom: '', | |||
marginTop: '', | |||
marginBottom: '' | |||
}); | |||
}); | |||
} else { | |||
$animTarget | |||
$ | |||
.stop(true, false) | .stop(true, false) | ||
. | .slideUp(200, function () { | ||
/* | /* | ||
* | * 다 접힌 뒤 collapsed 복원 | ||
*/ | */ | ||
$target.addClass('mw-collapsed'); | |||
$(this).css({ | $(this).css({ | ||
display: '', | display: 'none', | ||
height: '', | height: '', | ||
overflow: '', | overflow: '', | ||
| 115번째 줄: | 153번째 줄: | ||
}); | }); | ||
}); | }); | ||
} | |||
$toggles.attr( | |||
'aria-expanded', | |||
opening ? 'true' : 'false' | |||
); | |||
return false; | |||
}); | |||
} | |||
/* | |||
* ----------------------------------------------------- | |||
* 아나운서처럼 | |||
* | |||
* 상단 버튼 | |||
* 실제 패널 | |||
* 다음 버튼 | |||
* 실제 패널 | |||
* | |||
* 구조인 경우 | |||
* ----------------------------------------------------- | |||
*/ | |||
function initStackedCollapsible($content, cls, $targets) { | |||
/* | |||
* wikitable이 들어 있는 것이 실제 패널 | |||
*/ | |||
var $panel = $targets.filter(function () { | |||
return $(this).find('table.wikitable').length > 0; | |||
}).first(); | |||
if (!$panel.length) { | |||
return; | |||
} | |||
/* | |||
* 나머지가 위쪽 버튼 wrapper | |||
*/ | |||
var $topWrapper = $targets.not($panel).filter(function () { | |||
return $(this).find('.' + cls).length > 0; | |||
}).first(); | |||
var $topToggle = $topWrapper.find('.' + cls).first(); | |||
var $panelToggle = $panel.find('.' + cls).first(); | |||
if (!$topToggle.length || !$panelToggle.length) { | |||
return; | |||
} | |||
/* | |||
* 초기에는 패널 숨김 | |||
*/ | |||
$panel.hide(); | |||
/* | |||
* 위 버튼 클릭 | |||
*/ | |||
$topToggle | |||
.off('click.smoothSlide') | |||
.on('click.smoothSlide', function (e) { | |||
e.preventDefault(); | |||
e.stopImmediatePropagation(); | |||
if ($panel.is(':animated') || $panel.is(':visible')) { | |||
return false; | return false; | ||
} | } | ||
/* | |||
* 원래 상단 버튼 제거 | |||
* | |||
* DOM 위치는 유지되므로 | |||
* 뒤의 여성/다음 버튼이 아래로 내려감 | |||
*/ | |||
. | $topWrapper.hide(); | ||
/* | |||
* 중요: | |||
} | * 패널 자체를 움직이지 않음 | ||
*/ | |||
$panel | |||
.removeClass('mw-collapsed') | |||
.stop(true, false) | |||
.hide() | |||
.slideDown(200, function () { | |||
$(this).css({ | |||
height: '', | |||
overflow: '', | |||
paddingTop: '', | |||
paddingBottom: '', | |||
marginTop: '', | |||
marginBottom: '' | |||
}); | |||
}); | |||
$topToggle.attr('aria-expanded', 'true'); | |||
$panelToggle.attr('aria-expanded', 'true'); | |||
return false; | |||
}); | |||
/* | |||
* 펼쳐진 패널 안쪽 버튼 클릭 | |||
*/ | |||
$panelToggle | |||
.off('click.smoothSlide') | |||
.on('click.smoothSlide', function (e) { | |||
e.preventDefault(); | |||
e.stopImmediatePropagation(); | |||
if ($panel.is(':animated')) { | |||
return false; | return false; | ||
}); | } | ||
$panel | |||
.stop(true, false) | |||
.slideUp(200, function () { | |||
$(this) | |||
.addClass('mw-collapsed') | |||
.css({ | |||
display: 'none', | |||
height: '', | |||
overflow: '', | |||
paddingTop: '', | |||
paddingBottom: '', | |||
marginTop: '', | |||
marginBottom: '' | |||
}); | |||
/* | |||
* 애니메이션이 끝난 뒤 | |||
* 원래 상단 버튼 복귀 | |||
*/ | |||
$topWrapper.show(); | |||
}); | |||
$topToggle.attr('aria-expanded', 'false'); | |||
$panelToggle.attr('aria-expanded', 'false'); | |||
return false; | |||
}); | |||
} | |||
}); | }); | ||
2026년 8월 20일 (목) 15:01 판
/* MediaWiki:Common.js */
mw.hook('wikipage.content').add(function ($content) {
var initialized = {};
$content.find('[class*="mw-customtoggle-"]').each(function () {
var classList = (this.className || '').split(/\s+/);
classList.forEach(function (cls) {
if (cls.indexOf('mw-customtoggle-') !== 0) {
return;
}
var suffix = cls.substring('mw-customtoggle-'.length);
if (initialized[suffix]) {
return;
}
initialized[suffix] = true;
var targetId = 'mw-customcollapsible-' + suffix;
/*
* ID 중복 가능성을 고려해서 attribute selector 사용
*/
var $targets = $content.find('[id="' + targetId + '"]');
if (!$targets.length) {
return;
}
/*
* =====================================================
* 1. 아나운서형 특수 구조
*
* 같은 ID가 여러 개 있고,
* 그중 하나가 wikitable을 포함하는 경우
* =====================================================
*/
if (
$targets.length > 1 &&
$targets.filter(function () {
return $(this).find('table.wikitable').length > 0;
}).length
) {
initStackedCollapsible(
$content,
cls,
$targets
);
return;
}
/*
* =====================================================
* 2. 일반 MediaWiki collapsible
* =====================================================
*/
initNormalCollapsible(
$content,
cls,
$targets.first()
);
});
});
/*
* -----------------------------------------------------
* 일반 펼치기 · 접기
* -----------------------------------------------------
*/
function initNormalCollapsible($content, cls, $target) {
var $toggles = $content.find('.' + cls);
/*
* 실제로 애니메이션할 부분
*/
var $contentTarget = $target.children('.mw-collapsible-content');
if (!$contentTarget.length) {
$contentTarget = $target.find('.mw-collapsible-content').first();
}
/*
* mw-collapsible-content가 없다면
* target 자체를 애니메이션
*/
var $animTarget = $contentTarget.length
? $contentTarget
: $target;
$toggles
.off('click.smoothSlide')
.on('click.smoothSlide', function (e) {
/*
* MediaWiki 기본 이벤트까지 완전히 죽이지 않고
* 우리가 애니메이션만 담당
*/
e.preventDefault();
e.stopImmediatePropagation();
var opening = !$animTarget.is(':visible');
if (opening) {
/*
* 먼저 collapsed 해제
*/
$target.removeClass('mw-collapsed');
$animTarget
.stop(true, false)
.slideDown(200, function () {
$(this).css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
});
} else {
$animTarget
.stop(true, false)
.slideUp(200, function () {
/*
* 다 접힌 뒤 collapsed 복원
*/
$target.addClass('mw-collapsed');
$(this).css({
display: 'none',
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
});
}
$toggles.attr(
'aria-expanded',
opening ? 'true' : 'false'
);
return false;
});
}
/*
* -----------------------------------------------------
* 아나운서처럼
*
* 상단 버튼
* 실제 패널
* 다음 버튼
* 실제 패널
*
* 구조인 경우
* -----------------------------------------------------
*/
function initStackedCollapsible($content, cls, $targets) {
/*
* wikitable이 들어 있는 것이 실제 패널
*/
var $panel = $targets.filter(function () {
return $(this).find('table.wikitable').length > 0;
}).first();
if (!$panel.length) {
return;
}
/*
* 나머지가 위쪽 버튼 wrapper
*/
var $topWrapper = $targets.not($panel).filter(function () {
return $(this).find('.' + cls).length > 0;
}).first();
var $topToggle = $topWrapper.find('.' + cls).first();
var $panelToggle = $panel.find('.' + cls).first();
if (!$topToggle.length || !$panelToggle.length) {
return;
}
/*
* 초기에는 패널 숨김
*/
$panel.hide();
/*
* 위 버튼 클릭
*/
$topToggle
.off('click.smoothSlide')
.on('click.smoothSlide', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
if ($panel.is(':animated') || $panel.is(':visible')) {
return false;
}
/*
* 원래 상단 버튼 제거
*
* DOM 위치는 유지되므로
* 뒤의 여성/다음 버튼이 아래로 내려감
*/
$topWrapper.hide();
/*
* 중요:
* 패널 자체를 움직이지 않음
*/
$panel
.removeClass('mw-collapsed')
.stop(true, false)
.hide()
.slideDown(200, function () {
$(this).css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
});
$topToggle.attr('aria-expanded', 'true');
$panelToggle.attr('aria-expanded', 'true');
return false;
});
/*
* 펼쳐진 패널 안쪽 버튼 클릭
*/
$panelToggle
.off('click.smoothSlide')
.on('click.smoothSlide', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
if ($panel.is(':animated')) {
return false;
}
$panel
.stop(true, false)
.slideUp(200, function () {
$(this)
.addClass('mw-collapsed')
.css({
display: 'none',
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
/*
* 애니메이션이 끝난 뒤
* 원래 상단 버튼 복귀
*/
$topWrapper.show();
});
$topToggle.attr('aria-expanded', 'false');
$panelToggle.attr('aria-expanded', 'false');
return false;
});
}
});