I am after a definitive, cross-browser solution to set the cursor/caret position to the last known position when a contentEditable='on' <div> regains focus. It appears default functionality of a content editable div is to move the caret/cursor to the beginning of the text in the div each time you click on it, which is undesirable.
I believe I would have to store in a variable the current cursor position when they are leaving focus of the div, and then re-set this when they have focus inside again, but I have not been able to put together, or find a working code sample yet.
If anybody has any thoughts, working code snippets or samples I'd be happy to see them.
I don't really have any code yet but here is what I do have:
<script type="text/javascript">
// jQuery
$(document).ready(function() {
$('#area').focus(function() { .. } // focus I would imagine I need.
}
</script>
<div id="area" contentEditable="true"></div>
PS. I have tried this resource but it appears it does not work for a <div>. Perhaps only for textarea (How to move cursor to end of contenteditable entity)
Update
I've written a cross-browser range and selection library called Rangy that incorporates an improved version of the code I posted below. You can use the selection save and restore module for this particular question, although I'd be tempted to use something like @Nico Burns's answer if you're not doing anything else with selections in your project and don't need the bulk of a library.
Previous answer
You can use IERange (http://code.google.com/p/ierange/) to convert IE's TextRange into something like a DOM Range and use it in conjunction with something like eyelidlessness's starting point. Personally I would only use the algorithms from IERange that do the Range <-> TextRange conversions rather than use the whole thing. And IE's selection object doesn't have the focusNode and anchorNode properties but you should be able to just use the Range/TextRange obtained from the selection instead.I might put something together to do this, will post back here if and when I do.
EDIT:
I've created a demo of a script that does this. It works in everything I've tried it in so far except for a bug in Opera 9, which I haven't had time to look into yet. Browsers it works in are IE 5.5, 6 and 7, Chrome 2, Firefox 2, 3 and 3.5, and Safari 4, all on Windows.
http://www.timdown.co.uk/code/selections/
Note that selections may be made backwards in browsers so that the focus node is at the start of the selection and hitting the right or left cursor key will move the caret to a position relative to the start of the selection. I don't think it is possible to replicate this when restoring a selection, so the focus node is always at the end of the selection.
I will write this up fully at some point soon.
This is compatible with the standards-based browsers, but will probably fail in IE. I'm providing it as a starting point. IE doesn't support DOM Range.
This solution works in all major browsers:
saveSelection()
is attached to theonmouseup
andonkeyup
events of the div and saves the selection to the variablesavedRange
.restoreSelection()
is attached to theonfocus
event of the div and reselects the selection saved insavedRange
.This works perfectly unless you want the selection to be restored when the user clicks the div aswell (which is a bit unintuitative as normally you expect the cursor to go where you click but code included for completeness)
To achieve this the
onclick
andonmousedown
events are canceled by the functioncancelEvent()
which is a cross browser function to cancel the event. ThecancelEvent()
function also runs therestoreSelection()
function because as the click event is cancelled the div doesn't receive focus and therefore nothing is selected at all unless this functions is run.The variable
isInFocus
stores whether it is in focus and is changed to "false"onblur
and "true"onfocus
. This allows click events to be cancelled only if the div is not in focus (otherwise you would not be able to change the selection at all).If you wish to the selection to be change when the div is focused by a click, and not restore the selection
onclick
(and only when focus is given to the element programtically usingdocument.getElementById("area").focus();
or similar then simply remove theonclick
andonmousedown
events. Theonblur
event and theonDivBlur()
andcancelEvent()
functions can also safely be removed in these circumstances.This code should work if dropped directly into the body of an html page if you want to test it quickly:
I had a related situation, where I specifically needed to set the cursor position to the END of a contenteditable div. I didn't want to use a full fledged library like Rangy, and many solutions were far too heavyweight.
In the end, I came up with this simple jQuery function to set the carat position to the end of a contenteditable div:
The theory is simple: append a span to the end of the editable, select it, and then remove the span - leaving us with a cursor at the end of the div. You could adapt this solution to insert the span wherever you want, thus putting the cursor at a specific spot.
Usage is simple:
That's it!
I took Nico Burns's answer and made it using jQuery:
div contentEditable="true"
You'll need jQuery 1.6 or higher:
After playing around I've modified eyelidlessness' answer above and made it a jQuery plugin so you can just do one of these:
Excuse the long code post, but it may help someone: