この回答はおそらく数年遅すぎますが、同様の問題に直面し、Google での最初のヒットであるため、ここに文書化したいと思いました。
繰り返しますが、問題は、次のように、ユーザー選択から Range オブジェクトをキャプチャして、スタイル付きの div で囲みたいということです。
function highlightSelection() {
var userSelection = window.getSelection().getRangeAt(0);
highlightRange(userSelection);
}
function highlightRange(range) {
var newNode = document.createElement("div");
newNode.setAttribute(
"style",
"background-color: yellow; display: inline;"
);
range.surroundContents(newNode);
}
しかし、元の親が述べているように、これは安全ではありません。選択が要素の境界を越えない場合は機能しますが、ユーザー選択によって作成された範囲が HTML タグの境界を越える危険な範囲である場合、DOM エラーが発生します。
解決策は、より小さな Range オブジェクトの配列を生成することです。いずれも個別に要素バリアを越えることはありませんが、ユーザーが選択した Range を集合的にカバーします。これらの安全な範囲のそれぞれは、上記のように強調表示できます。
function getSafeRanges(dangerous) {
var a = dangerous.commonAncestorContainer;
// Starts -- Work inward from the start, selecting the largest safe range
var s = new Array(0), rs = new Array(0);
if (dangerous.startContainer != a)
for(var i = dangerous.startContainer; i != a; i = i.parentNode)
s.push(i)
;
if (0 < s.length) for(var i = 0; i < s.length; i++) {
var xs = document.createRange();
if (i) {
xs.setStartAfter(s[i-1]);
xs.setEndAfter(s[i].lastChild);
}
else {
xs.setStart(s[i], dangerous.startOffset);
xs.setEndAfter(
(s[i].nodeType == Node.TEXT_NODE)
? s[i] : s[i].lastChild
);
}
rs.push(xs);
}
// Ends -- basically the same code reversed
var e = new Array(0), re = new Array(0);
if (dangerous.endContainer != a)
for(var i = dangerous.endContainer; i != a; i = i.parentNode)
e.push(i)
;
if (0 < e.length) for(var i = 0; i < e.length; i++) {
var xe = document.createRange();
if (i) {
xe.setStartBefore(e[i].firstChild);
xe.setEndBefore(e[i-1]);
}
else {
xe.setStartBefore(
(e[i].nodeType == Node.TEXT_NODE)
? e[i] : e[i].firstChild
);
xe.setEnd(e[i], dangerous.endOffset);
}
re.unshift(xe);
}
// Middle -- the uncaptured middle
if ((0 < s.length) && (0 < e.length)) {
var xm = document.createRange();
xm.setStartAfter(s[s.length - 1]);
xm.setEndBefore(e[e.length - 1]);
}
else {
return [dangerous];
}
// Concat
rs.push(xm);
response = rs.concat(re);
// Send to Console
return response;
}
次に、この変更されたコードを使用して、ユーザー選択を強調表示 (表示) することができます。
function highlightSelection() {
var userSelection = window.getSelection().getRangeAt(0);
var safeRanges = getSafeRanges(userSelection);
for (var i = 0; i < safeRanges.length; i++) {
highlightRange(safeRanges[i]);
}
}
ユーザーが一緒に見栄えのする多くの異なる要素を作成するには、おそらくより洗練された CSS が必要になることに注意してください。最終的に、これがインターネット上の他の疲れた魂に役立つことを願っています!