문서 편집 권한이 없습니다. 다음 이유를 확인해주세요: 이 문서는 이 위키의 소프트웨어 인터페이스에 쓰이는 문서로, 부정 행위를 막기 위해 보호되어 있습니다. 모든 위키에 대한 번역을 추가하거나 바꾸려면 미디어위키 지역화 프로젝트인 translatewiki.net에 참여하시기 바랍니다.모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다. 문서의 원본을 보거나 복사할 수 있습니다. /* All JavaScript here will be loaded for users of the MinervaNeue skin */ /* 미네르바 노이에 전용 커스텀 메뉴 (PC/모바일 공통) * MediaWiki:Minerva.js 에 넣는 것을 기준으로 작성되었습니다. * 이 스크립트는 미네르바 스킨의 햄버거 메뉴 안에 * "게시판 / 버그/기능 개선 / 도구 / 도움말" 메뉴와 하위 메뉴를 추가합니다. */ ( function ( mw, $ ) { 'use strict'; // 미네르바 스킨이 아닐 경우 아무 것도 하지 않는다. if ( mw.config.get( 'skin' ) !== 'minerva' ) { return; } /* ----------------------------- * 1. 메뉴 설정 (질문에서 주신 구조 그대로) * ----------------------------- */ // 미네르바에서 사용할 아이콘 클래스는 // https://www.mediawiki.org/wiki/Topic:Vqy1kx6q4e0bzvyb 등에서 정리된 목록에 기반합니다. :contentReference[oaicite:5]{index=5} // 필요하면 iconClass 값을 수정하여 원하는 아이콘으로 교체하면 됩니다. var gaonMenuConfig = [ { // * icon=comments | display=게시판 label: '게시판', iconClass: 'mw-ui-icon-minerva-speechBubbles', children: [ // ** icon=pencil-alt | display=위키방 | link=https://bbs.gaonwiki.com | title=https://bbs.gaonwiki.com { label: '위키방', href: 'https://bbs.gaonwiki.com', title: 'https://bbs.gaonwiki.com', iconClass: 'mw-ui-icon-minerva-speechBubbles' }, // ** icon=copyright | display=저작권 처리 게시판 | link=https://bbs.gaonwiki.com/copyrights | title=https://bbs.gaonwiki.com/copyrights { label: '저작권 처리 게시판', href: 'https://bbs.gaonwiki.com/copyrights', title: 'https://bbs.gaonwiki.com/copyrights', iconClass: 'mw-ui-icon-minerva-speechBubbles' }, // ** icon=comments | display=자유게시판 | link=https://bbs.gaonwiki.com/free | title=https://bbs.gaonwiki.com/free { label: '자유게시판', href: 'https://bbs.gaonwiki.com/free', title: 'https://bbs.gaonwiki.com/free', iconClass: 'mw-ui-icon-minerva-speechBubbles' } ] }, { // * icon=exclamation | display=버그/기능 개선 label: '버그/기능 개선', iconClass: 'mw-ui-icon-minerva-die', // 경고/이슈 느낌의 주사위 아이콘 사용 예시 children: [ // ** icon=bullhorn | display=이슈 등록 | link=https://bbs.gaonwiki.com/issue | title=https://bbs.gaonwiki.com/issue { label: '이슈 등록', href: 'https://bbs.gaonwiki.com/issue', title: 'https://bbs.gaonwiki.com/issue', iconClass: 'mw-ui-icon-minerva-die' }, // ** icon=hands-helping | display=기능 구현 도움 | link=... | title=... { label: '기능 구현 도움', href: 'https://www.gaonwiki.com/w/%EA%B0%80%EC%98%A8_%EC%9C%84%ED%82%A4:%EA%B8%B0%EB%8A%A5_%EA%B5%AC%ED%98%84_%EB%B6%88%EA%B0%80-%EB%88%84%EA%B0%80_%ED%95%B4%EA%B2%B0%EC%B1%85%EC%9D%84_%EC%95%8C%EB%A0%A4%EC%A3%BC%EC%84%B8%EC%9A%94!', title: 'https://www.gaonwiki.com/w/가온_위키:기능_구현_불가-누가_해결책을_알려주세요!', iconClass: 'mw-ui-icon-wikimedia-edit-base20' }, // ** icon=bug | display=알려진 문제들 | link=... | title=... { label: '알려진 문제들', href: 'https://www.gaonwiki.com/w/%EA%B0%80%EC%98%A8_%EC%9C%84%ED%82%A4/%EC%95%8C%EB%A0%A4%EC%A7%84_%EB%AC%B8%EC%A0%9C%EB%93%A4', title: 'https://www.gaonwiki.com/w/가온_위키/알려진_문제들', iconClass: 'mw-ui-icon-wikimedia-history-base20' } ] }, { // * icon=gear | display=도구 label: '도구', iconClass: 'mw-ui-icon-minerva-settings', children: [ // ** icon=wrench | display=특수 문서 목록 | link=특수:특수문서 | title=특수:특수문서 { label: '특수 문서 목록', // mw.util.getUrl 을 사용하면 위키 내 링크를 환경에 맞게 자동으로 생성합니다. href: mw.util.getUrl( '특수:특수문서' ), title: '특수:특수문서', iconClass: 'mw-ui-icon-minerva-settings' }, // ** icon=upload | display=파일 올리기 { label: '파일 올리기', href: '#', // 상위 항목은 드롭다운용이므로 실제 링크는 서브 메뉴에 둡니다. title: '파일 올리기', iconClass: 'mw-ui-icon-minerva-download', children: [ // *** icon=cloud-upload-alt | display=(기존) 업로드 | link=특수:올리기 | title=특수:올리기 { label: '(기존) 업로드', href: mw.util.getUrl( '특수:올리기' ), title: '특수:올리기', iconClass: 'mw-ui-icon-minerva-download' }, // *** icon=file-upload | display=(신규) 업로드 마법사 | link=특수:UploadWizard | title=특수:UploadWizard { label: '(신규) 업로드 마법사', href: mw.util.getUrl( '특수:UploadWizard' ), title: '특수:UploadWizard', iconClass: 'mw-ui-icon-minerva-download' } ] }, // ** icon=flag | display=이슈 트래커 | link=https://bbs.gaonwiki.com/issue/ | title=... { label: '이슈 트래커', href: 'https://bbs.gaonwiki.com/issue/', title: 'https://bbs.gaonwiki.com/issue/', iconClass: 'mw-ui-icon-minerva-die' }, // ** icon=flask | display=가온 위키 베타 | link=https://beta.gaonwiki.com | title=... { label: '가온 위키 베타', href: 'https://beta.gaonwiki.com', title: 'https://beta.gaonwiki.com', iconClass: 'mw-ui-icon-minerva-mapPin' } ] }, { // * icon=book | display=도움말 label: '도움말', iconClass: 'mw-ui-icon-wikimedia-help-base20', // 도움말 느낌의 아이콘 children: [ // ** icon=spell-check | display=위키 문법 | link=도움말:위키_문법 | title=도움말:위키_문법 { label: '위키 문법', href: mw.util.getUrl( '도움말:위키_문법' ), title: '도움말:위키_문법', iconClass: 'mw-ui-icon-wikimedia-help-base20' }, // ** icon=book | display=설명서 | link=도움말:설명서 | title=도움말:설명서 { label: '설명서', href: mw.util.getUrl( '도움말:설명서' ), title: '도움말:설명서', iconClass: 'mw-ui-icon-wikimedia-help-base20' } ] } ]; /* ----------------------------- * 2. DOM 유틸리티 함수 * ----------------------------- */ /** * 하위 항목(2단계, 3단계)을 생성하고, 지정된 <ul> 안에 넣는 재귀 함수입니다. * * @param {jQuery} $ul 현재 레벨의 <ul> 요소(jQuery 객체) * @param {Object} item 메뉴 항목 정의 (label, href, title, iconClass, children 등) * @param {number} level 현재 레벨(2, 3 ...) */ function appendGaonMenuItem( $ul, item, level ) { // <li> 생성 var $li = $( '<li>' ) .addClass( 'gaon-menu-item' ) .addClass( 'gaon-menu-item-level' + level ); // 실제 링크가 없고 드롭다운 전용인 항목이면 href 를 '#' 으로 둡니다. var href = item.href || '#'; // <a> 생성 및 속성 설정 var $a = $( '<a>' ) .attr( 'href', href ) // title 이 지정되어 있으면 title 사용, 없으면 label 사용 .attr( 'title', item.title || item.label || '' ) // 미네르바 아이콘 스타일 적용 .addClass( 'mw-ui-icon mw-ui-icon-before' ); // 아이콘 클래스가 지정되어 있다면 추가 if ( item.iconClass ) { $a.addClass( item.iconClass ); } // 화면에 표시될 텍스트는 <span> 안에 넣습니다. var $span = $( '<span>' ).text( item.label || '' ); $a.append( $span ); $li.append( $a ); $ul.append( $li ); // children 이 있다면 하위 <ul> 을 하나 더 만들어 재귀적으로 추가합니다. if ( Array.isArray( item.children ) && item.children.length > 0 ) { var nextLevel = level + 1; var $subUl = $( '<ul>' ) .addClass( 'gaon-menu' ) .addClass( 'gaon-menu-level' + nextLevel ); item.children.forEach( function ( child ) { appendGaonMenuItem( $subUl, child, nextLevel ); } ); // 여기서는 부모 <li> 아래에 중첩 <ul> 을 넣어 구조를 명확히 합니다. $li.append( $subUl ); } } /** * 상위 그룹(게시판, 버그/기능 개선 등)을 생성합니다. * 각 그룹은 level1 <ul> 안에 헤더 <li> 와 하위 level2 <ul> 을 가지게 됩니다. * * @returns {jQuery} 햄버거 메뉴에 삽입할 상위 DOM 묶음(jQuery 객체) */ function buildGaonMenu() { // 루트 컨테이너 역할을 할 <div> 를 하나 만든 뒤, // 그 안에 여러 개의 <ul class="gaon-menu gaon-menu-level1"> 을 쌓습니다. var $container = $( '<div>' ).addClass( 'gaon-menu-container' ); gaonMenuConfig.forEach( function ( group, index ) { // 각 그룹마다 level1 <ul> 하나씩 생성 var $level1 = $( '<ul>' ) .addClass( 'gaon-menu' ) .addClass( 'gaon-menu-level1' ) .attr( 'data-gaon-group-index', index ); // 헤더(클릭 시 하위 level2 열고 닫는 부분) <li> var $headerLi = $( '<li>' ) .addClass( 'gaon-menu-header' ); var $headerA = $( '<a>' ) // 상위 그룹은 토글 전용이므로 href="#" 로 두고 기본 동작을 막습니다. .attr( 'href', '#' ) .attr( 'title', group.label || '' ) .addClass( 'mw-ui-icon mw-ui-icon-before' ); if ( group.iconClass ) { $headerA.addClass( group.iconClass ); } $headerA.append( $( '<span>' ).text( group.label || '' ) ); $headerLi.append( $headerA ); $level1.append( $headerLi ); // 하위 메뉴(level2) 생성 if ( Array.isArray( group.children ) && group.children.length > 0 ) { var $level2 = $( '<ul>' ) .addClass( 'gaon-menu' ) .addClass( 'gaon-menu-level2' ); group.children.forEach( function ( item ) { appendGaonMenuItem( $level2, item, 2 ); } ); $level1.append( $level2 ); } $container.append( $level1 ); } ); // 컨테이너 안의 자식 요소들만 반환합니다. return $container.children(); } /* ----------------------------- * 3. 메뉴를 미네르바 햄버거 메뉴 안에 삽입 * ----------------------------- */ /** * 실제로 DOM 을 찾아서, 기본 메뉴 아래에 가온 메뉴를 삽입하는 함수입니다. */ function insertGaonMenuIntoMinerva() { // 미네르바 햄버거 메뉴에서, 기존 최상위 <ul> 을 찾습니다. // Qiita 예제에서는 '.menu ul:first' 를 기준으로 사용합니다. :contentReference[oaicite:6]{index=6} var $firstUl = $( '.menu ul:first' ); if ( !$firstUl.length ) { return; } // 중복 삽입 방지: 이미 가온 메뉴를 추가했으면 다시 하지 않습니다. if ( $firstUl.data( 'gaonMenuInjected' ) ) { return; } $firstUl.data( 'gaonMenuInjected', true ); // 우리의 메뉴 DOM 을 생성합니다. var $gaonMenuNodes = buildGaonMenu(); // 기존 첫 번째 <ul> 바로 뒤에 삽입합니다. $firstUl.after( $gaonMenuNodes ); // 하위 레벨 메뉴(level2, level3 …)는 기본적으로 숨겨 둡니다. $( '.gaon-menu-level2, .gaon-menu-level3' ).hide(); // 상위 그룹(게시판 / 버그/기능 개선 / 도구 / 도움말) 클릭 시, // 해당 그룹 내부의 level2 <ul> 을 토글합니다. $( '.gaon-menu-header > a' ).on( 'click', function ( e ) { e.preventDefault(); var $header = $( this ); var $level1 = $header.closest( '.gaon-menu-level1' ); var $level2 = $level1.children( '.gaon-menu-level2' ); $level2.slideToggle( 200 ); } ); // "파일 올리기" 같은 중간 단계에 children 이 있는 항목은 // 자신의 하위 level3 <ul> 을 토글합니다. $( '.gaon-menu-item-level2 > a' ).each( function () { var $a = $( this ); var $li = $a.closest( 'li' ); var $subUl = $li.children( '.gaon-menu-level3' ); if ( $subUl.length ) { // children 이 있는 항목은 토글 버튼 역할을 하도록 클릭 핸들러를 붙입니다. $a.on( 'click', function ( e ) { e.preventDefault(); $subUl.slideToggle( 200 ); } ); } } ); } /* ----------------------------- * 4. 메뉴 DOM 생성 시점 기다리기 * ----------------------------- */ // 미네르바 메뉴 HTML 은 JS 로 동적으로 만들어지는 경우가 있기 때문에, // DOM 이 준비될 때까지 주기적으로 검사하는 방식(Qiita 예제와 동일한 방식)을 사용합니다. :contentReference[oaicite:7]{index=7} var maxAttempts = 50; // 최대 50번(약 5초)까지 시도 var attemptCount = 0; function waitForMinervaMenu() { var $firstUl = $( '.menu ul:first' ); if ( $firstUl.length ) { // 메뉴를 찾았으면 바로 삽입 시도 insertGaonMenuIntoMinerva(); } else if ( attemptCount < maxAttempts ) { attemptCount += 1; setTimeout( waitForMinervaMenu, 100 ); } } // 문서 로드 이후에 검사 시작 $( waitForMinervaMenu ); }( mediaWiki, jQuery ) ); 미디어위키:Minerva.js 문서로 돌아갑니다.