2 votes

textRange MoveToPoint() IE

J'ai un problème avec la méthode moveToPoint() de textRange IE11 ;

Il semble que ça ne fonctionne pas si le nœud pointé n'est pas dans le premier écran ;

document.addEventListener( "click", function(e) {
    var x = e.clientX; 
    var y = e.clientY; 
    var range = document.body.createTextRange();
    range.moveToPoint(x, y);
    range.expand('word');
    console.log(range);
    console.log(range.text);
});

Ce code récupère les mots à partir du point de clic, mais il ne fonctionne normalement que si nous cliquons dans les nœuds qui étaient sur le premier scroll.

Si nous descendons un peu vers le nœud qui n'était pas dans le premier scroll, nous allons attraper l'exception.

Quelqu'un sait-il comment gérer correctement cette situation ?

1voto

JAYBEkster Points 584

Vous pensez que vos collègues n'utilisent pas stackoverflow, n'est-ce pas ? Tant que vous n'êtes pas en période d'essai, ce n'est pas un bon karma de poster des questions d'examen. Je suggère que cette information soit transmise à votre équipe et que vous ayez des conséquences désagréables.

0voto

Denis Sokolov Points 30

Vous pouvez utiliser les propriétés offsetX, offsetY. Ou vous pouvez ajouter la position de défilement aux variables x et y, en utilisant les propriétés scrollLeft et scrollTop de l'élément parent.

0voto

Kirill K Points 51

Je peux confirmer qu'un tel bogue existe dans IE11. Vous pouvez trouver les détails ici dans les commentaires : http://generatedcontent.org/post/69213745095/ie11review-part1

Solution possible (après avoir créé une gamme) :

range.moveToElementText(e.target);
range.collapse(true)
range.expand("word")

Vous avez maintenant le premier mot sélectionné. Vous devez maintenant vérifier si le mot sélectionné correspond à la position du clic de la souris en utilisant les propriétés de TextRange boundingHeight, boundingWidth, boundingLeft et boundingTop. Si ce n'est pas le cas, vous vous déplacez en cycle vers le mot suivant :

range.collapse(false);
range.expand("word");

0voto

Tigran Tigran Points 24

Eh bien, inspiré par @dinalt et @JAYBEkster, j'ai trouvé cette solution. Peut-être que quelqu'un en aura besoin après tout.

Le code ci-dessous (pour IE, je n'ai pas vérifié toutes les versions, mais il fonctionne bien dans la version 11+) permet de saisir un mot dans un html complexe imbriqué.

Comment ça marche, étape par étape :

  1. En premier lieu, nous créons une gamme à partir de e.target
  2. Nous le ramenons au début.
  3. Ce serait génial si nous pouvions simplement expand("word") et itérer chaque mot, mais malheureusement nous ne pouvons pas. Donc on boucle sur les caractères, on les divise en mots et on compare leurs limites avec e.clientX, et Y, d'un autre côté en itérant les caractères au lieu des mots on a plus de contrôle.
  4. Nous obtenons la bonne et divisons target.innerText avec elle, pour obtenir les parties gauche et droite du texte du noeud.
  5. Après cela, nous divisons à nouveau chaque partie mais avec nos séparateurs (regexp avec tous les espaces blancs et les séparateurs de mots que je peux imaginer) et nous obtenons deux arr.

Pourquoi faire les étapes 4 et 5 ? Parce que nous trouvons du texte qui se termine dans ce noeud, mais ce n'est peut-être pas la fin ou le début du mot, pour certaines raisons de style, la partie acent du mot peut être son propre noeud et le noeud cible peut juste être la partie centrale du mot. Donc nous devons sauter à travers les noeuds et trouver la fin du mot.

Si vous êtes sûr que votre html ne se plaint pas, vous pouvez sauter toutes les autres étapes.

  1. Ensuite, si arr est vide, nous exécutons notre fonction récursive qui parcourt les noeuds et saisit le texte jusqu'à ce qu'elle trouve un séparateur.

Ouais, ça ressemble vraiment à un rocher puisque pour un tel, on peut penser à une tâche simple. Mais je n'ai pas trouvé de meilleure solution, il y avait quelques options, mais toutes n'étaient pas aussi universelles que je le voulais.

L'avantage de ce code est qu'il ne se soucie pas du tout de la complexité du html.

Je vais poster ici le lien vers mon dépôt github où vous pouvez trouver le code complet de wordGraber, qui fonctionnera avec Chrome, Safari, FF et IE bien sûr.

https://github.com/6graNik/wordGrabber

Vous trouverez ci-dessous une partie seulement pour l'IE.

function getWordFromEventIE(e) {
  const x = e.clientX;
  const y = e.clientY;
  const innerText = e.target && e.target.innerText;
  const separators = /([\s&^:;,!?(){}])+/;
  const IErange = global.document.body.createTextRange();

  try {
    IErange.moveToElementText(e.target);
    IErange.collapse(true);

    let wholeSentenceLength = 0;
    const reqIEcharTest = () => {
      do {
        IErange.expand("character");
        wholeSentenceLength += 1;
      }
      while (!separators.test(IErange.text.slice(-1)) && wholeSentenceLength <= innerText.length);
      const {boundingLeft, boundingTop, boundingWidth, boundingHeight, text} = IErange;

      if (boundingLeft <= x && x <= (boundingLeft + boundingWidth)
       && boundingTop <= y && y <= (boundingTop + boundingHeight)) {
        if (wholeSentenceLength <= innerText.length && !separators.test(text.slice(-1)) ) {
          return text;
        }
        return text.substr(0, text.length - 1);
      }
      IErange.collapse(false);
      return reqIEcharTest();
    };
    const text = reqIEcharTest().trim();
    const innerTextArr = innerText.split(text);
    const innerTextLeft = innerTextArr[0].split(separators);
    const innerTextRight = innerTextArr[1].split(separators);

    let leftPart;
    if (innerTextLeft <= 1) {
      leftPart = recursionWordGet(e.target, 'left') + innerTextLeft.slice(-1)[0];
    } else {
      leftPart = innerTextLeft.slice(-1)[0];
    }
    let rightPart;
    if (innerTextRight <= 1) {
      rightPart = innerTextRight[0] + recursionWordGet(e.target, 'right');
    } else {
      rightPart = innerTextRight[0];
    }

    return leftPart + text + rightPart;
  } catch (err) {
    console.log('>>>>>>>>>>>>>>>>>> text', err);
  }
}

function recursionWordGet(target, option) {
  const separators = /([\s&^:;,!?(){}])+/;
  const uniqString = Date.now();

  target.setAttribute("data-target", uniqString);
  const {parentNode} = target;
  const copyNode = parentNode.cloneNode(true);

  copyNode.querySelector(`[data-target="${uniqString}"]`).innerText = uniqString;
  const tagName = copyNode.tagName;

  const text = copyNode.innerText;
  const textArr = text.split(uniqString);
  const textLeftPartArr = textArr[0].split(separators);
  const textRightPartArr = textArr[1].split(separators);

  if (option === 'right') {
    let returnText;
    if (textRightPartArr.length <= 1 && tagName === 'span') {
      returnText = textRightPartArr[0] + recursionWordGet(parentNode, 'right');
    } else {
      returnText = textRightPartArr[0];
    }
    return returnText;
  }

  if (option === 'left') {
    let returnText;
    if (textLeftPartArr <= 1 && tagName === 'span') {
      returnText = recursionWordGet(parentNode, 'left') + textLeftPartArr.slice(-1)[0];
    } else {
      returnText = textLeftPartArr.slice(-1)[0];
    }
    return returnText;
  }

  return '';
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X