Come spostare il cursore alla fine dell’ quadro contenteditable

Devo spostare il caret alla fine del nodo contenteditable come nel widget delle note di Gmail.

Ho letto i thread su StackOverflow, ma queste soluzioni si basano sull’utilizzo degli input e non funzionano con elementi contenteditable .

C’è anche un altro problema.

La soluzione di Nico Burns funziona se il div contenteditable non contiene altri elementi multilinea.

Ad esempio, se un div contiene altri div, e questi altri div contengono altre cose all’interno, potrebbero verificarsi alcuni problemi.

Per risolverli, ho organizzato la seguente soluzione, ovvero un miglioramento di quello di 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://stackoverflow.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://stackoverflow.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); 

In questo modo, il cursore è sicuramente posizionato alla fine dell’ultimo elemento, eventualmente annidato.

EDIT # 1 : per essere più generico, la dichiarazione while dovrebbe considerare anche tutti gli altri tag che non possono contenere testo. Questi elementi sono chiamati elementi void , e in questa domanda ci sono alcuni metodi su come testare se un elemento è vuoto. Quindi, supponendo che esista una funzione chiamata canContainText che restituisce true se l’argomento non è un elemento void, la seguente riga di codice:

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

dovrebbe essere sostituito con:

 canContainText(getLastChildElement(contentEditableElement)) 

EDIT # 2 : il codice sopra è completamente aggiornato, con tutte le modifiche descritte e discusse

La soluzione di Geowa4 funzionerà per una textarea, ma non per un elemento contenteditable.

Questa soluzione è per spostare il cursore alla fine di un elemento contenteditable. Dovrebbe funzionare in tutti i browser che supportano 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 } } 

Può essere usato con un codice simile a:

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

È ansible impostare il cursore alla fine attraverso l’intervallo:

 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; } 

Ho avuto un problema simile cercando di rendere un elemento modificabile. Era ansible in Chrome e in FireFox, ma in FireFox il cursore si spostava all’inizio dell’input o si spostava uno spazio dopo la fine dell’input. Molto confuso per l’utente finale, penso, cercando di modificare il contenuto.

Non ho trovato nessuna soluzione per provare diverse cose. L’unica cosa che ha funzionato per me è stata “aggirare il problema” inserendo un vecchio input di testo INSIDE my. Ora funziona. Sembra che “content-editable” sia ancora una tecnologia all’avanguardia, che potrebbe funzionare o meno come vorresti che funzionasse, a seconda del contesto.