192 votes

Obtenir la position du caret contentEditable

Je trouve des tonnes de bonnes réponses, multi-navigateur, sur comment set la position du caret dans un contentEditable mais aucune sur la façon de obtenir la position du caret en premier lieu.

Ce que je veux faire, c'est connaître la position du caret dans un div sur keyup . Ainsi, lorsque l'utilisateur tape du texte, je peux, à tout moment, connaître la position du signe d'insertion dans l'image. contentEditable élément.

<div id="contentBox" contentEditable="true"></div>

$('#contentbox').keyup(function() { 
    // ... ? 
});

0 votes

Regardez sa position dans le texte. Ensuite, recherchez la dernière occurrence de '@' avant cette position. Donc, juste un peu de logique de texte.

0 votes

De plus, je ne prévois pas d'autoriser d'autres balises à l'intérieur du <diV>, seulement du texte.

0 votes

Ok, oui je Je suis going to need other tags within the <div>. Il y aura des balises <a>, mais il n'y aura pas d'imbrication...

15voto

Nishad Up Points 1631
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
    };
}

14voto

J.Y Han Points 77

Essayez ça :

Caret.js Obtenir la position et le décalage de la carette à partir d'un champ de texte

https://github.com/ichord/Caret.js

démo : http://ichord.github.com/Caret.js

0 votes

C'est mignon. J'avais besoin de ce comportement pour placer le signe d'insertion à la fin d'un fichier contenteditable li lorsqu'on clique sur un bouton pour renommer li du contenu.

0 votes

@AndroidDev Je ne suis pas l'auteur de Caret.js mais avez-vous considéré que l'obtention de la position du caret pour tous les principaux navigateurs est plus complexe que quelques lignes ? Connaissez-vous ou avez-vous créé une alternative non-bloquée que vous pouvez partager avec nous ?

8voto

Chris Sullivan Points 873

Comme cela m'a pris une éternité pour comprendre l'utilisation de la nouvelle window.getSelection API que je vais partager pour la postérité. Notez que MDN suggère que window.getSelection bénéficie d'une prise en charge plus large, mais votre avis peut varier.

const getSelectionCaretAndLine = () => {
    // our editable div
    const editable = document.getElementById('editable');

    // collapse selection to end
    window.getSelection().collapseToEnd();

    const sel = window.getSelection();
    const range = sel.getRangeAt(0);

    // get anchor node if startContainer parent is editable
    let selectedNode = editable === range.startContainer.parentNode
      ? sel.anchorNode 
      : range.startContainer.parentNode;

    if (!selectedNode) {
        return {
            caret: -1,
            line: -1,
        };
    }

    // select to top of editable
    range.setStart(editable.firstChild, 0);

    // do not use 'this' sel anymore since the selection has changed
    const content = window.getSelection().toString();
    const text = JSON.stringify(content);
    const lines = (text.match(/\\n/g) || []).length + 1;

    // clear selection
    window.getSelection().collapseToEnd();

    // minus 2 because of strange text formatting
    return {
        caret: text.length - 2, 
        line: lines,
    }
} 

Voici un jsfiddle qui se déclenche au démarrage. Notez cependant que les pressions rapides sur les touches directionnelles, ainsi que les suppressions rapides semblent être des événements à sauter.

4voto

Parthybaraja V Points 21

Celui-ci fonctionne pour angular

private getCaretPosition() {
   let caretRevCount = 0;
   if (window.getSelection) {
      const selection = window.getSelection();
      const currentNode = selection.focusNode.parentNode;
      caretRevCount = selection.focusOffset;
      let previousNode = currentNode.previousSibling;
      while(previousNode && previousNode.nodeName === 'SPAN') { 
      // you can check specific element
      caretRevCount += previousNode.textContent.length;
      previousNode = previousNode.previousSibling;
      }
    }
    return caretRevCount;
}

4voto

Nico Burns Points 6012
//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 plage lui-même peut être stocké dans une variable et peut être re-sélectionné à tout moment, sauf si le contenu de la division modifiable 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 la documentation de Mozilla, mais le code fonctionne aussi dans chrome, safari, opera et ie9)

1 votes

Merci, mais comment puis-je obtenir l'index de la position du curseur dans le contenu du div ?

0 votes

OK, il semble que l'appel de .baseOffset sur .getSelection() fasse l'affaire. Ceci, ainsi que votre réponse, répond à ma question. Je vous remercie.

2 votes

Malheureusement, .baseOffset ne fonctionne que dans webkit (je pense). It also only gives you the offset from the imediate parent of the caret (if you have a <b> tag inside the <div> it will give the offset from the start of the <b>, not the start of the <div>. Les plages basées sur des normes peuvent utiliser range.endOffset range.startOffset range.endContainer et range.startContainer pour obtenir le décalage du parent. nœud de la sélection, et le noeud lui-même (ceci inclut les noeuds de texte). IE fournit range.offsetLeft, qui est le décalage par rapport à la gauche dans la zone de texte. pixels et ainsi de suite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X