J'ai essay� de faire 5 actions, que je vais d�crire dans cet article :

  1. obtenir le texte s�lectionn� dans un textarea donn� ;
  2. obtenir la position du d�but de la selection du contenu du textarea (en commen�ant � 0) ;
  3. obtenir la position de la fin de la selection du contenu ;
  4. d�placer le curseur � une position, en pr�cisant �ventuellement une position de fin pour cr�er une selection ;
  5. remplacer le texte s�lectionn� par un autre.

D'abord, examinons le comportement standard (test� sous Mozilla Firefox >= 1.5).

  • Chaque textarea sauvegarde sa propre selection.
  • Chaque textarea contient 2 variables selectionStart et selectionEnd qui contiennent � tout moment les coordonn�es de la selection (si rien n'est selectionn�, selectionStart est �gal � selectionEnd)
  • Chaque textarea poss�de une m�thode setSelectionRange(start, end) qui permet de cr�er une selection ou de positionner le curseur (en passant 2 fois la m�me valeur).
  • Pour remplacer le texte selectionn�, il faut couper le texte en 3 : avant, selection, apr�s, et le remplacer par avant + nouvelle selection + apr�s. Il faut penser � remettre d'indice de scroll afin de conserver la barre de d�filement � la m�me position.

Voyons maintenant le comportement d'Internet Explorer, qui, comme a son habitude, est totalement illogique, incoh�rent et, disons-le, compl�tement con.

  • Internet Explorer ne g�re qu'une seule s�lection pour toute le document, accessible via document.selection. En cons�quence de quoi, il faut toujours penser � faire un focus() sur le textarea � traiter, sans quoi on risque d'avoir des r�sultats totalement incoh�rents.
  • Cependant, il est possible de cr�er une selection pour chaque textarea. Mais ces selections ne contiendront pas le texte selectionn�, elles servent uniquement � d�placer le curseur (!) (j'avais pr�venu que c'�tait compl�tement con...).
  • Pour manipuler une selection, il faut cr�er un objet TextRange, qui permet de faire des tas de choses (y compris des choses document�es comme � opaque � par Microsoft), mais pas de r�cup�rer la position du curseur.
  • Il est impossible se sp�cifier directement la position du curseur.
  • Il y a une m�thode propri�taire pour remplacer la s�lection, en mettant � jour l'attribut text de l'objet range (range.text = 'toto').

Voyons maintenant comment dominer IE.

Note : Les fonctions propos�es ici sont destin�es � �tre utilis�e dans une classe o� this repr�sente l'objet textarea. N'h�sitez � pas adapter pour votre propre besoin :)

Obtenir la s�lection

La fonction suivante permet d'obtenir le texte s�lectionn� dans un textarea.

getSelection: function ()
{
        if (this.setSelectionRange)
                return this.value.substring(this.selectionStart, this.selectionEnd);
        else if (document.selection) {
                this.focus();
                return document.selection.createRange().text;
        }
}

Obtenir les coordonn�es du curseur

Alors l�, �a devient rigolo. La solution : r�cup�rer la selection globale, puis la recopier dans une selection locale au textarea. Ensuite, d�placer la fin de la selection le plus possible (la selection locale, contraiement � la selection globale du document, s'arrettera � la fin de texte). Enfin, effectuer une petite soustraction.

getSelectionStart: function()
{
        if ( typeof this.selectionStart != 'undefined' )
                return this.selectionStart;
        
        // IE Support
        this.focus();
        var range = this.createTextRange();
        range.moveToBookmark(document.selection.createRange().getBookmark());
        range.moveEnd('character', this.value.length);
        return this.value.length - range.text.length;
}

M�me principe pour la fin.

getSelectionEnd: function()
{
        if ( typeof this.selectionEnd != 'undefined' )
                return this.selectionEnd;

        // IE Support
        this.focus();
        var range = this.createTextRange();
        range.moveToBookmark(document.selection.createRange().getBookmark());
        range.moveStart('character', - this.value.length);
        return range.text.length;
}

Positionner le curseur

Cette fois ci, la technique est de cr�er une selection vide, de la positionner au bon endroit, de d'utiliser la m�thode select() pour la faire apparaitre.

setCaretPos: function(start, end)
{
        end = end || start;
        this.focus();
        if (this.setSelectionRange)
                this.setSelectionRange(start, end);
        else if (document.selection) {
                var range = this.createTextRange();
                range.moveStart('character', start);
                range.moveEnd('character', - this.value.length + end);
                range.select();
        }
}

Remplacer la s�lection

Avec toutes ces m�thodes cross-browser, la fonction de remplacement est un jeu d'enfant !

J'ai ajout� un param�tre keep indiquant s'il faut garder ou non le texte selectionn� apr�s remplacement.

replaceSelection: function (str, keep)
{
        this.focus();
        
        var start = this.getSelectionStart();
        var stop = this.getSelectionEnd();
        var end = start + str.length;
        var scrollPos = this.scrollTop;
                
        this.value = this.value.substring(0, start) + str + this.value.substring(stop);
        if ( keep ) this.setCaretPos(start, end);
        else this.setCaretPos(end);
        this.scrollTop = scrollPos;
}

En esperant que tout ceci vous servira :)