Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying innerHTML in a contentEditable="true" DIV causes loss of focus or wrong selection

Here is the full page:

<html>
<head>
<title>Test</title>
<style type="text/css">
  .edit { border: 1px solid blue; font-size: 20pt }
</style>
<script type="text/javascript">
  function clean(id) {
    setTimeout('clean2("'+id+'")', 1)
  }
  function clean2(id) {
    el=document.getElementById(id)
    off=window.getSelection().anchorOffset
    el.innerHTML = el.innerHTML.replace(/(<([^>]+)>)/ig,""); 
    el.innerHTML = el.innerHTML.replace(/([0-9])/ig,"<font color='red'>$1</font>");
    return false;
  }
</script>
</head>

<body onload="document.getElementsByClassName('edit')[0].focus()">

<h1>Type in here</h1>
<div id="e1" class="edit" contentEditable="true" onkeyup="clean('e1')"></div>

</body>
</html>

The goal here is to highlight all numbers in red. (In the future I will actually use a little more complicated coloring rules). Currently this color substitution is happening, but as soon as you add a number to the box, focus is lost.

Any hints? (Using Chorme dev)

like image 644
William Entriken Avatar asked Sep 07 '25 14:09

William Entriken


2 Answers

Focus is being lost because clean2() manipulates the div. In FF the caret gets reset to the beginning of the editable div for the same reason. You can force the focus to stay by manually calling el.focus() in clean2(), however this will not fix the caret issue. You can set the caret position with something like:

window.getSelection().removeAllRanges();
var range = document.createRange();
range.setStart(el,start)
range.setEnd(el,start);
window.getSelection().addRange(range);

However, this wont work for you because the "el" you need to set the cursor position in is the newly created text node. Unfortunately, the type of syntax highlighting you are trying to do is very complicated. If you wish to pursue it, check out:

Set cursor position on contentEditable <div>

Get caret position in contentEditable div

like image 59
jordancpaul Avatar answered Sep 09 '25 04:09

jordancpaul


If you have to manipulate innerHTML like that, I'd suggest using the selection save and restore module from my Rangy library, which uses invisible elements to mark the beginning and end of the selection.

like image 25
Tim Down Avatar answered Sep 09 '25 05:09

Tim Down