Position einer Selektion Herausfinden im IE
Koki_87
- javascript
Hallo,
leider komme mit dem Internet Explorer nicht weiter. Bastle einen WYSIWYG-Editor und das funktionier auch soweit ganz gut.
Ich möchte eine Tabelle (später villeicht auch mehr, derzeit reicht aber eine Tabelle) an der Cursor-Position oder anstatt des selektierten Objektes einfügen. Im FF und Opera funktioniert das einfügen an der Cursor Position schon einwandfrei, das reicht mir auch erstmal. Aber da der IE Range-Objekte nicht kennt, bzw. besser gesagt die "startContainer" und "startOffset" Methoden, komme ich nicht an diese eindeutige stelle ran.
hier mal der Code, den ich für Opera und FF benutze, das alles wird dann in einem Iframe angezeigt.
function insert_in_iframe(win, insertNode)
{
if (navigator.appName == 'Microsoft Internet Explorer') { // abfrage nach internet explorer -- docu ist bei der firefox und opera durchführung
var range = win.document.selection.createRange(); // erstellen einer TextRange um die selektierung
var text = range.text; // ermitteln des Textes der Sekektion
}else if (navigator.appName == 'Netscape' || navigator.appName == 'Opera') { // abfrage nach gecko browser
var selection = win.getSelection(); // bekommen der selektion
var range = selection.getRangeAt(0); // anlegen einer range für das selektierte objekt
var container = range.startContainer; // im container ist der gesamt inhalt des knotens, in welcher die selektion enthalten ist
var position = range.startOffset; // erhält die genaue position der Cursor stelle in dem container (ist ein integer wert)
var afterNode;
range = document.createRange();
if (container.nodeType==3) { // nodeType 3 -> textknoten
var textNode = container; // enthält den gesamten inhalt des knotens, in welcher die selektion enthalten ist
container = textNode.parentNode; // container wird das übergeordnetete element
var text = textNode.nodeValue; // enthält den text der selektion
var textBefore = text.substr(0,position); // text vor der selektion
var textAfter = text.substr(position); // text nach der selektion
var beforeNode = document.createTextNode(textBefore); // erstellen des knotens nach der selektion
afterNode = document.createTextNode(textAfter); // erstellen des knotens vor der selektion
container.insertBefore(afterNode, textNode); // erstellen des neuen knotens, hinereinander weg
container.insertBefore(insertNode, afterNode);
container.insertBefore(beforeNode, insertNode);
container.removeChild(textNode); // löschen des alten textknotens
} else {
// für FireFox interessant, da dies eine viel schnellere methode ist, wenn etwas nur ans ende angefügt werden soll
afterNode = container.childNodes[position];
container.insertBefore(insertNode, afterNode);
}
range.setEnd(afterNode, 0);
range.setStart(afterNode, 0);
selection.addRange(range);
}
}
/*
* nur das erstellen einer tabelle ist möglich
* damit externe benutzer ein einheitliches layout erzeugen können
*
* es werden nur einfache tabellen erstellt, d.h. es wird keine abfrage nach kopf und fuß - zeile geben
*/
function create_table()
{
var insert_table = document.getElementById('textEdit'); // pfad zum iframe
alert("Es wird ein Hilfsrahmen erzeugt. Dieser wird beim speichern wieder herausgenommen");
//var rows = prompt("Anzahl Zeilen eingeben"); // abfrage nach zeilenanzahl
//var cols = prompt("Anzahl Spalten eingeben"); // abfrage nach spaltenanzahl
//var width = prompt("Breite der Tabelle eingeben"); // abfrage nach tabellenbreite
// umwandeln der eingaben in integerzahlen, damit kein error kommt (falls buchstaben eingetippt wurden)
rows = 2; //parseInt(rows);
cols = 2; //parseInt(cols);
width = 25; //parseInt(width);
if (rows != 0 && cols != 0) // wenn tabelle spalten und zeilen besitzt wird sie erstellt
{
var table = insert_table.contentWindow.document.createElement("table"); // erstellen des elementes
table.setAttribute("border", "0"); // setzen der eigenschaften
table.setAttribute("cellpadding", "2");
table.setAttribute("cellspacing", "2");
var tbody = insert_table.contentWindow.document.createElement("tbody"); // erstellen des körperbreiches
for (var i=0; i < rows; i++) // abarbeiten der erstellung der zeilenanzahl
{
var tr = insert_table.contentWindow.document.createElement("tr");
for (var j=0; j < cols; j++) // abarbeiten der erstellung der spaltenanzahl
{
var td = insert_table.contentWindow.document.createElement("td");
td.setAttribute("width", width); // vordefinieren der spaltenbreite
td.setAttribute("style", "border:1px solid black;") // erstellen eines hilfsborder, dieser wird am ende wieder gelöscht
var br = insert_table.contentWindow.document.createElement("br");
td.appendChild(br); // br wird als kindelement von td definiert
tr.appendChild(td); // td wird als kindelement von tr definiert
}
tbody.appendChild(tr); // tbody wird als elternelement von tr festgelegt
}
table.appendChild(tbody); // table ist das oberelternelement der tabelle, tbody ist unterelement
insert_in_iframe(insert_table.contentWindow, table); // ausführen der funktion und einfügen in den code
}
}
hoffe ihr versteht mich, wäre für Hilfen und Anregungen dankbar
da der IE Range-Objekte nicht kennt, bzw. besser gesagt die "startContainer" und "startOffset" Methoden, komme ich nicht an diese eindeutige stelle ran.
Im IE ist das Modell von Ranges ganz anders.
parentElement
Man kommt m.W. nicht so ohne weiteres an den Offset, vermutlich nutzt man eher dies:
pasteHTML
if (navigator.appName == 'Microsoft Internet Explorer')
Vermeide solche Browserabfragen und frage stattdessen ab, welche Objekte zur Verfügung stehen und ob die fraglichen Methoden brauchbare Werte zurückgeben. Opera implementiert z.B. beide Ansätze und es macht u.U. Sinn, ihn den anderen Zweig ausführen zu lassen. Außerdem hast du mit der Browserweiche, die gerade mal drei Browser anhand ihres Namens berücksichtigt, alle anderen unnötigerweise ausgesperrt.
Mathias
Man kommt m.W. nicht so ohne weiteres an den Offset
was heißt denn ohne weiteres, gibt es da villeicht eine methode oder kann ich gleich sagen, dass es nicht im ie umzusetzen geht
Vermeide solche Browserabfragen und frage stattdessen ab, welche Objekte zur Verfügung stehen und ob die fraglichen Methoden brauchbare Werte zurückgeben. Opera implementiert z.B. beide Ansätze und es macht u.U. Sinn, ihn den anderen Zweig ausführen zu lassen. Außerdem hast du mit der Browserweiche, die gerade mal drei Browser anhand ihres Namens berücksichtigt, alle anderen unnötigerweise ausgesperrt.
ja ist auch erstmal nur vorrübergehend, desweiteren wird dies sowieso nur im backend eingesetzt, d.h. unsere Mitarbeiter benutzen nur Browser ala Opera oder FF und leider benutzen auch ein Paar solche komischen Anzeige Programme wie den IE :( , auf die muss ich auch rücksicht nehmen. Aber mit den Browserweichen hast du natürlich Recht.
was heißt denn ohne weiteres, gibt es da villeicht eine methode oder kann ich gleich sagen, dass es nicht im ie umzusetzen geht
Wenn ich mich recht erinnere, kann man mit den move-Methoden herumspielen, bis die Range irgendwann aus dem ursprünglichen Element läuft. Die einzelnen Zeichenschritte bis dahin kann man zählen.
Mathias
also erstmal danke molily, du hast mir sehr geholfen. die genaue Positionierung habe ich dann in Blubber21 Thread's doch noch gefunden ;)
hier nur so wie es in jedem browser funktioniert (einfach Einfügen an einer bestimmten Stelle, nicht ersetzen, ist aber auch nicht so schwer, dies umzusetzen)
function insert_in_iframe(win, insertNode)
{
var selectionText; // selektierter text
var range; // range um das selektierte objekt
var parentElement; // eltern knoten des selektierten objektes
var container; // inhalt des eltern knotens
var positionStart; // anfangspunkt der selektierung
var positionEnd; // endpunkt der selektierung
var text; // text des gesamten elementes, in welcher die selektion ist
var textBefore // inhalt des Textes vor der Selektion
var textAfter // inhalt des Textes nach der Selektion
var beforeNode; // text-knoten, der vor der selektierung kommt
var afterNode; // text-knoten, der hinter der selektierung kommt
// range.pasteHTML(text); // erstezt die selektierte range mit dem neune wert, alles wird xHtml konform geschrieben
if (document.uniqueID) { // abfrage nur nach dem ie, funktion ist nur für diesen vorgesehen, obwohl opera auch einig methoden ausführen könnte
range = win.document.selection.createRange();
parentElement = range.parentElement();
container = range.duplicate(); // erstellen einer 2. textrange, die den gesamten inhalt des eltern elementes hat
container.moveToElementText(parentElement); // bekommen des gesamten parent inhaltes
container.setEndPoint('EndToEnd', range); // bekommen des Textes des aktuellen Knotens bis zum ende der Selektion
positionStart = container.text.length - range.text.length;
positionEnd = positionStart + range.length;
// beginn der formatierung
container = ""; // zurücksetzen des containers auf den gesamten inhalt des knotens, in welcher die selektion ist
container = range.duplicate(); // -||-
container.moveToElementText(parentElement); // -||-
text = container.text;
textBefore = text.substr(0, positionStart);
textAfter = text.substr(positionStart);
beforeNode = document.createTextNode(textBefore);
afterNode = document.createTextNode(textAfter);
var newNode = beforeNode.nodeValue +" "+ insertNode.nodeValue +" "+ afterNode.nodeValue;
parentElement.firstChild.replaceData(0, container.text.length, newNode);
} else if (window.getSelection) { // diese Schleife sollte nur noch für netscape browser (FireFox, GoogleChrome und Safari) sein
selectionText = win.getSelection();
range = selectionText.getRangeAt(0);
container = range.startContainer; // im container ist der gesamt inhalt des knotens, in welcher die selektion enthalten ist
positionStart = range.startOffset; // erhält die genaue position der Cursor stelle in dem container (ist ein integer wert)
// beginn der formatierung
parentElement = container.parentNode;
text = container.nodeValue;
textBefore = text.substr(0, positionStart);
textAfter = text.substr(positionStart); // text nach der selektion mit der selektierung als erstes element
beforeNode = document.createTextNode(textBefore);
afterNode = document.createTextNode(textAfter);
alert(parentElement);
parentElement.insertBefore(afterNode, container); // der neue Knoten, erst vor der selektierung
parentElement.insertBefore(insertNode, afterNode); // jetzt kommt die neue stelle
parentElement.insertBefore(beforeNode, insertNode); // nun kommt der rest des alten elementes
parentElement.removeChild(container); // löschen des alten textknotens
//range.setEnd(afterNode, 0);
//range.setStart(afterNode, 0);
//selectionText.addRange(range);
}
}