Obtenir la position du curseur dans contentEditable div
Je trouve des tonnes de bons anwers crossbrowser sur la façon de définir la position du curseur ou du curseur dans un DIV contentEditable, mais aucun sur la façon d'obtenir ou de trouver sa position...
Ce que je veux faire est de connaître la position du curseur dans cette div, sur keyup.
Ainsi, lorsque l'utilisateur tape du texte, je peux à tout moment connaître la position de son curseur dans le div.
EDIT: je cherche l'INDEX dans le contenu div (texte), pas les coordonnées du curseur.
<div id="contentBox" contentEditable="true"></div>
$('#contentbox').keyup(function() {
// ... ?
});
6 réponses
Le code suivant suppose:
- Il y a toujours un seul nœud de texte dans l'éditable
<div>
et aucun autre nœud - le div modifiable n'a pas la propriété CSS
white-space
définie surpre
Code:
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;
}
#caretposition {
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="contentbox" contenteditable="true">Click me and move cursor with keys or mouse</div>
<div id="caretposition">0</div>
<script>
var update = function() {
$('#caretposition').html(getCaretPosition(this));
};
$('#contentbox').on("mousedown mouseup keydown keyup", update);
</script>
Essayez ceci:
Caret.js Obtenir la position du caret et le décalage du champ de texte
$("#editable").on('keydown keyup mousedown mouseup',function(e){
if($(window.getSelection().anchorNode).is($(this))){
$('#position').html('0')
}else{
$('#position').html(window.getSelection().anchorOffset);
}
});
body{
padding:40px;
}
#editable{
height:50px;
width:400px;
border:1px solid #000;
}
#editable p{
margin:0;
padding:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<div contenteditable="true" id="editable">move the cursor to see position</div>
<div>
position : <span id="position"></span>
</div>
//global savedrange variable to store text range in
var savedrange = null;
function getSelection()
{
var savedRange;
if(window.getSelection && window.getSelection().rangeCount > 0) //FF,Chrome,Opera,Safari,IE9+
{
savedRange = window.getSelection().getRangeAt(0).cloneRange();
}
else if(document.selection)//IE 8 and lower
{
savedRange = document.selection.createRange();
}
return savedRange;
}
$('#contentbox').keyup(function() {
var currentRange = getSelection();
if(window.getSelection)
{
//do stuff with standards based object
}
else if(document.selection)
{
//do stuff with microsoft object (ie8 and lower)
}
});
Remarque: l'objet range lui-même peut être stocké dans une variable, et peut être re-sélectionné à tout moment à moins que le contenu de la div contenteditable change.
Référence pour IE 8 et inférieur: http://msdn.microsoft.com/en-us/library/ms535872 (VS.85).aspx
Référence pour les navigateurs standards (tous les autres) : https://developer.mozilla.org/en/DOM/range (c'est les documents mozilla, mais le code fonctionne aussi dans chrome, safari, opera et ie9)
Celui-ci fonctionne pour moi:
function getCaretCharOffsetInDiv(element) {
var caretOffset = 0;
if (typeof window.getSelection != "undefined") {
var range = window.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
else if (typeof document.selection != "undefined" && document.selection.type != "Control")
{
var textRange = document.selection.createRange();
var preCaretTextRange = document.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
La ligne d'appel dépend du type d'événement, pour l'événement clé, utilisez ceci:
getCaretCharOffsetInDiv(e.target) + ($(window.getSelection().getRangeAt(0).startContainer.parentNode).index());
Pour l'événement de la souris, utilisez ceci:
getCaretCharOffsetInDiv(e.target.parentElement) + ($(e.target).index())
Sur ces deux cas, je prends soin des lignes de rupture en ajoutant l'index cible
function getCaretPosition() {
var x = 0;
var y = 0;
var sel = window.getSelection();
if(sel.rangeCount) {
var range = sel.getRangeAt(0).cloneRange();
if(range.getClientRects()) {
range.collapse(true);
var rect = range.getClientRects()[0];
if(rect) {
y = rect.top;
x = rect.left;
}
}
}
return {
x: x,
y: y
};
}