Selection API
Selection API는 웹 브라우저에서 현재 선택된 텍스트 또는 커서의 위치에 관련된 정보 제공 및 선택된 텍스트와 커서의 위치를 조작할 수 있는 메서드들을 제공하는 Web API다. 2022년 현재 거의 대부분의 브라우저에서 지원하고 있다.
<div>가나다라마바사</div>
window.getSelection();
window.getSelection()은 현재 선택된 범위에 대한 Selection 객체를 반환한다.
Selection 객체의 프로퍼티에 대해 알아보자.
anchorNode / focusNode
anchorNode와 focusNode는 각각 선택이 시작된 노드와 선택이 끝난 노드를 나타낸다.
위 예제에서 선택이 시작된 노드와 선택이 끝난 노드는 각각 "다"의 앞부분과 "마"의 뒷부분이 속한 노드를 가리키며, 둘 다 "가나다라마바사"라는 같은 텍스트 노드를 가리키게 된다. div를 가리키는 것이 아니다.
anchorOffset / focusOffset
anchorOffset과 focusOffset은 각각 선택이 시작된 지점과 선택이 끝난 지점을 나타낸다.
"가나다라마바사"에서 "가"의 왼쪽의 offset이 0이고, "사"의 오른쪽의 offset이 7이다.
위 예제에서 "다라마"를 선택하려면 offset 2부터 offset 5까지 선택해야 하므로, anchorOffset과 focusOffset은 각각 2, 5가 된다.
여기서 주의할 점은, "선택"이라는 이벤트는 반드시 앞에서 뒤로만 이루어지지 않는다는 것이다. 마우스 드래그를 오른쪽에서 왼쪽으로 긁어서 텍스트를 선택했다면, anchorOffset과 focusOffset은 정반대가 된다.
base~ / extent~
base~와 extent~는 각각 anchor와 focus의 alias다. 따라서 baseNode는 anchorNode와 동일하고, extentOffset은 focusOffset과 동일하다.
isCollapsed
isCollapsed는 anchorOffset과 focusOffset이 동일한 지점에 있는지 여부를 나타낸다.
"가나다라마바사"에서 "나"와 "다" 사이에서 마우스를 클릭한 뒤 Selection 객체를 보면 isCollapsed는 true로 나온다.
const { anchorOffset, focusOffset, isCollapsed } = window.getSelection();
console.log(anchorOffset, focusOffset, isCollapsed); // 2 2 true
여기서 동일한 지점에 있다는 것은 단순히 anchorOffset과 focusOffset이 동일하기만 하다는 의미는 아니다.
<div>가나다라마바사</div>
<div>가나다라마바사</div>
const { anchorOffset, focusOffset, isCollapsed } = window.getSelection();
console.log(anchorOffset, focusOffset, isCollapsed); // 2 2 false
위 예제의 경우에 두 개의 서로 다른 요소를 동시에 선택하고 있다. 이런 경우 anchorNode와 focusNode는 서로 다른 노드를 가리키게 된다. 그리고 anchorOffset과 focusOffset은 각각 anchorNode에서의 시작되는 지점과 focusNode에서의 끝나는 지점을 가리키게 된다. 이런 경우 anchorOffset과 focusOffset은 같지만, 같은 노드의 같은 위치를 나타내는 것이 아니기 때문에 isCollapsed는 false가 된다.
rangeCount
Selection 객체는 Range 객체를 포함하고 있다. Range 객체는 노드나 텍스트 노드의 일부분을 포함하는 문서의 조각(fragment)이며, Selection은 여러 개의 Range 객체를 가질 수 있다. rangeCount는 Selection 객체가 갖고 있는 Range 객체의 개수를 나타낸다.
대부분의 브라우저는 선택을 한 번만 할 수 있기 때문에 Selection 객체가 1개의 Range 객체를 가질 수 있다. 하지만, FireFox는 Ctrl 키를 누르고 여러 개의 선택을 할 수 있는 기능을 제공하고 있다. 따라서 FireFox에서는 Selection 객체가 여러 개의 Range 객체를 가질 수 있다.
각 Range에 Selection.prototype.getRangeAt을 통해 접근할 수 있다. Range가 1개뿐인 브라우저에서는 Selection.prototype.getRangeAt(0)을 통해 현재 선택된 범위에 대한 Range 객체를 얻을 수 있다.
const selection = window.getSeleciton();
const range = selection.getRangeAt(0);
console.log(range);
type
처음에 아무런 선택 이벤트가 발생하지 않은 상태에는 "None"이다. isCollapsed가 true라면 "Caret"을, 그렇지 않으면 "Range"를 반환한다.
현재 선택된 범위와 커서의 위치를 다룰 수 있는 Selection API는 텍스트를 입력하고 편집하는 에디터를 만들 때 유용하게 사용할 수 있을 것 같다. 실제로 나도 Selection API를 활용하여 유사(?) 에디터를 만들어 보기도 하였다.
이 글에서는 Selection 객체의 프로퍼티 위주로 설명하였지만, Selection API는 여러 유용한 메서드들을 제공하고 있다. 자세한 내용은 MDN 문서를 참고해보면 좋을 것 같다.
참고자료
https://developer.mozilla.org/ko/docs/Web/API/Selection
https://gdtbgl93.tistory.com/175
'IT > JavaScript' 카테고리의 다른 글
[JS] 자바스크립트로 엑셀 파일(xlsx) 만들어서 다운받기 (0) | 2022.08.05 |
---|---|
[JS] Invalid regular expression: invalid group specifier name (0) | 2022.06.21 |
[JS] 자바스크립트의 배열 생성 방법 (0) | 2021.07.29 |
[JS] 함수의 매개변수와 RangeError (0) | 2021.07.23 |
Node.js로 백준(BOJ) 문제 풀 때 유의할 점들 (12) | 2021.04.10 |