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 :
- En premier lieu, nous créons une gamme à partir de e.target
- Nous le ramenons au début.
- 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.
- Nous obtenons la bonne et divisons target.innerText avec elle, pour obtenir les parties gauche et droite du texte du noeud.
- 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.
- 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 '';
}