개요
그동안 블로그를 운영하며 별 고민 없이 콘텐츠를 무단으로 복사할 수 없도록 티스토리에서 제공하는 플러그인을 사용하여 마우스의 사용을 막아 놓았습니다.
하지만 가만히 생각해보니 제 블로그에 기록해 놓은 많은 코드 부분(이하 코드 블록)의 경우 사용하기 위해서는 Copy & Paste 작업이 필요한 것을 깨닫게 되었습니다.
최근 이를 위하여 코드블록에 대해서 마우스를 이용하여 선택을 할 수 있도록 변경하였습니다.
이번에는 여기에 더하여 코드블록의 오른쪽 상단에 복사를 할 수 있는 버튼을 추가하여 사용자가 직접 드래그 등의 추가 조작 없이 편리하게 해당 콘텐츠를 이용할 수 있도록 하는 기능을 추가하였습니다.
이번 포스트에서는 티스토리의 스킨을 편집하여 코드블록에 복사 버튼을 추가한 내용을 정리하겠습니다.
결과물은 다음 링크에서 확인할 수 있습니다. (또한 본 포스트에 소스코드 항목에 마우스를 가져가면 결과물을 확인할 수 있습니다.)
코드 부분에 마우스를 가져가면 오른쪽에 버튼이 표시되고 해당 버튼을 누르면 코드의 내용이 클립보드로 복사됩니다.
※ JavaScript 를 전문적으로 다루는 일이 없기 때문에 해당 코드에 대한 설명이 부족하거나 틀릴 수 있습니다. 혹시 설명에 오류가 있다면 알려주시면 수정하도록 하겠습니다.
작업내용
작업환경 구축
블로그에 바로 작업을 할 정도록 JavaScript 에 숙달하지 못하기 때문에 StackBlitz에서 작업후, 시험을 거쳐 script
및 css
파일을 블로그에 적용하였습니다.
StackBlitz에 접속하여 JavaScript 워크스페이스를 생성합니다.
생략
HTML 파일을 만듭니다.
수정해야 하는 파일은 index.js 파일입니다. 하지만 우리가 하고자 하는 작업은 JavaScript로 HTML내부의 DOM을 조작하고자 하는 것이므로 동작 확인을 위한 HTML 파일을 준비합니다.
티스토리 에디터에서 HTML 보기 모드로 전환하여 제 블로그의 가장 최신글의 HTML 내용을 복사한 후, 붙여 넣었습니다.
<h3>모듈로 연산 (Modulo Operation)</h3>
<p data-ke-size="size16" style="text-align: left;">모듈로 연산(Modulo operation)은 두 수가 주어졌을 때, 하나의 수로 다른 하나를 나눈 나머지를 구하는 것입니다.</p>
<p data-ke-size="size16" style="text-align: left;">이를 기호로 쓰면 A mod B = R 가 됩니다.</p>
<p data-ke-size="size16" style="text-align: left;">많은 프로그래밍 언어에는 자체적인 mod 연산자가 있으며 보통 % 기호로 표시합니다. 하지만 음수에 대해 이 연산자를 사용할 경우 JavaScript와 같은 일부 언어는 음수 결과값을 표시합니다.</p>
<p data-ke-size="size16" style="text-align: left;">즉, 다음과 같은 결과를 얻게 됩니다.</p>
<pre class="lsl">
<code>-5 % 3 = -2</code>
</pre>
<p>하지만 <b>나머지는 정의에 따라 0보다 크거나 같고 나누는 값보다 작아</b>야 하므로 그 결과는 <code>1</code>이 되어야 할 것입니다.</p>
<pre class="lsl">
<code>-5 = 3 * (-2) + 1</code>
</pre>
<p data-ke-size="size16" style="text-align: left;">모듈로연산(%)의 결과는 한정된 범위에서 시계처럼 반복되기 때문에 배열 Index를 증가/감소시킬 때 유용하게 사용할 수 있습니다. 이 경우 간단히 다음과 같이 작성을 한다면 앞서 본 것과 같이 음수의 경우 원하는 결과를 얻을 수 없습니다.</p>
<pre class="language-javascript">
<code>function mod(n, m) {
return (n % m);
}</code>
</pre>
<p data-ke-size="size16" style="text-align: left;">이 때는 다음과 같이 코드를 수정하도록 합니다.</p>
<pre class="language-javascript">
<code>function mod(n, m) {
return ((n % m) + m) % m;
}</code>
</pre>
<h3>참고</h3>
<ul style="list-style-type: disc;">
<li>
<a href="(https://ko.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic)">모듈로 연산이란?</a>
</li>
</ul>
해당 문서에는 조작할 코드블록(<code>
태그)이 4개 있습니다.
이제 JavaScript (index.js)를 수정합니다.
기능을 직접 구현할 수도 있으나 외부모듈(clipboard.js
)을 이용하는 쪽이 더 빠르고 안전하게 원하는 목적을 이룰 수 있습니다.
clipboard.js모듈의 홈페이지로 이동하여 사용법을 익힙니다.
안내에 따라 앞서 작성한 HTML 파일에서 clipboard.js를 불러오도록 합니다.
<head>
<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
</head>
<body>
.... 앞서 붙여 넣은 내용 ....
</body>
버튼을 추가합니다.
let pre = document.querySelectorAll('pre');
pre.forEach((snippet) => {
let button = document.createElement('button');
button.className = 'copy-btn';
button.innerHTML = 'Copy';
snippet.appendChild(button)
});
저는 현재 블로그에 구문강조를 위하여 Prism을 적용하였습니다. 따라서 모든 코드 블록은 <pre></pre>
태그로 감싸지고 있습니다. 이를 기준으로 검색한 후, <button></button>
태그를 자식 노드로 추가하였습니다.
버튼의 동작(기능)을 추가합니다.
let copyCode = new ClipboardJS('.copy-btn', {
target: function(trigger) {
return trigger.previousElementSibling;
}
});
앞서 추가한 버튼을 ClipboardJs와 연결합니다. 이때 기준은 버튼의 ClassName copy-btn
입니다. 해당 버튼을 클릭하면 버튼의 이전 DOM(<code></code>
)을 클립보드로 복사합니다.
버튼의 모양과 위치를 수정합니다.
버튼의 위치가 마음에 들지 않습니다. 오른쪽 상단에 표시되었으면 합니다. Clipboard.js 홈페이지에 구현되어 있는 내용을 토대로 좀 더 보기 좋게 만들어 보았습니다.
이에 대한 설명은 최종결과물의 링크로 대체합니다.
최종결과
동작하는 데모 및 최종 소스코드는 StackBlitz에서 확인할 수 있습니다.
// codeCopyButton.js
let pre = document.querySelectorAll('pre');
pre.forEach((snippet) => {
let button = document.createElement('button');
button.className = 'copy-btn';
// button.innerText = 'Copy'; // Text 버튼을 이미지로 변경
// (option) 마우스를 Code 블록에 올리면 버튼이 나타나도록 함
button.addEventListener('mouseleave', clearTooltip);
button.addEventListener('blur', clearTooltip);
// (option) Text 버튼 -> 이미지 버튼
let img = document.createElement('img');
img.className = "clippy";
img.setAttribute('width', '13');
img.setAttribute('src', 'https://tistory3.daumcdn.net/tistory/1888377/skin/images/clippy.svg');
img.setAttribute('alt', 'Copy to clipboard');
button.appendChild(img);
snippet.appendChild(button)
});
let copyCode = new ClipboardJS('.copy-btn', {
target: function(trigger) {
return trigger.previousElementSibling;
}
});
copyCode.on('success', function(event) {
event.clearSelection();
showTooltip(event.trigger, 'Copied!');
});
copyCode.on('error', function(event) {
showTooltip(event.trigger, fallbackMessage(event.action));
});
function clearTooltip(event) {
event.currentTarget.setAttribute('class', 'copy-btn');
event.currentTarget.removeAttribute('aria-label');
}
function showTooltip(elem, msg) {
elem.setAttribute('class', 'copy-btn tooltipped tooltipped-s');
elem.setAttribute('aria-label', msg);
}
function fallbackMessage(action) {
let actionMsg = '';
let actionKey = (action === 'cut' ? 'X' : 'C');
if (/iPhone|iPad/i.test(navigator.userAgent)) {
actionMsg = 'No support :(';
} else if (/Mac/i.test(navigator.userAgent)) {
actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
} else {
actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
}
return actionMsg;
}
이것을 자신의 티스토리의 스킨 HTML 부분에 추가하고 script 파일은 별도로 작성하여 파일을 업로드한 후, HTML에서 불러옵니다.
기타
티스토리의 플러그인과 충돌이 있는 것으로 보입니다. 때문에 이를 비활성화해주었습니다.
참고
'티스토리 > 스킨제작' 카테고리의 다른 글
[티스토리] Prism.js 줄번호 플러그인 적용 (0) | 2021.12.15 |
---|---|
티스토리 스킨 제작기 - 카테고리 메뉴 변경 (0) | 2018.08.29 |
티스토리 prismjs 구문강조(syntax highliter) 적용하기 (0) | 2018.06.30 |
티스토리 스킨 제작기 - 기타 (0) | 2018.06.30 |
티스토리 스킨 제작기 - 본문 (0) | 2018.06.29 |