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