Question

Je rencontre un problème inhabituel avec un document IE avec contentEditable défini sur true. Si vous appelez select () sur une plage située à la fin d'un nœud de texte juste avant un élément de bloc, la sélection est décalée vers le caractère de droite et s'affiche là où elle ne devrait pas. J'ai soumis un bogue à Microsoft contre IE8. Si vous le pouvez, votez pour ce problème afin qu'il soit corrigé.

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

J'ai écrit un scénario de test pour démontrer l'effet:

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

Le problème est exposé dans la fonction myhandler. C'est tout ce que je fais. Il n'y a pas d'étape 3 entre l'enregistrement et la restauration de la sélection, et pourtant le curseur se déplace. Cela ne semble se produire que si la sélection est vide (c'est-à-dire que j'ai un curseur clignotant mais pas de texte), et cela ne semble se produire que lorsque le curseur se trouve à la fin d'un nœud de texte qui précède immédiatement un nœud de bloc.

Il semble que la plage est toujours dans la position correcte (si j'appelle parentElement sur la plage, elle renvoie le div), mais si j'obtiens une nouvelle plage de la sélection actuelle, la nouvelle plage se trouve à l'intérieur de la balise de paragraphe, et c'est son parentElement.

Comment puis-je contourner ce problème et enregistrer et restaurer régulièrement la sélection dans Internet Explorer?

Était-ce utile?

La solution

J'ai découvert quelques méthodes pour gérer des plages IE telles que celle-ci.

Si tout ce que vous voulez faire est de sauvegarder le curseur, puis de le restaurer, vous pouvez utiliser la méthode pasteHTML pour insérer une plage vide à la position actuelle du curseur, puis utiliser la méthode moveToElementText pour le remettre en place. à nouveau à cette position:

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

Vous pouvez également compter le nombre de caractères précédant la position actuelle du curseur et enregistrer ce nombre:

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

Pour restaurer le curseur, définissez-le au début, puis déplacez-le d'un nombre de caractères donné:

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

J'espère que cela vous aidera.

Autres conseils

J'ai eu un peu de mal à comprendre malheureusement, je ne vois pas de solution de contournement ... Bien que l’une des choses que j’ai remarquées lors du débogage de javascript, il semble que le problème vienne de l’objet range lui-même plutôt que de la suivante range.select () . Si vous examinez les valeurs de l'objet plage que selection.createRange () renvoie, oui, l'objet dom parent peut être correct, mais les informations de positionnement font déjà référence au début de la ligne suivante (c'est-à-dire offsetLeft / Top, boundingLeft / Top, etc. ont déjà tort).

D'après les informations ici , ici et ici , je pense que vous n’avez pas de chance avec IE, car vous n’avez accès qu’à l’objet TextRange de Microsoft, qui semble cassé. De mon expérimentation, vous pouvez déplacer la plage et la positionner exactement où elle devrait être, mais une fois que vous le faites, l’objet de plage passe automatiquement à la ligne suivante avant même que vous ayez essayé de .select () il. Par exemple, vous pouvez voir le problème en mettant ce code entre vos étapes Step 1 & amp; Étape 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);
}

Donc, malheureusement, il ne semble pas y avoir de moyen de s'assurer que la plage est au bon endroit lorsque vous la sélectionnez à nouveau.

Évidemment, il existe une solution triviale à votre code ci-dessus, en modifiant l'étape 2 en ceci:

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

Mais vous voulez probablement faire quelque chose entre l'étape 1 & amp; L'étape 2 de votre travail réel implique le déplacement de la sélection, d'où la nécessité de la réinitialiser. Mais juste au cas où. :)

Donc, le mieux que je puisse faire est d'aller & amp; votez pour le bug que vous avez créé ... J'espère qu'ils vont le réparer.

J'ai récemment travaillé sur un site utilisant Microsoft CMS avec le "pack MSIB +". des contrôles incluant un éditeur WYSIWYG exécuté dans Internet Explorer.

Je semble me souvenir de certains commentaires de l'éditeur Javascript côté client, qui étaient spécifiquement liés à ce bogue dans IE et à la méthode Range.Select ().

Malheureusement, je ne travaille plus là-bas, je ne peux donc pas accéder aux fichiers Javascript, mais vous pourrez peut-être les obtenir ailleurs?

Bonne chance

Peut-être que je ne comprends pas bien, mais si je clique à droite de la première ligne, mon curseur apparaît déjà immédiatement au début de la seconde ligne. Ce n'est donc pas un problème TextRange, n'est-ce pas?

Ajouter un type de document pour que la page de test soit rendue en mode standard au lieu du mode quirks résout ce problème pour moi.

Et je ne peux pas reproduire ce que fait votre fonction myhandler, car cliquer sur ce bouton déplace le focus sur le bouton afin que je ne puisse plus voir le curseur ni le récupérer. Recherche de la position du curseur dans une zone contentEditable semble être un tout autre problème .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top