front-end / / 2022. 12. 29. 09:48

textarea에 syntax highlighter 적용하기

textarea에 하이라이팅 기능을 적용할 일이 있었는데 기본적으로 하이라이팅을 적용할 수가 없다.

그래서 자료를 참고해서 만들어 보았다.

우선 textarea에 영역을 덮어서 변경되는 값을 표시하면서 하이라이팅을 적용하는 방법을 알아냈다.

하이라이팅은 highlight.min.js를 이용하여 적용하였다.

1. style 적용

<style>
    #editing-code, #highlighting-code {
      font-family: Menlo, Consolas, Liberation Mono, monospace;
      position: absolute;
      margin: 0;
      padding: 0;
      top: 0;
      white-space: nowrap;
      overflow-x: hidden;
      font-size: 15px;
      line-height: 20px;
      padding: 10px;
    }

    #editing-code {
      font-family: Menlo, Consolas, Liberation Mono, monospace;
      color: transparent;
      background-color: transparent;
      caret-color: red;
      border: none;
      z-index: 1;
      resize: none;
      outline: none;
      font-size: 14px;
    }


    #highlighting-code {
      border-radius: 2px;
      z-index: 0;
      font-size: 14px;
    }

    .hljs {
      display: inline-block;
      font-family: Menlo,Consolas,Liberation Mono,monospace;
      font-size: 14px;
      font-weight: 400;
      line-height: 20px;
      letter-spacing: 0;
      text-align: left;
      white-space: pre;
      word-spacing: normal;
      word-break: normal;
      overflow-wrap: normal;
      tab-size: 4;
      hyphens: none;
      color: #fd971f;
      background: rgb(53, 55, 97) !important;
      overflow: auto;
    }

    .hljs-string {
      color: #fff;
    }
  </style>

2. script 적용

<script>
    function update_code() {
      const result_elem = document.querySelector("#highlighting-code code");
      let text = document.querySelector("#editing-code").value;
      if (text[text.length-1] == "\n") {
        text += "  ";
      } else if (text == "") {
        text += "\n  ";
      } else if (text.indexOf("\n", 1) < 0) {
        text += "\n  ";
      }

      result_elem.innerHTML = text;
      hljs.highlightBlock(result_elem)
    }

    function sync_scroll(element) {
      let result_element = document.querySelector("#highlighting-code");
      result_element.scrollTop = element.scrollTop;
      result_element.scrollLeft = element.scrollLeft;
    }

    function check_tab(element, event) {
      let code = element.value;
      if(event.key == "Tab") {
        event.preventDefault();
        let before_tab = code.slice(0, element.selectionStart);
        let after_tab = code.slice(element.selectionEnd, element.value.length); //
        let cursor_pos = element.selectionEnd + 2;
        element.value = before_tab + "  " + after_tab;
        element.selectionStart = cursor_pos;
        element.selectionEnd = cursor_pos;
        update_code(element.value);
      }
    }

    function resize() {
        const editor = document.querySelector('#editing-code');
        const precode = document.querySelector('#highlighting-code');
        precode.style.width = "calc(" + window.getComputedStyle(editor).width + " + 35px)";
        editor.style.height = "20px";
        if (editor.scrollHeight > 30) {
            editor.style.height = (editor.scrollHeight + 5)+"px";
        } else {
            editor.style.height = "60px";
        }
    }

    document.addEventListener("DOMContentLoaded", () => {
      update_code();
      resize();
    });
  </script>
  1. html 적용
<!doctype html>
<html lang="ko">
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/rainbow/1.2.0/themes/github.min.css" /> </head>
<body>
  <main>
    <div id="code-editor">
      <textarea
      cols="100"
      id="editing-code"
      spellcheck="false"
      oninput="update_code(this.value); resize();"
      onkeydown="check_tab(this, event);"
      >curl 'http://localhost:8080/users' -i -X PUT \
    -H 'Content-Type: application/json' \
    -H 'Accept: application/json' \
    -d '{
  "name" : "rudaks",
  "comment" : "user comment"
}'</textarea>
      <pre id="highlighting-code" class="hljs">
        <code class="language-bash hljs" data-lang="bash"></code>
      </pre>
    </div>
  </main>

</body>
</html>

 

결과 화면)

기본화면

적용하고 나면 아래와 같은 모양이 된다.

language-bash로 적용을 했지만 다른 언어로 변경하기 위해서 스타일링이 필요할 수도 있다.

textarea.html
0.00MB

참고: https://css-tricks.com/creating-an-editable-textarea-that-supports-syntax-highlighted-code/

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유