Koki_87: Position einer Selektion Herausfinden im IE

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

  1. 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

    1. 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.

      1. 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

        1. 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);  
              }  
          }