Question

Je travaille sur un éditeur intégré au navigateur dans une zone de texte . J'ai commencé à chercher des informations sur le traitement de la sélection textarea et à trouver ce plugin jQuery, fieldSelection qui effectue quelques manipulations simples.

Cependant, cela n'explique pas ce qui se passe.

Je souhaite en savoir plus sur la sélection de textarea en JavaScript, avec de préférence une description des scénarios antérieurs à DOM3 et postérieurs à DOM30.

Était-ce utile?

La solution

Commencez par la introduction aux plages de PPK . La connexion du développeur Mozilla contient des informations sur les sélections du W3C . Le système de leur Microsoft est documenté sur MSDN . Vous trouverez quelques astuces supplémentaires dans les réponses ici .

Outre les interfaces incompatibles, vous serez heureux de savoir que les nœuds textarea présentent un surcroît de bizarrerie. Si je me souviens bien, ils se comportent comme tous les autres noeuds lorsque vous les sélectionnez dans IE, mais dans d'autres navigateurs, ils ont une plage de sélection indépendante qui est exposée via .selectionEnd et .selectionStart propriétés sur le nœud.

De plus, vous devriez vraiment jeter un oeil à .contentEditable comme moyen de modifier les choses en direct. Depuis la sortie de Firefox3, ceci est maintenant supporté par tous les navigateurs.

Autres conseils

function get_selection(the_id)
{
    var e = document.getElementById(the_id);

    //Mozilla and DOM 3.0
    if('selectionStart' in e)
    {
        var l = e.selectionEnd - e.selectionStart;
        return { start: e.selectionStart, end: e.selectionEnd, length: l, text: e.value.substr(e.selectionStart, l) };
    }
    //IE
    else if(document.selection)
    {
        e.focus();
        var r = document.selection.createRange();
        var tr = e.createTextRange();
        var tr2 = tr.duplicate();
        tr2.moveToBookmark(r.getBookmark());
        tr.setEndPoint('EndToStart',tr2);
        if (r == null || tr == null) return { start: e.value.length, end: e.value.length, length: 0, text: '' };
        var text_part = r.text.replace(/[\r\n]/g,'.'); //for some reason IE doesn't always count the \n and \r in the length
        var text_whole = e.value.replace(/[\r\n]/g,'.');
        var the_start = text_whole.indexOf(text_part,tr.text.length);
        return { start: the_start, end: the_start + text_part.length, length: text_part.length, text: r.text };
    }
    //Browser not supported
    else return { start: e.value.length, end: e.value.length, length: 0, text: '' };
}

function replace_selection(the_id,replace_str)
{
    var e = document.getElementById(the_id);
    selection = get_selection(the_id);
    var start_pos = selection.start;
    var end_pos = start_pos + replace_str.length;
    e.value = e.value.substr(0, start_pos) + replace_str + e.value.substr(selection.end, e.value.length);
    set_selection(the_id,start_pos,end_pos);
    return {start: start_pos, end: end_pos, length: replace_str.length, text: replace_str};
}

function set_selection(the_id,start_pos,end_pos)
{
    var e = document.getElementById(the_id);

    //Mozilla and DOM 3.0
    if('selectionStart' in e)
    {
        e.focus();
        e.selectionStart = start_pos;
        e.selectionEnd = end_pos;
    }
    //IE
    else if(document.selection)
    {
        e.focus();
        var tr = e.createTextRange();

        //Fix IE from counting the newline characters as two seperate characters
        var stop_it = start_pos;
        for (i=0; i < stop_it; i++) if( e.value[i].search(/[\r\n]/) != -1 ) start_pos = start_pos - .5;
        stop_it = end_pos;
        for (i=0; i < stop_it; i++) if( e.value[i].search(/[\r\n]/) != -1 ) end_pos = end_pos - .5;

        tr.moveEnd('textedit',-1);
        tr.moveStart('character',start_pos);
        tr.moveEnd('character',end_pos - start_pos);
        tr.select();
    }
    return get_selection(the_id);
}

function wrap_selection(the_id, left_str, right_str, sel_offset, sel_length)
{
    var the_sel_text = get_selection(the_id).text;
    var selection =  replace_selection(the_id, left_str + the_sel_text + right_str );
    if(sel_offset !== undefined && sel_length !== undefined) selection = set_selection(the_id, selection.start +  sel_offset, selection.start +  sel_offset + sel_length);
    else if(the_sel_text == '') selection = set_selection(the_id, selection.start + left_str.length, selection.start + left_str.length);
    return selection;
}

Je viens d'adopter la solution présentée par user357565 et recodée pour une utilisation directe jQuery:

(function ($) {
  $.fn.get_selection = function () {
    var e = this.get(0);
    //Mozilla and DOM 3.0
    if('selectionStart' in e) {
      var l = e.selectionEnd - e.selectionStart;
      return { start: e.selectionStart, end: e.selectionEnd, length: l, text: e.value.substr(e.selectionStart, l) };
    }
    else if(document.selection) {    //IE
      e.focus();
      var r = document.selection.createRange();
      var tr = e.createTextRange();
      var tr2 = tr.duplicate();
      tr2.moveToBookmark(r.getBookmark());
      tr.setEndPoint('EndToStart',tr2);
      if (r == null || tr == null) return { start: e.value.length, end: e.value.length, length: 0, text: '' };
      var text_part = r.text.replace(/[\r\n]/g,'.'); //for some reason IE doesn't always count the \n and \r in length
      var text_whole = e.value.replace(/[\r\n]/g,'.');
      var the_start = text_whole.indexOf(text_part,tr.text.length);
      return { start: the_start, end: the_start + text_part.length, length: text_part.length, text: r.text };
    }
    //Browser not supported
    else return { start: e.value.length, end: e.value.length, length: 0, text: '' };
  };

  $.fn.set_selection = function (start_pos,end_pos) {
    var e = this.get(0);
    //Mozilla and DOM 3.0
    if('selectionStart' in e) {
      e.focus();
      e.selectionStart = start_pos;
      e.selectionEnd = end_pos;
    }
    else if (document.selection) { //IE
      e.focus();
      var tr = e.createTextRange();

      //Fix IE from counting the newline characters as two seperate characters
      var stop_it = start_pos;
      for (i=0; i < stop_it; i++) if( e.value[i].search(/[\r\n]/) != -1 ) start_pos = start_pos - .5;
      stop_it = end_pos;
      for (i=0; i < stop_it; i++) if( e.value[i].search(/[\r\n]/) != -1 ) end_pos = end_pos - .5;

      tr.moveEnd('textedit',-1);
      tr.moveStart('character',start_pos);
      tr.moveEnd('character',end_pos - start_pos);
      tr.select();
    }
    return this.get_selection();
  };

  $.fn.replace_selection = function (replace_str) {
    var e = this.get(0);
    selection = this.get_selection();
    var start_pos = selection.start;
    var end_pos = start_pos + replace_str.length;
    e.value = e.value.substr(0, start_pos) + replace_str + e.value.substr(selection.end, e.value.length);
    this.set_selection(start_pos,end_pos);
    return {start: start_pos, end: end_pos, length: replace_str.length, text: replace_str};
  };

  $.fn.wrap_selection = function (left_str, right_str, sel_offset, sel_length) {
    var the_sel_text = this.get_selection().text;
    var selection =  this.replace_selection(left_str + the_sel_text + right_str );
    if(sel_offset !== undefined && sel_length !== undefined) 
      selection = this.set_selection(selection.start +  sel_offset, selection.start +  sel_offset + sel_length);
    else if(the_sel_text == '') 
      selection = this.set_selection(selection.start + left_str.length, selection.start + left_str.length);
    return selection;
  };
}(jQuery));

J'espère que quelqu'un le trouvera utile!

La seule chose que je puisse ajouter, c'est qu'il semble (cela n'a pas été essayé) que cela devrait défiler à chaque fois que vous modifiez le contenu. un remède eay est d’envelopper la ligne qui fait

e.value =

avec deux lignes pour copier et restaurer scrollTop, comme suit:

var rememberScrollTop = e.scrollTop;
e.value = .... (same as in user357565 snippet)
e.scrollTop = rememberScrollTop;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top