javascript contenteditable cursor-position

javascript - Cómo mover el cursor al final de la entidad contenteditable



cursor-position (3)

Necesito mover el cursor al final del nodo contenteditable como en el widget de notas de Gmail.

Leo hilos en StackOverflow, pero esas soluciones se basan en el uso de entradas y no funcionan con elementos contenteditable .


Es posible hacer establecer el cursor hasta el final a través del rango:

setCaretToEnd(target/*: HTMLDivElement*/) { const range = document.createRange(); const sel = window.getSelection(); range.selectNodeContents(target); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); target.focus(); range.detach(); // optimization // set scroll to the end if multiline target.scrollTop = target.scrollHeight; }


La solución de Geowa4 funcionará para un área de texto, pero no para un elemento contento.

Esta solución es para mover el cursor al final de un elemento contento. Debería funcionar en todos los navegadores compatibles con contenteditable.

function setEndOfContenteditable(contentEditableElement) { var range,selection; if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ { range = document.createRange();//Create a range (a range is a like the selection but invisible) range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start selection = window.getSelection();//get the selection object (allows you to change selection) selection.removeAllRanges();//remove any selections already made selection.addRange(range);//make the range you have just created the visible selection } else if(document.selection)//IE 8 and lower { range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible) range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start range.select();//Select the range (make it the visible selection } }

Puede ser usado por un código similar a:

elem = document.getElementById(''txt1'');//This is the element that you want to move the caret to the end of setEndOfContenteditable(elem);


También hay otro problema.

La solución de Nico Burns funciona si el div contenteditable no contiene otros elementos multilínea.

Por ejemplo, si un div contiene otros divs, y estos otros divs contienen otras cosas adentro, podrían ocurrir algunos problemas.

Para resolverlos, he dispuesto la siguiente solución, que es una mejora de la de Nico :

//Namespace management idea from http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/ (function( cursorManager ) { //From: http://www.w3.org/TR/html-markup/syntax.html#syntax-elements var voidNodeTags = [''AREA'', ''BASE'', ''BR'', ''COL'', ''EMBED'', ''HR'', ''IMG'', ''INPUT'', ''KEYGEN'', ''LINK'', ''MENUITEM'', ''META'', ''PARAM'', ''SOURCE'', ''TRACK'', ''WBR'', ''BASEFONT'', ''BGSOUND'', ''FRAME'', ''ISINDEX'']; //From: https://.com/questions/237104/array-containsobj-in-javascript Array.prototype.contains = function(obj) { var i = this.length; while (i--) { if (this[i] === obj) { return true; } } return false; } //Basic idea from: https://.com/questions/19790442/test-if-an-element-can-contain-text function canContainText(node) { if(node.nodeType == 1) { //is an element node return !voidNodeTags.contains(node.nodeName); } else { //is not an element node return false; } }; function getLastChildElement(el){ var lc = el.lastChild; while(lc && lc.nodeType != 1) { if(lc.previousSibling) lc = lc.previousSibling; else break; } return lc; } //Based on Nico Burns''s answer cursorManager.setEndOfContenteditable = function(contentEditableElement) { while(getLastChildElement(contentEditableElement) && canContainText(getLastChildElement(contentEditableElement))) { contentEditableElement = getLastChildElement(contentEditableElement); } var range,selection; if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ { range = document.createRange();//Create a range (a range is a like the selection but invisible) range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start selection = window.getSelection();//get the selection object (allows you to change selection) selection.removeAllRanges();//remove any selections already made selection.addRange(range);//make the range you have just created the visible selection } else if(document.selection)//IE 8 and lower { range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible) range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start range.select();//Select the range (make it the visible selection } } }( window.cursorManager = window.cursorManager || {}));

Uso:

var editableDiv = document.getElementById("my_contentEditableDiv"); cursorManager.setEndOfContenteditable(editableDiv);

De esta forma, el cursor seguramente se posiciona al final del último elemento, finalmente anidado.

EDIT # 1 : para ser más genérico, la sentencia while debería considerar también todas las otras etiquetas que no pueden contener texto. Estos elementos se denominan elementos vacíos , y en esta pregunta hay algunos métodos sobre cómo probar si un elemento es nulo. Entonces, suponiendo que exista una función llamada canContainText que devuelve true si el argumento no es un elemento nulo, la siguiente línea de código:

contentEditableElement.lastChild.tagName.toLowerCase() != ''br''

debe ser reemplazado por:

canContainText(getLastChildElement(contentEditableElement))

EDIT # 2 : El código anterior está completamente actualizado, con cada cambio descrito y discutido