Rangeオブジェクトメモ

リファレンスは、こことかここ

DOM Range

setStartやsetEndは、第一引数要素の第二引数位置へ始点(終点)を移動する。
下記の例だと、2から4までつまり、"cd"を選択している。

<span>abcde</span>
var range = document.createRange();
var node = document.getElementsByTagName("span").item(0);
var startOffset = 2;
var endOffset = 4;

range.setStart(node, startOffset);
range.setEnd(node, endOffset);

TextRange

moveStartやmoveEndは、第一引数単位で第二引数分だけ始点(終点)を進める。
下記の例だと、

処理 選択されている文字列
一番最初のspan要素を選択 abcde
選択開始位置を2文字進める cde
選択終了位置を4文字進める cdefghi

により、"cdefghi"が選択される。

<span>abcde</span>
<span>fghij</span>
var range = document.body.createTextRange();
var node = document.getElementsByTagName("span").item(0);
var startOffset = 2;
var endOffset = 4;

range.moveToElementText(node);
range.moveStart('character', startOffset);
range.moveEnd('character', endOffset);

両者の差を考慮して

DOM Rangeの仕様にIEの方も合わせてみました。

var R = window.R = function(selection) {
  var
    // DOM Level 2 Rangeをサポートしているかどうかでラッパーを変える
    methods = (function() {
      var m;

      // DOM Level 2 Rangeをサポートしているブラウザ向けメソッド
      if (document.createRange) {
        m = {
          start: function(node, offset) {
            this.setStart(node.firstChild, offset || 0);
            return this;
          },

          end: function(node, offset) {
            this.setEnd(node.firstChild, offset || 0);
            return this;
          },

          sel: function(node) {
            this.selectNode(node);
            return this;
          },

          wrap: function(elem) {
            this.surroundContents(elem);
            return this; 
          }  
        }
      // IE用
      } else if (document.body.createTextRange) {
        m = {
          startOffset: 0, // 選択開始位置

          start: function(node, offset) {
            this.startOffset = offset;
            this.moveToElementText(node);
            this.moveStart('character', offset || 0);
            return this;
          },

          end: function(node, offset) {
            if (this.startOffset == 0)
              this.moveToElementText(node);

            this.setEndPoint('EndToStart', this);
            this.moveEnd('character', (offset - this.startOffset) || 0);
            return this;
          },

          sel: function(node) {
            this.moveToElementText(node);
            return this;
          },

          wrap: function(elem) {
            elem.innerHTML = this.htmlText;
            this.pasteHTML(elem.outerHTML);
            return this; 
          },

          detach: function() {
            console.log(document.body.innerHTML);
          }
        };
      } else {
        alert('Rangeをサポートしていないブラウザです。\nFirefox, Operaなどのブラウザで閲覧してください。');
      }

      return m;
    })(),

    // Rangeオブジェクト取得
    range = (function() {
      var r = new Object();

      if (document.createRange)
        r = (selection) ? selection.getRangeAt(0) : document.createRange();
      else if (document.body.createTextRange)
        r = (selection) ? selection.createRange() : document.body.createTextRange(); 

      return r;
    })();

  // Rangeオブジェクトにラッパーメソッドを設定
  for (var o in methods)
    range[o] = methods[o];

  return range;
};