2008-09-24 30 views
7

Tengo un problema inusual con un documento de IE con contentEditable establecido en verdadero. Al llamar a select() en un rango que se ubica al final de un nodo de texto que precede inmediatamente a un elemento de bloque, la selección se desplaza al carácter correcto y aparece donde no debería. He enviado un error a Microsoft contra IE8. Si puedes, vota por este problema para que se solucione.El método de selección IE TextRange no funciona correctamente

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

He escrito un caso de prueba para demostrar el efecto:

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

El problema se expone en la función myhandler. Esto es todo lo que estoy haciendo, no hay Paso 3 entre guardar y restaurar la selección, y sin embargo, el cursor se mueve. No parece suceder a menos que la selección esté vacía (es decir, tengo un cursor parpadeante, pero no texto), y solo parece suceder cuando el cursor está al final de un nodo de texto que precede inmediatamente a un nodo de bloque.

Parece que el rango sigue en la posición correcta (si llamo parentElement al rango devuelve el div), pero si obtengo un nuevo rango de la selección actual, el nuevo rango está dentro de la etiqueta de párrafo, y ese es su elemento principal.

¿Cómo puedo solucionar esto y siempre guardar y restaurar la selección en Internet Explorer?

+0

Después de haber dedicado un tiempo a esto, estoy razonablemente convencido de que no hay forma de colocar programáticamente el cursor al final de un nodo de texto que precede inmediatamente a un elemento de bloque. –

Respuesta

12

He descubierto algunos métodos para manejar rangos de IE como este.

Si todo lo que quiere hacer es guardar donde está el cursor y luego restaurarlo, puede usar el método pasteHTML para insertar un tramo vacío en la posición actual del cursor y luego usar el método moveToElementText para colocarlo de vuelta en esa posición otra vez:

// 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); 

Alternativamente, se puede contar el número de caracteres preceden a la posición actual del cursor y guardar ese número:

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

para restaurar el cursor, lo establece en el principio y luego moverlo ese número de chara cters:

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

Espero que esto ayude.

0

Recientemente trabajé en un sitio que utilizaba Microsoft CMS con el "paquete MSIB +" de controles que incluía un editor WYSIWYG que se ejecutaba en Internet Explorer.

Parece que recuerdo algunos comentarios en el editor del lado del cliente de Javascript que estaban específicamente relacionados con este error en IE y el método Range.Select().

Desafortunadamente, ya no estoy trabajando allí, así que no puedo acceder a los archivos de Javascript, pero ¿quizás pueda obtenerlos de otro lado?

Buena suerte

+0

¿Sabe si el editor WYSIWYG tenía un nombre? Podría facilitar la búsqueda ... –

+0

He logrado obtener una copia del paquete MSIB +, pero parece que no puedo encontrar el editor WYSIWYG dentro. No estoy seguro de si la copia que tengo está desactualizada, o si el editor es realmente parte del editor de CMS ... –

1

que he tenido un poco de una excavación & desafortunadamente no puede ver una solución ... Aunque una cosa que he notado durante la depuración del Javascript, parece que el problema es en realidad con la gama objeto en sí mismo en lugar de con el siguiente range.select(). Si observa los valores en el objeto de rango que devuelve selection.createRange(), sí, el objeto dom principal puede ser correcto, pero la información de posicionamiento ya se refiere al comienzo de la línea siguiente (es decir, offsetLeft/Top, boundingLeft/Top, etc. ya están incorrecto).

Con base en la información here, here y here, creo que estás fuera de suerte con el IE, ya que sólo tienen acceso a objeto TextRange de Microsoft, que parece no estar funcionando. A partir de mi experimentación, puede mover el rango y ubicarlo exactamente donde debería estar, pero una vez que lo hace, el objeto de rango cambia automáticamente a la siguiente línea incluso antes de intentar .select(). Por ejemplo, se puede ver el problema al poner este código en entre el Paso 1 & Paso 2:

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

Así que, por desgracia, no parece que haya ninguna manera de asegurar que el rango está en el lugar correcto cuando lo seleccionas de nuevo

Obviamente está la solución trivial para el código anterior, cambiando el paso 2 a esto:

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

Pero es de suponer, en realidad se quiere hacer algo entre Paso 1 & Paso 2 en su real que implica el movimiento la selección, de ahí la necesidad de volver a establecerlo. Pero solo por si acaso. :)

Por lo tanto, lo mejor que puedo hacer es ir & vote por el error que ha creado ... Afortunadamente lo arreglarán.

+0

Gracias por echar un vistazo. Sé que es un error en IE, solo estoy buscando una solución segura porque necesito mover la selección antes de restaurarla. –

0

Quizás malinterprete, pero si hago clic a la derecha de esa primera línea, mi cursor ya aparece inmediatamente al comienzo de la segunda línea, entonces eso no es un problema de TextRange, ¿verdad?

Añadiendo un doctype para que la página de prueba se represente en el modo estándar en lugar del modo peculiar que correcciones que para mí.

Y no puedo reproducir lo que hace su función myhandler, porque al hacer clic en ese botón se mueve el foco hacia el botón para que ya no pueda ver el cursor y tampoco pueda recuperarlo. Encontrar la posición del cursor en un área de contentEditableseems to be a different problem altogether.