javascript - span - ¿Cómo rastrear caret/cursor en contenteditable?
table content editable javascript (4)
En Mozilla y Opera, la desagradable tarea de manejar eventos clave y de mouse es su única opción. No solo es complicado, sino que tampoco cubre todos los casos: es posible cambiar la selección a través de los menús de edición y de contexto (por ejemplo, Seleccionar todo). Para cubrir eso, también debe agregar algún tipo de sondeo del objeto de selección.
Sin embargo, en IE (todo el camino de regreso a al menos 5.5) y el WebKit reciente-ish, hay un evento de cambio de selectionchange
que se activa en el documento cada vez que la selección cambia.
document.onselectionchange = function() {
alert("Selection changed!");
};
Existe la posibilidad de que Mozilla lo soporte en el futuro: https://bugzilla.mozilla.org/show_bug.cgi?id=571294
Me gustaría rastrear el movimiento del cursor / cursor en un contenteditable. Sin embargo, no estoy seguro de cuál es la mejor manera de hacer esto.
Actualmente estoy escuchando click, keydown, keyup. (la pulsación de teclas, por supuesto, ni siquiera se dispara para cosas como las teclas de flecha o ctrl-x).
Si bien el clic funciona bien, el problema con el keydown es que se dispara antes de que realmente se mueva el cursor, así que cuando pregunto el rango de selección del documento actual, obtengo la posición anterior y no la nueva. Pero si confío en keyup para obtener la posición actualizada, se dispara demasiado tarde: el cursor se mueve tan pronto como se presiona la tecla, pero la tecla se suelta un tiempo arbitrario más tarde.
Esto debe ser posible porque cosas como CKeditor pueden hacer esto. ¿Alguna pista?
Es bueno leer que la gente está hablando de CKEditor :). Soy uno de sus desarrolladores y no he estado trabajando mucho en la selección, pero intentaré ayudar.
Lo que sé es que tenemos un evento selectionChange
interno. Entonces, ¿cuándo comprobamos si ha cambiado? ... ... Al menos una vez por cada 200 ms :) Ver:
http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L39
También verificamos la selección cada vez que sabemos que podría haber cambiado (por ejemplo, por la API o en keyup / mouseup o en la selección nativa cambiar - http://dev.ckeditor.com/browser/CKEditor/trunk/_source/plugins/selection/plugin.js#L554 ). Entonces ... casi todo el tiempo :) AFAIK hacemos algunos trucos, para que no queme tu CPU, pero sigue siendo pesado. Sin embargo, si hiciéramos esto, entonces es la única manera posible de que esto funcione tan bien.
Desafortunadamente, el manejo de la selección es, con mucho, la peor tarea en el mundo de wysiwygs. Está tan roto en todos los navegadores viejos y nuevos. Más del 75% de LOC en el archivo que vinculé anteriormente son hacks y trucos. Eso es una completa locura.
No es una tarea fácil por las razones que dijiste. Se me ocurrió un poco de este tipo de cosas:
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;
});
Podría haber un pequeño problema si alguien intenta presionar hacia la izquierda y hacia la derecha al mismo tiempo . Para ctrl-X y ctrl-V, debes capturar el evento de cut
y paste
, y eso es realmente otro dolor en los bollocks.
Al final, decidí que no valía la pena el esfuerzo para mis propósitos. Tal vez usted tiene diferentes necesidades.
WRT captura el evento después de que se actualice la selección: simplemente envuelvo mis funciones de controlador en tiempos de espera:
editor.onkeydown = function() {
window.setTimeout( function(){
// Your handler code here
}, 0 );
};
Esto registra su controlador para que se ejecute en el bucle de eventos del navegador tan pronto como sea posible, pero después de que el evento actual (por ejemplo, haga clic) se procese. Pero tenga en cuenta las posibles carreras si tiene otros scripts que modifican el contenido; no hay garantía de que su tiempo de espera sea el siguiente en la línea que se ejecutará.