최근 바뀜
도구
업로드
도움말
길라잡이
위키 문법
특수 문서
문의·신고
디스코드
IP 사용자
216.73.216.63
로그인
미디어위키:Common.js 문서 원본 보기
←
미디어위키:Common.js
편집
토론
역사
새로고침
주시
역링크
정보
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다:
사용자
.
이 문서는 이 위키의 소프트웨어 인터페이스에 쓰이는 문서로, 부정 행위를 막기 위해 보호되어 있습니다. 모든 위키에 대한 번역을 추가하거나 바꾸려면 미디어위키 지역화 프로젝트인
translatewiki.net
에 참여하시기 바랍니다.
모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다.
문서의 원본을 보거나 복사할 수 있습니다.
/** * 이 스크립트는 위키백과 전체에 적용됩니다. 고칠 때는 주의해주세요. * [[위키백과:위키프로젝트 시스템]] 참고 * * 스크립트를 넣을 때는 충분한 설명, 출처를 넣어주세요! 이후 관리가 어려워집니다. **//* 이 자바스크립트 설정은 리버티 스킨을 사용하는 사용자에게 적용됩니다 */ 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'], function () { $( function () { var action = mw.config.get( 'wgAction' ); if ( action !== 'edit' && action !== 'submit' ) { return; } // 원본 편집기(위키텍스트 편집기)가 아닌 경우(시각편집기 등)는 건너뜀 var $textbox = $( '#wpTextbox1' ); if ( !$textbox.length ) { return; } 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 $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 $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 ); // 미리보기 토글 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 ); // 저장 버튼 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. 편집 영역과 미리보기 영역 레이아웃 구성 * ================================ */ // textarea 래퍼 만들기 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 ); // 실시간 미리보기 확장기 컨테이너 이동 시도 함수 var previewInitialized = false; function initRealtimePreviewPane () { if ( previewInitialized ) { return; } // realtimepreview 확장이 만든 컨테이너를 찾아서 옮김 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', '각주' ); /* ================================ * 4. 덜 중요한 그룹 숨기기 / 정리 (옵션) * ================================ */ // 필요 없으면 주석 처리 // 고급 탭의 '찾아 바꾸기' 아이콘 그룹은 "더 보기" 느낌이라 오른쪽으로 밀기 $toolbar.find( '.section-advanced .group-search' ) .addClass( 'mw-edit-toolbar-group-secondary' ); } ); } );
미디어위키:Common.js
문서로 돌아갑니다.