javascript - ToastUI Editor 삽질기 (CustomHTMLRender, AST, Observer 함수)

송현섭 ·2024년 7월 17일
0

개별공부

목록 보기
40/44

  • 현재 Toast UI의 Editor를 적용해서 게시글 작성 페이지를 구상하고 있다. 다만 아쉬운 점이 있다면 폰트사이즈, 폰트 색상 옵션에 대해 기본적으로 제공을 하지 않는다는 것이다. 물론 이 부분은 플러그인만 추가하면 쉽게 해결이 가능하나 본인에게는 살짝 못미더운 부분이 있었다.
    필자는 일반적인 네이버의 에디터 화면처럼 현재 커서가 위치한 곳에서 폰트사이즈나 색상을 바꾸면 그 커서위치부터 입력되는 값은 적용한 스타일셋이 그대로 유지되기를 원했다. 그러나 ToastUI 의 경우 반드시 드래그 하여 선택범위를 지정해주어야만 여기에 태그가 덧씌워져서 스타일이 적용되는 듯했다.

  • 그리고 이 문제는 현재진행형이다. 사실 구현하지 못한 것을 블로그에 기술하면 뭐하나 싶지만, 요 근래에 내가 썼던 글들을 다시 훑어보면서 복습의 시간을 가지고 있기에 이렇게 기록이라도 남겨두면 언젠가 발견하고, 다시 새로운 방법을 찾아 해결할 수 있지 않을까 싶다.
    (아래는 몇가지 시도해 본 방법들이다.)






시도 1. customHTMLRenderer 속성 활용

  • ToastUI 관련 git에서 customHTMLRender 에 대해 상세히 설명하고 있는 문서를 발견했고, 이를 토대로 적용해보았다.
    이름 그대로 Editor에 html문서를 렌더링하여 보여줄 때 이 설정을 사용자 정의로 수정할 수 있도록 제공되는 옵션이다.



  • 보기와 같이 옵션 내부에 들어갈 객체를 정의해주는데 각 html 태그같은 부분은 설정 시 제공되는 토큰객체를 이용, 이 토큰객체를 이용해서 렌더링 시 각 값에 맞게 HTML 변환된다.

  • 위 코드의 경우 입력되는 값에 자식 노드로 span 태그를 추가하고, 여기에 스타일값을 줘서 폰트사이즈를 변경하도록 짜여졌다. 이렇게 하면 이후 markdown에 작성되는 글들은 기본적으로 35px의 폰트사이즈를 가지고 입력되게 된다.



  • 그리고 속성을 이렇게 집어넣어주기만 하면 바로 적용이 가능하다.
    그러나 이 방식은 문제가 있는데 wysiwyg 모드에서 작성하는 것에는 적용이 되지 않는다는 점이었다. 대신 markdown 모드에서 옆에 wysiwyg 모드 버전으로 미리보는 화면상에는 잘 적용된채로 보여졌다.

  • 왜 마크다운 모드에서는 잘 보이는 걸까 ? 문서를 꼼꼼히 다시 읽어보면 그 이유를 찾을 수 있었다.



  • Editor 는 자체 마크다운 파서를 이용합니다. 마크다운 텍스트를 AST 로 변환합니다.

  • 그러니까 애초에 markdown 문법을 html 형식으로 변환시켜준다는 것이다. 아마 이 부분 때문에 처음부터 wysiwyg 모드에서 작성하면 해당 모드에서는 변경점이 적용되지 않는 듯 했다. (아직 확실치는 않음)

  • 그나저나 저기서 AST라는 생소한 용어가 궁금해져서 조금 찾아봤다. 이름만 직역해보면 추상구문트리, 무언가 추상적으로 트리구조를 간략하게 잡아서 생성하는 그런 느낌이다.



AST (추상구문트리)

  • 컴파일러가 사용하는 파일구조의 일종으로, 각 코드를 추상적인 집합으로 된 토큰 객체로 만들고, 이를 트리구조로 재구성한 결과물이다. 좀 더 쉽게 이해하자면 각 구문에 대해 해당 구문의 타입, 위치, 식별자 등을 토큰화 해서 트리로 나타내어 컴파일러 같은 프로그램이 각 코드의 역할을 보다 쉽게 이해할 수 있게 해준다고 볼 수 있다.

  • 즉 컴파일러가 소스코드를 해석화는 일련의 과정들 중, 구문분석을 할 때 이 시점에 생성되는 트리다. 각 트리는 코드 상에 선언된 함수, 변수, 속성 등의 값에 대해 객체형식의 데이터구조로 짜여져있으며 이를 토대로 개별 소스들을 이해하고 확인하기 위해 효율적으로 활용가능하다고 하다.
    (추상구문트리를 활용하는 예시 = Eslint)

  • AST 부분은 나중에 따로 더 깊이 파볼 필요가 있을듯하다. 아무튼 그래서 내가 사용하려는 이 customHTMLRender 또한 마크다운으로 입력된 값을 렌더링하기 전에 우선 AST 로 트리구조화 하는데, 개발자가 여기서 이 토큰객체를 입맛에 맞게 커스텀할 수 있도록 지원해주고 있는 것이었다.



    +) 모 블로그에서 iframe 을 커스텀 블록으로 만들어서 집어넣는 코드를 보고 영감이 떠올랐다. 그 분의 경우 iframe 태그를 삽입하기 전 모드를 markdown으로 바꾼 후 데이터를 넣고, 다시 wysiwyg 모드로 변환하는 방식을 취하고 있었다. 다만 본인의 경우 실시간으로 입력되는 값에 대한 태그구조를 변경학 싶은거라 이 경우에는 evnetListener로 매 입력마다 모드를 바꾸고, 집어넣는 과정을 반복해야 되는데, 이게 과연 효율성이 있는 것인가에 의구심이 들어 아직 시도해보지는 않았다. (더 좋은 방법을 찾았으면 ..ㅜ)






시도2 - Observer 함수 활용

  • 이번에 시도를 통해 처음으로 observer를 제대로 활용해보았다. 물론 이 방법도 결과적으로는 실패였으나 Observer에 대해 나름 공부하고 찾아보는 유의미한 시간이었다고 생각한다.

  • 위 코드는 wysiwyg(Editor 의 wysiwyg 화면 element) 에 대해 구독(감시)를 하는 함수다. 내부 로직에 따라 Observer 는 wysiwyg element 의 각 하위 child 요소들과 그 하위 요소들(subtree) 까지 변경점을 감시하는데 이 중 새로 삽입된 요소들 중 p태그를 찾는다.

  • 찾았을 경우 span 태그를 만들어서 스타일속성을 부여한 후, 노드의 자식으로 집어넣는다.

    (콘솔에서 확인해보면 정상적으로 노드에 자식으로 들어가 있지 않음을 확인했다. 기존 라이브러리 코드가 선행되면서 이 코드는 무시되는건지 모르겠으나 이 부분 역시 속시원한 답안을 찾아내지는 못했다..)




Observer 함수

// 1. 감지 대상 요소 
const target = document.getElementById('id');

// 2. 옵저버 콜백 함수 선언
const callback = (mutationList, observer) => {
  console.log(mutationList);
};

// 3. 옵저버 인스턴스 생성
const observer = new MutationObserver(callback); // 타겟에 변화가 일어나면 콜백함수를 실행하게 된다.

// 4. 변경감지 트리거 여부
const config = { 
    attributes: true, // 속성 변화 할때 감지
    childList: true, // 자식노드 추가/제거 감지
    characterData: true // 데이터 변경전 내용 기록
};

// 5. 감시 시작
observer.observe(target, config);

// 6. 중단
observer.disconnect();
  • Observer 는 DOM의 속성, 텍스트, 자식 노드들에 대한 변경을 감지할 수 있는 내장 API이다. 특정 노드 객체를 관찰하고, 변경이 발생했을 경우 콜백함수가 실행된다.

  • target은 말 그대로 추적감시의 대상이다.

  • callback 은 변경사항이 감지될 때마다 반복되서 실행되는 함수다.

  • config 객체에는 어떤 변화를 감지할지를 정의할 수 있다. boolean 값에 따라 observer 실행의 트리거 기준이 바뀐다.

  • observe로 감시를 시작하며 disconnect 로 종료가능하다.
    (일반적으로 감시가 끝나고 원하는 실행이 끝나면 observe의 감시를 종료하는 게 좋음)



    보통 DOM 요소의 특정 값이 바뀌거나, 새로추가될 때 내부적으로 새 요소를 만들어서 추가하거나 하는 식으로 뭔가 동적인 변경이 필요할 때 사용하면 좋을 것 같다고 생각된다.

profile
막 발걸음을 뗀 신입

0개의 댓글