クロスブラウザでDOM Rangeを扱えるようにした・・・い

IE対応しようとすると、途端にめんどくさくなる。
早さとかいいから、JSのエンジン変え(ry


IE8の開発者ツールは、時代に追いついた感じで素晴らしい。
みんな、せめてIE8にしてくれ。


まだ、途中ですが経過報告。
メソッド毎にDOM Rangeのサポート有無で振り分けるのもなんなので、ラッパーメソッドからして分けてみようと思いました。

ソース

var R = window.R = function(selection) {
  var
    // DOM Level 2 Rangeをサポートしているかチェック
    supportRange = !!document.createRange,

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

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

          end: function(textNode, index) {
            this.setEnd(textNode, index || 0);
            return this;
          },

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

          wrap: function(elem) {
            this.surroundContents(elem);
            return this; 
          }  
        }
      // DOM Level 2 Rangeをサポートしていないブラウザ向けメソッド(IE当て決め)
      } else {
        m = {
          start: function(node, index) {
            this.moveToElementText(node);
            this.moveStart('character', index || 0);
            return this;
          },

          end: function(node, index) {
            this.moveToElementText(node);
            this.moveEnd('character', (0 - index || 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() {
          }
        };
      }

      return m;
    })(),

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

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

      return r;
    })();

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

  return range;
};

理想

  var test1 = document.getElementById('test1');
  var span  = document.createElement('span');
  span.style.color = 'red';

  // id="test1"の3文字目から5文字目を赤くする
  new R()
    .start(test1, 3)
    .end(test1, 5)
    .wrap(span)
    .detach();

問題点

STARTとENDが同一要素ならいいが、複数の要素を跨いだ場合の色付けが期待通りにならない。