Этот ответ, вероятно, на несколько лет опоздал для вас, но я столкнулся с подобной проблемой и хотел документировать ее здесь, поскольку это первый хит в 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);
}
Но, как заявляет Первоначальный Родитель, это небезопасно. Это сработает, если выделение не пересекает границы элементов, но выдает ошибку DOM, если диапазон, созданный с помощью выбора пользователя, является небезопасным диапазоном, пересекающим границы тегов HTML.
Решение состоит в том, чтобы создать массив меньших объектов 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 для создания множества разнородных элементов, с которыми пользователь мог бы хорошо выглядеть вместе. Я надеюсь, что в конечном итоге это поможет другой уставшей душе в интернете!