Created
October 7, 2021 13:08
-
-
Save mzechmeister/e0c55a237f15071575a6b482785ee3e9 to your computer and use it in GitHub Desktop.
handling caret contenteditable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<style> | |
div {background-color: #dfd; width:300px;} | |
span {background-color: #fbb;} | |
span:nth-child(even) {background-color: #ccf;} | |
input {width:90%; font-size: 11px;} | |
</style> | |
<body> | |
Works good with firefox. Android chrome has another behaviour. | |
<div id="div1" contenteditable onkeydown="check_caret(event)" onkeyup="focusToChild(event)"><span>START</span>Here <span>mark_active()+check_caret()</span> lets appear the span focussed <span>set</span><span>caret</span> (indicated by the border when active). <span>END</span></div> | |
<script> | |
for (x of document.getElementById("div1").children) | |
x.tabIndex = -1 | |
function focusToChild(e) { | |
// focus to child | |
var sel = window.getSelection() | |
var foc = sel.focusNode.parentElement | |
if (foc.tagName == "SPAN") // && foc.parentElement==e.target) | |
foc.focus() | |
} | |
function check_caret(e) { | |
var sel = window.getSelection() | |
var foc = sel.focusNode.parentElement | |
if (e.key == 'ArrowRight') { | |
if (sel.focusOffset == sel.focusNode.length-1) { | |
// work around that the last element is not covered | |
e.preventDefault() // do not blur | |
setCaret(sel.focusNode, sel.focusNode.length) | |
} else if (sel.focusOffset == sel.focusNode.length) { | |
if (foc.nextSibling == foc.nextElementSibling) { | |
// next element is again a contain not text | |
// focus between the two elements first | |
childnum = [...foc.parentNode.childNodes].indexOf(foc) | |
setCaret(div1, childnum+1) | |
e.preventDefault() | |
} else | |
e.target.parentElement.focus() | |
} | |
} else if (e.key == 'ArrowLeft') { | |
if (sel.focusOffset == 0) { | |
if (foc.previousSibling == foc.previousElementSibling) { | |
// next element is again a contain not text | |
// focus between the two elements first | |
childnum = [...foc.parentNode.childNodes].indexOf(foc) | |
setCaret(div1, childnum) | |
//setCaret(sel.focusNode.parentNode, 1) | |
//e.target.parentElement.focus() | |
e.preventDefault() | |
} else | |
e.target.parentElement.focus() | |
} | |
} | |
} | |
var selection = window.getSelection() | |
function setCaret(elem, pos=0) { | |
var range = document.createRange() // Create a range (a range is a like the selection but invisible) | |
range.selectNodeContents(elem) // Select the entire contents of the element with the range | |
range.setStart(elem, pos) | |
range.collapse(true) // Collapse the range to the end point. false means collapse to end rather than the start object (allows you to change selection) | |
selection.removeAllRanges() // Remove any selections already made | |
selection.addRange(range) // Make the range you have just created the visible selection | |
elem.parentElement.focus() | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment