I have this script adding a new span inside an editable div each time the user input a dot in the input text, trying to separate text written in different spans based on the presence of a dot separating them. (I use a custom tag 'mytag' but it behaves actually like a span)
<div style="border:1px solid black;" id='editor-container' contenteditable="true"><mytag id="0">test</mytag></div>
JS:
var divContainer = document.getElementById("editor-container");
var nodeIdIncrement = 0;
var htmlBefore = divContainer.innerHTML;
var html;
var editedCharIndex;
moveCursorOnDiv("0");
divContainer.addEventListener("input", function(e) {
html=divContainer.innerHTML;
editedCharIndex=findFirstDiffPos(htmlBefore,html);
console.log("html[editedCharIndex]: "+html[editedCharIndex]);
if(html[editedCharIndex]=="."){
nodeIdIncrement++;
htmlBefore=html.substring(0, editedCharIndex+1)+'</mytag><mytag id="'+nodeIdIncrement+'">'+html.substring(editedCharIndex+1);
divContainer.innerHTML = htmlBefore;
moveCursorOnDiv(nodeIdIncrement);
}else{
htmlBefore = divContainer.innerHTML;
}
}, false);
// Find index of newly added character making a diff between previuos situation and present one
function findFirstDiffPos(a, b) {
var shorterLength = Math.min(a.length, b.length);
for (var i = 0; i < shorterLength; i++){
if (a[i] !== b[i]) return i;
}
if (a.length !== b.length) return shorterLength;
return -1;
}
function moveCursorOnDiv(divId){
console.log("divId: "+divId);
var el = document.getElementById(divId);
console.log("inner: "+el.innerHTML);
var range = document.createRange();
var sel = window.getSelection();
range.setStart(el, 0);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
Here it is the JSFIDDLE
Let's say I input a char 'A' in the editable div "editor-container" the result will be:
<div style="border:1px solid black;" id="editor-container" contenteditable="true">
<mytag id="0">A</mytag>
</div>
Then I add a dot. The result will be:
<div style="border:1px solid black;" id="editor-container" contenteditable="true">
<mytag id="0">A.</mytag>
<mytag id="1"></mytag>
</div>
When the dot gets added, I force programatically (function moveCursorOnDiv) the cursor to move on the new div. The expected result would be that input an another character 'B' would result in situation:
<div style="border:1px solid black;" id="editor-container" contenteditable="true">
<mytag id="0">A.</mytag>
<mytag id="1">B</mytag>
</div>
Instead it actually result in Chrome in:
<div style="border:1px solid black;" id="editor-container" contenteditable="true">
<mytag id="0">A.B</mytag>
<mytag id="1"></mytag>
</div>
While in Firefox behaves as expected 90% of times, but sometimes randomly behaves as in Chrome.
So, if I have the cursor between two adjacent span how html decide if the next input will be put in a span or in the other? There's a way to force the expected behaviour?
EDIT: Pretty obviously, this happens only in case the following div is empty for there is ambiguity. If you put a char in the following div and move the caret in position '1' it works like a charm. (Just to say that the problem is not directly dependent from this specific code, which under different conditions works perfectly)
JSFIDDLE 2
This means also the problem can be solved adding something like a &nb sp; when adding a new div, but it not a clean solution.
First: You set <div id="editor-container".....> </div>
as editable so when you are typing .
it is creating a new <mytag>
with a new Id
but it is not giving an editable option to the new <mytag>
and as it is not editable the mouse pointer remains in the same position.
Here I made some changes: Added some border and margin so that it is visible
var divContainer = document.getElementById("editor-container");
var nodeIdIncrement = 0;
var htmlBefore = divContainer.innerHTML;
var html;
var editedCharIndex;
moveCursorOnDiv("0");
divContainer.addEventListener("input", function(e) {
html=divContainer.innerHTML;
editedCharIndex=findFirstDiffPos(htmlBefore,html);
console.log("html[editedCharIndex]: "+html[editedCharIndex]);
if(html[editedCharIndex]=="."){
nodeIdIncrement++;
htmlBefore=html.substring(0, editedCharIndex+1)+'</mytag><mytag id="'+nodeIdIncrement+'" contenteditable="true" style="margin: 10px;">'+html.substring(editedCharIndex+1);
divContainer.innerHTML = htmlBefore;
moveCursorOnDiv(nodeIdIncrement);
}else{
htmlBefore = divContainer.innerHTML;
}
}, false);
// Find index of newly added character making a diff between previuos situation and present one
function findFirstDiffPos(a, b) {
var shorterLength = Math.min(a.length, b.length);
for (var i = 0; i < shorterLength; i++){
if (a[i] !== b[i]) return i;
}
if (a.length !== b.length) return shorterLength;
return -1;
}
function moveCursorOnDiv(divId){
console.log("divId: "+divId);
var el = document.getElementById(divId);
console.log("inner: "+el.innerHTML);
var range = document.createRange();
var sel = window.getSelection();
range.setStart(el, 0);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
mytag {
border: 1px solid black;
}
<div id='editor-container'>
<mytag id="0" contenteditable="true">test</mytag>
</div>
In JS Made changes here:
htmlBefore=html.substring(0, editedCharIndex+1)+'</mytag><mytag id="'+nodeIdIncrement+'" contenteditable="true" style="margin: 10px; border: 1px solid black;">'+html.substring(editedCharIndex+1);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With