I have this contentedittable div
<div contenteditable="true" id="text">minubyv<img src="images/smiley/Emoji Smiley-01.png" class="emojiText" />iubyvt</div>
Here is an image description of the code output
so I want to get the caret position of the div and lets assume that the cursor is after the last character. And this is my code for getting the caret position
function getCaretPosition(editableDiv) {
var caretPos = 0,
sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
if (range.commonAncestorContainer.parentNode == editableDiv) {
caretPos = range.endOffset;
}
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
if (range.parentElement() == editableDiv) {
var tempEl = document.createElement("span");
editableDiv.insertBefore(tempEl, editableDiv.firstChild);
var tempRange = range.duplicate();
tempRange.moveToElementText(tempEl);
tempRange.setEndPoint("EndToEnd", range);
caretPos = tempRange.text.length;
}
}
return caretPos;
}
var update = function() {
console.log(getCaretPosition(this));
};
$('#text').on("mousedown mouseup keydown keyup", update);
But the problem is that it returns 6
instead of 14
. The caret position goes back to 0
after the image. Please is there a way I can get the caret position to be 14
in this case.
EDIT
I want to also insert some element starting from the caret position. so this is my function to do that
selectStart = 0;
var update = function() {
selectStart = getCaretPosition(this);
};
function insertEmoji(svg){
input = $('div#text').html();
beforeCursor = input.substring(0, selectStart);
afterCursor = input.substring(selectStart, input.length);
emoji = '<img src="images/smiley/'+svg+'.png" class="emojiText" />';
$('div#text').html(beforeCursor+emoji+afterCursor);
}
See Tim Down's answer on Get a range's start and end offset's relative to its parent container.
Try to use the function he has to get the selection index with nested elements like this:
I wrote my own function, based on Tim Down's, that works like you want it. I changed the
treeWalker
to filterNodeFilter.ELEMENT_NODE
insted ofNodeFilter.SHOW_TEXT
, and now<img/>
elements also get processed inside our loop. I start by storing therange.startOffset
and then recurse through all the selection tree nodes. If it finds animg
node, then it adds just 1 to the position; if the current node element is different than ourrange.startContainer
, then it adds that node's length. The position is altered by a different variablelastNodeLength
that is adds to thecharCount
at each loop. Finally, it adds whatever is left in thelastNodeLength
to thecharCount
when it exists the loop and we have the correct final caret position, including image elements.Final working code (it returns 14 at the end, exactly as it should and you want)