Issues with Javascript Selection API with Chrome (setBaseAndExtent method)

116 Views Asked by At

I am facing a very strange issue with the Selection API (https://developer.mozilla.org/en-US/docs/Web/API/Selection) on Chrome. I think I am using the API correctly, and tried different things but I always end up with the same outcome.

Considering the example HTML page below, with some static behaviour, the backwards selection doesn't work correclty: I always get the focus back to the right-most span element. (To get the Selection API running on this example, for a backwards selection, press the left key at the beginning of the right-most span element, the one with "abc..").

It doesn't seem to be something already mentioned on forums, so I must be doing something wrong but... I can't find out why. Firefox works as I expect: running that example, I get the caret and focus on the first span (the one with numbers).

Thanks a lot for your help!

<html>
<head>
</head>
<body>
<div id="parent1">
    <span id="span0" contenteditable="true" onfocus="onFocus('span0')" onblur="onBlur('span0')">987654</span>
    <span>+</span>
    <span id="span1" contenteditable="true" onfocus="onFocus('span1')" onblur="onBlur('span1')">1234 6789</span>
    <span>µ</span>
    <span id="span2" contenteditable="true"onfocus="onFocus('span2')" onblur="onBlur('span2')">abcdefg</span>
</div>
<br><br>
<button onclick="doForwardSelection()">click</button>

<script>
span0 = document.getElementById("span0");
span2 = document.getElementById("span2");

function onFocus(id){
    console.log("FOCUS on " + id);
}

function onBlur(id){
    console.log("BLUR on " + id);
}

function doForwardSelection(){
    docSel = document.getSelection();
    
    // remove existing selection
    docSel.removeAllRanges();
    
    // set a new forward selection
    docSel.setBaseAndExtent(span0.firstChild, 1, span2.firstChild, 2);
}

function onKeyDown(event){
    //console.log(event);
    if(event.key == "ArrowLeft" && document.getSelection().getRangeAt(0).startOffset == 0){
        event.stopImmediatePropagation();
        event.stopPropagation();
        event.preventDefault();
        // Do the selection manually
        doMultiSelection();
    }
}

function doMultiSelection(){
    docSel = document.getSelection();
    // first focus target
    span0.focus();
    console.log(docSel)
    // then do the extent
    console.log("I call Selection.setBaseAndExtent() now...")
    //docSel.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
    docSel.setBaseAndExtent(span2.firstChild, 2, span0.firstChild, 1);
    console.log(docSel);
}


document.getElementById("span2").addEventListener('keydown', onKeyDown);

</script>
</body>
</html>                   
1

There are 1 best solutions below

0
On

So, I think I understand why what I tried didn't work. The selection I want to make isn't in a single editable element (multiple spans), and their common ancestor isn't an editable element (div).

If I changed things by setting the div parent editable (contenteditable="true"), I can do the selection as I wanted to.

Based on the documentation on MDN, it may explain why Chrome behaved the way it did with my initial example.