فهم ما يجري مع اختيار جزء النص مع جافا سكريبت

StackOverflow https://stackoverflow.com/questions/401593

  •  03-07-2019
  •  | 
  •  

سؤال

وأنا أعمل على محرر في المتصفح ضمن textarea. لقد بدأت تبحث عن بعض المعلومات حول التعامل مع اختيار textarea وجدت هذا البرنامج المساعد مسج، fieldSelection أن يفعل بعض التلاعب بسيطة.

ومع ذلك، فإنه لا يفسر ما يحدث.

وأريد أن أفهم أكثر على اختيار جزء النص في جافا سكريبت، ويفضل مع وصف كل من قبل DOM3 وسيناريوهات ما بعد DOM30.

هل كانت مفيدة؟

المحلول

مقدمة PPK لنطاقات . موزيلا اتصال المطور لديه معلومات حول W3C التحديدات . مايكروسوفت على موثقة على MSDN . بعض مزيد من الحيل يمكن العثور في الأجوبة هنا .

وبالإضافة إلى واجهات تتعارض سوف نكون سعداء لمعرفة أن هناك الغرابة اضافية يحدث مع العقد textarea. إذا كنت أتذكر بشكل صحيح يتصرفون مثل أي العقد الأخرى عند تحديدها في IE، ولكن في المتصفحات الأخرى لديهم نطاق الاختيار المستقل الذي يتعرض عبر .selectionEnd و.selectionStart الخصائص على العقدة.

وبالإضافة إلى ذلك، يجب أن تأخذ حقا نظرة على .contentEditable كوسيلة لتحرير الأشياء تعيش. من إطلاق Firefox3، وهذا ما يؤيد الآن من قبل جميع المتصفحات.

نصائح أخرى

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

ولقد اعتمدت فقط الحل قدم من قبل user357565، وإعادة ترميز للمسج الاستخدام المباشر:

(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));

وآمل أن هناك من يرى أنه من المفيد!

والشيء الوحيد الذي يمكنني أن أضيف أن الأمر يبدو و(لم acually محاولة منه) أن هذا ينبغي أن انتقل كل وسيلة تصل كلما manpulate المحتوى. وسيلة انتصاف eay هو التفاف الخط الذي يفعل

e.value =

ومع خطين لنسخ واستعادة scrollTop، كما يلي:

var rememberScrollTop = e.scrollTop;
e.value = .... (same as in user357565 snippet)
e.scrollTop = rememberScrollTop;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top