자바스크립트를 사용하여 드래그했거나 커서가 있는 위치에 텍스트 및 DOM 엘리먼트를 추가하는 방법에 대하여 알아봅니다.



# 커서 위치에 텍스트, 엘리먼트 추가
만약 위지윅 에디터를 직접 만들어 구현한다고 생각해보겠습니다.  div 등의 태그를 하나 만들고 어트리뷰트로 contentEditable을 가지는 경우 이 내부에 위치한 커서에 텍스트나 이미지 등의 엘리먼트를 추가하려고 한다면 어떻게 할 수 있을까요?


? 커서 위치에 추가하는 방법은...
기존에 Webisfree에서도 아를 구현하기 위한 비슷한 글을 찾을 수 있습니다. 하지만 오늘 알아볼 방법은 조금 다를 수 있는데요 ~ 커서의 위치가 다른 곳으로 변경되거나 아니면 커서가 없더라도 원하는 위치에 이동하는 방법을 찾기 위해서 입니다.


! 예제 코드 알아보기
먼저 간단한 예제를 만들어서 알아봅니다. 입력이 가능한 div 태그에 contentEditable 어트리뷰트를 추가하여 편집이 가능한 요소를 만들었습니다.
<div id="editor" contentEditable="true"></div>

(contentEditable 어트리뷰트를 사용하면 엘리먼트에 텍스트 등을 추가하는 등 조작이 가능합니다.)

이제 해당 영역에 커서를 위치시키고 특정 텍스트를 추가하려면 어떻게 할까요? 우선 잘 알려진 getSelection()을 사용합니다.
const selection = window.getSelection();

이제 변수 selection에는 현재 위치한 커서의 위치 정보를 저장하고 있습니다. 그런데 이 위치 정보를 임의로 변경하는 것이 가능할까요? 물론 가능합니다. getSelection()을 사용하여 얻은 인스턴스는 내부에 선택되거나 커서의 위치 range 정보를 가지고 있습니다. 이 값을 원하는 값으로 변경하면 원하는 위치로 변경하는 것이 가능하죠.

range : 현재 커서가 위치한 node 정보와 위치 index 값이 저장되어 있음


이제 새로운 range값으로 업데이트를 위하여 기존의 range 정보를 삭제해보겠습니다. 이를 위해서 removeAllRanges()를 사용합니다.
selection.removeAllRanges();

기존의 range 값이 삭제되었습니다. 다음으로 selection에 새로운 range 정보가 저장하려고 합니다. 새로운 range 정보를 추가하기위해서는 addRange()를 사용할 수 있습니다. 아래와 같이 range를 저장하려고 합니다.
const newRange = selection.getRangeAt(0);을 사용해 저장한 다른 range의 값
selection.addRange(newRange);

위와 같이 실행하면 기존의 selection에 새로운 range인 위치 정보가 저장되게 됩니다. 위에서는 newRange를 추가하였는데 newRange는 새로운 위치 정보를 가진 변수로 다른 getSelection()에서 getRangeAt(0)을 사용하여 저장했던 range 정보입니다. 여기서는 예를 들지 않았지만 newRange를 임의로 만드는 것도 가능합니다. 위치 값으로 사용할 node 정보만 있다면 말이죠.


@ range에 새로운 노드를 추가하기
이제 변경된 range에 새로운 텍스트나 엘리먼트, node를 추가하고자 합니다. 아래에서 보시는 것처럼 createElement()를 사용해 새로운 엘리먼트를 만들고 이를 추가하는 방법입니다.
let tmpNode = document.createElement('span');
tmpNode.innerHTML = `<b>웹이즈프리</b>`;
newRange.deleteContents();
newRange.insertNode(tmpNode);

위 코드를 실행하면 새로운 엘리먼트인 <b>웹이즈프리</b>가 해당 커서의 위치로 추가되게 됩니다.


여기까지의 진행된 과정을 보면 간단하지만 전체를 이해하기는 조금 어려울 수 있습니다. 즉 추가할 새로운 엘리먼트 노드를 만들고 range 정보의 기존 콘텐츠를 deleteContents() 함수를 사용하여 삭제한 후  insertNode()를 사용하여 새로운 노드 정보를 추가하는 과정이 중요합니다.


! 정리하면서
위의 과정들 중 다시 인지해야 할 가장 중요한 부분은 아래와 같습니다.

- getSelection()은 range 정보를 가지고 있다
- 저장된 range  정보는 삭제 후 새로운 range를 임의로 추가할 수 있다
- range에 새로운 엘리먼트나 텍스트를 추가하면 원하는 위치에 추가된다


이 부분을 유념하여 적용하면 될 것 같습니다. 여기까지 커서 위치에 특정 요소, 텍스트 등을 추가하는 등의 과정을 알아보았습니다.