19 votes

Comment suivre les caret/curseur dans contenteditable ?

J'aimerais suivre le mouvement du curseur dans un contenteditable. Je ne suis pas sûr de la meilleure façon de le faire.

Je suis actuellement à l'écoute de click, keydown, keyup (keypress bien sûr ne se déclenche pas pour des choses comme les touches fléchées ou ctrl-x).

Si le clic fonctionne bien, le problème de la touche bas est qu'elle est déclenchée avant que le curseur ne se déplace réellement, de sorte que lorsque j'interroge la plage de sélection du document en cours, j'obtiens l'ancienne position et non la nouvelle. Mais si je compte sur keyup pour obtenir la position mise à jour, il se déclenche trop tard : le curseur se déplace dès que la touche est enfoncée, mais la touche est relâchée un temps arbitraire plus tard.

Cela doit être possible car des choses comme CKeditor sont capables de le faire. Des conseils ?

10voto

Reinmar Points 9306

C'est agréable de lire que les gens parlent de CKEditor :). Je suis l'un de ses développeurs et je n'ai pas beaucoup travaillé sur la sélection, mais je vais essayer d'aider.

Ce que je sais, c'est que nous avons un programme interne selectionChange événement. Alors quand vérifions-nous s'il a changé ? ... ... Au moins une fois toutes les 200 ms :) Voir :

http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L39

Nous vérifions également la sélection chaque fois que nous savons qu'elle a pu être modifiée (par l'API, par un keyup/mouseup ou par un changement de sélection natif, par exemple). http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L554 ). Donc... à peu près tout le temps :) AFAIK nous avons fait quelques astuces, de sorte qu'il ne brûle pas votre CPU, mais il est encore lourd. Cependant, si nous avons fait cela, alors c'est le seul moyen possible pour que cela fonctionne si bien.

Malheureusement, la gestion des sélections est de loin la le pire tâche dans le monde des wysiwygs. C'est cassé dans tous les navigateurs, anciens et nouveaux. Plus de 75% des LOC dans le fichier que j'ai lié ci-dessus sont des hacks et des astuces. C'est de la folie totale.

5voto

Tim Down Points 124501

Dans Mozilla et Opera, la gestion des événements liés aux touches et à la souris est votre seule option. Non seulement c'est compliqué, mais cela ne couvre pas tous les cas : il est possible de modifier la sélection via les menus d'édition et contextuels (via Select All, par exemple). Pour couvrir cela, il faudrait également ajouter une sorte d'interrogation de l'objet de sélection.

Cependant, dans IE (depuis au moins la version 5.5) et dans WebKit plus récent, il y a une erreur d'affichage. selectionchange événement qui se déclenche sur le document à chaque fois que la sélection change.

document.onselectionchange = function() {
    alert("Selection changed!");
};

Il y a une chance que Mozilla le prenne en charge à l'avenir : https://bugzilla.mozilla.org/show_bug.cgi?id=571294

0voto

MaxArt Points 8278

Ce n'est pas une tâche facile pour les raisons que vous avez dites. J'ai trouvé une solution de fortune comme celle-ci :

var caretInterval, caretOffset;
document.addEventListener("keydown", function(e) {
    if (!e.target.contentEditable || caretInterval) return;
    if (e.keyCode !== 37 && e.keyCode !== 39) // Left and right
        return;
    var sel = getSelection();
    caretInterval = setInterval(function() {
        if (sel.type === "Caret") caretOffset = sel.baseOffset;
    }, 50);
});
document.addEventListener("keyup", function(e) {
    if (e.keyCode !== 37 && e.keyCode !== 39) // Left and right
        return;
    clearInterval(caretInterval);
    caretInverval = null;
    var sel = getSelection();
    if (sel.type === "Caret") caretOffset = sel.baseOffset;
});

Il pourrait y avoir un petit problème si quelqu'un essaie d'appuyer à gauche et à droite. en même temps . Pour ctrl-X et ctrl-V, vous devriez attraper la commande cut y paste événement, et c'est en fait une autre douleur dans les couilles.

En fin de compte, j'ai décidé que cela ne valait pas la peine pour mes besoins. Peut-être avez-vous des besoins différents.

0voto

Siemen Points 101

Comment assister à l'événement après la sélection est mise à jour : J'ai simplement enveloppé mes fonctions de gestion dans des délais d'attente :

editor.onkeydown = function() {
  window.setTimeout( function(){
    // Your handler code here
  }, 0 );
};

Cela permet à votre gestionnaire d'être exécuté dans la boucle d'événements du navigateur dès que possible, mais après le traitement de l'événement en cours (par exemple, le clic). Mais soyez conscient des courses possibles si vous avez d'autres scripts modifiant le contenu ; il n'y a aucune garantie que votre temporisateur soit le prochain en ligne à être exécuté.

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