修改 HTML 后无法恢复选择,即使是相同的 HTML
我正在尝试存储一个 contentEditable 元素的选择并稍后恢复它.
I'm trying to store a selection of a contentEditable element and restore it later.
我想观察 paste
事件并像以前一样存储 HTML,清除 html 然后在所选位置手动插入粘贴的文本并进行一些更改.
I want to observe the paste
event and store the HTML as it was before, clear the html and then manually insert the pasted text with some changes at the selected position.
看看这个例子:jsfiddle.net/gEhjZ
当您选择文本的一部分时,点击 store
,再次删除选择并点击 restore
,它按预期工作.
When you select a part of the text, hit store
, remove the selection again and hit restore
, it's working as expected.
但是当你第一次点击 store
时,然后通过点击 overwrite html
将 HTML 替换为完全相同的 HTML,然后尝试 restore
,什么都没有发生.
But when you first hit store
, then replace the HTML with the exact same HTML by hitting overwrite html
and then try to restore
, nothing happens.
我认为使用 .cloneRange()
会有所作为,但事实并非如此.即使是对象的深层副本 ($.extend(true, {}, oldRange)
) 也无法解决问题.一旦我覆盖 HTML,选择对象 sel
也会被更改.更改选择上下文将擦除范围对我来说很有意义,但我正在尝试将其恢复为完全相同的 HTML.
I thought that using .cloneRange()
would make a difference, but it won't. Even a deep copy of the object ($.extend(true, {}, oldRange)
) won't do the trick. As soon as I overwrite the HTML, the selection object sel
is being changed too. It makes sense for me that changing the selection context will wipe the range, but I'm trying to restore it for the exact same HTML.
我知道我可以使用 rangy,但我真的不想使用巨大的图书馆只是为了这个小功能.我错过了什么?任何帮助将不胜感激!
I know I could use rangy, but I really don't want to use a huge library just for this small feature. What am I missing? Any help would be much appreciated!
注意:仅适用于 Firefox/Chrome,因此无需跨浏览器破解.
Note: only Firefox/Chrome, so no crossbrowser-hacks needed.
@Tim Down 的答案在使用 div 时有效,但我实际上使用的是 iframe.当我做这个例子时,我认为它不会有任何区别.
@Tim Down's answer works when using a div, but I'm actually using an iframe. When I made that example, I thought it wouldn't make any difference.
现在,当我尝试恢复 iframe 的主体时,我收到以下错误:TypeError: Value does not implement interface Node.
in the following line preSelectionRange.selectNodeContents(containerEl);代码>.我没有从谷歌搜索中得到太多.我试图包装正文的内容并恢复包装的html,但我得到了同样的错误.
Now when I try to restore the iframe's body, i get the following error: TypeError: Value does not implement interface Node.
in the following line preSelectionRange.selectNodeContents(containerEl);
. I didn't get much from googling. I tried to wrap the contents of the body and restore the wrap's html, but I get the same error.
jsfiddle 在这种情况下不起作用,因为它使用 iframe 来显示结果本身,所以我在这里举了一个例子:snipt.org/AJad3
jsfiddle isn't working in this case because it is using iframes to display the results itself, so I put an example here: snipt.org/AJad3
没有包装也一样:snipt.org/AJaf0
更新 2:当然,我认为我必须使用 editable.get(0)
.但是现在 iframe 选择的 start
和 end
为 0.参见 snipt.org/AJah2
Update 2:
I figured that I have to use editable.get(0)
, of course. But now the start
and end
of the iframe's selection is 0. see snipt.org/AJah2
推荐答案
您可以使用以下函数保存和恢复字符位置:
You could save and restore the character position using functions like these:
https://stackoverflow.com/a/13950376/96100
我已经稍微调整了这些函数以适用于 iframe 中的元素.
I've adapted these function slightly to work for an element inside an iframe.
演示:http://jsfiddle.net/timdown/gEhjZ/4/
代码:
var saveSelection, restoreSelection;
if (window.getSelection && document.createRange) {
saveSelection = function(containerEl) {
var doc = containerEl.ownerDocument, win = doc.defaultView;
var range = win.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
};
};
restoreSelection = function(containerEl, savedSel) {
var doc = containerEl.ownerDocument, win = doc.defaultView;
var charIndex = 0, range = doc.createRange();
range.setStart(containerEl, 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = win.getSelection();
sel.removeAllRanges();
sel.addRange(range);
};
} else if (document.selection) {
saveSelection = function(containerEl) {
var doc = containerEl.ownerDocument, win = doc.defaultView || doc.parentWindow;
var selectedTextRange = doc.selection.createRange();
var preSelectionTextRange = doc.body.createTextRange();
preSelectionTextRange.moveToElementText(containerEl);
preSelectionTextRange.setEndPoint("EndToStart", selectedTextRange);
var start = preSelectionTextRange.text.length;
return {
start: start,
end: start + selectedTextRange.text.length
};
};
restoreSelection = function(containerEl, savedSel) {
var doc = containerEl.ownerDocument, win = doc.defaultView || doc.parentWindow;
var textRange = doc.body.createTextRange();
textRange.moveToElementText(containerEl);
textRange.collapse(true);
textRange.moveEnd("character", savedSel.end);
textRange.moveStart("character", savedSel.start);
textRange.select();
};
}
相关文章