I am faced with following: when I try to select text in a contenteditable
element and the end of the selection is the start of the element content, then no select event is fired and there are no Selection
and Range
objects.
Could somebody please give me any advice on why this might occur or how I can prevent this?
Code responsible for getting selection range:
$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
lastCaretIndex = getSelectionRange();
});
function getSelectionRange() {
var sel;
if (window.getSelection) {
sel = window.getSelection();
console.log(sel); // this doesn't print anything event empty string
if (sel.rangeCount) {
return sel.getRangeAt(0);
}
} else if (document.selection) {
return document.createRange();
}
return null;
}
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
JSFiddle (open your browser console to make sure that selection doesn't get logged).
The issue is that you only log selection changes when specific events occur on the
contenteditable
element. More specifically, you haveIn particular the
mouseup
event will normally be triggered when the selection changes. Except when it doesn't. When you release the mouse outside of the editablediv
(which you do in your example!), then thediv
will never receive amouseup
event and thus never log the selection.There are two ways around this:
body
. Downsides are that you receive more events that do not influence the selection and that it is still possible to getmouseup
events outside of the page.selectionchange
event.You can of course still access the selection as you currently do inside this event handler. This event is triggered every time the selection changes, so you may want to throttle it.
Full implementation of that can be found below.
Your actual code works perfectly and logs a Selection object in the console, even if the end of the selection is the start of the element content.
Indeed you need to log this
Selection
text instead of logging the wholeobject
which reflects the whole Selection object changes for each event.I updated your snippet to log the text of the selection using
Selection.toString()
, you can see it working here:You can check this answer, it shows and explains the perfect way to get text selection.