I have div with some text and contenteditable="true". When I single click on this div - works some my scripts, it is not very important. And when I double click on this div - need to edit text in div. Edit text need to be only after double click, not after single. And very imortant, when I double click on div - caret need stay under mouse cursor. No need selection text. I found some script for single/double. But have problem. When I double click on div - text are selection. Selection no need. Need editor caret where I clicked. I do not understand how. http://jsfiddle.net/X6auM/
Asked
Active
Viewed 1.1k times
9
-
Single-click-to edit is the expected result for `contenteditable` element. If you want to use double-click, set the `contenteditable` *only* when the element is double-clicked. Once editable, focus to the element, then set the caret based on the mouse position from the double-click event. Finally, when focus is lost, disable the `contenteditable`. – Jay Oct 16 '12 at 18:16
-
1I do not understand how to place the cursor exactly at the place where there was a click. This with .focus(). But caret go to start of line. http://jsfiddle.net/jupUh/ – Alex-cr Oct 16 '12 at 18:27
-
How can I find the position of caret if it has not been in div? – Alex-cr Oct 16 '12 at 18:36
-
I found script which get caret position. Script works but not in this situation. http://jsfiddle.net/9Z3bp/1/ – Alex-cr Oct 16 '12 at 19:18
3 Answers
27
Every current major browser provides an API to create a range from a mouse event, although there are four different code branches needed.
Here is some background:
- https://stackoverflow.com/a/10659990/96100
- https://stackoverflow.com/a/12705894/96100
- Creating a collapsed range from a pixel position in FF/Webkit
Here's a demo: http://jsfiddle.net/timdown/krtTD/10/
And here's some code:
function getMouseEventCaretRange(evt) {
var range, x = evt.clientX, y = evt.clientY;
// Try the simple IE way first
if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToPoint(x, y);
}
else if (typeof document.createRange != "undefined") {
// Try Mozilla's rangeOffset and rangeParent properties,
// which are exactly what we want
if (typeof evt.rangeParent != "undefined") {
range = document.createRange();
range.setStart(evt.rangeParent, evt.rangeOffset);
range.collapse(true);
}
// Try the standards-based way next
else if (document.caretPositionFromPoint) {
var pos = document.caretPositionFromPoint(x, y);
range = document.createRange();
range.setStart(pos.offsetNode, pos.offset);
range.collapse(true);
}
// Next, the WebKit way
else if (document.caretRangeFromPoint) {
range = document.caretRangeFromPoint(x, y);
}
}
return range;
}
function selectRange(range) {
if (range) {
if (typeof range.select != "undefined") {
range.select();
} else if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
}
}
document.getElementById("editor").ondblclick = function(evt) {
evt = evt || window.event;
this.contentEditable = true;
this.focus();
var caretRange = getMouseEventCaretRange(evt);
// Set a timer to allow the selection to happen and the dust settle first
window.setTimeout(function() {
selectRange(caretRange);
}, 10);
return false;
};
-
It's amazing! Yesterday I made a few other methods. But does not work very well. Your version works fine. Thank you! – Alex-cr Oct 17 '12 at 09:19
-
1
$('p').dblclick(function(event) {
$this = $(this);
$this.attr('contenteditable', "true");
$this.blur();
$this.focus();
});

Cihad
- 29
- 1
-
3A suggestion, your answer would be complete if you explained what you were doing as well. – Rohit Gupta Jul 01 '15 at 11:48
0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<!-- <link rel="stylesheet" href="../tailwind.css" /> -->
</head>
<body>
<div id="editor" style="user-select:none;" contenteditable="false">Some editableasa text. Double click to eadsit</div>
<script>
function getMouseEventCaretRange(evt) {
var range, x = evt.clientX, y = evt.clientY;
// Try the simple IE way first
if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToPoint(x, y);
}
else if (typeof document.createRange != "undefined") {
// Try Mozilla's rangeOffset and rangeParent properties, which are exactly what we want
if (typeof evt.rangeParent != "undefined") {
range = document.createRange();
range.setStart(evt.rangeParent, evt.rangeOffset);
range.collapse(true);
}
// Try the standards-based way next
else if (document.caretPositionFromPoint) {
var pos = document.caretPositionFromPoint(x, y);
range = document.createRange();
range.setStart(pos.offsetNode, pos.offset);
range.collapse(true);
}
// Next, the WebKit way
else if (document.caretRangeFromPoint) {
range = document.caretRangeFromPoint(x, y);
}
}
return range;
}
function selectRange(range) {
if (range) {
if (typeof range.select != "undefined") {
range.select();
} else if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
}
}
document.getElementById("editor").ondblclick = function (evt) {
evt = evt || window.event;
this.contentEditable = true;
this.focus();
var caretRange = getMouseEventCaretRange(evt);
selectRange(caretRange);
this.style = ""
};
</script>
</body>
</html>
An improvement of accepted answer that does not create the temp flash it uses css user-select property to it's advantage

Chetan Jain
- 236
- 6
- 16