2008-09-24 12 views
7

Ich habe ein ungewöhnliches Problem mit einem IE-Dokument mit contentEditable auf True festgelegt. Das Aufrufen von select() in einem Bereich, der sich am Ende eines Textknotens befindet, der einem Blockelement unmittelbar vorausgeht, bewirkt, dass die Auswahl nach dem rechten einen Zeichen verschoben wird und dort erscheint, wo es nicht sollte. Ich habe einen Fehler an Microsoft gegen IE8 eingereicht. Wenn Sie können, stimmen Sie bitte für dieses Problem ab, damit es behoben werden kann.IE TextRange Select-Methode funktioniert nicht richtig

https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=390995

ich einen Testfall geschrieben haben, die Wirkung zu zeigen:

<html> 
    <body> 
    <iframe id="editable"> 
     <html> 
     <body> 
      <div id="test"> 
      Click to the right of this line -&gt; 
      <p id="par">Block Element</p> 
      </div> 
     </body> 
     </html> 
    </iframe> 
    <input id="mytrigger" type="button" value="Then Click here to Save and Restore" /> 
    <script type="text/javascript"> 
     window.onload = function() { 
      var iframe = document.getElementById('editable'); 
      var doc = iframe.contentDocument || iframe.contentWindow.document; 

      // An IFRAME without a source points to a blank document. Here we'll 
      // copy the content we stored in between the IFRAME tags into that 
      // document. It's a hack to allow us to use only one HTML file for this 
      // test. 
      doc.body.innerHTML = iframe.textContent || iframe.innerHTML; 

      // Marke the IFRAME as an editable document 
      if (doc.body.contentEditable) { 
       doc.body.contentEditable = true; 
      } else { 
       var mydoc = doc; 
       doc.designMode = 'On'; 
      } 

      // A function to demonstrate the bug. 
      var myhandler = function() { 
       // Step 1 Get the current selection 
       var selection = doc.selection || iframe.contentWindow.getSelection(); 
       var range = selection.createRange ? selection.createRange() : selection.getRangeAt(0); 

       // Step 2 Restore the selection 
       if (range.select) { 
        range.select(); 
       } else { 
        selection.removeAllRanges(); 
        selection.addRange(range); 
        doc.body.focus(); 
       } 
      } 

      // Set up the button to perform the test code. 
      var button = document.getElementById('mytrigger'); 
      if (button.addEventListener) { 
       button.addEventListener('click', myhandler, false); 
      } else { 
       button.attachEvent('onclick', myhandler); 
      } 
      } 
    </script> 
    </body> 
</html> 

Das Problem wird in der MyHandler Funktion ausgesetzt. Das ist alles, was ich mache, es gibt keinen Schritt 3 zwischen dem Speichern und Wiederherstellen der Auswahl, und dennoch bewegt sich der Cursor. Es scheint nicht zu passieren, wenn die Auswahl leer ist (dh ich habe einen blinkenden Cursor, aber keinen Text), und es scheint nur dann zu passieren, wenn der Cursor am Ende eines Textknotens steht, der einem Blockknoten unmittelbar vorangeht.

Es scheint, dass der Bereich immer noch in der richtigen Position ist (wenn ich ParentElement auf den Bereich aufrufen, wird das div zurückgegeben), aber wenn ich einen neuen Bereich von der aktuellen Auswahl erhält, ist der neue Bereich innerhalb der Absatzmarke und das ist das Elternelement.

Wie kann ich das umgehen und die Auswahl im Internet Explorer konsistent speichern und wiederherstellen?

+0

Nachdem ich einige Zeit damit verbracht habe, bin ich einigermaßen überzeugt, dass es keine Möglichkeit gibt, das Caret programmatisch am Ende eines Textknotens zu platzieren, der einem Blockelement unmittelbar vorangeht. –

Antwort

12

Ich habe ein paar Methoden zum Umgang mit IE-Bereichen wie diesem herausgefunden. Wenn Sie nur den Cursor speichern und dann wiederherstellen möchten, können Sie die pasteHTML-Methode verwenden, um an der aktuellen Position des Cursors einen leeren Bereich einzufügen. Verwenden Sie anschließend die moveToElementText-Methode, um den Cursor einzufügen.

zurück an dieser Position wieder:

// Save position of cursor 
range.pasteHTML('<span id="caret"></span>') 

... 

// Create new cursor and put it in the old position 
var caretSpan = iframe.contentWindow.document.getElementById("caret"); 
var selection = iframe.contentWindow.document.selection; 
newRange = selection.createRange(); 
newRange.moveToElementText(caretSpan); 

Alternativ können Sie zählen, wie viele Zeichen der aktuellen Cursorposition vorangehen und diese Nummer speichern:

var selection = iframe.contentWindow.document.selection; 
var range = selection.createRange().duplicate(); 
range.moveStart('sentence', -1000000); 
var cursorPosition = range.text.length; 

um den Cursor wiederherzustellen, Sie setzen es auf den Anfang und dann verschiebe es diese Anzahl von Charas cters:

var newRange = selection.createRange(); 
newRange.move('sentence', -1000000); 
newRange.move('character', cursorPosition); 

Hoffe das hilft.

0

Ich arbeitete vor kurzem auf einer Website, die Microsoft CMS mit dem "MSIB + Pack" von Steuerelementen verwendet, die einen WYSIWYG-Editor enthalten, der in Internet Explorer ausgeführt wurde.

Ich erinnere mich an einige Kommentare im Editor clientseitigen Javascript, die speziell auf diesen Fehler in IE und der Range.Select() -Methode bezogen wurden.

Leider arbeite ich nicht mehr dort, so kann ich nicht auf die Javascript-Dateien zugreifen, aber vielleicht können Sie sie von anderswo bekommen?

Viel Glück

+0

Wissen Sie, ob der WYSIWYG-Editor einen Namen hat? Könnte es einfacher für die Suche machen ... –

+0

Ich habe es geschafft, eine Kopie des MSIB + -Pack zu bekommen, aber ich kann nicht scheinen, den WYSIWYG-Editor darin zu finden. Ich bin mir nicht sicher, ob die Kopie, die ich habe, veraltet ist, oder der Redakteur ist eigentlich ein Teil des CMS-Editors ... –

1

ich & leider ein bisschen eine Grabung hatte nicht eine Abhilfe sehen ... Obwohl eine Sache, die ich während der Javascript-Debugging bemerkt haben, wie es scheint, das Problem tatsächlich mit dem Bereich Objekt selbst statt mit der nachfolgenden range.select(). Wenn Sie die Werte des Bereichsobjekts betrachten, die selection.createRange() zurückgibt, ist das übergeordnete dom-Objekt zwar korrekt, aber die Positionierungsinformationen beziehen sich bereits auf den Anfang der nächsten Zeile (dh offsetLeft/Top, boundingLeft/Top usw.) falsch).

Basierend auf den Informationen here, here und here, ich glaube, Sie mit IE kein Glück, da Sie nur Zugriff auf Microsofts Objekt Textrange haben, die gebrochen zu sein scheint. Bei meinen Experimenten können Sie den Bereich verschieben und genau dort positionieren, wo er sein sollte. Wenn Sie dies jedoch tun, wird das Bereichsobjekt automatisch in die nächste Zeile verschoben, noch bevor Sie es mit .select() versucht haben. Zum Beispiel können Sie das Problem, indem Sie diesen Code in zwischen Schritt 1 & Schritt 2 siehe:

if (range.boundingWidth == 0) 
{ 
    //looks like its already at the start of the next line down... 
    alert('default position: ' + range.offsetLeft + ', ' + range.offsetTop); 
    //lets move the start of the range one character back 
    //(i.e. select the last char on the line) 
    range.moveStart("character", -1); 
    //now the range looks good (except that its width will be one char); 
    alert('one char back: ' + range.offsetLeft + ', ' + range.offsetTop); 
    //calculate the true end of the line... 
    var left = range.offsetLeft + range.boundingWidth; 
    var top = range.offsetTop; 
    //now we can collapse back down to 0 width range 
    range.collapse(); 
    //the position looks right 
    alert('moving to: ' + left + ', ' + top); 
    //move there. 
    range.moveToPoint(left, top); 
    //oops... on the next line again... stupid IE. 
    alert('moved to: ' + range.offsetLeft + ', ' + range.offsetTop); 
} 

Also, leider sieht es nicht wie es eine Möglichkeit ist, um sicherzustellen, dass der Bereich an der richtigen Stelle ist wenn Sie es erneut auswählen.

Offensichtlich gibt es die triviale Lösung, um den Code oben, Schritt 2 es zu dieser Veränderung:

// Step 2 Restore the selection 
if (range.select) { 
    if (range.boundingWidth > 0) { 
     range.select(); 
    } 
} else { 
    selection.removeAllRanges(); 
    selection.addRange(range); 
    doc.body.focus(); 
} 

Aber vermutlich, Sie wollen tatsächlich etwas zwischen Schritt 1 & Schritt 2 in Ihrem aktuellen tun, das Umlagern die Auswahl, daher die Notwendigkeit, es neu zu setzen. Aber nur für den Fall. :)

Also, das Beste, was ich tun kann, ist gehen & Abstimmung für den Fehler, den Sie erstellt ... Hoffentlich werden sie es beheben.

+0

Vielen Dank für einen Blick. Ich weiß, dass es ein Fehler im IE ist, ich suche nur nach einem sicheren Workaround, da ich die Auswahl verschieben muss, bevor ich sie wiederherstelle. –

0

Vielleicht missverstehe ich, aber wenn ich rechts von dieser ersten Zeile klicke, erscheint mein Cursor bereits sofort am Anfang der zweiten Zeile, also ist das kein TextRange-Problem, oder?

Hinzufügen eines Doctype, so dass die Testseite im Standard-Modus statt Quirks-Modus gerendert wird, das für mich behebt.

Und ich kann nicht reproduzieren, was Ihre Myhandler-Funktion tut, weil das Klicken auf diese Schaltfläche den Fokus weg von der Schaltfläche verschiebt, so dass ich den Cursor nicht mehr sehen kann und es auch nicht zurückbekomme. Suchen der Cursorposition in einem contentEditable Bereich seems to be a different problem altogether.