사용자:하늘/EditTools.js

< 사용자:하늘
하늘 (토론 | 기여)님의 2022년 7월 26일 (화) 23:00 판

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.

  • 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
  • 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
  • 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
  • 오페라: Ctrl-F5를 입력.
/**
 * 원본 [[mw:User:Alex Smotrov/edittools.js]], 수정본 리브레 위키 이용자 Cerulean, Utolee90
 * 
 * Configuration (to be set from [[Special:MyPage/common.js]]):
 *   window.charinsertCustom – Object. Merged into the default charinsert list. For example, setting
 *       this to { Symbols: '‽' } will add the interrobang to the end of the Symbols section.
 *   window.editToolsRecall – Boolean. Set true to create a recall switch.
 *   window.charinsertDontMove – Boolean. Set true to leave the box in its default position, rather
 *       than moving it above the edit summary.
 *   window.updateEditTools() – Function. Call after updating window.charinsertCustom to regenerate the
 *       EditTools window.
 * 
 *	global jQuery, mw, charinsertCustom
 *	window.updateEditTools = function () {};
*/

$(".mw-editTools > #mw-edittools-charinsert").remove(); //기존 edittools 제거
mw.loader.load('//librewiki.net/index.php?title=User:하늘/EditTools.css&action=raw&ctype=text/css', 'text/css');

var editTools;
//editTools.charinsert.로마자  editTools.charinsert.그리스어처럼 다른 js 코드에서 편집 도구들을 추가할 수 있습니다.

$(document).ready(function ($) {
	var $currentFocused;

	function getSelectedSection() {
		var selectedSection = mw.storage.get(editTools.storageKey) || mw.storage.session.get(editTools.storageKey);
		return selectedSection;
	}

	function saveSelectedSection(newIndex) {
		mw.storage.set(editTools.storageKey, newIndex) || mw.storage.session.set(editTools.storageKey, newIndex);
	}

	editTools = {
		// 각 심볼은 '카테고리 이름' : '문자셋 이름', 형태로 작성합니다. 자바스크립트 오브젝트 형식으로 처리하므로 반드시 카테고리 이름, 문자셋 이름 앞뒤로 따옴표를 추가하고, 맨 뒤에는 반점(,)으로 구분하셔야 합니다.
		// 카테고리를 구별할 때에는 문자셋 이름 부분에 (카테고리명): 기호를 추가합니다.
		// 심볼을 구분할 때에는 띄어쓰기를 이용하며, 같은 심볼 안에서 공백을 입력할 때에는 온점 .을 이용합니다. 단 =기호 이후에는 .을 입력하면 온점이 입력되는 현상이 있어 공백을 삽입할 때 _기호를 사용합니다.
		// 버튼 형태로 심볼을 분리할 때에는 _기호를 사용하면 됩니다. 
		// + 기호를 입력하면 심볼을 입력할 때 커서가 위치하는 지점을 지정할 수 있습니다.
		// 줄넘김을 표현할 때에는 \n을 삽입합니다. 반드시 뒤에 공백을 띄워줘야 제대로 작동합니다. 
		// 정규표현식으로 처리하므로 중괄호 여는 기호 {나 대괄호 여는 기호 [를 입력하기 위해서는 앞에 \ 기호를 써서 \{, \[라고 사용해야 합니다. 닫을 때에는 알아서 처리하므로 \ 기호를 삽입할 필요는 없습니다. 
		// 예시 : 다른 뜻 틀 삽입 => \{\{다른.뜻|+}}
		// 기호 앞에 ␥ (U+2425 SYMBOL FOR DELETE FORM TWO)이 붙어있으면 메인 이름공간(0번)에서는 표시되지 않습니다.

		// 이 오브젝트 안에 '카테고리 이름' : '문자셋 이름' 형태로 작성하면 됩니다.
		charinsert: {
			'기본': '괄호: (+) [+] {+} 〔+〕 〈+〉 【+】 ' +
				'위키텍스트: {\{크기||+}} [\[+]] [\[#+]] {\{+}} <!--+--> /*+*/ [\[분류:+]] [\[분류:+|_]] [\[파일:+]] &nbsp; <del>+</del> <br/> <hr/> ---- {\{-}} {\{각주}} <ref>+</ref> <ref.name="+"_/> {\{URL|+}} __TOC__ <span.id="+"/> ' +
				'틀: {\{색||+}} {\{lang||+}} {\{llang||+}} {\{=|+}} {\{|+}} {\{PAGENAME}} {\{FULLPAGENAME}} {\{삭제|+}} {\{특정판.삭제|+}} {\{유튜브|+}} {\{퍼온문서|문서=+|판=_|일부=_}} {\{번역된.문서|en|+||}} {\{string|+}} {\{배지|+}} {\{인용문|+}}  {\{PD-author}}',
			'틀 작성': '{\{\{+}}} {\{\{+|}}} <onlyinclude>+</onlyinclude> <includeonly>+</includeonly> <noinclude>+</noinclude> {\{풀기:+}} <templatestyles.src="+/styles.css"/>  파서함수: {\{#expr:+}} {\{#if:+}} {\{#ifeq:+}} {\{#iferror:+}} {\{#ifexist:+}} {\{#switch:+}} {\{#time:+}} {\{#titlepart:+}} {\{#invoke:+|}}',
			'코드': '<p>+</p> <div>+</div> <div.style="">+</div> <div.class="".style="">+</div> <span>+</span> <span.style="">+</span> <span.class="".style="">+</span> <code>+</code> <code><nowiki>+</nowiki></code> <pre>+</pre> <syntaxhighlight.lang="console">\n+\n</syntaxhighlight>',
			'파일 저작권': '{\{PD-self}} {\{PD-old}} {\{PD-author}} {\{CC-BY-3.0}} {\{CC-BY-SA-3.0}}',
			'수학·논리학': '− × ÷ ⋅ ° ∗ ∘ ± ∓ ≤ ≥ ≠ ≡ ≅ ≜ ≝ ≐ ≃ ≈ ⊕ ⊗ ⇐ ⇔ ⇒ ∞ ← ↔ → ≪ ≫ ∝ √ ∤ ≀ ◅ ▻ ⋉ ⋊ ⋈ ∴ ∵ ↦ ¬ ∧ ∨ ⊻ ∀ ∃ ∈ ∉ ∋ ⊆ ⊈ ⊊ ⊂ ⊄ ⊇ ⊉ ⊋ ⊃ ⊅ ∪ ∩ ∑ ∏ ∐ ′ ∫ ∬ ∭ ∮ ∇ ∂ ∆ ∅ ℂ ℍ ℕ ℙ ℚ ℝ ℤ ℵ ⌊ ⌋ ⌈ ⌉ ⊤ ⊥ ⊢ ⊣ ⊧ □ ∠ ⟨ ⟩ <math>+</math> {\{수학|+}} {\{수학.변수|+}} {\{분수|+|}} {\{수직분수|+|}}'
		},
		// 문자열 나누는 기호
		charinsertDivider: "\240",

		storageKey: 'edittoolscharsubset',

		createEditTools: function (placeholder) {
			var sel, id;
			var box = document.createElement('div');
			var prevSubset = 0, curSubset = 0;
			box.id = 'editpage-specialchars';
			box.className = "nopopups";
			// 문자 선택시 나타나는 제목 이름
			box.title = '편집 창에 입력할 글자 혹은 태그를 클릭하세요';

			// append user-defined sets
			if (window.charinsertCustom) {
				for (id in charinsertCustom) {
					if (!editTools.charinsert[id]) {
						editTools.charinsert[id] = '';
					}
				}
			}

			// 문자셋 드랍다운 메뉴를 만듭니다.
			sel = document.createElement('select');
			for (id in editTools.charinsert) {
				sel.options[sel.options.length] = new Option(id, id);
			}
			sel.selectedIndex = 0;
			sel.style.marginRight = '.3em';
			// 입력상자 타이틀
			sel.title = 'Choose character subset';
			sel.onchange = sel.onkeyup = selectSubset;
			box.appendChild(sel);

			// create "recall" switch
			if (window.editToolsRecall) {
				var recall = document.createElement('span');
				recall.appendChild(document.createTextNode('↕')); // ↔
				recall.onclick = function () {
					sel.selectedIndex = prevSubset;
					selectSubset();
				};
				recall.style.cssFloat = 'left';
				recall.style.marginRight = '5px';
				recall.style.cursor = 'pointer';
				box.appendChild(recall);
			}

			if (getSelectedSection()) {
				sel.selectedIndex = getSelectedSection();
			}

			placeholder.parentNode.replaceChild(box, placeholder);
			selectSubset();
			return;

			function selectSubset() {
				// remember previous (for "recall" button)
				prevSubset = curSubset;
				curSubset = sel.selectedIndex;
				//save into web storage for persistence
				saveSelectedSection(curSubset);

				//hide other subsets
				var pp = box.getElementsByTagName('p');
				for (var i = 0; i < pp.length; i++) {
					pp[i].style.display = 'none';
				}
				//show/create current subset
				var id = sel.options[curSubset].value;
				var p = document.getElementById(id);
				if (!p) {
					p = document.createElement('p');
					p.className = 'nowraplinks';
					p.id = id;
					if (id == 'Arabic' || id == 'Hebrew') {
						p.style.fontSize = '120%';
						p.dir = 'rtl';
					}
					var tokens = editTools.charinsert[id];
					if (window.charinsertCustom && charinsertCustom[id]) {
						if (tokens.length > 0) {
							tokens += ' ';
						}
						tokens += charinsertCustom[id];
					}
					editTools.createTokens(p, tokens);
					box.appendChild(p);
				}
				p.style.display = 'inline';
			}
		},

		createTokens: function (paragraph, str) {
			var tokens = str.split(' '), token, i, n;
			for (i = 0; i < tokens.length; i++) {
				token = tokens[i];
				n = token.indexOf('+');
				if (token.charAt(0) === '␥') {
					if (token.length > 1 && mw.config.get('wgNamespaceNumber') === 0) {
						continue;
					} else {
						token = token.substring(1);
					}
				}
				if (token === '' || token === '_') {
					addText(editTools.charinsertDivider + ' ');
				} else if (token === '\n') {
					paragraph.appendChild(document.createElement('br'));
				} else if (token === '___') {
					paragraph.appendChild(document.createElement('hr'));
				} else if (token.charAt(token.length - 1) === ':') { // : at the end means just text
					addBold(token);
				} else if (n === 0) { // +<tag>  ->   <tag>+</tag>
					addLink(token.substring(1), '</' + token.substring(2), token.substring(1));
				} else if (n > 0) { // <tag>+</tag>
					addLink(token.substring(0, n), token.substring(n + 1));
				} else if (token.length > 2 && token.charCodeAt(0) > 127) { // a string of insertable characters
					for (var j = 0; j < token.length; j++) {
						addLink(token.charAt(j), '');
					}
				} else {
					addLink(token, '');
				}
			}
			return;

			function addLink(tagOpen, tagClose, name) {
				var handler;
				var dle = tagOpen.indexOf('\x10');
				var a = document.createElement('a');

				if (dle > 0) {
					var path = tagOpen.substring(dle + 1).split('.');
					tagOpen = tagOpen.substring(0, dle);
					handler = window;
					for (var i = 0; i < path.length; i++) {
						handler = handler[path[i]];
					}
					$(a).on('click', handler);
				} else {
					tagOpen = tagOpen.replace(/\./g, ' ');
					tagClose = tagClose ? tagClose.replace(/_/g, ' ') : '';
					$(a).on('click', {
						tagOpen: tagOpen,
						sampleText: '',
						tagClose: tagClose
					}, insertTags);
				}

				name = name || tagOpen + tagClose;
				name = name.replace(/\\n/g, '');
				a.appendChild(document.createTextNode(name));
				a.href = '';
				paragraph.appendChild(a);
				addText(' ');
			}

			function addBold(text) {
				var b = document.createElement('b');
				b.appendChild(document.createTextNode(text.replace(/_/g, ' ')));
				paragraph.appendChild(b);
				addText(' ');
			}
			function addText(txt) {
				paragraph.appendChild(document.createTextNode(txt));
			}
			function insertTags(e) {
				e.preventDefault();
				if ($currentFocused && $currentFocused.length && !$currentFocused.prop('readonly')) {
					$currentFocused.textSelection(
						'encapsulateSelection', {
						pre: e.data.tagOpen,
						peri: e.data.sampleText,
						post: e.data.tagClose
					}
					);
				}
			}
		},

		setup: function () {
			var placeholder;
			if ($('#editpage-specialchars').length) {
				placeholder = $('#editpage-specialchars')[0];
			} else {
				placeholder = $('<div id="editpage-specialchars"> </div>').prependTo('.mw-editTools')[0];
			}
			if (!placeholder) {
				return;
			}
			if (!window.charinsertDontMove) {
				$('.editOptions').before(placeholder);
			}
			// Find the element that is focused
			$currentFocused = $('#wpTextbox1');
			// Apply to dynamically created textboxes as well as normal ones
			$(document).on('focus', 'textarea, input:text', function () {
				$currentFocused = $(this);
			});

			// Used to determine where to insert tags
			editTools.createEditTools(placeholder);
			window.updateEditTools = function () {
				editTools.createEditTools($('#editpage-specialchars')[0]);
			};
			
			document.querySelector('#editpage-specialchars').style.borderColor = window.getComputedStyle(document.querySelector('.wikiEditor-ui-view')).borderRightColor
		}
	}; // end editTools

	editTools.setup();
});