44 votes

Mise en évidence d'une plage de texte à l'aide de JavaScript

J'aimerais mettre en évidence (appliquer les css) une certaine plage de texte, désignée par sa position de début et de fin. C'est plus difficile qu'il n'y paraît, car il peut y avoir d'autres balises dans le texte, qui doivent être ignorées.

Exemple :

<div>abcd<em>efg</em>hij</div>

highlight(2, 6) doit mettre en évidence "cdef "sans retirer l'étiquette.

J'ai déjà essayé d'utiliser un objet TextRange, mais sans succès.

Merci d'avance !

0 votes

Pouvez-vous supprimer les balises dans une chaîne temporaire, puis effectuer une sous-chaîne à partir de cette chaîne ?

0 votes

Vous ne pouvez pas ignorer les balises, sinon vous obtiendrez un code html non valide : ab<x>cd<em>ef</x>f</em> . Vous devriez faire quelque chose comme ab<x>cd</x><em><x>ef</x>g</em>

1 votes

Bien sûr, je ne peux pas ignorer les balises, mais ce serait bien si le navigateur pouvait résoudre ces problèmes pour moi d'une manière ou d'une autre.

69voto

Tim Down Points 124501

La fonction ci-dessous permet de définir la sélection sur une paire de décalages de caractères à l'intérieur d'un élément particulier. Il s'agit d'une implémentation naïve : elle ne prend pas en compte le texte qui peut être rendu invisible (soit par CSS, soit parce qu'il se trouve à l'intérieur d'un élément de type <script> o <style> par exemple) et peut présenter des différences entre les navigateurs (IE et tous les autres) en ce qui concerne les sauts de ligne, et ne tient pas compte des espaces blancs réduits (comme 2 ou plusieurs caractères d'espacement consécutifs se réduisant à un espace visible sur la page). Cependant, il fonctionne pour votre exemple dans tous les principaux navigateurs.

Pour l'autre partie, la mise en évidence, je suggère d'utiliser document.execCommand() pour cela. Vous pouvez utiliser ma fonction ci-dessous pour définir la sélection et appeler ensuite document.execCommand() . Vous devrez rendre le document temporairement modifiable dans les navigateurs non IE pour que la commande fonctionne. Voir ma réponse ici pour le code : getSelection & surroundContents sur plusieurs balises

Voici un exemple de jsFiddle montrant l'ensemble, fonctionnant dans tous les principaux navigateurs : http://jsfiddle.net/8mdX4/1211/

Et le code de réglage de la sélection :

function getTextNodesIn(node) {
    var textNodes = [];
    if (node.nodeType == 3) {
        textNodes.push(node);
    } else {
        var children = node.childNodes;
        for (var i = 0, len = children.length; i < len; ++i) {
            textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
        }
    }
    return textNodes;
}

function setSelectionRange(el, start, end) {
    if (document.createRange && window.getSelection) {
        var range = document.createRange();
        range.selectNodeContents(el);
        var textNodes = getTextNodesIn(el);
        var foundStart = false;
        var charCount = 0, endCharCount;

        for (var i = 0, textNode; textNode = textNodes[i++]; ) {
            endCharCount = charCount + textNode.length;
            if (!foundStart && start >= charCount
                    && (start < endCharCount ||
                    (start == endCharCount && i <= textNodes.length))) {
                range.setStart(textNode, start - charCount);
                foundStart = true;
            }
            if (foundStart && end <= endCharCount) {
                range.setEnd(textNode, end - charCount);
                break;
            }
            charCount = endCharCount;
        }

        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (document.selection && document.body.createTextRange) {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(true);
        textRange.moveEnd("character", end);
        textRange.moveStart("character", start);
        textRange.select();
    }
}

3voto

yumyo Points 321

Vous pouvez jeter un coup d'œil sur le fonctionnement de ce puissant utilitaire JavaScript qui prend en charge la sélection de plusieurs éléments du DOM :

MASHA (abréviation de Mark & Share) vous permet de marquer les parties intéressantes du contenu d'une page web et de les partager

http://mashajs.com/index_eng.html

Il est également disponible sur GitHub https://github.com/SmartTeleMax/MaSha

Fonctionne même sur Mobile Safari et IE !

0voto

Bill Points 71

En se basant sur les idées de la jQuery.highlight plugin.

    private highlightRange(selector: JQuery, start: number, end: number): void {
        let cur = 0;
        let replacements: { node: Text; pos: number; len: number }[] = [];

        let dig = function (node: Node): void {
            if (node.nodeType === 3) {
                let nodeLen = (node as Text).data.length;
                let next = cur + nodeLen;
                if (next > start && cur < end) {
                    let pos = cur >= start ? cur : start;
                    let len = (next < end ? next : end) - pos;
                    if (len > 0) {
                        if (!(pos === cur && len === nodeLen && node.parentNode &&
                            node.parentNode.childNodes && node.parentNode.childNodes.length === 1 &&
                            (node.parentNode as Element).tagName === 'SPAN' && (node.parentNode as Element).className === 'highlight1')) {

                            replacements.push({
                                node: node as Text,
                                pos: pos - cur,
                                len: len,
                            });
                        }
                    }
                }
                cur = next;
            }
            else if (node.nodeType === 1) {
                let childNodes = node.childNodes;
                if (childNodes && childNodes.length) {
                    for (let i = 0; i < childNodes.length; i++) {
                        dig(childNodes[i]);
                        if (cur >= end) {
                            break;
                        }
                    }
                }
            }
        };

        selector.each(function (index, element): void {
            dig(element);
        });

        for (let i = 0; i < replacements.length; i++) {
            let replacement = replacements[i];
            let highlight = document.createElement('span');
            highlight.className = 'highlight1';
            let wordNode = replacement.node.splitText(replacement.pos);
            wordNode.splitText(replacement.len);
            let wordClone = wordNode.cloneNode(true);
            highlight.appendChild(wordClone);
            wordNode.parentNode.replaceChild(highlight, wordNode);
        }
    }

0voto

Niklas Points 17865

La solution suivante ne fonctionne pas pour IE, vous devrez appliquer les objets TextRange etc. pour cela. Comme cette solution utilise des sélections, elle ne devrait pas perturber le code HTML dans les cas normaux, par exemple :

<div>abcd<span>efg</span>hij</div>

Con highlight(3,6);

des sorties :

<div>abc<em>d<span>ef</span></em><span>g</span>hij</div>

Notez que le premier caractère à l'extérieur de l'intervalle est enveloppé dans une balise em et ensuite le reste dans le cadre de la span dans une nouvelle. Alors que s'il l'ouvrait simplement au caractère 3 et le terminait au caractère 6, il donnerait un balisage invalide comme :

<div>abc<em>d<span>ef</em>g</span>hij</div>

Le code :

~~var r = document.createRange(); var s = window.getSelection()

r.selectNode($('div')[0]);
s.removeAllRanges();
s.addRange(r);

// not quite sure why firefox has problems with this
if ($.browser.webkit) {
    s.modify("move", "backward", "documentboundary");
}

function highlight(start,end){
    for(var st=0;st<start;st++){
        s.modify("move", "forward", "character");
    }

    for(var st=0;st<(end-start);st++){
        s.modify("extend", "forward", "character");
    }
}

highlight(2,6);

var ra = s.getRangeAt(0);
var newNode = document.createElement("em");
newNode.appendChild(ra.extractContents()); 
ra.insertNode(newNode);

Exemple : http://jsfiddle.net/niklasvh/4NDb9/

éditer Il semblerait qu'au moins mon FF4 ait eu des problèmes avec

s.modify("move", "backward", "documentboundary");

mais en même temps, cela semble fonctionner sans, donc je l'ai changé en

if ($.browser.webkit) {
        s.modify("move", "backward", "documentboundary");
}~~ 

éditer comme l'a souligné Tim, modifier n'est disponible qu'à partir de FF4, j'ai donc adopté une approche différente pour obtenir la sélection, qui n'a pas besoin de la méthode modifier, dans l'espoir de la rendre un peu plus compatible avec les navigateurs (IE a toujours besoin de sa propre solution).

Le code :

var r = document.createRange();
var s = window.getSelection()

var pos = 0;

function dig(el){
    $(el).contents().each(function(i,e){
        if (e.nodeType==1){
            // not a textnode
         dig(e);   
        }else{
            if (pos<start){
               if (pos+e.length>=start){
                range.setStart(e, start-pos);
               }
            }

            if (pos<end){
               if (pos+e.length>=end){
                range.setEnd(e, end-pos);
               }
            }            

            pos = pos+e.length;
        }
    });  
}
var start,end, range;

function highlight(element,st,en){
    range = document.createRange();
    start = st;
    end = en;
    dig(element);
    s.addRange(range);

}
highlight($('div'),3,6);

var ra = s.getRangeAt(0);

var newNode = document.createElement("em");
newNode.appendChild(ra.extractContents()); 
ra.insertNode(newNode);

exemple : http://jsfiddle.net/niklasvh/4NDb9/

0voto

FrameMuse Points 43

Je sais que la question ne porte pas sur ce sujet, mais c'est ce que je cherchais en fait.

Si vous devez mettre en surbrillance le TEXTE SÉLECTIONNÉ

Appliquer le principe suivant : opérer avec Selection Range comme suit

document.getSelection().getRangeAt(0).surroundContents(YOUR_WRAPPER_NODE) // Adds wrapper
document.getSelection().getRangeAt(0).insertNode(NEW_NODE) // Inserts a new node

Voilà, je vous recommande d'en savoir plus sur les sujets suivants Range des méthodes.

J'ai eu du mal avec cela et mes demandes de recherche étaient incorrectes, j'ai donc décidé de le poster ici pour le cas où il y aurait des gens comme moi.

Désolé encore une fois pour cette réponse hors sujet.

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