참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.
- 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
- 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
- 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
- 오페라: Ctrl-F5를 입력.
/* 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가 있을 수 있으므로 #id 대신 attribute selector 사용
*/
var $targets = $content.find('[id="' + targetId + '"]');
if (!$targets.length) {
return;
}
/*
* =====================================================
* 특수형
*
* 아나운서 표처럼:
*
* 상단 버튼 wrapper
* 실제 내용 패널
*
* 이 같은 ID를 공유하고,
* 실제 패널 안에 wikitable이 있는 구조
* =====================================================
*/
var $specialPanel = $targets.filter(function () {
return $(this).find('table.wikitable').length > 0;
});
if ($targets.length > 1 && $specialPanel.length) {
initStackedCollapsible(
$content,
cls,
$targets
);
return;
}
/*
* =====================================================
* 일반 MediaWiki collapsible
* =====================================================
*/
initNormalCollapsible(
$content,
cls,
$targets.first()
);
});
});
/*
* =============================================================
* 일반 펼치기 · 접기
* =============================================================
*/
function initNormalCollapsible($content, cls, $target) {
var $toggles = $content.find('.' + cls);
/*
* 일반 MediaWiki 구조:
*
* .mw-collapsible
* └ .mw-collapsible-content
*
* content가 있으면 content만 애니메이션
*/
var $contentTarget = $target.children('.mw-collapsible-content');
if (!$contentTarget.length) {
$contentTarget = $target.find('.mw-collapsible-content').first();
}
var $animTarget = $contentTarget.length
? $contentTarget
: $target;
/*
* 현재 상태를 기준으로 초기 aria 설정
*/
var initiallyOpen = $animTarget.is(':visible');
$toggles.attr(
'aria-expanded',
initiallyOpen ? 'true' : 'false'
);
$toggles
.off('click.smoothSlide')
.on('click.smoothSlide', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
/*
* 애니메이션 중 다시 눌렀을 때
* queue가 꼬이는 것을 방지
*/
if ($animTarget.is(':animated')) {
return false;
}
var opening = !$animTarget.is(':visible');
/*
* -------------------------------------------------
* 펼치기
* -------------------------------------------------
*/
if (opening) {
/*
* MediaWiki의 collapsed 상태를 먼저 제거
*/
$target.removeClass('mw-collapsed');
/*
* slideDown
*/
$animTarget
.stop(true, false)
.hide()
.slideDown(250, function () {
/*
* jQuery가 남기는 애니메이션용 inline style 정리
*/
$(this).css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
});
$toggles.attr('aria-expanded', 'true');
}
/*
* -------------------------------------------------
* 접기
* -------------------------------------------------
*/
else {
$animTarget
.stop(true, false)
.slideUp(250, function () {
/*
* 애니메이션이 끝난 뒤 collapsed 복원
*/
$target.addClass('mw-collapsed');
$(this).css({
display: 'none',
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
});
$toggles.attr('aria-expanded', 'false');
}
return false;
});
}
/*
* =============================================================
* 아나운서형 특수 펼치기 · 접기
* =============================================================
*
* DOM 예:
*
* [남성 버튼 wrapper]
* [남성 실제 패널]
* [여성 버튼 wrapper]
* [여성 실제 패널]
*
* 패널은 원래 DOM 위치에 유지한다.
*
* 남성을 펼치면 여성 버튼은
* 자연스럽게 아래로 밀려난다.
*
* 단,
* 상단 버튼과 패널을 완전히 동시에 움직이지 않고
* 짧은 시차를 주어 겹침을 방지한다.
* =============================================================
*/
function initStackedCollapsible($content, cls, $targets) {
/*
* wikitable이 들어 있는 요소를 실제 패널로 사용
*/
var $panel = $targets.filter(function () {
return $(this).find('table.wikitable').length > 0;
}).first();
if (!$panel.length) {
return;
}
/*
* 실제 패널이 아닌 동일 ID 요소 중
* 해당 toggle을 포함하는 요소 = 상단 버튼 wrapper
*/
var $topWrapper = $targets.not($panel).filter(function () {
return $(this).find('.' + cls).length > 0;
}).first();
if (!$topWrapper.length) {
return;
}
var $topToggle = $topWrapper.find('.' + cls).first();
var $panelToggle = $panel.find('.' + cls).first();
if (!$topToggle.length || !$panelToggle.length) {
return;
}
/*
* =========================================================
* 애니메이션 설정
* =========================================================
*
* wrapperDuration
* 상단 버튼이 사라지고 나타나는 속도
*
* panelDuration
* 실제 패널 펼침/접힘 속도
*
* openDelay
* 상단 버튼이 접히기 시작한 뒤
* 패널이 펼쳐지기 시작하는 시점
*
* closeDelay
* 패널이 접히기 시작한 뒤
* 상단 버튼이 복귀하기 시작하는 시점
*/
var wrapperDuration = 180;
var panelDuration = 240;
var openDelay = 65;
var closeDelay = 80;
/*
* =========================================================
* 최초 상태
* =========================================================
*/
$panel
.stop(true, true)
.addClass('mw-collapsed')
.hide()
.css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: '',
opacity: ''
});
$topWrapper
.stop(true, true)
.show()
.css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: '',
opacity: ''
});
$topToggle.attr('aria-expanded', 'false');
$panelToggle.attr('aria-expanded', 'false');
/*
* =========================================================
* 위쪽 버튼 클릭 → 펼치기
* =========================================================
*/
$topToggle
.off('click.smoothSlide')
.on('click.smoothSlide', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
/*
* 중복 클릭 방지
*/
if (
$panel.is(':animated') ||
$topWrapper.is(':animated') ||
$panel.is(':visible')
) {
return false;
}
/*
* MediaWiki collapsed 상태 해제
*/
$panel.removeClass('mw-collapsed');
/*
* -------------------------------------------------
* 1.
* 위쪽 버튼 wrapper를 먼저 접기 시작
*
* 높이뿐 아니라 opacity도 같이 낮춰
* 훨씬 자연스럽게 사라지도록 한다.
* -------------------------------------------------
*/
$topWrapper
.stop(true, false)
.css({
overflow: 'hidden'
})
.animate(
{
height: 0,
paddingTop: 0,
paddingBottom: 0,
marginTop: 0,
marginBottom: 0,
opacity: 0
},
{
duration: wrapperDuration,
queue: false,
complete: function () {
$(this)
.hide()
.css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: '',
opacity: ''
});
}
}
);
/*
* -------------------------------------------------
* 2.
* 버튼이 어느 정도 접힌 뒤
* 실제 패널 펼치기 시작
*
* 완전 순차식이 아니기 때문에
* 움직임이 끊겨 보이지 않는다.
* -------------------------------------------------
*/
setTimeout(function () {
/*
* 혹시 다른 처리로 이미 표시되었으면 중단
*/
if ($panel.is(':visible')) {
return;
}
$panel
.stop(true, false)
.hide()
.slideDown(
panelDuration,
function () {
/*
* jQuery animation inline style 정리
*/
$(this).css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: '',
opacity: ''
});
}
);
}, openDelay);
/*
* ARIA
*/
$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') ||
$topWrapper.is(':animated')
) {
return false;
}
/*
* -------------------------------------------------
* 1.
* 패널 먼저 접기 시작
* -------------------------------------------------
*/
$panel
.stop(true, false)
.slideUp(
panelDuration,
function () {
$(this)
.addClass('mw-collapsed')
.css({
display: 'none',
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: '',
opacity: ''
});
}
);
/*
* -------------------------------------------------
* 2.
* 패널이 어느 정도 접힌 뒤
* 원래 버튼을 복귀시키기 시작
* -------------------------------------------------
*/
setTimeout(function () {
/*
* 이미 보이는 상태라면 중복 실행하지 않음
*/
if ($topWrapper.is(':visible')) {
return;
}
/*
* opacity 0으로 시작
*/
$topWrapper
.stop(true, false)
.css({
opacity: 0
})
.hide();
/*
* 높이 복귀
*/
$topWrapper
.slideDown({
duration: wrapperDuration,
step: function () {
/*
* slideDown 도중 overflow는
* jQuery가 자동 관리
*/
},
complete: function () {
$(this).css({
height: '',
overflow: '',
paddingTop: '',
paddingBottom: '',
marginTop: '',
marginBottom: ''
});
}
});
/*
* opacity는 slideDown과 동시에 진행
*
* queue:false이므로
* 높이 애니메이션을 기다리지 않는다.
*/
$topWrapper
.animate(
{
opacity: 1
},
{
duration: 130,
queue: false,
complete: function () {
$(this).css({
opacity: ''
});
}
}
);
}, closeDelay);
/*
* ARIA
*/
$topToggle.attr('aria-expanded', 'false');
$panelToggle.attr('aria-expanded', 'false');
return false;
});
}
});