javascript range selection contenteditable

javascript - Modo de navegador cruzado para insertar etiquetas BR o P al presionar Enter en un elemento contentEditable



range selection (2)

Cuando presiona la tecla Intro en un elemento contentEditable , cada navegador maneja el código resultante de manera diferente: Firefox inserta una etiqueta BR, Chrome inserta una etiqueta DIV mientras que Internet Explorer inserta una etiqueta P.

Estaba buscando desesperadamente una solución para al menos usar un BR o P para todos los navegadores y la respuesta más común fue esta:

insertando la etiqueta BR:

$("#editableElement").on("keypress", function(e){ if (e.which == 13) { if (window.getSelection) { var selection = window.getSelection(), range = selection.getRangeAt(0), br = document.createElement("br"); range.deleteContents(); range.insertNode(br); range.setStartAfter(br); range.setEndAfter(br); selection.removeAllRanges(); selection.addRange(range); return false; } } });

Pero esto no funciona porque parece que los navegadores no saben cómo configurar el cursor después de <br> que significa que lo siguiente no está haciendo nada útil (especialmente si presionas Intro cuando el cursor se coloca al final del texto) :

range.setStartAfter(br); range.setEndAfter(br);

Algunas personas dirían: use doble <br><br> pero esto se traduce en dos saltos de línea cuando presiona entrar dentro de un nodo de texto.

Otros dirían que siempre agregue una página adicional al final de contentEditable, pero si tiene un <div contenteditable><p>text here</p></div> y coloca el cursor al final del texto, presione el botón Entra, obtendrás el comportamiento equivocado.

Entonces me dije a mí mismo que tal vez podamos usar P en lugar de BR, y la respuesta común es:

insertando la etiqueta P:

document.execCommand(''formatBlock'', false, ''p'');

Pero esto tampoco funciona de manera consistente.

Como puede ver, todas estas soluciones dejan algo que desear. ¿Hay otra solución que resuelva este problema?


Puedes ver una implementación completa de navegador cruzado here . Hay tantos hacks para que funcione. Este código del enlace lo ayudará a instalar una solución.

Ejemplo de un hack de Geko e IE:

doc.createElement( ''br'' ).insertAfter( startBlock ); // A text node is required by Gecko only to make the cursor blink. if ( CKEDITOR.env.gecko ) doc.createText( '''' ).insertAfter( startBlock ); // IE has different behaviors regarding position. range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START );


Una posible solución: agregue un nodo de texto con un carácter de espacio de ancho cero después del elemento <br> . Este es un carácter de ancho cero no imprimible que está diseñado específicamente para:

... indica los límites de las palabras a los sistemas de procesamiento de texto cuando se usan scripts que no usan espacios explícitos, o después de los caracteres (como la barra diagonal) que no están seguidos por un espacio visible pero después de los cuales puede haber un salto de línea.

(Wikipedia)

Probado en Chrome 48, Firefox 43 e IE11.

$("#editableElement").on("keypress", function(e) { //if the last character is a zero-width space, remove it var contentEditableHTML = $("#editableElement").html(); var lastCharCode = contentEditableHTML.charCodeAt(contentEditableHTML.length - 1); if (lastCharCode == 8203) { $("#editableElement").html(contentEditableHTML.slice(0, -1)); } // handle "Enter" keypress if (e.which == 13) { if (window.getSelection) { var selection = window.getSelection(); var range = selection.getRangeAt(0); var br = document.createElement("br"); var zwsp = document.createTextNode("/u200B"); var textNodeParent = document.getSelection().anchorNode.parentNode; var inSpan = textNodeParent.nodeName == "SPAN"; var span = document.createElement("span"); // if the carat is inside a <span>, move it out of the <span> tag if (inSpan) { range.setStartAfter(textNodeParent); range.setEndAfter(textNodeParent); } // insert the <br> range.deleteContents(); range.insertNode(br); range.setStartAfter(br); range.setEndAfter(br); // create a new span on the next line if (inSpan) { range.insertNode(span); range.setStart(span, 0); range.setEnd(span, 0); } // add a zero-width character range.insertNode(zwsp); range.setStartBefore(zwsp); range.setEndBefore(zwsp); // insert the new range selection.removeAllRanges(); selection.addRange(range); return false; } } });

#editableElement { height: 150px; width: 500px; border: 1px solid black; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div contenteditable=true id="editableElement"> <span>sample text</span> </div>