4 votes

JS - comment obtenir le texte entre le début du nœud et la position actuelle du curseur de texte (caret) ?

J'ai besoin d'obtenir le texte (ou tout le code HTML interne) d'un noeud, tronqué à la position actuelle du curseur dans un élément avec contenteditable défini sur true. J'ai essayé d'utiliser range.setStart(), etc., mais je n'arrive pas à m'en sortir...

Modifier : Pour clarifier, lors de certains événements, je veux que le script extrait le texte du début du noeud qui a actuellement le focus jusqu'à la position du curseur (là où se trouve actuellement la ligne verticale clignotante si un champ éditable a le focus) et le stocke dans une variable. Action similaire à ce qui se passerait si un utilisateur appuyait sur ctrl+shift+home et ctrl+c

Exemple : Donné le HTML :

Hello, world Good bye, World

Et en supposant que le curseur est entre "Good" et "bye", je voudrais récupérer

"Hello, world Good"

7voto

Tim Down Points 124501

Je suggérerais l'approche suivante:

  • créer une plage englobant le contenu souhaité

  • appeler la méthode cloneContents() de la plage pour obtenir un DocumentFragment représentant le contenu de la plage

  • créer un élément

    ou et y ajouter le fragment

  • obtenir le innerHTML de l'élément

Exemple: http://jsfiddle.net/sUSYG/

Code:

function getHtmlPrecedingSelectionIn(container) {
    var html = "";
    if (window.getSelection && document.createRange) {
        var sel = window.getSelection();
        if (sel.rangeCount > 0) {
            var selRange = sel.getRangeAt(0);
            var range = document.createRange();
            range.selectNodeContents(container);
            range.setEnd(selRange.startContainer, selRange.startOffset);

            var frag = range.cloneContents();
            var el = document.createElement("body");
            el.appendChild(frag);
            html = el.innerHTML;
        }
    }
    return html;
}

Avertissements:

  • cela ne fonctionnera pas dans IE <= 8, bien qu'il ne soit pas trop difficile de le faire (soit en codant quelque chose en utilisant son API de sélection/plage différente, soit en utilisant une bibliothèque telle que Rangy)
  • l'HTML produit n'est pas garanti d'être une sous-chaîne de l'HTML d'origine du span éditable.

6voto

Vous pouvez le faire assez facilement en utilisant Rangy et jQuery.

Voici un <a href="http://jsfiddle.net/aSWD8/3/" rel="noreferrer"><strong>jsFiddle</strong></a> démontrant cette approche. Les commentaires expliquent ce qui se passe.

$("contenteditable-element").click(function () {
    // Obtenez la sélection actuelle avec Rangy
    var sel = rangy.getSelection()
    // Insérez un élément caret temporaire à la position du curseur
    // (qui se trouve à l'intérieur de l'élément contenteditable)
    if (sel.rangeCount) sel.getRangeAt(0).insertNode($("")[0]);
    // Lire le code HTML à l'intérieur de l'élément contenteditable
    var innerHTML = $("contenteditable-element").html();
    // Nettoyez, supprimez l'élément caret
    $("caret").remove();
    // Ne conservez que le texte avant la première occurrence de l'élément caret
    innerHTML = innerHTML.substr(0, innerHTML.indexOf(''));
});

0voto

bouscher Points 1240

Peut-être que cela vous poussera dans la bonne direction: Obtenez les décalages de début et de fin d'une plage par rapport à son conteneur parent

J'ai créé un exemple, qui montre la fonction en action avec votre exemple: http://jsfiddle.net/Kn8qr/2/

function getCaret(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;
}
var elCont=element.innerHTML;

var truncCont=elCont.substr(0,caretOffset);

alert(truncCont);
}

Le crédit pour cela revient à l'auteur de la fonction, j'ai juste apporté quelques modifications.

0voto

Zim84 Points 1816

Jetez un œil à cette réponse : https://stackoverflow.com/a/16575647/1532004 Je pense qu'il fait quelque chose de similaire. Peut-être qu'il vise la lune, mais il a une solution fonctionnelle :)

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