Domanda

Sto lavorando a un editor nel browser all'interno di un textarea . Ho iniziato a cercare alcune informazioni su come gestire la selezione textarea e ho trovato questo plugin jQuery, fieldSelection che esegue alcune semplici manipolazioni.

Tuttavia, non spiega cosa sta succedendo.

Voglio saperne di più sulla selezione di textarea in JavaScript, preferibilmente con una descrizione degli scenari pre-DOM3 e post-DOM30.

È stato utile?

Soluzione

Inizia con la introduzione alle gamme . La connessione per sviluppatori Mozilla contiene informazioni su Selezioni W3C . Microsoft ha il suo sistema documentato su MSDN . Altri trucchi sono disponibili nelle risposte qui .

Oltre alle interfacce incompatibili, sarai felice di sapere che ci sono altre stranezze in corso con i nodi textarea . Se ricordo correttamente si comportano come qualsiasi altro nodo quando li selezioni in IE, ma in altri browser hanno un intervallo di selezione indipendente che viene esposto tramite .selectionEnd e .selectionStart proprietà sul nodo.

Inoltre, dovresti dare un'occhiata a .contentEditable come mezzo per modificare le cose dal vivo. Dalla versione di Firefox3, questo è ora supportato da tutti i browser.

Altri suggerimenti

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;
}

Ho appena adottato la soluzione presentata dall'utente357565 e ricodificata per l'uso diretto di 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));

Spero che qualcuno lo trovi utile!

l'unica cosa che posso aggiungere è che sembra (non averlo provato concretamente) che questo dovrebbe scorrere fino in alto ogni volta che manipoli il contenuto. un rimedio facile è quello di avvolgere la linea che lo fa

e.value =

con due righe per copiare e ripristinare scrollTop, in questo modo:

var rememberScrollTop = e.scrollTop;
e.value = .... (same as in user357565 snippet)
e.scrollTop = rememberScrollTop;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top