Discontigious Selection is not supported error in google chrome and chromium

10,419

Solution 1

Write

window.getSelection().removeAllRanges();

immediately before creating range.

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

Solution 2

Here's the only possible way of doing this that I was able to come up with:

Wrap the selection in <span style="background: Highlight;">...</span>.

But note:

  • Obviously, you have to remove those spans again as soon as anything else is selected, but that shouldn't be too difficult. However, you should use window.onmousedown for that rather than window.onclick, because onclick is fired after any button is pressed, so when pressing your "Show stored selections" button, a new selection will be created, thus destroying the one that was supposed to be captured.
  • Removing or replacing any elements in which a stored selection starts or ends will invalidate that selection, so when clicking "Show stored selections", nothing will show up.
  • If the selection spans over multiple elements, it needs to split up into one selection for each element, otherwise inserting the span will either fail or cut other elements (like buttons) in half.

The following code (fiddle) is the best I was able to do:

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 = [];
}
.highlight
{
    background: Highlight;
}
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>

It works in Firefox, Safari and Chrome, but has the following shortcomings:

  • Selections over multiple lines don't select the blank area between the end of the line and the border of the parent element, like actual selections do.
  • Sometimes when starting a selection at a point before the start of a stored selection, displaying them will merge the ranges, so the text in between is selected too. Sorting the array of stored selections doesn't seem to help.
  • In Safari, the tab crashed multiple times with a segmentation fault when selecting multiple lines and ending/starting a selection in the middle of a button's text.

However, I doubt that anything better is possible in browsers other than Firefox, but even Firefox has a ticket to drop discontiguous selections.

Solution 3

FYI I was getting a similar error when rolling my own "copy to clipboard" feature. I'm not going to address OP's provided code, but I'll tell you how I fixed it in my own code.

Reproduce:

  1. Copy some other text on the page to the clipboard, e.g. "foo".
  2. Paste the text somewhere. It outputs "foo".
  3. Click your "copy to clipboard" button, which copies e.g. "bar".
  4. Paste the text somewhere.

Expected:

"bar" is outputted.

Actual:

"Discontiguous selection is not supported"

Fix:

Call window.getSelection().removeAllRanges() at the start of your "copy to clipboard" event handler. "Discontiguous" means "not connected". So my guess is that the browser copies the first range (the node containing "foo"), and then gets angry when you try to select another range that is not next to the first node.

Share:
10,419

Related videos on Youtube

Sajid Ahmad
Author by

Sajid Ahmad

Updated on July 18, 2022

Comments

  • Sajid Ahmad
    Sajid Ahmad almost 2 years

    I am working on a bookmark app where i have to store the user's selected keywords or words or content. I am using the createRange() and addRange() javascript methods to create the range and then find out the selected elements/contents by the user. The code i written for this is as follow.

    <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>
    

    This code is working perfectly on Firefox. I am able to select multiple things one by one and able to show the selected content again but on chrome and chromium i am getting Discontiguous selection is not supported. error when i store more than one elements in range array and click on show stored selections button.

    Help will be appreciated. And please suggest me if there is some other alternatives do accomplish this bookmarking task.

  • Adam Clark
    Adam Clark over 7 years
    this error comes up when you have the device toolbar toggled and refresh in chrome
  • Adam Clark
    Adam Clark over 7 years
    after a refresh in device toolbar devtools that error comes up.dropbox.com/s/ngab9c9ydy1r9ye/…
  • Siguza
    Siguza over 7 years
    @AdamClark I'm fairly certain that isn't caused by my code. Link to full code?
  • Adam Clark
    Adam Clark over 7 years
    No, certainly not. I got this error this afternoon and started investigating.. This was the first stackoverflow question I saw and felt like anyone else looking for similar reasons would appreciate my insight.
  • Rav
    Rav about 7 years
    Perfect, it works for me and this answer is so much simpler than others.
  • Dropout
    Dropout about 7 years
    The bug might be fixed, as of 20Feb - bugs.chromium.org/p/chromium/issues/detail?id=353069#c4