웹 브라우저에서 사용자가 선택한 텍스트 정보를 알 수 있는 API입니다.
selection 객체를 얻기 위해선 window.getSelection() 메서드를 사용합니다.
selection 객체을 얻었으면 사용자에 의해 선택된 텍스트의 시작과 끝을 나타냅니다.
🤔그러면 JavaScript는 범위를 어떻게 이해할까요?
사용자가 본문에 response ~ 응답 까지 드래그를 했다고 가정합니다.


Range객체를 출력해보겠습니다.

startContainer: 범위의 시작을 정의하는 DOM 노드입니다.pm.response를 담고 있는 TEXT Node가 됩니다.TEXT Node는 HTML태그가 아닌 순수한 텍스트를 의미합니다.<strong>pm.reponse</strong> 태그 내부의 텍스트를 나타냅니다.startOffset: 해당 노드 내에서 시작 위치의 오프셋(인덱스) 입니다.endContainer: 범위의 끝을 정의하는 DOM 노드입니다."는 응답 데이터와 관련된 정보를 제공한다."를 담고 있는 TEXT Node가 됩니다.<p>는 응답 데이터와 관련된 정보를 제공한다.</p> 태그 내부의 텍스트를 나타냅니다.endOffset: 해당 노드 내에서 마지막 위치의 오프셋(인덱스) 입니다.+1을 해준 값을 반환합니다.정리하자면
JavaScript는startContainer의 startOffset부터endContainer의 endOffset까지의 모든 텍스트를 사용자가 지정한 범위로 이해합니다.
결론부터 말하자면
Range객체 범위에 있는 Text Node에 커스텀 태그를 추가하는 것입니다.
예제를 보면서 이해해 봅시다.
사용자가 DOM 이란 텍스트를 선택했다고 가정해봅시다.
해당 Text Node를 찾아 커스텀 태그 bee를 추가한 결과를 보여줍니다.
코드를 보면서 이해해보겠습니다.
function findTextNodesInRange(range) {
let textNodes = [];
function isTextNode(node) {
return node.nodeType === Node.TEXT_NODE;
}
function isNonEmptyTextNode(node) {
return !/^\s*$/.test(node.nodeValue);
}
function recurse(node) {
if (
isTextNode(node) &&
range.intersectsNode(node) &&
isNonEmptyTextNode(node)
) {
textNodes.push(node);
} else {
node.childNodes.forEach(recurse);
}
}
recurse(range.commonAncestorContainer);
return textNodes.filter((node) => range.intersectsNode(node));
}
위 함수는 range 객체 안에 있는 Text Node를 찾는 함수입니다.
commonAncestorContainer : startContainer와 endContainer가 공유하는 가장 가까운 공통 조상 노드입니다.
HTML부터 탐색하는 대신, 공통 조상 노드 부터 시작하면 더 효육적으로 빠르게 탐색할 수 있습니다.range.intersectsNode: Range객체에서 특정 노드가 해당 Range객체와 겹치는 부분이 있는지 확인합니다.
true를 반환하고, 범위 밖에 있다면 false를 반환하게 됩니다.정리하자면
1. 텍스트 노드인지
2. 범위 내에 있는지
3. 비어있지 않는지 체크를 합니다.
만족하면 배열에 저장해 둡니다.
이 과정을 기반으로 재귀적으로 탐색을 진행합니다.
이제 찾은 Text Node들에 커스텀 태그를 추가하기만 하면 됩니다.
코드를 통해 이해해 봅시다.
function highlightTextNodes(textNodes, range, color, colorh, data) {
textNodes.forEach((node) => {
const nodeRange = createNodeRange(node, range);
const highlightBeeTag = createHighlightBeeTag(data.id, color);
nodeRange.surroundContents(highlightBeeTag);
});
highLightHover(data.id, color, colorh, range);
}
Text Node에 대해 range객체를 만들어 줍니다.range.selectNodeContents(해당 텍스트 노드)를 하게 되면 Range객체를 쉽게 만들 수 있습니다.bee를 생성합니다.surroundContents 함수를 통해 텍스트 범위에 bee 태그를 감쌉니다.이렇게 한다면 복잡한 구조를 가진 태그에서도 정상적으로 형광펜이 칠해질 것입니다.