Memories in SeoK

기억하고 싶은 것들, 기억해야 하는 것들

개발/자바 Java

[jQuery] 코드 블럭 복사하기 - (문제 해결) 플러그인과 함께 사용하기

Seo K 2024. 5. 18. 00:17

이전 글 요약

 

[jQuery] 코드 블럭 복사하기 - (문제 인지) 플러그인들과의 충돌

clipboard.js 라이브러리를 활용하여 코드 블록의 내용을 복사하는 버튼을 구현했으나 "저작권자 표시" 플러그인과의 충돌이 있음을 발견하고 문제를 해결해 가는 과정을 적었습니다 빠른 답을 찾

mem-in-seok.tistory.com

  1. "마우스 오른쪽 클릭 방지" 플러그인 때문에 코드 블록의 소스를 복사할 수 없음
  2. clipboard.js 라이브러리를 활용해 코드 블럭 소스를 복사하는 버튼 구현
  3. "저작권자 표시" 플러그인 때문에 정상 동작하지 않음

수정 계획

저작권자 표시 플러그인 소스
저작권자 표시 플러그인의 텍스트 복사 함수
  • 일단 "마우스 오른쪽 클릭 방지" 플러그인 소스를 수정할 수 있는 게 최선
  • 이단으로 코드 블록 내부 텍스트를 Script로 선택하는 방법을 찾아보고,
  • 최종 삼단은 최악으로, 플러그인 사용을 포기하고 직접 구현하는 것이다

일단 (플러그인 소스 수정)

생각이 떠오를 때 동시에 될 리가 없다고 예상했다
에디터는 고사하고 소스를 제대로 보는 것부터가 어려웠으니까 말이다
여기저기 조금 뒤져보고 검색해보고 했지만 역시 방법은 없는 것 같아 금방 포기했다

이단 (코드로 강제 텍스트 선택)

실제 클립보드로 복사하는 것은 "저작권자 표시" 플러그인에서 하고 있으니, 복사할 데이터만 잘 지정해 주면 의외로 쉽게 해결될 것이라고 생각했다
찾아보니 기쁘게도 방법이 굉장히 쉽게 나왔다 (아싸! 삼단까지 안 가도 된다ㅋㅋ)
document의 Selection 객체를 활용하면 된다고 한다

참고한 글: 호기심 많은 오리님의 블로그

 

[javascript] Selection과 Range를 통해 내맘대로 커서 조작하기 - Selection편

Selection : 사용자가 마우스를 통해 드래그&클릭하거나 키보드를 통해 선택한 텍스트의 범위를 나타냅니다. 혹은 유저의 현재 커서 위치(caret)를 나타냅니다. 크롬, IE 등 브라우저에서는 사용자가

gdtbgl93.tistory.com

텍스트 선택 성공
오오 원하던 대로 정확히 텍스트를 선택한다

끝날 때까지 끝난 게 아니다 (복사 이벤트 발생시키기)

생각이 짧은 나는 여기만 오면 끝일 줄 알았다
하지만 텍스트 선택이 됐다면 copy Event를 발생시켜야 "저작권자 표시" 플러그인의 함수가 동작할 것이 아닌가

분명 "마우스 오른쪽 클릭 방지" 플러그인이 복사 단축키 Ctrl+C까지 막는 건 아니지만,
텍스트 선택 후 할 수 있는 일이라곤 복사 밖엔 없는데 사용자에게 버튼을 누른 후 단축키까지 입력하라고 요구하는 건 지나친 것이기도 하고, 무엇보다 미완성이라 느껴져서 내가 용납이 안 된다
(일부 단축키를 잘 모르시는 분들도 계시고!)

 

단순하게 생각하고 jQuery trigger 함수로 copy Event를 발생시켜 봤지만, 무엇이 문제인지 플러그인에서 붙인 copy Event Listener는 동작하지 않았다

(원인 아시는 분 댓글로 가르침 좀 부탁드려요)

 

한참 삽질을 하다가 javascript 자체 기능이 있을 것 같아 다시 조사를 했다
그다지 고생하지 않고 execCommand 함수를 금방 찾을 수 있었다
역시 안 된다 싶으면 빠르게 다른 길을 찾는 게 필요하다는 교훈을 새기며 적용시켰다
결과는 대성공.. 테스트하면서 뿌듯함을 만끽했다

 

스킨 편집 > HTML (head 태그)

  <!-- jQuery 라이브러리가 사용중인 스킨에 이미 있다면 굳이 추가 안해도 된다 -->
  <script src="//t1.daumcdn.net/tistory_admin/lib/jquery/jquery-1.12.4.min.js"></script>

  <script>
    $(document).ready( function() {
      ...
      // 복사 버튼 [S]
      const button = '<button type="button" class="copy-button">Copy</button>';
      $( 'pre[id^="code"]' ).each( function( index, e ) {
        const clnBtn = $(button).clone()
            .data( 'clipboardText', e.innerText )
            .on( 'click', function( event ) {
              const codeBlk = event.target.previousSibling;
              const selection = window.getSelection();
              selection.selectAllChildren( codeBlk );

              let isSuccCopy = false;
              try {
                isSuccCopy = document.execCommand( 'copy' );
              } finally {
                $( event.target ).addClass( 'copy-message' );
                $( event.target ).attr( 'data-copy-message', isSuccCopy ? '복사 성공' : '실패 (다시 누르기)' );
                selection.removeAllRanges();
              }
            } )
            .on( 'mouseleave', function( event ) {
              $( event.target ).removeAttr( 'data-copy-message' );
              $( event.target ).removeClass( 'copy-message' );
            } );
        e.appendChild( clnBtn[0] );
      } );
      // 복사 버튼 [E]
    } );
  </script>

 

스킨 편집 > CSS (이전 글에서 바뀐 것은 없다)

/* 복사 버튼 [S] */
pre[id^="code"] {
  position: relative;
  /*overflow: visible;*/
}
pre .copy-button {
  opacity: 0.35;
  position: absolute;
  right: 8px; top: 4px;
  padding: 6px 18px;
  color: #fff;
  background: rgba(255, 240, 50, 0.8);
  border-radius: 5px;
  transition: opacity .3s ease-in-out;
  cursor: pointer;
}
pre:hover .copy-button {
  opacity: 1;
}
pre .copy-button:hover {
  background: rgba(255, 210, 0, 1);
  transition: all ease-in-out 0.3s;
}
pre .copy-button:active {
  color: #333;
  background: #eee;
  transition: all ease-in-out 0.2s;
}
.copy-message:before {
  content: attr( data-copy-message );
  position: absolute;
  left: -95px; top: 0px;
  padding: 6px;
  color: #fff;
  background: rgba(255, 210, 0, 1);
  border-radius: 5px;
}
/* 복사 버튼 [E] */