ちょっと柔軟なscrollIntoView

grep を 作っていて
ヒットした位置にスクロールする処理で困りました。


DOMNode には、scrollIntoViewで スクロールできますが、
textnode に対してできないので、
多きなtextnodeの一部の場合 画面内含まれる保証がありません。
(あとセンタリングできない)


そのため、自力算出前提で調べていたら、良いものを見つけたのでメモ
nsISelection2のscrollIntoViewです。


いい加減な説明は

void scrollIntoView(
//nsISelectionController.SELECTION_ANCHOR_REGION だと 先頭基準
//nsISelectionController.SELECTION_FOCUS_REGION だと 末尾基準
in short aRegion, 
//true で 即反映 false で 後で反映
in boolean aIsSynchronous, 
//垂直水平方向移動位置 を 割合で指定 
//0 で上(左)寄せ
//50 で センタリング
//100 で 下(右)寄せ
//-1 でスクロール量を最小限
in short aVPercent, 
in short aHPercent) 

となります。


選択範囲 を 画面に 対して 水平垂直に 割合指定 でスクロールができます。
これで、自力計算しないですみましす。ヽ(´ー`)ノ


とりあず、frame,iframe, overflow要素内 1 つ づつ試したところ
上手くやってくれました。


以下に、Node に 適応してみました

(function(){
  function scrollIntoView2(aNode, aVPercent, aHPercent){
    var doc = aNode.ownerDocument;
    var win = doc.defaultView;
    var selection = win.getSelection();
    var ranges = function(selection){
      var selection = win.getSelection();
      for(var i=0,j=selection.rangeCount;i<j;++i){
        yield selection.getRangeAt(i);
      }
    };

    var back = [r for(r in ranges(selection))];
    selection.removeAllRanges();
    var r = doc.createRange();

    r.selectNode(aNode);
    selection.addRange(r);
    selection
			.QueryInterface(Components.interfaces.nsISelection2)
			.scrollIntoView(
        Components.interfaces.nsISelectionController.SELECTION_ANCHOR_REGION
        ,true,aVPercent,aHPercent);

    selection.removeAllRanges();

    for(let [,r] in Iterator(back)){
      selection.addRange(r);
    }
  }

  //nodeは 適当に選択する

  //node.scrollIntoView(true)相当
  scrollIntoView2(node, 0, 0);

  //センタリング
  scrollIntoView2(node, 50, 50);

  //node.scrollIntoView(false)相当
  scrollIntoView2(node, 100, 100);

  //最小スクロール量で画面内に納める
  scrollIntoView2(node, -1, -1);
})();