Zrozumienie, co dzieje się z zaznaczeniem textarea za pomocą JavaScript

Pracuję nad edytorem w przeglądarce w textarea. Zacząłem szukać informacji na temat radzenia sobie z selekcją textarea i znalazłem ten plugin jQuery, fieldSelection , który wykonuje prostą manipulację.

To jednak nie wyjaśnia, co się dzieje.

Chcę zrozumieć więcej na temat wyboru textarea w JavaScript, najlepiej z opisem zarówno scenariuszy pre-DOM3, jak i post-DOM30.

Author: random, 2008-12-31

4 answers

Zacznij od wprowadzenia PPK do zakresów . Mozilla developer connection zawiera informacje o selekcjach W3C . Microsoft ma swój system udokumentowany na MSDN . Więcej trików można znaleźć w odpowiedziach tutaj .

Oprócz niekompatybilnych interfejsów z pewnością ucieszy cię fakt, że z textarea węzłami dzieje się jeszcze więcej dziwnych rzeczy. O ile dobrze pamiętam zachowują się jak inne węzły po wybraniu ich w IE, ale w innych przeglądarkach mają niezależny zakres selekcji, który jest wyświetlany za pomocą właściwości .selectionEnd i .selectionStart na węźle.

Dodatkowo, powinieneś spojrzeć na .contentEdiable jako środek do edycji rzeczy na żywo. Od wydania Firefox3 jest to teraz obsługiwane przez wszystkie przeglądarki.

 10
Author: Borgar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:01
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;
}
 29
Author: user357565,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-19 08:08:23

Właśnie przyjąłem rozwiązanie przedstawione przez user357565 i przekodowałem do jQuery direct use:

(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));
Mam nadzieję, że komuś się przyda!
 5
Author: Fèlix Galindo Allué,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-23 21:52:22

Jedyne, co mogę dodać, to to, że wydaje się (nie próbowałem), że powinno to przewijać się do góry, gdy wypełniasz zawartość. eay remedium jest owinięcie linii, która robi

e.value =

Z dwoma liniami do kopiowania i przywracania scrollTop, jak TAK:

var rememberScrollTop = e.scrollTop;
e.value = .... (same as in user357565 snippet)
e.scrollTop = rememberScrollTop;
 1
Author: anon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 06:41:51