Ich muss die Einfügemarke an das Ende des contenteditable
-Knotens wie in Google Mail-Notizen-Widget verschieben.
Ich habe Threads in StackOverflow gelesen, aber diese Lösungen basieren auf der Verwendung von Eingaben und funktionieren nicht mit contenteditable
-Elementen.
Es gibt auch ein anderes Problem.
Die Lösung von Nico Burns funktioniert, wenn contenteditable
div keine anderen mehrzeiligen Elemente enthält.
Wenn zum Beispiel ein div andere divs enthält und diese anderen divs anderes Material enthalten, können einige Probleme auftreten.
Um sie zu lösen, habe ich folgende Lösung arrangiert, nämlich eine Verbesserung der Nico s:
//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 || {}));
Verwendungszweck:
var editableDiv = document.getElementById("my_contentEditableDiv");
cursorManager.setEndOfContenteditable(editableDiv);
Auf diese Weise wird der Cursor sicher am Ende des letzten Elements positioniert und eventuell verschachtelt.
EDIT # 1: Um generischer zu sein, sollte die while-Anweisung auch alle anderen Tags berücksichtigen, die keinen Text enthalten können. Diese Elemente heißen void elements, und in diese Frage gibt es einige Methoden, um zu testen, ob ein Element ungültig ist. Angenommen, es gibt eine Funktion namens canContainText
, die true
zurückgibt, wenn das Argument kein ungültiges Element ist, die folgende Codezeile:
contentEditableElement.lastChild.tagName.toLowerCase() != 'br'
sollte ersetzt werden durch:
canContainText(getLastChildElement(contentEditableElement))
EDIT # 2: Der obige Code wird vollständig aktualisiert, wobei alle Änderungen beschrieben und diskutiert werden
Die Geowa4-Lösung funktioniert für einen Textbereich, jedoch nicht für ein inhaltsfähiges Element.
Diese Lösung dient zum Verschieben des Caret-Elements an das Ende eines inhaltsfähigen Elements. Es sollte in allen Browsern funktionieren, die contenteditable unterstützen.
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
}
}
Es kann durch folgenden Code verwendet werden:
elem = document.getElementById('txt1');//This is the element that you want to move the caret to the end of
setEndOfContenteditable(elem);
Es ist möglich, den Cursor durch den Bereich auf das Ende zu setzen:
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;
}
Wenn Sie sich nicht für ältere Browser interessieren, hat dieser für mich den Trick getan.
// [optional] make sure focus is on the element
yourContentEditableElement.focus();
// select all the content in the element
document.execCommand('selectAll', false, null);
// collapse selection to the end
document.getSelection().collapseToEnd();
Bewegen des Cursors an das Ende des bearbeitbaren Bereichs als Reaktion auf das Fokusereignis:
moveCursorToEnd(el){
if(el.innerText && document.createRange)
{
window.setTimeout(() =>
{
let selection = document.getSelection();
let range = document.createRange();
range.setStart(el.childNodes[0],el.innerText.length);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
}
,1);
}
}
Und nenne es im Event-Handler (hier reagieren):
onFocus={(e) => this.moveCursorToEnd(e.target)}}
Ich hatte ein ähnliches Problem beim Versuch, ein Element editierbar zu machen. In Chrome und FireFox war dies möglich, aber in FireFox ging das Caret entweder an den Anfang der Eingabe oder nach dem Ende der Eingabe ein Leerzeichen. Sehr verwirrend für den Endbenutzer, denke ich, der versucht, den Inhalt zu bearbeiten.
Ich habe keine Lösung gefunden, die mehrere Dinge versucht. Das Einzige, was für mich funktionierte, war "das Problem zu umgehen", indem eine einfache alte Texteingabe in INSIDE my eingefügt wurde. Jetzt gehts. Es scheint, als sei "inhaltsbearbeitbar" immer noch Edge Edge-Technologie, die je nach Kontext möglicherweise nicht so funktioniert, wie Sie möchten.