[javascript] Selection과 Range를 통해 내맘대로 커서 조작하기 - Selection편
Selection : 사용자가 마우스를 통해 드래그&클릭하거나 키보드를 통해 선택한 텍스트의 범위를 나타냅니다. 혹은 유저의 현재 커서 위치(caret)를 나타냅니다.
크롬, IE 등 브라우저에서는 사용자가 선택한 텍스트에 대한 처리를 지원하기 위해 Selection API를 지원하고 있습니다.
특히 Selection과 Range 객체는 특히 위지위그(WYSIWYG) 에디터, 텍스트 리치 에디터등을 구현할때 중요하게 사용되니까 필요하신 분들은 꼭 알아두시기 바랍니다.
Selection은 anchor와 focus를 가지는데요.
anchor는 텍스트 선택을 시작한 지점, focus는 선택을 끝낸 지점을 말합니다.
Selection은 방향을 가질 수 있습니다.
이 말은 텍스트의 왼쪽에서 오른쪽으로, 혹은 오른쪽에서 왼쪽으로 선택할 수 있다는 말인데요.
이 경우 anchor와 focus는 반대가 될 수 있습니다.
큐리덕 이라는 문자열을 마우스 드래그로 선택한다고 가정해보면
왼쪽 -> 오른쪽으로 선택했을 때는 anchor가 0, focus가 2가 되었다면
오른쪽 -> 왼쪽으로 선택했을때는 anchor가 2, focus가 0이 되는 식입니다.
Selection 객체는 browsing context를 나타내는 window 객체에서 뽑아올 수 있습니다.
일반적인 사용법은 window.getSelection()으로 Selection 객체를 호출하며 불러오며, Selection 객체는 Range 객체를 가질 수 있습니다.
Range 객체는 특정 테두리를 가진 문자열을 말하는데요.
Selection을 통해 선택된 텍스트 범위에 대한 정보가 들어있습니다. (노드의 시작 시점, 시작하는 지점에 있는 컨테이너 노드, 공통 부모노드 등등..)
즉 Selection이 Range를 포함하는 개념이며, Selection안에는 여러개의 Range를 가질 수 있다는 것이죠.
그러나!
FireFox의 경우는 한 Selection 안에 여러개의 Range 객체를 가질 수 있지만,
그 외의 브라우저들은 하나의 Selection 객체안에 단 하나의 Range 객체만을 허용합니다.
위에서 보듯이 Firefox 브라우저의 경우 getRangeAt으로 여러개의 Range 객체에 접근할 수 있음을 볼 수 있습니다.
( 파이어폭스 브라우저를 지원할 계획이라면, 크로스 브라우징 처리시에 고려해야할 사항이겠죠? )
Selection 객체를 얻는 방법은 두 가지가 있습니다.
첫째, window object에서 getSelection() 메소드를 통해 불러오는 방법
둘째, document object에서 getSelection() 메소드를 통해 불러오는 방법인데요.
두 함수 모두 동일한 Selection 객체를 반환합니다.
Window 객체의 getSelection 메소드의 경우, Window 객체 안의 document 속성에 기반하는 Selection 객체를 반환합니다.
속성
속성명 | 설명 |
anchorNode |
드래그나 키보드 이벤트 등으로 선택이 시작되어진 노드를 반환합니다. 없으면 null을 반환합니다 |
anchorOffset |
선택이 시작되어진 노드에서, 시작되어진 텍스트의 시작 지점을 말합니다. 노드의 맨 첫 시작점의 offset은 0입니다. 예를들어, "안녕하세요 반갑습니다!" 라는 문장에서, 실제 선택되어진 문장이 "하세요 반갑습니다" 인 경우에, 시작지점은 2이고, 끝 지점은 11 입니다. 그래서 anchorOffset은 2가 됩니다. |
focusNode | 선택이 끝난 지점에 있는 노드를 반환합니다. 없으면 null을 반환합니다. |
focusOffset | 선택이 끝난 노드에서, 텍스트의 종료 지점을 말합니다. 노드의 맨 첫 시작점의 offset은 0입니다. |
isCollapsed | anchor와 focus가 같은 지점에 있는지 여부를 반환합니다. 클릭하면 anchor와 focus가 같은 지점에 존재합니다. 입력이 가능하면 커서가 깜박이고 있을겁니다. |
rangeCount | 현재 브라우저 컨텍스트에 존재하는 존재하는 Range의 개수를 반환합니다. |
type |
collapsed이면 "Caret", 범위가 선택된 상태면 "Range", 아무것도 선택되어진 상태가 아니라면 ( 아무 이벤트도 발생되지 않은경우라면 ) "None"을 반환합니다. |
메소드
메소드명 | 파라미터 | 파라미터 설명 | 설명 |
getRangeAt | index | 꺼내올 Range 객체의 인덱스 번호입니다. | 특정 index에 있는 Range 객체를 꺼내옵니다. |
addRange | range | 추가할 Range 객체 | 현재 Selection에 Range를 추가합니다. |
collapse | node |
접을 노드 (Selection 안에 존재하는 노드이어야함) |
넘겨진 노드와 offset으로 Range를 접습니다. |
offset | optional, 이동시킬 노드가 자식 노드를 가지고 있을 경우에, 몇 번째 자식노드에서 접을것인지 지정할 수 있습니다.기본값의 경우 0으로 설정되어 있습니다. | ||
collapseToEnd | 선택되어진 range의 끝 지점으로 접습니다. | ||
collapseToStart | 선택되어진 range의 시작 지점으로 접습니다. | ||
containsNode | node | 포함되어 있는지 확인할 노드 | 주어진 노드가 선택된 범위 안에 존재하는지 확인하여 boolean 값으로 반환합니다. |
partialContainment |
optional, 기본값은 false입니다. 노드의 시작과 끝이 선택된 범위와 동일할때 반환될 방식을 지정 true: 노드와 선택된 범위가 동일할때 포함된 것으로 침 false: 노드와 선택된 범위가 동일할때 포함되지 않은것으로 침 |
||
deleteFromDocument | 선택된 범위를 Document 객체에서 제거합니다. ( 선택된 범위를 아예 문서에서 없애버리는 메소드 ) | ||
removeAllRanges | Selection 객체 안에 있는 모든 Range를 제거하여, 아무것도 선택되지 않은 상태로 만듭니다. | ||
removeRange | range | 제거할 Range 객체 |
특정 range를 Selection 객체 안에서 제거합니다. 제거할 Range 객체는 Selection 객체 안에 포함되어 있어야 합니다. |
extend | node | focus로 지정할 노드 | anchor는 가만히 두고 focus만 주어진 노드와 offset으로 이동시킵니다. |
offset |
optional, 이동시킬 노드가 자식 노드를 가지고 있을 경우에, 몇 번째 자식노드로 focus를 이동시킬것인지 지정할 수 있습니다.기본값의 경우 0으로 설정되어 있습니다. |
||
setBaseAndExtent |
anchorNode | anchor로 지정할 노드 |
주어진 노드들로 선택 범위의 시작과 끝 지점을 지정합니다. extend가 선택의 끝만 지정했다면, setBaseAndExtent는 시작 노드와 끝 노드를 지정할 수 있습니다. |
anchorOffset | 이동시킬 노드가 자식 노드를 가지고 있을 경우에, 몇 번째 자식노드로 anchor를 이동시킬것인지 지정할 수 있습니다.기본값의 경우 0으로 설정되어 있습니다. | ||
focusNode | focus로 지정할 노드 | ||
focusOffset | 이동시킬 노드가 자식 노드를 가지고 있을 경우에, 몇 번째 자식노드로 focus를 이동시킬것인지 지정할 수 있습니다.기본값의 경우 0으로 설정되어 있습니다. | ||
selectAllChildren | parentNode | 자식들을 선택할 부모노드 | 부모 노드를 넘겨주면, 부모노드 아래에 있는 모든 자식 노드가 선택되어 집니다. |
setPosition | collapse() 메소드와 동일함 | ||
empty | removeAllRange() 메소드와 동일함 |
이벤트
이벤트명 | 설명 |
selectstart | 유저의 드래그나 클릭 등의 행위에 의해 새로운 Range 객체가 연결될 때, 발생되는 이벤트 |
selectionchange | 현재 붙어있는 Range 객체가 떨어지고 새로운 Range 객체가 붙거나, 현재 Range 객체의 경계선이 변형될때 발생하는 이벤트. |
아래의 예제를 보면서 API의 동작을 확인해 보시기 바랍니다.
브라우저의 개발자 도구를 켜고 확인하셔야 합니다.