overflow ノードの スクロール その2

久しぶりに MSDN で 調べものをしていたら、スクロール処理の拡張が動作していないことが発覚したので修正。(多分 2.2から)


vimperator本体に干渉するものはしっかりチェックしないといけませんね…

(function(){
  const attr_name="vimperator_scroll_node";
	const aMap = "d";
	const bufferContext = buffer.evaluateXPath;

	function hook(obj, attr, func){
		var orgFunc = let(f=obj[attr]) f.original || f;
		obj[attr] = function(){
			if(func.apply(this,arguments) === false){
				orgFunc.apply(this,arguments);
			}
		}
		obj[attr].original = orgFunc;
	}

	var OverFlowScroller ={
    tags:function(){
			OverFlowScroller.addMark(content.window);
      return "//*[@"+attr_name+">'0']";
    },
		addMark:function(aWindow){
      Array.forEach(aWindow.document.body.getElementsByTagName("*"),function(e){
        if((e.offsetHeight !== e.scrollHeight) ||
          (e.offsetWidth !== e.scrollWidth)){
          e.setAttribute(attr_name,"1");
        }
      });
      Array.forEach(aWindow.frames, arguments.callee);
    },
		removeMark:function(aWindow){
      if(!aWindow) aWindow=content.window;
      var doc=aWindow.document;
      for(let x in buffer.evaluateXPath("//*[@"+attr_name+"]",doc)){
        x.removeAttribute(attr_name);
      }
      Array.forEach(aWindow.frames,arguments.callee);
    },
		mark:function(e){
      e.setAttribute(attr_name,"2");
      liberator.echo("mark node!");
    },
		getElementCore:function(aWindow){
      var e=aWindow.document.evaluate("//*[@"+attr_name+"='2']",aWindow.document,null,9,null).singleNodeValue;
      if(!e) for(var f in util.Array.itervalues(aWindow.frames)){
        if(e = arguments.callee(f)) break;
      }
      return e;
    },
		getElement:function() OverFlowScroller.getElementCore(content.window),
		action:{
			scrollLines:function(aLines){
				var e=OverFlowScroller.getElement();
				if(!e) return false;
				OverFlowScroller.scrollVertical(e, "lines", aLines);
				return true;
			},
			scrollPages:function(pages){
				var e=OverFlowScroller.getElement();
				if(!e) return false;
				OverFlowScroller.scrollVertical(e, "pages", pages);
				return true;
			},
			scrollToPercent:function(x, y){
				var e=OverFlowScroller.getElement();
				if(!e) return false;

        if (x != null)
            e.scrollLeft = (e.scrollWidth - e.clientWidth) * (x/100);

        if (y != null)
            e.scrollTop = (e.scrollHeight - e.clientHeight) * (y/100);

				return true;
			},
			scrollColumns:function(cols){
				var e=OverFlowScroller.getElement();
				if(!e) return false;
				OverFlowScroller.scrollHorizontal(e, "columns", cols);
				return true;
			},
      scrollStart:function(x) OverFlowScroller.action.scrollToPercent(0, null),
      scrollEnd:function(x) OverFlowScroller.action.scrollToPercent(100, null),
		},
		onEscape:function(){
			OverFlowScroller.removeMark();
			return false;
		}
  };

	let(list=[
		"scrollVertical",
		"scrollHorizontal",
	]){
		for(let [,a] in Iterator(list))
			OverFlowScroller[a] = liberator.eval(a, bufferContext);
	}

	for(let [a,f] in Iterator(OverFlowScroller.action)){
		hook(buffer, a, f);
	}
	let(a="onEscape")
		hook(events, a, OverFlowScroller[a]);

	hints.addMode(aMap, "overflow scroll", OverFlowScroller.mark, OverFlowScroller.tags);
})();