웹 브라우저에서 사용자가 선택한 텍스트 정보를 알 수 있는 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
태그를 감쌉니다.이렇게 한다면 복잡한 구조를 가진 태그에서도 정상적으로 형광펜이 칠해질 것입니다.