404 votes

Sélection de texte dans un élément (semblable à la mise en évidence avec votre souris)

Je voudrais que les utilisateurs cliquent sur un lien, puis qu'ils sélectionnent le texte HTML dans un autre élément ( no une entrée).

Par "sélectionner", je veux dire de la même manière que vous sélectionnez du texte en faisant glisser votre souris dessus. Les recherches ont été difficiles car tout le monde parle de "sélection" ou de "surbrillance" en d'autres termes.

Est-ce possible ? Mon code jusqu'à présent :

HTML:

<a href="javascript:" onclick="SelectText('xhtml-code')">Select Code</a>
<code id="xhtml-code">Some Code here </code>

JS :

function SelectText(element) {
    $("#" + element).select();
}

Est-ce que j'ai manqué quelque chose de flagrant ?

584voto

Jason Points 20255

J'ai trouvé une solution à ce problème, grâce à ce fil trouvé par TheVillageIdiot. J'ai pu modifier les informations données et les mélanger avec un peu de jQuery pour créer une fonction totalement géniale pour sélectionner le texte dans n'importe quel élément, quel que soit le navigateur :

function SelectText(element) {
    var text = document.getElementById(element);
    if ($.browser.msie) {
        var range = document.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if ($.browser.mozilla || $.browser.opera) {
        var selection = window.getSelection();
        var range = document.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($.browser.safari) {
        var selection = window.getSelection();
        selection.setBaseAndExtent(text, 0, text, 1);
    }
}

MODIFIER (9/28/11) :

Cela fait un moment que cette réponse n'a pas été mise à jour, et j'ai beaucoup appris en tant que développeur depuis que j'ai posé cette question et y ai répondu. Elle a également suscité beaucoup plus d'attention que je ne le pensais. Je souhaite proposer une meilleure solution que celle que j'ai publiée à l'origine, une solution qui ne repose pas sur des méthodes jQuery obsolètes, ni sur jQuery tout court, d'ailleurs. Vous pourriez utiliser jQuery pour vous aider ? Bien sûr, mais si vous pouvez obtenir le même résultat sans jQuery et en utilisant la détection des fonctionnalités au lieu du reniflage du navigateur, pourquoi ne le feriez-vous pas ? Voici donc ma réponse actualisée :

function selectText(element) {
    var doc = document
        , text = doc.getElementById(element)
        , range, selection
    ;    
    if (doc.body.createTextRange) { //ms
        range = doc.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if (window.getSelection) { //all others
        selection = window.getSelection();        
        range = doc.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);
    }
}

Voici un actualisé Démonstration de travail . Pour ceux d'entre vous qui cherchent un plugin jQuery, j'ai fait un de ceux-là aussi (à nouveau mis à jour).

MISE À JOUR (1/10/2012) Selon la suggestion de Tim Down, setBaseAndExtent() n'est pas nécessaire pour webkit.

123voto

Tim Down Points 124501

Voici une version sans reniflage du navigateur et sans recours à jQuery :

function selectElementText(el, win) {
    win = win || window;
    var doc = win.document, sel, range;
    if (win.getSelection && doc.createRange) {
        sel = win.getSelection();
        range = doc.createRange();
        range.selectNodeContents(el);
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (doc.body.createTextRange) {
        range = doc.body.createTextRange();
        range.moveToElementText(el);
        range.select();
    }
}

selectElementText(document.getElementById("someElement"));
selectElementText(elementInIframe, iframe.contentWindow);

19voto

lepe Points 8959

Le code de Jason ne peut pas être utilisé pour les éléments à l'intérieur d'un iframe (car la portée diffère de la fenêtre et du document). J'ai corrigé ce problème et je l'ai modifié pour qu'il puisse être utilisé comme tout autre plugin jQuery (chaînable) :

Exemple 1 : Sélection de tout le texte à l'intérieur des balises < code > en un seul clic et ajout de la classe "selected" :

$(function() {
    $("code").click(function() {
        $(this).selText().addClass("selected");
    });
});

Exemple 2 : Au clic du bouton, sélectionner un élément à l'intérieur d'un Iframe :

$(function() {
    $("button").click(function() {
        $("iframe").contents().find("#selectme").selText();
    });
});

Remarque : n'oubliez pas que la source de l'iframe doit résider dans le même domaine pour éviter les erreurs de sécurité.

Plugin jQuery :

jQuery.fn.selText = function() {
    var obj = this[0];
    if ($.browser.msie) {
        var range = obj.offsetParent.createTextRange();
        range.moveToElementText(obj);
        range.select();
    } else if ($.browser.mozilla || $.browser.opera) {
        var selection = obj.ownerDocument.defaultView.getSelection();
        var range = obj.ownerDocument.createRange();
        range.selectNodeContents(obj);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($.browser.safari) {
        var selection = obj.ownerDocument.defaultView.getSelection();
        selection.setBaseAndExtent(obj, 0, obj, 1);
    }
    return this;
}

Je l'ai testé dans IE8, Firefox, Opera, Safari, Chrome (versions actuelles). Je ne suis pas sûr qu'il fonctionne dans les anciennes versions d'IE (sincèrement, je m'en fiche).

16voto

TheVillageIdiot Points 22158

Ce site filetage contient des choses vraiment merveilleuses. Mais je ne suis pas en mesure de le faire correctement sur cette page en utilisant FF 3.5b99 + FireBug en raison d'une "erreur de sécurité".

Yipee !! J'ai pu sélectionner toute la barre latérale droite avec ce code, j'espère que cela vous aidera :

    var r = document.createRange();
    var w=document.getElementById("sidebar");  
    r.selectNodeContents(w);  
    var sel=window.getSelection(); 
    sel.removeAllRanges(); 
    sel.addRange(r);

PS:- Je n'ai pas pu utiliser les objets retournés par les sélecteurs jquery comme

   var w=$("div.welovestackoverflow",$("div.sidebar"));

   //this throws **security exception**

   r.selectNodeContents(w);

5voto

Madbreaks Points 8759

J'ai aimé la réponse de Lepe, sauf pour certaines choses :

  1. Le reniflage du navigateur, jQuery ou pas, n'est pas optimal.
  2. SEC
  3. Ne fonctionne pas dans IE8 si le parent de l'objet ne supporte pas l'option createTextRange
  4. La capacité de Chrome à utiliser setBaseAndExtent doit être optimisé (IMO)
  5. Ne sélectionne pas le texte qui s'étend sur plusieurs éléments du DOM (éléments dans l'élément "sélectionné"). En d'autres termes, si vous appelez selText sur un div contenant plusieurs éléments span, il va no sélectionner le texte de chacun de ces éléments. C'était un obstacle pour moi, mais je ne suis pas sûr.

Voici ce que j'ai trouvé, avec un clin d'œil à la réponse de Lepe pour l'inspiration. Je suis sûr que je vais être ridiculisé car c'est peut-être un peu lourd (et pourrait l'être davantage, mais je m'égare). Mais ça marche et ça évite de renifler le navigateur et d'avoir des problèmes de sécurité. c'est le but .

selectText:function(){

    var range,
        selection,
        obj = this[0],
        type = {
            func:'function',
            obj:'object'
        },
        // Convenience
        is = function(type, o){
            return typeof o === type;
        };

    if(is(type.obj, obj.ownerDocument)
        && is(type.obj, obj.ownerDocument.defaultView)
        && is(type.func, obj.ownerDocument.defaultView.getSelection)){

        selection = obj.ownerDocument.defaultView.getSelection();

        if(is(type.func, selection.setBaseAndExtent)){
            // Chrome, Safari - nice and easy
            selection.setBaseAndExtent(obj, 0, obj, $(obj).contents().size());
        }
        else if(is(type.func, obj.ownerDocument.createRange)){

            range = obj.ownerDocument.createRange();

            if(is(type.func, range.selectNodeContents)
                && is(type.func, selection.removeAllRanges)
                && is(type.func, selection.addRange)){
                // Mozilla
                range.selectNodeContents(obj);
                selection.removeAllRanges();
                selection.addRange(range);
            }
        }
    }
    else if(is(type.obj, document.body) && is(type.obj, document.body.createTextRange)) {

        range = document.body.createTextRange();

        if(is(type.obj, range.moveToElementText) && is(type.obj, range.select)){
            // IE most likely
            range.moveToElementText(obj);
            range.select();
        }
    }

    // Chainable
    return this;
}

C'est tout. Une partie de ce que vous voyez l'est pour des raisons de lisibilité et/ou de commodité. Testé sur Mac dans les dernières versions d'Opera, Safari, Chrome, Firefox et IE. Testé également dans IE8. En outre, je ne déclare généralement les variables que si/quand elles sont nécessaires à l'intérieur des blocs de code, mais jslint a suggéré qu'elles soient toutes déclarées en haut. Ok jslint.

Editar J'ai oublié d'inclure le lien avec le code de l'opérateur :

function SelectText(element) {
    $("#" + element).selectText();
}

Cheers

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