당신이 이것을 위해 완전한 해결책을 얻으려고 많이 요구하고 있다고 생각하지만, 재미있어 보였습니다. 그래서 구현했습니다. 다음은 OS 3.0을 실행하는 iPhone의 Safari를 포함하여 최근 WebKit 브라우저에서 작동합니다. 그것은 비표준이지만 편리한 intersectsNode
방법을 사용합니다. Range
은 WebKit에 있지만 3.0의 Firefox에서 제거되었으므로 최신 버전의 Firefox에서는 작동하지 않지만 그렇게 할 수는 있습니다.
다음은 각 선택된 텍스트 노드를 "someclass"클래스의 <span>
요소로 둘러 쌉니다. 또한 쉽게 되돌리기를 허용하는 고유 한 클래스도 있습니다. applyClassToSelection
은이 고유 한 클래스를 반환합니다. 이 클래스를 removeSpansWithClass
에 전달하여 범위를 제거하십시오.
UPDATE : 지금 테스트 OS 3.0을 실행 아이폰에서 작동 : 선택은 전적으로 하나의 텍스트 노드
업데이트 2에 포함되어 고정 문제.
업데이트 3 :rangeIntersectsNode
Firefox 3.0 이상을 지원하는 기능이 추가되었습니다. 이 코드는 이제 Firefox 1.0 이상, Safari 3.1 이상, Google Chrome, Opera 9.6 이상 및 기타 (아직까지 테스트되지 않음)에서 작동합니다. Internet Explorer에서 전혀 작동하지 않으며 해당 브라우저에서 오류가 발생합니다. 곧 IE 버전을 사용할 계획입니다.
<script type="text/javascript">
var nextId = 0;
var rangeIntersectsNode = (typeof window.Range != "undefined"
&& Range.prototype.intersectsNode) ?
function(range, node) {
return range.intersectsNode(node);
} :
function(range, node) {
var nodeRange = node.ownerDocument.createRange();
try {
nodeRange.selectNode(node);
} catch (e) {
nodeRange.selectNodeContents(node);
}
return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
};
function applyClassToSelection(cssClass) {
var uniqueCssClass = "selection_" + (++nextId);
var sel = window.getSelection();
if (sel.rangeCount < 1) {
return;
}
var range = sel.getRangeAt(0);
var startNode = range.startContainer, endNode = range.endContainer;
// Split the start and end container text nodes, if necessary
if (endNode.nodeType == 3) {
endNode.splitText(range.endOffset);
range.setEnd(endNode, endNode.length);
}
if (startNode.nodeType == 3) {
startNode = startNode.splitText(range.startOffset);
range.setStart(startNode, 0);
}
// Create an array of all the text nodes in the selection
// using a TreeWalker
var containerElement = range.commonAncestorContainer;
if (containerElement.nodeType != 1) {
containerElement = containerElement.parentNode;
}
var treeWalker = document.createTreeWalker(
containerElement,
NodeFilter.SHOW_TEXT,
// Note that Range.intersectsNode is non-standard but
// implemented in WebKit
function(node) {
return rangeIntersectsNode(range, node) ?
NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
},
false
);
var selectedTextNodes = [];
while (treeWalker.nextNode()) {
selectedTextNodes.push(treeWalker.currentNode);
}
var textNode, span;
// Place each text node within range inside a <span>
// element with the desired class
for (var i = 0, len = selectedTextNodes.length; i < len; ++i) {
textNode = selectedTextNodes[i];
span = document.createElement("span");
span.className = cssClass + " " + uniqueCssClass;
textNode.parentNode.insertBefore(span, textNode);
span.appendChild(textNode);
}
return uniqueCssClass;
}
function removeSpansWithClass(cssClass) {
var spans = document.body.getElementsByClassName(cssClass),
span, parentNode;
// Convert spans to an array to prevent live updating of
// the list as we remove the spans
spans = Array.prototype.slice.call(spans, 0);
for (var i = 0, len = spans.length; i < len; ++i) {
span = spans[i];
parentNode = span.parentNode;
parentNode.insertBefore(span.firstChild, span);
parentNode.removeChild(span);
// Glue any adjacent text nodes back together
parentNode.normalize();
}
}
var c;
</script>
<input type="button" onclick="c = applyClassToSelection('someclass')"
value="Add class">
<input type="button" onclick="removeSpansWithClass(c)"
value="Remove class">
감사합니다. 이것은 내가 원하는 것 이상입니다. – drawnonward
아마도 이것을 github에 넣을 수 있습니다. – Mark
개선 된 버전이 포함될 크로스 브라우저 범위/선택 라이브러리에서 작업 중입니다. 아직 진행 단계는 아니지만 다음과 같이 Google 코드 프로젝트를 만들었습니다. http://code.google.com/p/rangy/ –