Google Chrome和Chrome不支持Discontigious Selection错误

时间:2015-01-29 12:39:57

标签: javascript jquery google-chrome firefox chromium

我正在开发一个书签应用程序,我必须存储用户选择的关键字或文字或内容。我使用createRange()和addRange()javascript方法创建范围,然后由用户找出所选元素/内容。我为此编写的代码如下。

<head>
<script type="text/javascript">
    var storedSelections = [];

    function StoreSelection () {
        if (window.getSelection) {
            var currSelection = window.getSelection ();
            for (var i = 0; i < currSelection.rangeCount; i++) {
                storedSelections.push (currSelection.getRangeAt (i));
            }
            currSelection.removeAllRanges ();
        } else {
            alert ("Your browser does not support this example!");
        }
    }

    function ClearStoredSelections () {
        storedSelections.splice (0, storedSelections.length);
    }

    function ShowStoredSelections () {
        if (window.getSelection) {
            var currSelection = window.getSelection ();
            currSelection.removeAllRanges ();
            for (var i = 0; i < storedSelections.length; i++) {
                currSelection.addRange (storedSelections[i]);
            }
        } else {
            alert ("Your browser does not support this example!");
        }
    }
</script>
</head>
<body>
    Select some content on this page and use the buttons below.<br />         <br />
    <button onclick="StoreSelection ();">Store the selection</button>
    <button onclick="ClearStoredSelections ();">Clear stored selections
</button>
    <button onclick="ShowStoredSelections ();">Show stored selections</button>

</body>

此代码在Firefox上完美运行。我可以逐个选择多个内容,并且能够再次显示所选内容但是在chrome和chromium上,当我在范围数组中存储多个元素并单击show stored selections按钮时,我收到Discontiguous selection is not supported.错误。

帮助将不胜感激。如果有其他替代方案可以完成此书签任务,请建议我。

3 个答案:

答案 0 :(得分:9)

window.getSelection().removeAllRanges();

在创建范围之前。

https://bugs.chromium.org/p/chromium/issues/detail?id=399791

答案 1 :(得分:6)

这是我能够做到这一点的唯一可行方法:

将选择内容包裹在<span style="background: Highlight;">...</span>

但请注意:

  • 显然,只要选择了其他任何内容,就必须再次删除这些跨度,但这不应该太困难。但是,您应该使用window.onmousedown而不是window.onclick,因为{/ 1}}在按下任何按钮后触发,因此当您按下&#34;显示时存储的选择&#34;按钮,将创建一个新的选择,从而摧毁应该被捕获的那个。
  • 删除或替换存储选择开始或结束的任何元素将使该选择无效,因此当点击&#34;显示存储的选择&#34;时,不会显示任何内容。
  • 如果选择跨越多个元素,则需要将每个元素拆分为一个选择,否则插入跨度将失败或将其他元素(如按钮)切成两半。

以下代码(fiddle)是我能做的最好的代码:

&#13;
&#13;
onclick
&#13;
var storedSelections = [];
var simulatedSelections = [];

window.onmousedown = clearSimulatedSelections;

function storeSelection()
{
    if(window.getSelection)
    {
        var currSelection = window.getSelection();
        for(var i = 0; i < currSelection.rangeCount; i++)
        {
            storeRecursive(currSelection.getRangeAt(i));
        }
        currSelection.removeAllRanges();
    }
    else
    {
        alert("Your browser does not support this example!");
    }
}

function storeRecursive(selection, node, started)
{
    node = node || document.body;
    started = started || false;
    var nodes = node.childNodes;
    for(var i = 0; i < nodes.length; i++)
    {
        if(nodes[i].nodeType == 3)
        {
            var first = nodes[i] == selection.startContainer;
            var last = nodes[i] == selection.endContainer;
            if(first)
            {
                started = true;
            }
            if(started)
            {
                var sel = selection.cloneRange();
                if(!first)
                {
                    sel.setStartBefore(nodes[i]);
                }
                if(!last)
                {
                    sel.setEndAfter(nodes[i]);
                }
                storedSelections.push(sel);
                if(last)
                {
                    return false;
                }
            }
        }
        else
        {
            started = storeRecursive(selection, nodes[i], started);
        }
    }
    return started;
}

function clearStoredSelections()
{
    storedSelections = [];
}

function showStoredSelections()
{
    if(window.getSelection)
    {
        var currSelection = window.getSelection();
        currSelection.removeAllRanges();
        for(var i = 0; i < storedSelections.length; i++)
        {
            var node = document.createElement("span");
            node.className = "highlight";
            storedSelections[i].surroundContents(node);
            simulatedSelections.push(node);
        }
    }
    else
    {
        alert("Your browser does not support this example!");
    }
}

function clearSimulatedSelections()
{
    for(var i = 0; i < simulatedSelections.length; i++)
    {
        var sec = simulatedSelections[i];
        var pn = sec.parentNode;
        while(sec.firstChild)
        {
            pn.insertBefore(sec.firstChild, sec);
        }
        pn.removeChild(sec);
    }
    simulatedSelections = [];
}
&#13;
.highlight
{
    background: Highlight;
}
&#13;
&#13;
&#13;

适用于Firefox,Safari和Chrome,但有以下缺点:

  • 多行选择不要选择行尾与父元素边框之间的空白区域,就像实际选择一样。
  • 有时,在存储选择开始之前的某个点开始选择时,显示它们将合并范围,因此也会选择其中的文本。对存储的选择数组进行排序似乎没有帮助。
  • 在Safari中,当选择多行并在按钮文本中间结束/开始选择时,选项卡会因分段错误而多次崩溃。

但是,我怀疑除了Firefox之外的其他浏览器有什么更好的方法,甚至是Firefox has a ticket to drop discontiguous selections

答案 2 :(得分:3)

仅供参考我在将自己的#34;副本复制到剪贴板时遇到了类似的错误。特征。我不打算解决OP提供的代码,但我会告诉您如何在我自己的代码中修复它。

重现:

  1. 将页面上的其他文字复制到剪贴板,例如&#34;富&#34;
  2. 将文字粘贴到某处。它输出&#34; foo&#34;。
  3. 点击你的&#34;复制到剪贴板&#34;按钮,例如&#34;杆&#34;
  4. 将文字粘贴到某处。
  5. 预期:

    &#34;杆&#34;输出。

    实际值:

    &#34;不支持不连续的选择&#34;

    修正:

    在你的&#34; <#>复制到剪贴板&#34;的开始处致电window.getSelection().removeAllRanges()事件处理程序&#34;不连续&#34;意味着&#34;没有连接&#34;。所以我的猜测是浏览器复制第一个范围(包含&#34; foo&#34;的节点),然后当你尝试选择另一个不在第一个节点旁边的范围时生气。