HTML修改后无法恢复选择,即使它是相同的HTML [英] Can't restore selection after HTML modify, even if it's the same HTML

查看:124
本文介绍了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然后尝试restore,将HTML替换为完全相同的HTML,没有任何反应.

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的主体时,在以下行preSelectionRange.selectNodeContents(containerEl);中收到以下错误:TypeError: Value does not implement interface Node..我从谷歌搜索中得到的并不多.我尝试包装正文的内容并恢复包装的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

And the same without the wrap: snipt.org/AJaf0

更新2: 我想当然必须使用editable.get(0).但是现在iframe选择的startend为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();
    };
}

这篇关于HTML修改后无法恢复选择,即使它是相同的HTML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆