¿Por qué mi Cursor Contenteditable salta al final en Chrome?

Guión

Tengo un área

contenteditable, y dentro de esta área puedo tener algunos contengan texto. La idea es que estos elementos de tramo representarán texto con estilo que no se puede editar, pero se pueden eliminar desde el área

pulsando la tecla de retroceso.

Problema

La colocación del cursor es el gran problema aquí. si elimina uno de estos elementos , el cursor salta al final de

. Más interesante, si escribe texto mientras el cursor está “al final”, la colocación del texto está bien … Entonces, si elimina el texto recién escrito, ¡el cursor saltará hacia atrás!

He preparado un violín que demostrará esto. Necesito que esto funcione solo en Chrome , y otros navegadores no son de preocupación por ahora o tienen soluciones alternativas. (También tenga en cuenta que el Fiddle preparado está diseñado para demostrar esto solo en Chrome).

Violín


Instrucción Fiddle: versión de Chrome 39.0.2171.95 m (64 bits) reproducida también en 32 bits

  1. Haga clic en el área
  2. Escriba “123”
  3. Retroceso “3” Retroceso “2” Retroceso “1” enter image description here

Detalles relacionados

Investigando esto extensamente, me he encontrado con varias preguntas de SO que son similares, pero tomar prestadas las soluciones asociadas no ha resultado ser la bala de plata que busco. También he encontrado problemas para el proyecto Chrome que parecen apuntar (tal vez no de la manera exacta) al problema descrito anteriormente, y se pueden ver a continuación.

  1. Problema 384357: posición de Caret dentro de la región contenteditable con nodos no editables
  2. Problema 385003: El estilo de inserción de intercalación es incorrecto al llegar al final de una línea en un elemento contenteditable
  3. Problema 71598: Caret en posición incorrecta después del elemento no editable al final del contenido Editable

La solución SO más cercana que he encontrado puede estar aquí . La idea en esta solución es colocar caracteres después de los elementos , pero si ahora quiero eliminar mi , en su lugar, el … forzando al cursor a saltar al final, ofreciendo una experiencia de IU extraña al no eliminar mi en mi “pulsación de tecla de eliminación inicial”.

Pregunta

¿Alguien ha experimentado este problema y ha encontrado un trabajo alternativo? Doy la bienvenida a cualquier posible solución, incluso cuando JS hacky como vengan. He aprendido que el apalancamiento de contenteditable viene con una larga lista de problemas, pero esta parece ser la última dificultad que tengo actualmente .

No sé por qué sucede esto, pero tuve la sensación de que tiene algo que ver con el tamaño del

, así que traté de jugar con la propiedad de display . Después de configurarlo inline-block en inline-block y de jugar un poco con el texto, descubrí que el problema desapareció después de realizar algunas ediciones, específicamente agregando una nueva línea.

Vi que, por alguna razón, la etiqueta
se mantiene en div.main después de eliminar mi nueva línea, pero la apariencia del

y la forma en que responde a las teclas de flecha es la misma que si hubiera no hay una nueva línea en él.

¡Así que reinicié el violín con el cambio de CSS y una etiqueta
en div.main y viola!

Entonces para concluir:

  1. Agregar display: inline-block to div.main
  2. agrega un
    al final de div.main

JSFiddle Link

El problema es que su elemento contenteditable es un div , que por defecto es display: block . Esto es lo que causa su problema de posición de cuidado. Esto se puede solucionar haciendo que el div más externo no sea editable y agregando un nuevo div editable que se tratará como inline-block .

El nuevo HTML tendría un nuevo div justo dentro del externo (y la etiqueta de cierre correspondiente al final):

 
...

Y agrega esto a tu CSS:

 div#editable { display: inline-block; } 

Con el fin de ver mejor la intercalación cuando se trata de elementos de span , también he agregado margin: 2px a la regla para div.main span en CSS, pero esto no es necesario para evitar el problema de salto de intercalación informado en la pregunta.

Aquí hay un violín .

A medida que comenzó a descubrir, contenteditable se maneja de forma incoherente en todos los navegadores. Hace unos años, comencé a trabajar en un proyecto (editor XML en el navegador) donde pensé que contenteditable haría todo más fácil. Luego, cuando desarrollé la aplicación, pronto me di cuenta de que estaba asumiendo las funciones que creía que lo que me daría la contenteditable me daría gratis. Hoy, lo único que me permite contenteditable es que enciende los eventos del teclado en los elementos que quiero editar. Todo lo demás, incluido el movimiento del cursor y la visualización del cursor, se gestiona mediante un código personalizado.

Por lo tanto, tengo una implementación ligeramente más clara de su enfoque, que se basa en el evento de input que se desencadena cuando se actualiza un campo contenteditable . Este evento no es compatible con IE, pero parece que contenteditable es bastante inseguro en IE de todos modos.

Básicamente inyecta elementos alrededor de cada elemento marcado como contenteditable="false" . Probablemente podría hacerse en la carga inicial en lugar de solo en el evento de input , pero pensé que podría haber formas de inyectar más span a la región, por lo que la input debería dar cuenta de esto.

Las limitaciones incluyen un comportamiento extraño que rodea las teclas de flecha, como te has visto a ti mismo. Sobre todo lo que he visto es que el cursor mantiene su posición correcta cuando retrocedes por los tramos, pero no cuando avanzas.

JSFiddle Link

Javascript

 $('#main').on('input', function() { var first = true; $(this).contents().each(function(){ if ($(this).is('[contenteditable=false]')) { $("").insertAfter(this); if (first) { $("").insertBefore(this); first = false } } }); }).trigger('input'); 

CSS

 div.main { width: 400px; height: 250px; border: solid 1px black; } div.main span { width:40px; background-color: red; border-radius: 5px; color: white; cursor: pointer; } i.wrapper { font-style: normal; } 

He encontrado una manera estrafalaria de resolver el problema inicial del comportamiento incorrecto del cursor al final del

con algo de JQuery. Básicamente, estoy insertando un vacío para que el cursor “cierre” al final del contenido de

. Esta etiqueta funciona para mí porque no hay diferencia de UI para el usuario final al retroceder desde el texto normal debido a la anulación font-style: normal (ver violín), y también necesitaba algo diferente a para insertar

No estoy particularmente entusiasmado con esta solución, especialmente al elegir un solo porque, pero no he encontrado una mejor alternativa, y aún así recibo mejores soluciones, ¡si es que existen! Planeo seguir trabajando en esto para poder descubrir las teclas de flecha también, pero afortunadamente solo me molesta este problema en el Fiddle y no mi código.

Fiddle (solo Chrome)

 
item item item

 function hackCursor() { return $('#main :last-child').get(0).tagName === 'SPAN' ? $('#main span:last-child').after('') : false; } $(function(){ hackCursor(); $('#main').bind({ 'keyup': function(e) { hackCursor(); } }) }); 

Simplemente agregue una nueva línea char ( \n ) antes de cerrar la etiqueta contenteditable . Por ejemplo, en JavaScript: var html = '

' + content + "\n" + '

'