미디어위키:Common.js: 두 판 사이의 차이

편집 요약 없음
편집 요약 없음
1,054번째 줄: 1,054번째 줄:


/* DO NOT ADD CODE BELOW THIS LINE */
/* DO NOT ADD CODE BELOW THIS LINE */
/* ================================
/* =========================================
  * Source editor UI 개선 스크립트 (wikiEditor 훅 사용)
  * Source editor UI 개선 스크립트 (툴바 로딩 이후 실행)
  * 위치: MediaWiki:Common.js
  * 위치: MediaWiki:Common.js
  * ================================ */
  * ========================================= */
mw.loader.using( ['jquery', 'ext.wikiEditor', 'mediawiki.util'], function () {
mw.loader.using( ['jquery', 'mediawiki.util'] ).then( function () {
    // wikiEditor 툴바 준비가 끝났을 때 호출되는 훅
    mw.hook('wikiEditor.toolbarReady').add(function ($textarea) {
        var action = mw.config.get('wgAction');
        if ( action !== 'edit' && action !== 'submit' ) {
            return;
        }


        // 원본 편집 textarea 확인
function initCustomEditUI( $textbox ) {
        var $textbox = $('#wpTextbox1');
// 같은 textarea에 두 번 적용 방지
        if ( !$textbox.length ) {
if ( !$textbox || !$textbox.length || $textbox.data( 'mwCustomEditUiDone' ) ) {
            return;
return;
        }
}
$textbox.data( 'mwCustomEditUiDone', true );


        // toolbar DOM
var action = mw.config.get( 'wgAction' );
        var $toolbar = $('#wikiEditor-ui-toolbar');
if ( action !== 'edit' && action !== 'submit' ) {
        if ( !$toolbar.length ) {
return;
            console.log('wikiEditor toolbar not found');
}
            return;
        }


        $('body').addClass('mw-custom-edit-ui');
// 위키에디터 툴바
        console.log('Custom editor UI init');
var $toolbar = $( '#wikiEditor-ui-toolbar' );
if ( !$toolbar.length ) {
// 혹시 셀렉터가 다르면 콘솔에서 구조 한 번 확인 필요
return;
}


        /* ================================
$('body').addClass( 'mw-custom-edit-ui' );
        * 1. 상단 커스텀 헤더
        * ================================ */


        var isSourceModeActive = $('.oo-ui-tool-name-editModeSource.oo-ui-tool-active').length > 0;
var $saveBtn = $( '#wpSave' );
        var $origSourceSwitch = $('.oo-ui-tool-name-editModeSource .oo-ui-tool-link');
        var $origVisualSwitch = $('.oo-ui-tool-name-editModeVisual .oo-ui-tool-link');
        var $origRealtimePreviewBtn = $('.ext-WikiEditor-realtimepreview-button .oo-ui-buttonElement-button');
        var $saveBtn = $('#wpSave');


        var $header = $('<div>', { 'class': 'mw-edit-header-custom' });
/* -------------------------------
* 모드 전환 버튼 원본 (있으면 사용)
* ------------------------------- */
var $origSourceSwitch = $( '.oo-ui-tool-name-editModeSource .oo-ui-tool-link' );
var $origVisualSwitch = $( '.oo-ui-tool-name-editModeVisual .oo-ui-tool-link' );
var $origRealtimePreviewBtn = $( '.ext-WikiEditor-realtimepreview-button .oo-ui-buttonElement-button' );
var isSourceModeActive = $origSourceSwitch.closest( '.oo-ui-tool' ).hasClass( 'oo-ui-tool-active' );


        // 편집 모드 토글
/* ===============================
        var $modeGroup = $('<div>', { 'class': 'mw-edit-header-group mw-edit-header-modes' });
* 1. 상단 헤더 생성
        var $sourceBtn = $('<button>', {
* =============================== */
            'type': 'button',
            'class': 'mw-edit-header-btn mode-btn mode-source' + ( isSourceModeActive ? ' is-active' : '' ),
            'text': '원본 편집'
        });
        var $visualBtn = $('<button>', {
            'type': 'button',
            'class': 'mw-edit-header-btn mode-btn mode-visual' + ( !isSourceModeActive ? ' is-active' : '' ),
            'text': '시각 편집'
        });


        $sourceBtn.on('click', function () {
var $header = $( '<div>', { 'class': 'mw-edit-header-custom' } );
            if ( $origSourceSwitch.length ) {
                $origSourceSwitch.trigger('click');
            }
        });
        $visualBtn.on('click', function () {
            if ( $origVisualSwitch.length ) {
                $origVisualSwitch.trigger('click');
            }
        });


        $modeGroup.append($sourceBtn, $visualBtn);
// (1) 편집 모드 토글
var $modeGroup = $( '<div>', { 'class': 'mw-edit-header-group mw-edit-header-modes' } );
var $sourceBtn = $( '<button>', {
type: 'button',
class: 'mw-edit-header-btn mode-btn mode-source' + ( isSourceModeActive ? ' is-active' : '' ),
text: mw.msg( 'wikieditor-sourcemode-label' ) || '원본 편집'
} );
var $visualBtn = $( '<button>', {
type: 'button',
class: 'mw-edit-header-btn mode-btn mode-visual' + ( !isSourceModeActive ? ' is-active' : '' ),
text: mw.msg( 'wikieditor-visualmode-label' ) || '시각 편집'
} );


        // 미리보기 토글
$sourceBtn.on( 'click', function () {
        var $previewGroup = $('<div>', { 'class': 'mw-edit-header-group mw-edit-header-preview' });
if ( $origSourceSwitch.length ) {
        var $previewLabel = $('<label>', { 'class': 'mw-edit-header-preview-label' });
$origSourceSwitch.trigger( 'click' );
        var $previewCheckbox = $('<input>', {
}
            'type': 'checkbox',
} );
            'id': 'mw-custom-preview-toggle'
$visualBtn.on( 'click', function () {
        });
if ( $origVisualSwitch.length ) {
        var $previewText = $('<span>', { text: '실시간 미리 보기' });
$origVisualSwitch.trigger( 'click' );
        $previewLabel.append($previewCheckbox, $previewText);
}
        $previewGroup.append($previewLabel);
} );


        // 저장 버튼
$modeGroup.append( $sourceBtn, $visualBtn );
        var $actionsGroup = $('<div>', { 'class': 'mw-edit-header-group mw-edit-header-actions' });
        var $saveProxyBtn = $('<button>', {
            'type': 'button',
            'class': 'mw-edit-header-btn mw-edit-header-save',
            'text': $saveBtn.val() || '저장'
        });
        $saveProxyBtn.on('click', function () {
            if ( $saveBtn.length ) {
                $saveBtn.trigger('click');
            }
        });
        $actionsGroup.append($saveProxyBtn);


        $header.append($modeGroup, $previewGroup, $actionsGroup);
// (2) 미리보기 토글
var $previewGroup = $( '<div>', { 'class': 'mw-edit-header-group mw-edit-header-preview' } );
var $previewLabel = $( '<label>', { 'class': 'mw-edit-header-preview-label' } );
var $previewCheckbox = $( '<input>', {
type: 'checkbox',
id: 'mw-custom-preview-toggle'
} );
var $previewText = $( '<span>', { text: '실시간 미리 보기' } );
$previewLabel.append( $previewCheckbox, $previewText );
$previewGroup.append( $previewLabel );


        // 툴바 위에 삽입
// (3) 저장 버튼 프록시
        $toolbar.before($header);
var $actionsGroup = $( '<div>', { 'class': 'mw-edit-header-group mw-edit-header-actions' } );
var $saveProxyBtn = $( '<button>', {
type: 'button',
class: 'mw-edit-header-btn mw-edit-header-save',
text: $saveBtn.val() || '저장'
} );
$saveProxyBtn.on( 'click', function () {
if ( $saveBtn.length ) {
$saveBtn.trigger( 'click' );
}
} );
$actionsGroup.append( $saveProxyBtn );


        /* ================================
$header.append( $modeGroup, $previewGroup, $actionsGroup );
        * 2. 편집 영역 + 미리보기 레이아웃
        * ================================ */


        var $textareaWrapper = $('<div>', {
// 툴바 위에 삽입
            'class': 'mw-edit-textarea-wrapper'
$toolbar.before( $header );
        });


        $textbox.before($textareaWrapper);
/* ===============================
        $textareaWrapper.append($textbox);
* 2. 편집/미리보기 2분할 레이아웃
* =============================== */


        $textareaWrapper.wrap(
var $textareaWrapper = $( '<div>', { 'class': 'mw-edit-textarea-wrapper' } );
            $('<div>', { 'class': 'mw-edit-main-layout' })
$textbox.before( $textareaWrapper );
        );
$textareaWrapper.append( $textbox );


        var $layout = $textareaWrapper.parent();
$textareaWrapper.wrap(
        var $previewPane = $('<div>', {
$( '<div>', { 'class': 'mw-edit-main-layout' } )
            'id': 'mw-custom-preview-pane',
);
            'class': 'mw-custom-preview-pane'
        }).append(
            $('<div>', { 'class': 'mw-custom-preview-placeholder', 'text': '미리 보기를 켜면 이 영역에 문서가 표시됩니다.' })
        );


        $layout.append($previewPane);
var $layout = $textareaWrapper.parent();
var $previewPane = $( '<div>', {
id: 'mw-custom-preview-pane',
'class': 'mw-custom-preview-pane'
} ).append(
$( '<div>', {
'class': 'mw-custom-preview-placeholder',
text: '미리 보기를 켜면 이 영역에 문서가 표시됩니다.'
} )
);


        var previewInitialized = false;
$layout.append( $previewPane );
        function initRealtimePreviewPane () {
            if ( previewInitialized ) return;


            var $rp = $('#wikiEditor-realtimepreview, [id*="realtimepreview-target"], .ext-WikiEditor-realtimepreview-container').first();
// realtime preview 컨테이너 이동
            if ( $rp.length ) {
var previewInitialized = false;
                previewInitialized = true;
function initRealtimePreviewPane () {
                $previewPane.empty().append($rp);
if ( previewInitialized ) return;
            }
        }


        $previewCheckbox.on('change', function () {
var $rp = $( '#wikiEditor-realtimepreview, [id*="realtimepreview-target"], .ext-WikiEditor-realtimepreview-container' ).first();
            var on = $(this).is(':checked');
if ( $rp.length ) {
            $('body').toggleClass('mw-edit-preview-on', on);
previewInitialized = true;
$previewPane.empty().append( $rp );
}
}


            if ( on ) {
$previewCheckbox.on( 'change', function () {
                if ( $origRealtimePreviewBtn.length ) {
var on = $( this ).is( ':checked' );
                    $origRealtimePreviewBtn.trigger('click');
$('body').toggleClass( 'mw-edit-preview-on', on );
                }
                setTimeout(initRealtimePreviewPane, 500);
            }
        });


        /* ================================
if ( on ) {
        * 3. 핵심 툴에 라벨 붙이기
if ( $origRealtimePreviewBtn.length ) {
        * ================================ */
$origRealtimePreviewBtn.trigger( 'click' );
        function addLabelToTool(rel, fallbackText) {
}
            var $tool = $toolbar.find('.group [rel="' + rel + '"] .oo-ui-buttonElement-button');
setTimeout( initRealtimePreviewPane, 500 );
            if (!$tool.length) return;
}
} );


            $tool.each(function () {
/* ===============================
                var $btn = $(this);
* 3. 주요 툴에 텍스트 라벨 붙이기
                if ($btn.find('.mw-edit-tool-label').length) return;
* =============================== */


                var title = $btn.attr('title') || fallbackText || '';
function addLabelToTool( rel, fallbackText ) {
                if (!title) return;
var $tool = $toolbar.find( '.group [rel="' + rel + '"] .oo-ui-buttonElement-button' );
if ( !$tool.length ) return;


                var $labelSpan = $('<span>', {
$tool.each( function () {
                    'class': 'mw-edit-tool-label',
var $btn = $( this );
                    'text': title
if ( $btn.find( '.mw-edit-tool-label' ).length ) return;
                });
                $btn.append($labelSpan);
            });
        }


        addLabelToTool('bold', '굵게');
var title = $btn.attr( 'title' ) || fallbackText || '';
        addLabelToTool('italic', '기울임');
if ( !title ) return;
        addLabelToTool('link', '링크');
 
        addLabelToTool('file', '이미지');
var $labelSpan = $( '<span>', {
        addLabelToTool('reference', '각주');
'class': 'mw-edit-tool-label',
    });
text: title
} );
$btn.append( $labelSpan );
} );
}
 
addLabelToTool( 'bold', '굵게' );
addLabelToTool( 'italic', '기울임' );
addLabelToTool( 'link', '링크' );
addLabelToTool( 'file', '이미지' );
addLabelToTool( 'reference', '각주' );
 
// 검색 그룹은 오른쪽으로 밀기 (옵션)
$toolbar.find( '.section-advanced .group-search' )
.addClass( 'mw-edit-toolbar-group-secondary' );
}
 
/* =========================================
* ① wikiEditor가 toolbar를 만들었을 때 hook 사용
*    (가장 안정적인 방법)
* ========================================= */
if ( mw.hook ) {
// 위키텍스트 편집기 툴바 준비 후 호출
mw.hook( 'wikiEditor.toolbarReady' ).add( function ( $textbox ) {
// $textbox: 해당 툴바가 연결된 textarea(jQuery 객체)
initCustomEditUI( $textbox );
} );
}
 
/* =========================================
* ② 혹시 hook이 안 먹는 환경 / 커스텀 스킨용 폴백:
*    DOM에 툴바가 생길 때까지 주기적으로 확인
* ========================================= */
$( function () {
var action = mw.config.get( 'wgAction' );
if ( action !== 'edit' && action !== 'submit' ) {
return;
}
 
var tries = 0;
function waitForToolbar() {
tries++;
var $textbox = $( '#wpTextbox1' );
var $toolbar = $( '#wikiEditor-ui-toolbar' );
 
if ( $textbox.length && $toolbar.length ) {
initCustomEditUI( $textbox );
} else if ( tries < 40 ) { // 최대 약 4초까지 시도 (100ms * 40)
setTimeout( waitForToolbar, 100 );
}
}
waitForToolbar();
});
});
});

2025년 11월 13일 (목) 22:18 판

/**
 * 이 스크립트는 위키백과 전체에 적용됩니다. 고칠 때는 주의해주세요.
 * [[위키백과:위키프로젝트 시스템]] 참고
 *
 * 스크립트를 넣을 때는 충분한 설명, 출처를 넣어주세요! 이후 관리가 어려워집니다.
 **//* 이 자바스크립트 설정은 리버티 스킨을 사용하는 사용자에게 적용됩니다 */

mw.loader.using(['mediawiki.util', 'jquery'], function () {
	function cleanUrlForMatch(url) {
		var u = new URL(url);

		u.searchParams.delete('enhanced');
		u.searchParams.delete('urlversion');
		u.searchParams.delete('days');
		u.searchParams.delete('hidebots');
		u.searchParams.delete('limit');

		return u.toString();
	}

	function buildQuickLinks($wrapper) {
		if (!$wrapper.length || $wrapper.data('quicklinks-initialized')) return;
		$wrapper.data('quicklinks-initialized', true);

		var links = [
			{
				label: '전체',
				href: 'https://w.halv.kr/%ED%8A%B9%EC%88%98:%EC%B5%9C%EA%B7%BC%EB%B0%94%EB%80%9C?hidebots=1&limit=250&days=7'
			},
			{
				label: '주시',
				href: 'https://w.halv.kr/%ED%8A%B9%EC%88%98:%EC%B5%9C%EA%B7%BC%EB%B0%94%EB%80%9C?watchlist=watched&limit=250&days=7'
			},
			{
				label: '새 문서',
				href: 'https://w.halv.kr/%ED%8A%B9%EC%88%98:%EC%B5%9C%EA%B7%BC%EB%B0%94%EB%80%9C?hidepageedits=1&hidelog=1&hidenewuserlog=1&limit=250&days=7'
			},
			{
				label: '되돌림',
				href: 'https://w.halv.kr/%ED%8A%B9%EC%88%98:%EC%B5%9C%EA%B7%BC%EB%B0%94%EB%80%9C?tagfilter=mw-rollback%7Cmw-undo&limit=250&days=7'
			}
		];

		// 🔹 현재 URL도 clean 처리
		var currentUrl = cleanUrlForMatch(location.href);

		var $container = $('<div>', { class: 'rc-quick-links' });
		var $buttons = $('<div>', { class: 'rc-quick-links__buttons' });

		links.forEach(function (link) {
			var $a = $('<a>', {
				class: 'rc-quick-links__btn',
				text: link.label,
				href: link.href
			});

			// 링크 쪽도 clean
			var linkClean = cleanUrlForMatch(link.href);

			// 🔹 완전히 같은지 비교
			if (currentUrl === linkClean) {
				$a.addClass('rc-quick-links__btn--active');
			}

			$buttons.append($a);
		});

		$container.append($buttons);
		$wrapper.empty().append($container);

		// fallback: 아무것도 active 아니면 첫 번째 버튼 활성화
		if (!$buttons.find('.rc-quick-links__btn--active').length) {
			$buttons.find('.rc-quick-links__btn').first().addClass('rc-quick-links__btn--active');
		}

		mw.util.addCSS(`
			.rc-quick-links {
				display: flex;
				flex-direction: column;
				gap: .5rem;
				padding: .75rem 1rem;
				border: none;
				border-radius: 6px;
				background-color: var(--bg);
				margin-left: -13px;
			}
			.rc-quick-links__buttons {
				display: flex;
				flex-wrap: wrap;
				gap: .4rem;
				width: 250px;
				justify-content: space-evenly;
				padding: 8px;
				border: 1px solid light-dark(#e1e8ed,var(--grey));
				border-radius: 0.5rem;
			}
			.rc-quick-links__btn {
				font-size: 1rem;
				text-decoration: none;
				color: var(--text);
				transition: .15s;
			}
			.rc-quick-links__btn:hover {
				font-weight: 600;
				color: light-dark(#81B11F, var(--text));
				text-decoration: none;
				box-shadow: 0em 0.2em light-dark(#81B11F70, var(--grey));
			}
			.rc-quick-links__btn--active {
				font-weight: 600;
				color: light-dark(#81B11F, var(--text));
				text-decoration: none;
				box-shadow: 0em 0.2em light-dark(#81B11F70, var(--grey));
			}
		`);
	}

	mw.hook('wikipage.content').add(function () {
		// 이 셀렉터가 실제로 존재하는지도 한 번 F12로 확인해보세요
		var $wrapper = $('.mw-rcfilters-head');
		if ($wrapper.length) buildQuickLinks($wrapper);
	});
});


(function () {

  const TEMPLATE_SOURCE = `
<tbody>
<tr class="mw-htmlform-field-UploadSourceField">
  <td class="mw-label">
    <label for="wpUploadFile">
      <span class="upload-badge">파일명</span>
    </label>
  </td>
  <td class="mw-input">
    <input id="wpUploadFile" name="wpUploadFile" size="60" type="file">
  </td>
</tr>
<tr>
  <td class="htmlform-tip" style="width: 129px;">
    <span class="upload-badge">최대 크기</span>
  </td>
  <td>2 MB</td>
</tr>
<tr class="mw-htmlform-field-HTMLInfoField">
  <td class="mw-label">
    <span class="upload-badge">형식</span>
  </td>
  <td>png, gif, jpg, jpeg, webp, svg, ico</td>
</tr>
</tbody>
`;

  const TEMPLATE_DESC = `
<tbody>
<tr class="mw-htmlform-field-HTMLTextField">
  <td class="mw-label">
    <label for="wpDestFile">
      <span class="upload-badge">파일명</span>
    </label>
  </td>
  <td class="mw-input">
    <input id="wpDestFile" name="wpDestFile" size="60">
  </td>
</tr>

<tr class="mw-htmlform-field-HTMLTextAreaField">
  <td class="mw-label">
    <label for="wpUploadDescription">
      <span class="upload-badge">요약</span>
    </label>
  </td>
  <td class="mw-input">
    <textarea id="wpUploadDescription" cols="80" rows="8" name="wpUploadDescription"></textarea>
  </td>
</tr>

<tr>
  <td></td>
  <td class="mw-input">
    <div class="mw-editTools" tabindex="0"></div>
  </td>
</tr>

<tr class="mw-htmlform-field-Licenses">
  <td class="mw-label">
    <label for="wpLicense">
      <span class="upload-badge">라이선스</span>
    </label>
  </td>
  <td class="mw-input">
    <select name="wpLicense" id="wpLicense">
      <option value="" selected="">선택하지 않음</option>
    </select>
  </td>
</tr>

<tr><td></td><td id="mw-license-preview"></td></tr>
<tr><td id="wpDestFile-warning" colspan="2"></td></tr>
</tbody>
`;

  function replaceTables() {
    let replaced = false;

    const sourceTable = document.querySelector("table#mw-htmlform-source");
    if (sourceTable) {
      sourceTable.innerHTML = TEMPLATE_SOURCE;
      replaced = true;
    }

    const descTable = document.querySelector("table#mw-htmlform-description");
    if (descTable) {
      descTable.innerHTML = TEMPLATE_DESC;
      replaced = true;
    }

    return replaced;
  }

  // Run once on DOM ready
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", replaceTables);
  } else {
    replaceTables();
  }

  // Mutation observer for late-loaded content
  const observer = new MutationObserver(() => {
    if (replaceTables()) {
      observer.disconnect();
    }
  });

  observer.observe(document.documentElement, {
    childList: true,
    subtree: true
  });

})();

mw.loader.using('mediawiki.util', function () {
  $(function () {
    // Check if the #timetable-indicator span exists
    if (document.getElementById('timetable-indicator')) {
      // Create a <style> element
      var style = document.createElement('style');
      style.textContent = `
        .Liberty .nav-wrapper .navbar .navbar-brand {
          background: transparent
                     url(/images/2/27/%EC%8B%9C%EA%B0%81%ED%91%9C%EB%A1%9C%EA%B3%A0.svg)
                     no-repeat left center / auto 1.6em !important;
        }

.mw-page-title-namespace {
  box-shadow: inset 0 -0.5rem 0 #ef413750;
}

.Liberty .nav-wrapper, .Liberty .content-wrapper .liberty-sidebar .live-recent-wrapper .live-recent .live-recent-footer .label:hover, .Liberty .nav-wrapper .navbar .navbar-nav .nav-item .nav-link:hover, .Liberty .nav-wrapper .navbar .navbar-nav .nav-item .nav-link:focus, .dropdown-menu .dropdown-item:hover {
  background-color: #ef4137;
}
        .Liberty .nav-wrapper .navbar .form-inline .btn:hover,
        .Liberty .nav-wrapper .navbar .form-inline .btn:focus,
        .Liberty .content-wrapper .liberty-sidebar
          .live-recent-wrapper .live-recent
          .live-recent-header .nav .nav-item .nav-link.active::before,
        .Liberty .content-wrapper .liberty-sidebar
          .live-recent-wrapper .live-recent
          .live-recent-header .nav .nav-item .nav-link:hover::before,
        .Liberty .content-wrapper .liberty-sidebar
          .live-recent-wrapper .live-recent
          .live-recent-header .nav .nav-item .nav-link:focus::before,
        .Liberty .content-wrapper .liberty-sidebar
          .live-recent-wrapper .live-recent
          .live-recent-header .nav .nav-item .nav-link:active::before,
        .Liberty .content-wrapper .liberty-sidebar
          .live-recent-wrapper .live-recent
          .live-recent-footer .label,
        .Liberty .content-wrapper .liberty-content
          .liberty-content-header .content-tools .tools-btn:hover,
        .Liberty .content-wrapper .liberty-content
          .liberty-content-header .content-tools .tools-btn:focus,
        .Liberty .content-wrapper .liberty-content
          .liberty-content-header .content-tools .tools-btn:active {
          background-color: #ef4137 !important;
        }
      `;
      document.head.appendChild(style);
    }
  });
});


(function () {
  function initStickyBorders(wrap) {
    const sticky = wrap.querySelector('#stickyparent');
    if (!sticky) return;

    function updateStickyWidth() {
      const w = sticky.getBoundingClientRect().width;
      wrap.style.setProperty('--sticky-w', w + 'px');
    }

    function updateScrollState() {
      const atLeft = wrap.scrollLeft < 5;
      wrap.classList.toggle('at-left', atLeft);
      wrap.classList.toggle('scrolled', !atLeft); // ← 추가: 왼쪽이 아니면 '띄우기' 상태
    }

    updateStickyWidth();
    updateScrollState();

    wrap.addEventListener('scroll', updateScrollState, { passive: true });
    window.addEventListener('resize', updateStickyWidth);
    if (document.fonts && document.fonts.ready) {
      document.fonts.ready.then(updateStickyWidth).catch(function(){});
    }
  }

  document.querySelectorAll('.table-wrap').forEach(initStickyBorders);
})();



(function () {
  function unwrapLibertyTable(wrapper) {
    if (!wrapper || !wrapper.querySelector('.timetable')) return;
    const table = wrapper.querySelector('.timetable');
    wrapper.parentNode.insertBefore(table, wrapper);
    wrapper.remove();
  }

  // Remove any that already exist
  document.querySelectorAll('.liberty-table-wrapper').forEach(unwrapLibertyTable);

  // Watch for new ones being added to the DOM
  const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
      mutation.addedNodes.forEach(node => {
        if (!(node instanceof HTMLElement)) return;
        if (node.matches('.liberty-table-wrapper') && node.querySelector('.timetable')) {
          unwrapLibertyTable(node);
        } else if (node.querySelector) {
          // If it's a container, check inside it
          node.querySelectorAll('.liberty-table-wrapper').forEach(unwrapLibertyTable);
        }
      });
    });
  });

  observer.observe(document.body, {
    childList: true,
    subtree: true
  });
})();



mw.loader.using( ['mediawiki.util', 'mediawiki.notify', 'jquery.client'], function () {
/* Begin of mw.loader.using callback */

/**
 * Map addPortletLink to mw.util 
 *
 * @deprecated: Use mw.util.addPortletLink instead.
 */
mw.log.deprecate( window, 'addPortletLink', mw.util.addPortletLink,
 'Use mw.util.addPortletLink instead' );
 
/**
 * Extract a URL parameter from the current URL
 *
 * @deprecated: Use mw.util.getParamValue with proper escaping
 */
mw.log.deprecate( window, 'getURLParamValue', mw.util.getParamValue, 'Use mw.util.getParamValue instead' );
 
/** 
 * Test if an element has a certain class
 *
 * @deprecated:  Use $(element).hasClass() instead.
 */
mw.log.deprecate( window, 'hasClass', function ( element, className ) {
    return $( element ).hasClass( className );
}, 'Use jQuery.hasClass() instead' );
 
/**
 * @source www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
 * @rev 5
 */
// CSS
var extraCSS = mw.util.getParamValue( 'withCSS' );
if ( extraCSS ) {
	if ( extraCSS.match( /^MediaWiki:[^&<>=%#]*\.css$/ ) ) {
		importStylesheet( extraCSS );
	} else {
		mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withCSS value' } );
	}
}
 
// JS
var extraJS = mw.util.getParamValue( 'withJS' );
if ( extraJS ) {
	if ( extraJS.match( /^MediaWiki:[^&<>=%#]*\.js$/ ) ) {
		importScript( extraJS );
	} else {
		mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withJS value' } );
	}
}
 

/**
 * Import more specific scripts if necessary
 */

if ( mw.config.get( 'wgNamespaceNumber' ) === 6 ) {
    /* file description page scripts */
    importScript( 'MediaWiki:Common.js/file.js' );
}

/* ([[위키백과:관리자 요청/2007년 5월#스크립트 추가 요청]]) */
/** Collapsible tables *********************************************************
 *
 *  Description: Allows tables to be collapsed, showing only the header. See
 *               [[:en:Wikipedia:NavFrame]].
 *  Maintainers: [[:en:User:R. Koot]]
 */
 
var autoCollapse = 2;
var collapseCaption = '숨기기';
var expandCaption = '보이기';

window.collapseTable = function ( tableIndex ) {
    var Button = document.getElementById( 'collapseButton' + tableIndex );
    var Table = document.getElementById( 'collapsibleTable' + tableIndex );

    if ( !Table || !Button ) {
        return false;
    }

    var Rows = Table.rows;
    var i;

    if ( Button.firstChild.data === collapseCaption ) {
        for ( i = 1; i < Rows.length; i++ ) {
            Rows[i].style.display = 'none';
        }
        Button.firstChild.data = expandCaption;
    } else {
        for ( i = 1; i < Rows.length; i++ ) {
            Rows[i].style.display = Rows[0].style.display;
        }
        Button.firstChild.data = collapseCaption;
    }
};

function createCollapseButtons() {
    var tableIndex = 0;
    var NavigationBoxes = {};
    var Tables = document.getElementsByTagName( 'table' );
    var i;

    function handleButtonLink( index, e ) {
        window.collapseTable( index );
        e.preventDefault();
    }

    for ( i = 0; i < Tables.length; i++ ) {
        if ( $( Tables[i] ).hasClass( 'collapsible' ) ) {

            /* only add button and increment count if there is a header row to work with */
            var HeaderRow = Tables[i].getElementsByTagName( 'tr' )[0];
            if ( !HeaderRow ) continue;
            var Header = HeaderRow.getElementsByTagName( 'th' )[0];
            if ( !Header ) continue;

            NavigationBoxes[ tableIndex ] = Tables[i];
            Tables[i].setAttribute( 'id', 'collapsibleTable' + tableIndex );

            var Button     = document.createElement( 'span' );
            var ButtonLink = document.createElement( 'a' );
            var ButtonText = document.createTextNode( collapseCaption );

            Button.className = 'collapseButton';  /* Styles are declared in Common.css */

            ButtonLink.style.color = Header.style.color;
            ButtonLink.setAttribute( 'id', 'collapseButton' + tableIndex );
            ButtonLink.setAttribute( 'href', '#' );
            $( ButtonLink ).on( 'click', $.proxy( handleButtonLink, ButtonLink, tableIndex ) );
            ButtonLink.appendChild( ButtonText );

            Button.appendChild( document.createTextNode( '[' ) );
            Button.appendChild( ButtonLink );
            Button.appendChild( document.createTextNode( ']' ) );

            Header.insertBefore( Button, Header.firstChild );
            tableIndex++;
        }
    }

    for ( i = 0;  i < tableIndex; i++ ) {
        if ( $( NavigationBoxes[i] ).hasClass( 'collapsed' ) || ( tableIndex >= autoCollapse && $( NavigationBoxes[i] ).hasClass( 'autocollapse' ) ) ) {
            window.collapseTable( i );
        } 
        else if ( $( NavigationBoxes[i] ).hasClass ( 'innercollapse' ) ) {
            var element = NavigationBoxes[i];
            while ((element = element.parentNode)) {
                if ( $( element ).hasClass( 'outercollapse' ) ) {
                    window.collapseTable ( i );
                    break;
                }
            }
        }
    }
}

mw.hook( 'wikipage.content' ).add( createCollapseButtons );

/* ([[위키백과:관리자 요청/2007년 5월#스크립트 추가 요청]]) */
/** Dynamic Navigation Bars (experimental) *************************************
 *
 *  Description: See [[:en:Wikipedia:NavFrame]].
 *  Maintainers: UNMAINTAINED
 */
 
// set up the words in your language
/* set up the words in your language */
var NavigationBarHide = '[' + collapseCaption + ']';
var NavigationBarShow = '[' + expandCaption + ']';

/**
 * Shows and hides content and picture (if available) of navigation bars
 * Parameters:
 *     indexNavigationBar: the index of navigation bar to be toggled
 **/
window.toggleNavigationBar = function ( indexNavigationBar, event ) {
    var NavToggle = document.getElementById( 'NavToggle' + indexNavigationBar );
    var NavFrame = document.getElementById( 'NavFrame' + indexNavigationBar );
    var NavChild;

    if ( !NavFrame || !NavToggle ) {
        return false;
    }

    /* if shown now */
    if ( NavToggle.firstChild.data === NavigationBarHide ) {
        for ( NavChild = NavFrame.firstChild; NavChild !== null; NavChild = NavChild.nextSibling ) {
            if ( $( NavChild ).hasClass( 'NavContent' ) || $( NavChild ).hasClass( 'NavPic' ) ) {
                NavChild.style.display = 'none';
            }
        }
    NavToggle.firstChild.data = NavigationBarShow;

    /* if hidden now */
    } else if ( NavToggle.firstChild.data === NavigationBarShow ) {
        for ( NavChild = NavFrame.firstChild; NavChild !== null; NavChild = NavChild.nextSibling ) {
            if ( $( NavChild ).hasClass( 'NavContent' ) || $( NavChild ).hasClass( 'NavPic' ) ) {
                NavChild.style.display = 'block';
            }
        }
        NavToggle.firstChild.data = NavigationBarHide;
    }

    event.preventDefault();
};

/* adds show/hide-button to navigation bars */
function createNavigationBarToggleButton() {
    var indexNavigationBar = 0;
    var NavFrame;
    var NavChild;
    /* iterate over all < div >-elements */
    var divs = document.getElementsByTagName( 'div' );
    for ( var i = 0; (NavFrame = divs[i]); i++ ) {
        /* if found a navigation bar */
        if ( $( NavFrame ).hasClass( 'NavFrame' ) ) {

            indexNavigationBar++;
            var NavToggle = document.createElement( 'a' );
            NavToggle.className = 'NavToggle';
            NavToggle.setAttribute( 'id', 'NavToggle' + indexNavigationBar );
            NavToggle.setAttribute( 'href', '#' );
            $( NavToggle ).on( 'click', $.proxy( window.toggleNavigationBar, window, indexNavigationBar ) );

            var isCollapsed = $( NavFrame ).hasClass( 'collapsed' );
            /**
             * Check if any children are already hidden.  This loop is here for backwards compatibility:
             * the old way of making NavFrames start out collapsed was to manually add style="display:none"
             * to all the NavPic/NavContent elements.  Since this was bad for accessibility (no way to make
             * the content visible without JavaScript support), the new recommended way is to add the class
             * "collapsed" to the NavFrame itself, just like with collapsible tables.
             */
            for ( NavChild = NavFrame.firstChild; NavChild != null && !isCollapsed; NavChild = NavChild.nextSibling ) {
                if ( $( NavChild ).hasClass( 'NavPic' ) || $( NavChild ).hasClass( 'NavContent' ) ) {
                    if ( NavChild.style.display === 'none' ) {
                        isCollapsed = true;
                    }
                }
            }
            if ( isCollapsed ) {
                for ( NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling ) {
                    if ( $( NavChild ).hasClass( 'NavPic' ) || $( NavChild ).hasClass( 'NavContent' ) ) {
                        NavChild.style.display = 'none';
                    }
                }
            }
            var NavToggleText = document.createTextNode( isCollapsed ? NavigationBarShow : NavigationBarHide );
            NavToggle.appendChild( NavToggleText );

            /* Find the NavHead and attach the toggle link (Must be this complicated because Moz's firstChild handling is borked) */
            for( var j = 0; j < NavFrame.childNodes.length; j++ ) {
                if ( $( NavFrame.childNodes[j] ).hasClass( 'NavHead' ) ) {
                    NavToggle.style.color = NavFrame.childNodes[j].style.color;
                    NavFrame.childNodes[j].appendChild( NavToggle );
                }
            }
            NavFrame.setAttribute( 'id', 'NavFrame' + indexNavigationBar );
        }
    }
}

mw.hook( 'wikipage.content' ).add( createNavigationBarToggleButton );

/***** 그림 정보 틀을 자동으로 불러옴 ********
 * Adds a link to subpages of current page
 * from commons.wikimedia.org
 *  Maintainers: [[User:Yonidebest]], [[User:Dschwen]]
 *  [[사용자:Kwj2772]]가 수정
 *  JSconfig items: bool 'loadAutoInformationTemplate'
 *                       (true=enabled (default), false=disabled)
 * JSConfig를 사용하지 않도록 수정함. --[[사용자:Klutzy|klutzy]] ([[사용자토론:Klutzy|토론]]) 2009년 9월 27일 (일) 20:33 (KST)
 ****/
if (mw.config.get('wgCanonicalSpecialPageName') == 'Upload') {
  importScript('MediaWiki:Upload.js');
}

/* 인터랙티브 지도. 영어 위키백과에서 가져옴. -- [[사용자:ChongDae]] 2010년 3월 28일 (일) 02:08 (KST) */
/**
 * WikiMiniAtlas
 *
 * Description: WikiMiniAtlas is a popup click and drag world map.
 *              This script causes all of our coordinate links to display the WikiMiniAtlas popup button.
 *              The script itself is located on meta because it is used by many projects.
 *              See [[Meta:WikiMiniAtlas]] for more information. 
 * Maintainers: [[User:Dschwen]]
 */
( function () {
    var require_wikiminiatlas = false;
    var coord_filter = /geohack/;
    $( function () {
        $( 'a.external.text' ).each( function( key, link ) {
            if ( link.href && coord_filter.exec( link.href ) ) {
                require_wikiminiatlas = true;
                // break from loop
                return false;
            }
        } );
        if ( $( 'div.kmldata' ).length ) {
            require_wikiminiatlas = true;
        }
        if ( require_wikiminiatlas ) {
            mw.loader.load( '//meta.wikimedia.org/w/index.php?title=MediaWiki:Wikiminiatlas.js&action=raw&ctype=text/javascript' );
        }
    } );
} )();

/**
 * Fix for Windows XP Unicode font rendering
 */
if ( navigator.appVersion.search(/windows nt 5/i) !== -1 ) {
    mw.util.addCSS( '.IPA { font-family: "Lucida Sans Unicode", "Arial Unicode MS"; } ' + 
                '.Unicode { font-family: "Arial Unicode MS", "Lucida Sans Unicode"; } ' );
}

/**
 * 편집 안내 ****************************************************
 *
 * 생존 인물에 대한 편집 안내. 영어 위키백과에서 가져옴 - ChongDae
 * Maintainers: [[User:RockMFR]]
 */
function addEditIntro( name ) {
    $( '.mw-editsection, #ca-edit' ).find( 'a' ).each( function ( i, el ) {
        el.href = $( this ).attr( 'href' ) + '&editintro=' + name;
    } );
}

if ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
    $( function () {
        var cats = mw.config.get('wgCategories');
        if ( !cats ) {
            return;
        }
        if ( $.inArray( '살아있는 사람', cats ) !== -1 || $.inArray( '생사 불명', cats ) !== -1 ) {
            addEditIntro( '틀:BLP_편집_안내' );
        }
    } );
}
/**
 * 
 * 
 * 
 */
function wikilink1() {
	location.href='https://jwiki.kr/wiki/index.php/철통같은_믿음으로';
}

/* End of mw.loader.using callback */
} );

$(document).ready(function () {

    /* ---------- helper for sub-pixel scroll height ---------- */
   /* ---------- helper for sub-pixel scroll height (accurate & shift-free) ---------- */
function getExactScrollHeight(el) {
  /* 1 — snapshot the current inline width so the clone wraps exactly the same */
  const liveRect = el.getBoundingClientRect();          // fractional width!
  const liveW    = liveRect.width + "px";

  /* 2 — make a deep clone and neutralise its layout impact */
  const clone = el.cloneNode(true);
  Object.assign(clone.style, {
    position      : "absolute",   // out of normal flow
    left          : "-9999px",    // off-screen (but in the DOM)
    top           : "0",
    width         : liveW,        // lock wrapping width
    height        : "auto",
    overflow      : "visible",
    visibility    : "hidden",
    pointerEvents : "none",
    transition    : "none"
  });

  /* 3 — measure, then discard */
  el.parentNode.appendChild(clone);                     // within same ancestor → exact CSS context
  const h = clone.getBoundingClientRect().height;       // accurate, fractional OK
  clone.remove();

  return h;                                             // sub-pixel-precise
}


    /* -------------------------------------------------------- */

    $('.toggleBtn').click(function () {
        var $button = $(this);

        if ($button.data('animating')) return;
        $button.data('animating', true);

        var targetId = $button.data('target');
        var growDiv  = document.getElementById(targetId);
        var $growDiv = $('#' + targetId);

        const cs = window.getComputedStyle(growDiv);
        var oldHeight = growDiv.getBoundingClientRect().height;
        var paddingAndBorder = parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom);

        $growDiv.toggleClass('collapsed');

        if (growDiv.clientHeight) {
            /* ---------- COLLAPSE ---------- */
setTimeout(() => growDiv.style.display = "none", 300);
            growDiv.style.height = 0;
            var heightDifference = 0 - oldHeight - paddingAndBorder;
        } else {
            /* ---------- EXPAND ---------- */
growDiv.style.display = "block";
            const exactScrollHeight = getExactScrollHeight(growDiv);

            if ($growDiv.hasClass('textcollapsible')) {
                growDiv.style.height = (exactScrollHeight + 6) + "px";
            } else {
                growDiv.style.height = (exactScrollHeight + 6.5) + "px";	
            }

            var heightDifference = exactScrollHeight - oldHeight - paddingAndBorder;
        }

        if ($growDiv.hasClass('textcollapsible') && !$growDiv.hasClass('collapsed')) {
            heightDifference += 6;
        } else if (!$growDiv.hasClass('textcollapsible') && !$growDiv.hasClass('collapsed')) {
            heightDifference += 6.5;
        }

        console.log(heightDifference);

        animateParentHeights(growDiv, heightDifference);

        setTimeout(() => $button.data('animating', false), 300);
    });

        function animateParentHeights(element, difference) {
        var parent = element.parentElement.closest('.collapsible');
        while (parent) {
            var intervalId = setInterval(() => {
                const p = element.parentElement.closest('.collapsible');
                p.style.height    = getExactScrollHeight(p) + 5 + 'px'; // float
            }, 30);

            setTimeout(() => {
                clearInterval(intervalId);
                const p = element.parentElement.closest('.collapsible');
                p.style.animation = '';
                p.style.height    = getExactScrollHeight(p) + 5 + 'px'; // float
            }, 310);

            parent = parent.parentElement.closest('.collapsible');
        }
    }
});

    const gemstoneColors = {
  "흙": "#4b4b4b",         // Coal - Dark gray
  "구리": "#c68346",       // Copper - Reddish-brown
  "청동": "#547865",       // Bronze - Warm brown
  "은": "#c0c0c0",         // Silver - Metallic silver
  "금": "#efbf04",         // Gold - Golden yellow
  "자수정": "#9966cc",     // Amethyst - Purple
  "터키석": "#069e80",     // Turquoise - Light blue
  "가넷": "#9b111e",       // Garnet - Deep red
  "토파즈": "#f0a641",     // Topaz - Golden orange
  "페리도트": "#81b11f",   // Peridot - Light green
  "에메랄드 I": "#39b647", // Emerald - Bright green
  "에메랄드 II": "#39b647",// Emerald - Bright green (variant)
  "에메랄드 III": "#39b647",// Emerald - Bright green (variant)
  "사파이어 I": "#0f52ba", // Sapphire - Rich blue
  "사파이어 II": "#0f52ba",// Sapphire - Rich blue (variant)
  "사파이어 III": "#0f52ba",// Sapphire - Rich blue (variant)
  "루비 I": "#e0115f",     // Ruby - Vivid red
  "루비 II": "#e0115f",    // Ruby - Vivid red (variant)
  "루비 III": "#e0115f",   // Ruby - Vivid red (variant)
  "다이아몬드 I": "#b9fcff", // Diamond - Pale blue/white
  "다이아몬드 II": "#b9fcff",// Diamond - Pale blue/white (variant)
  "다이아몬드 III": "#b9fcff"
    };


// Function to update background color
function updateBackgroundColor() {

  const existing = document.querySelector('span.pjcg-hwijang');
const appendafterthis = document.querySelector('.live-recent-content');
  if (existing) {
    const newDiv = document.createElement('div');
    newDiv.className = 'live-recent-fake-content';
    newDiv.setAttribute(
      'style',
      `
      margin-top: 1rem;
      background: url(https://w.halv.kr/images/4/4c/%EC%B2%AD%EA%B4%91%ED%9C%98%EC%9E%A5.png) center no-repeat, light-dark(#fff,#1c1d1f) !important;
      background-size: contain !important;
      width: 21.5rem !important;
height:16.76rem !important;
      `
    );

    appendafterthis.insertAdjacentElement('afterend', newDiv);
  };


  const list = document.querySelector('.live-recent-content');
  if (!list) return;

  const link = document.createElement('a');
  link.href = '/%ED%8A%B9%EC%88%98:%EC%B5%9C%EA%B7%BC%EB%B0%94%EB%80%9C';
  link.innerText = '최근 변경';
  link.style.display = 'block';
  link.style.fontSize = '20px';
  link.style.fontWeight = '500';
  link.style.marginTop = '3px';
  link.style.textDecoration = 'none';
  link.style.textAlign = 'left';
  link.style.color = 'var(--text)';

const link2 = document.createElement('a');
  link2.href = '/%ED%8A%B9%EC%88%98:%EC%B5%9C%EA%B7%BC%EB%B0%94%EB%80%9C';
  link2.innerText = '▶';
  link2.style.display = 'block';
  link2.style.fontSize = '14px';
  link2.style.fontWeight = '500';
  link2.style.marginTop = '3px';
  link2.style.textDecoration = 'none';
  link2.style.textAlign = 'right';
link2.style.opacity = '60%';
  link2.style.color = 'var(--text)';

const containeroflinks = document.createElement('div');
containeroflinks.style.display = 'flex';
containeroflinks.style.justifyContent = 'space-between';
containeroflinks.style.alignItems = 'center';

containeroflinks.append(link);
containeroflinks.append(link2);

  list.prepend(containeroflinks); // add to the top of the container

  const targetElements = document.querySelectorAll('.live-recent-content');
  targetElements.forEach((el) => {
    el.insertAdjacentHTML(
      'beforebegin',
      `<a href="https://www.postype.com/@whalvkr/membership">
         <div class="live-recent-fake-content" style="
           margin-bottom: 1rem;
           background: url(https://w.halv.kr/images/b/bd/후원처란.png) center no-repeat, light-dark(#fff,#1c1d1f) !important;
  height: 6rem;
           background-size: contain !important;
         "></div>
       </a>`
    );
  });


  const element = document.getElementById("honorific-level");
  const leveler = document.getElementById("points-level");
  const childElement = leveler.firstElementChild; // Access the first child of leveler
  const text = element.textContent.trim().replace(/[()]/g, ""); // Remove parentheses

  // Check if the text matches specific diamond levels and update the child element color
  if (text === "다이아몬드 I" || text === "다이아몬드 II" || text === "다이아몬드 III") {
    leveler.style.background = gemstoneColors[text] || "transparent";
    leveler.style.borderColor = "#22636652";
    if (childElement) {
      childElement.style.color = "#226366cc"; // Set the child element's text color to red
    }
  } else if (gemstoneColors[text]) {
    leveler.style.background = gemstoneColors[text];
    leveler.style.borderColor = gemstoneColors[text] + "52";
    if (childElement) {
      childElement.style.color = ""; // Reset child element's text color
    }
  } else {
    leveler.style.background = "transparent"; // Default if no match
    leveler.style.borderColor = "";
    if (childElement) {
      childElement.style.color = ""; // Reset child element's text color
    }
  }
}


  const head = document.head;

  const link3 = document.createElement('link');
  link3.rel = 'stylesheet';
  link3.href = 'https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&family=Zen+Kaku+Gothic+Antique:wght@300;400;500;700;900&display=swap';

  const link4 = document.createElement('link');
  link4.rel = 'stylesheet';
  link4.href = 'https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css';


  head.appendChild(link3);
head.appendChild(link4);

function stretchText(el) {
  // 1) target width in px from data-max-width (in rem)
  const maxWidth =
    parseFloat(getComputedStyle(document.documentElement).fontSize) *
    parseFloat(el.dataset.maxWidth);

  // 2) get the child <span> in a Safari-safe way
  const span = (el.querySelector && (el.querySelector(':scope > span') || el.querySelector('span'))) || null;
  if (!span) return;

  // 3) ensure predictable measuring
  const prev = el.style.transform;
  el.style.transform = 'translateX(-50%)'; // remove previous scale while measuring

  const measure = () => {
    // If fonts aren't ready yet, Safari may report 0
    const w = span.scrollWidth || span.getBoundingClientRect().width;
    if (!w) return requestAnimationFrame(measure);

    const scale = maxWidth / w;
    el.style.transformOrigin = 'center center';
    el.style.transform = `translateX(-50%) scaleX(${scale})`;
    el.style.position = 'absolute';
    el.style.position = 'absolute';
  };

  // Wait for fonts/layout in Safari
  if (document.fonts && document.fonts.ready) {
    document.fonts.ready.then(() => requestAnimationFrame(measure));
  } else {
    requestAnimationFrame(measure);
  }
}

// run once and on resize
const runAll = () => document.querySelectorAll('.stretch-text').forEach(stretchText);
runAll();
addEventListener('resize', runAll);

document.addEventListener("DOMContentLoaded", () => {
  document.querySelectorAll(".diff-menu").forEach(el => {
    const divider = document.createElement("div");
    divider.className = "dropdown-divider";
    el.insertAdjacentElement("afterend", divider);
  });
});

(function () {
  function addDropdownDividers(root = document) {
    const menus = root.querySelectorAll('.diff-menu');

    menus.forEach(menu => {
      const next = menu.nextElementSibling;

      // Avoid duplicates
      if (next && next.classList.contains('dropdown-divider')) {
        return;
      }

      const divider = document.createElement('div');
      divider.className = 'dropdown-divider';

      if (menu.parentNode) {
        menu.parentNode.insertBefore(divider, menu.nextSibling);
      }
    });
  }

  // Run after DOM is loaded
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => addDropdownDividers());
  } else {
    addDropdownDividers();
  }

  // Observe for new mutations
  const observer = new MutationObserver(mutations => {
    for (const mutation of mutations) {
      if (mutation.type === 'childList') {
        // Check in the subtree of added nodes
        mutation.addedNodes.forEach(node => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            addDropdownDividers(node);
          }
        });
      }
    }
  });

  observer.observe(document.documentElement, {
    childList: true,
    subtree: true
  });
})();


// Call the function
updateBackgroundColor();
changeTimeColor(); 

/* DO NOT ADD CODE BELOW THIS LINE */
/* =========================================
 * Source editor UI 개선 스크립트 (툴바 로딩 이후 실행)
 * 위치: MediaWiki:Common.js
 * ========================================= */
mw.loader.using( ['jquery', 'mediawiki.util'] ).then( function () {

	function initCustomEditUI( $textbox ) {
		// 같은 textarea에 두 번 적용 방지
		if ( !$textbox || !$textbox.length || $textbox.data( 'mwCustomEditUiDone' ) ) {
			return;
		}
		$textbox.data( 'mwCustomEditUiDone', true );

		var action = mw.config.get( 'wgAction' );
		if ( action !== 'edit' && action !== 'submit' ) {
			return;
		}

		// 위키에디터 툴바
		var $toolbar = $( '#wikiEditor-ui-toolbar' );
		if ( !$toolbar.length ) {
			// 혹시 셀렉터가 다르면 콘솔에서 구조 한 번 확인 필요
			return;
		}

		$('body').addClass( 'mw-custom-edit-ui' );

		var $saveBtn = $( '#wpSave' );

		/* -------------------------------
		 * 모드 전환 버튼 원본 (있으면 사용)
		 * ------------------------------- */
		var $origSourceSwitch = $( '.oo-ui-tool-name-editModeSource .oo-ui-tool-link' );
		var $origVisualSwitch = $( '.oo-ui-tool-name-editModeVisual .oo-ui-tool-link' );
		var $origRealtimePreviewBtn = $( '.ext-WikiEditor-realtimepreview-button .oo-ui-buttonElement-button' );
		var isSourceModeActive = $origSourceSwitch.closest( '.oo-ui-tool' ).hasClass( 'oo-ui-tool-active' );

		/* ===============================
		 * 1. 상단 헤더 생성
		 * =============================== */

		var $header = $( '<div>', { 'class': 'mw-edit-header-custom' } );

		// (1) 편집 모드 토글
		var $modeGroup = $( '<div>', { 'class': 'mw-edit-header-group mw-edit-header-modes' } );
		var $sourceBtn = $( '<button>', {
			type: 'button',
			class: 'mw-edit-header-btn mode-btn mode-source' + ( isSourceModeActive ? ' is-active' : '' ),
			text: mw.msg( 'wikieditor-sourcemode-label' ) || '원본 편집'
		} );
		var $visualBtn = $( '<button>', {
			type: 'button',
			class: 'mw-edit-header-btn mode-btn mode-visual' + ( !isSourceModeActive ? ' is-active' : '' ),
			text: mw.msg( 'wikieditor-visualmode-label' ) || '시각 편집'
		} );

		$sourceBtn.on( 'click', function () {
			if ( $origSourceSwitch.length ) {
				$origSourceSwitch.trigger( 'click' );
			}
		} );
		$visualBtn.on( 'click', function () {
			if ( $origVisualSwitch.length ) {
				$origVisualSwitch.trigger( 'click' );
			}
		} );

		$modeGroup.append( $sourceBtn, $visualBtn );

		// (2) 미리보기 토글
		var $previewGroup = $( '<div>', { 'class': 'mw-edit-header-group mw-edit-header-preview' } );
		var $previewLabel = $( '<label>', { 'class': 'mw-edit-header-preview-label' } );
		var $previewCheckbox = $( '<input>', {
			type: 'checkbox',
			id: 'mw-custom-preview-toggle'
		} );
		var $previewText = $( '<span>', { text: '실시간 미리 보기' } );
		$previewLabel.append( $previewCheckbox, $previewText );
		$previewGroup.append( $previewLabel );

		// (3) 저장 버튼 프록시
		var $actionsGroup = $( '<div>', { 'class': 'mw-edit-header-group mw-edit-header-actions' } );
		var $saveProxyBtn = $( '<button>', {
			type: 'button',
			class: 'mw-edit-header-btn mw-edit-header-save',
			text: $saveBtn.val() || '저장'
		} );
		$saveProxyBtn.on( 'click', function () {
			if ( $saveBtn.length ) {
				$saveBtn.trigger( 'click' );
			}
		} );
		$actionsGroup.append( $saveProxyBtn );

		$header.append( $modeGroup, $previewGroup, $actionsGroup );

		// 툴바 위에 삽입
		$toolbar.before( $header );

		/* ===============================
		 * 2. 편집/미리보기 2분할 레이아웃
		 * =============================== */

		var $textareaWrapper = $( '<div>', { 'class': 'mw-edit-textarea-wrapper' } );
		$textbox.before( $textareaWrapper );
		$textareaWrapper.append( $textbox );

		$textareaWrapper.wrap(
			$( '<div>', { 'class': 'mw-edit-main-layout' } )
		);

		var $layout = $textareaWrapper.parent();
		var $previewPane = $( '<div>', {
			id: 'mw-custom-preview-pane',
			'class': 'mw-custom-preview-pane'
		} ).append(
			$( '<div>', {
				'class': 'mw-custom-preview-placeholder',
				text: '미리 보기를 켜면 이 영역에 문서가 표시됩니다.'
			} )
		);

		$layout.append( $previewPane );

		// realtime preview 컨테이너 이동
		var previewInitialized = false;
		function initRealtimePreviewPane () {
			if ( previewInitialized ) return;

			var $rp = $( '#wikiEditor-realtimepreview, [id*="realtimepreview-target"], .ext-WikiEditor-realtimepreview-container' ).first();
			if ( $rp.length ) {
				previewInitialized = true;
				$previewPane.empty().append( $rp );
			}
		}

		$previewCheckbox.on( 'change', function () {
			var on = $( this ).is( ':checked' );
			$('body').toggleClass( 'mw-edit-preview-on', on );

			if ( on ) {
				if ( $origRealtimePreviewBtn.length ) {
					$origRealtimePreviewBtn.trigger( 'click' );
				}
				setTimeout( initRealtimePreviewPane, 500 );
			}
		} );

		/* ===============================
		 * 3. 주요 툴에 텍스트 라벨 붙이기
		 * =============================== */

		function addLabelToTool( rel, fallbackText ) {
			var $tool = $toolbar.find( '.group [rel="' + rel + '"] .oo-ui-buttonElement-button' );
			if ( !$tool.length ) return;

			$tool.each( function () {
				var $btn = $( this );
				if ( $btn.find( '.mw-edit-tool-label' ).length ) return;

				var title = $btn.attr( 'title' ) || fallbackText || '';
				if ( !title ) return;

				var $labelSpan = $( '<span>', {
					'class': 'mw-edit-tool-label',
					text: title
				} );
				$btn.append( $labelSpan );
			} );
		}

		addLabelToTool( 'bold', '굵게' );
		addLabelToTool( 'italic', '기울임' );
		addLabelToTool( 'link', '링크' );
		addLabelToTool( 'file', '이미지' );
		addLabelToTool( 'reference', '각주' );

		// 검색 그룹은 오른쪽으로 밀기 (옵션)
		$toolbar.find( '.section-advanced .group-search' )
			.addClass( 'mw-edit-toolbar-group-secondary' );
	}

	/* =========================================
	 * ① wikiEditor가 toolbar를 만들었을 때 hook 사용
	 *    (가장 안정적인 방법)
	 * ========================================= */
	if ( mw.hook ) {
		// 위키텍스트 편집기 툴바 준비 후 호출
		mw.hook( 'wikiEditor.toolbarReady' ).add( function ( $textbox ) {
			// $textbox: 해당 툴바가 연결된 textarea(jQuery 객체)
			initCustomEditUI( $textbox );
		} );
	}

	/* =========================================
	 * ② 혹시 hook이 안 먹는 환경 / 커스텀 스킨용 폴백:
	 *    DOM에 툴바가 생길 때까지 주기적으로 확인
	 * ========================================= */
	$( function () {
		var action = mw.config.get( 'wgAction' );
		if ( action !== 'edit' && action !== 'submit' ) {
			return;
		}

		var tries = 0;
		function waitForToolbar() {
			tries++;
			var $textbox = $( '#wpTextbox1' );
			var $toolbar = $( '#wikiEditor-ui-toolbar' );

			if ( $textbox.length && $toolbar.length ) {
				initCustomEditUI( $textbox );
			} else if ( tries < 40 ) { // 최대 약 4초까지 시도 (100ms * 40)
				setTimeout( waitForToolbar, 100 );
			}
		}
		waitForToolbar();
	});
});