최근 바뀜
도구
업로드
도움말
길라잡이
위키 문법
특수 문서
문의·신고
디스코드
IP 사용자
216.73.216.63
로그인
미디어위키:Gadget-newtoolbar.js 문서 원본 보기
←
미디어위키:Gadget-newtoolbar.js
편집
토론
역사
새로고침
주시
역링크
정보
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다:
사용자
.
이 문서는 이 위키의 소프트웨어 인터페이스에 쓰이는 문서로, 부정 행위를 막기 위해 보호되어 있습니다. 모든 위키에 대한 번역을 추가하거나 바꾸려면 미디어위키 지역화 프로젝트인
translatewiki.net
에 참여하시기 바랍니다.
모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다.
문서의 원본을 보거나 복사할 수 있습니다.
/* MediaWiki:Gadget-NewToolbar.js */ /* MediaWiki:Gadget-NewToolbar.js */ ( function ( mw, $ ) { 'use strict'; // ---- 찾기/바꾸기 상태 ---- var findState = { query: '', lastIndex: 0 }; /** * 선택 영역을 앞뒤 텍스트로 감싸기 (간단 버전) */ function surroundSelection( textarea, before, after ) { var $ta = $( textarea ); var start = textarea.selectionStart; var end = textarea.selectionEnd; if ( start == null || end == null ) { $ta.text( $ta.text() + before + after ); return; } var text = $ta.val(); var selected = text.slice( start, end ); var newText = text.slice( 0, start ) + before + selected + after + text.slice( end ); $ta.val( newText ); var newStart = start + before.length; var newEnd = newStart + selected.length; textarea.selectionStart = newStart; textarea.selectionEnd = newEnd; $ta.trigger( 'change' ); } function insertAtCursor( textarea, snippet ) { var $ta = $( textarea ); var start = textarea.selectionStart; var end = textarea.selectionEnd; var text = $ta.val(); if ( start == null || end == null ) { $ta.val( text + snippet ); return; } var newText = text.slice( 0, start ) + snippet + text.slice( end ); $ta.val( newText ); var pos = start + snippet.length; textarea.selectionStart = textarea.selectionEnd = pos; $ta.trigger( 'change' ); } function createButton( opts ) { var $btn = $( '<button>' ) .attr( 'type', 'button' ) .addClass( 'ntb-button' ) .append( $( '<span>' ) .addClass( 'ntb-icon ' + ( opts.icon || '' ) ) ) .append( $( '<span>' ) .addClass( 'ntb-label' ) .text( opts.label ) ) .on( 'click', function () { var textarea = document.getElementById( 'wpTextbox1' ); if ( typeof opts.onClick === 'function' ) { opts.onClick( textarea || null ); } if ( textarea ) { textarea.focus(); } } ); if ( opts.title ) { $btn.attr( 'title', opts.title ); } return $btn; } // ---- 찾기/바꾸기 패널 만들기 ---- function buildFindReplacePanel() { if ( $( '#ntb-find-panel' ).length ) { return $( '#ntb-find-panel' ); } var $panel = $( '<div>' ) .attr( 'id', 'ntb-find-panel' ) .addClass( 'ntb-find-panel' ); var $rowFind = $( '<div>' ).addClass( 'ntb-find-row' ); var $rowReplace = $( '<div>' ).addClass( 'ntb-find-row' ); var $rowButtons = $( '<div>' ).addClass( 'ntb-find-row ntb-find-row-buttons' ); var $inputFind = $( '<input>' ) .attr( { type: 'text', placeholder: '찾을 내용' } ) .addClass( 'ntb-input ntb-input-find' ); var $inputReplace = $( '<input>' ) .attr( { type: 'text', placeholder: '바꿀 내용' } ) .addClass( 'ntb-input ntb-input-replace' ); var $status = $( '<div>' ) .addClass( 'ntb-find-status' ) .text( '' ); var $btnNext = $( '<button>' ) .attr( 'type', 'button' ) .addClass( 'ntb-button ntb-button-small' ) .text( '다음 찾기' ); var $btnReplace = $( '<button>' ) .attr( 'type', 'button' ) .addClass( 'ntb-button ntb-button-small' ) .text( '바꾸기' ); var $btnReplaceAll = $( '<button>' ) .attr( 'type', 'button' ) .addClass( 'ntb-button ntb-button-small' ) .text( '모두 바꾸기' ); var $btnClose = $( '<button>' ) .attr( 'type', 'button' ) .addClass( 'ntb-button ntb-button-small ntb-button-quiet' ) .text( '닫기' ); $rowFind.append( $( '<label>' ).text( '찾기: ' ), $inputFind ); $rowReplace.append( $( '<label>' ).text( '바꾸기: ' ), $inputReplace ); $rowButtons.append( $btnNext, $btnReplace, $btnReplaceAll, $btnClose, $status ); $panel.append( $rowFind, $rowReplace, $rowButtons ); // ---- 동작 함수들 ---- function findNext( wrap ) { var textarea = document.getElementById( 'wpTextbox1' ); if ( !textarea ) { return; } var query = $inputFind.val(); if ( !query ) { $status.text( '찾을 내용을 입력하세요.' ); return; } var text = textarea.value; var startPos; // 새 검색어면 처음부터 if ( findState.query !== query ) { findState.query = query; findState.lastIndex = textarea.selectionEnd || 0; } startPos = textarea.selectionEnd || findState.lastIndex; var idx = text.indexOf( query, startPos ); // 못 찾으면, wrap이면 처음부터 다시 if ( idx === -1 && wrap !== false ) { idx = text.indexOf( query, 0 ); } if ( idx === -1 ) { $status.text( '더 이상 찾을 수 없습니다.' ); return; } textarea.selectionStart = idx; textarea.selectionEnd = idx + query.length; findState.lastIndex = idx + query.length; textarea.focus(); $status.text( '' ); } function doReplaceOnce() { var textarea = document.getElementById( 'wpTextbox1' ); if ( !textarea ) { return; } var query = $inputFind.val(); var replacement = $inputReplace.val() || ''; if ( !query ) { $status.text( '찾을 내용을 입력하세요.' ); return; } var text = textarea.value; var selStart = textarea.selectionStart; var selEnd = textarea.selectionEnd; var current = text.slice( selStart, selEnd ); // 현재 선택이 검색어와 다르면 먼저 찾기 if ( current !== query ) { findNext( false ); // 다시 selection 갱신 text = textarea.value; selStart = textarea.selectionStart; selEnd = textarea.selectionEnd; current = text.slice( selStart, selEnd ); if ( current !== query ) { $status.text( '대상이 선택되지 않았습니다.' ); return; } } var newText = text.slice( 0, selStart ) + replacement + text.slice( selEnd ); textarea.value = newText; var newPos = selStart + replacement.length; textarea.selectionStart = textarea.selectionEnd = newPos; findState.lastIndex = newPos; $( textarea ).trigger( 'change' ); $status.text( '1개 바꿈.' ); } function doReplaceAll() { var textarea = document.getElementById( 'wpTextbox1' ); if ( !textarea ) { return; } var query = $inputFind.val(); var replacement = $inputReplace.val() || ''; if ( !query ) { $status.text( '찾을 내용을 입력하세요.' ); return; } var text = textarea.value; var count = 0; var idx = text.indexOf( query ); if ( idx === -1 ) { $status.text( '일치하는 내용이 없습니다.' ); return; } while ( idx !== -1 ) { text = text.slice( 0, idx ) + replacement + text.slice( idx + query.length ); count++; idx = text.indexOf( query, idx + replacement.length ); } textarea.value = text; textarea.selectionStart = textarea.selectionEnd = 0; findState.lastIndex = 0; $( textarea ).trigger( 'change' ); $status.text( count + '개 바꿈.' ); } // 이벤트 연결 $btnNext.on( 'click', function () { findNext( true ); } ); $inputFind.on( 'keydown', function ( e ) { if ( e.key === 'Enter' ) { e.preventDefault(); findNext( true ); } } ); $btnReplace.on( 'click', doReplaceOnce ); $btnReplaceAll.on( 'click', doReplaceAll ); $btnClose.on( 'click', function () { $panel.hide(); } ); return $panel; } ( function ( mw, $ ) { 'use strict'; /** * 선택 영역을 앞뒤 텍스트로 감싸기 (간단 버전) */ function surroundSelection( textarea, before, after ) { var $ta = $( textarea ); var start = textarea.selectionStart; var end = textarea.selectionEnd; if ( start == null || end == null ) { // 구형 브라우저 fallback (거의 안 씀) $ta.text( $ta.text() + before + after ); return; } var text = $ta.val(); var selected = text.slice( start, end ); var newText = text.slice( 0, start ) + before + selected + after + text.slice( end ); $ta.val( newText ); // 커서/선택 다시 잡기 var newStart = start + before.length; var newEnd = newStart + selected.length; textarea.selectionStart = newStart; textarea.selectionEnd = newEnd; $ta.trigger( 'change' ); } /** * 현재 커서 위치에 텍스트 삽입 */ function insertAtCursor( textarea, snippet ) { var $ta = $( textarea ); var start = textarea.selectionStart; var end = textarea.selectionEnd; var text = $ta.val(); if ( start == null || end == null ) { $ta.val( text + snippet ); return; } var newText = text.slice( 0, start ) + snippet + text.slice( end ); $ta.val( newText ); var pos = start + snippet.length; textarea.selectionStart = textarea.selectionEnd = pos; $ta.trigger( 'change' ); } /** * 버튼 생성 헬퍼 */ function createButton( opts ) { var $btn = $( '<button>' ) .attr( 'type', 'button' ) .addClass( 'ntb-button' ) .append( $( '<span>' ) .addClass( 'ntb-icon ' + ( opts.icon || '' ) ) ) .append( $( '<span>' ) .addClass( 'ntb-label' ) .text( opts.label ) ) .on( 'click', function () { var textarea = document.getElementById( 'wpTextbox1' ); if ( textarea && typeof opts.onClick === 'function' ) { opts.onClick( textarea ); textarea.focus(); } } ); if ( opts.title ) { $btn.attr( 'title', opts.title ); } return $btn; } /** * 새 툴바 초기화 */ function initNewToolbar( $textarea ) { var $oldToolbar = $( '#wikiEditor-ui-toolbar' ); // wikiEditor 없는 페이지 or 이미 생성된 경우 if ( !$oldToolbar.length || $( '#ntb-toolbar' ).length ) { return; } var $toolbar = $( '<div>' ) .attr( 'id', 'ntb-toolbar' ) .addClass( 'ntb-toolbar' ); // --- 그룹 1: 텍스트 스타일 --- var $groupText = $( '<div>' ) .addClass( 'ntb-group ntb-group-text' ) .append( $( '<span>' ).addClass( 'ntb-group-label' ).text( '텍스트' ) ); $groupText.append( createButton( { icon: 'ntb-icon-bold', label: '굵게', title: "'''굵게'''", onClick: function ( ta ) { surroundSelection( ta, "'''", "'''" ); } } ), createButton( { icon: 'ntb-icon-italic', label: '기울임', title: "''기울임''", onClick: function ( ta ) { surroundSelection( ta, "''", "''" ); } } ) ); // --- 그룹 2: 문단/목록 --- var $groupBlock = $( '<div>' ) .addClass( 'ntb-group ntb-group-block' ) .append( $( '<span>' ).addClass( 'ntb-group-label' ).text( '문단' ) ); $groupBlock.append( createButton( { icon: 'ntb-icon-heading', label: '제목', title: '== 문단 제목 ==', onClick: function ( ta ) { insertAtCursor( ta, '\n== 새 문단 제목 ==\n' ); } } ), createButton( { icon: 'ntb-icon-ul', label: '글머리 목록', title: '* 글머리', onClick: function ( ta ) { insertAtCursor( ta, '\n* 항목\n' ); } } ), createButton( { icon: 'ntb-icon-ol', label: '번호 목록', title: '# 번호 항목', onClick: function ( ta ) { insertAtCursor( ta, '\n# 항목\n' ); } } ) ); // --- 그룹 3: 삽입 --- var $groupInsert = $( '<div>' ) .addClass( 'ntb-group ntb-group-insert' ) .append( $( '<span>' ).addClass( 'ntb-group-label' ).text( '삽입' ) ); $groupInsert.append( createButton( { icon: 'ntb-icon-link', label: '링크', title: '[[문서 링크]] 또는 [https://example.com 외부 링크]', onClick: function ( ta ) { insertAtCursor( ta, '[[링크 대상|표시 텍스트]]' ); } } ), createButton( { icon: 'ntb-icon-file', label: '파일', title: '[[파일:Example.png|thumb|캡션]]', onClick: function ( ta ) { insertAtCursor( ta, '[[파일:Example.png|thumb|캡션]]' ); } } ), createButton( { icon: 'ntb-icon-ref', label: '각주', title: '<ref>내용</ref>', onClick: function ( ta ) { surroundSelection( ta, '<ref>', '</ref>' ); } } ) ); // --- 그룹 4: 기타 도구 --- var $groupTools = $( '<div>' ) .addClass( 'ntb-group ntb-group-tools' ) .append( $( '<span>' ).addClass( 'ntb-group-label' ).text( '도구' ) ); $groupTools.append( createButton( { icon: 'ntb-icon-search', label: '찾기/바꾸기', title: '문서 내용 찾기 및 바꾸기', onClick: function () { var $panel = buildFindReplacePanel(); // 토글 if ( $panel.is( ':visible' ) ) { $panel.hide(); } else { $panel.show(); // 처음 열 때는 찾기 입력에 포커스 $panel.find( '.ntb-input-find' ).focus().select(); } } } ) ); $toolbar .append( $groupText ) .append( $groupBlock ) .append( $groupInsert ) .append( $groupTools ); // 기존 툴바 숨기고, 새 툴바 삽입 $oldToolbar.hide().before( $toolbar ); // 찾기/바꾸기 패널은 툴바 바로 아래에 붙이되 처음엔 숨김 var $panel = buildFindReplacePanel().hide(); $toolbar.after( $panel ); } $toolbar .append( $groupText ) .append( $groupBlock ) .append( $groupInsert ) .append( $groupTools ); // 기존 툴바 숨기고, 새 툴바 삽입 $oldToolbar.hide().before( $toolbar ); } ); // wikiEditor 준비되면 호출 mw.hook( 'wikiEditor.toolbarReady' ).add( initNewToolbar ); }( mediaWiki, jQuery ) );
미디어위키:Gadget-newtoolbar.js
문서로 돌아갑니다.