From a089699c8915636ba4f158d77dba9b012bc93208 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 4 Mar 2011 19:02:28 +0300 Subject: build custom layer of Dojo to speed up loading of tt-rss (refs #293) --- lib/dojo/robot.js | 244 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 170 insertions(+), 74 deletions(-) (limited to 'lib/dojo/robot.js') diff --git a/lib/dojo/robot.js b/lib/dojo/robot.js index 88af37cef..6cbe0bebc 100644 --- a/lib/dojo/robot.js +++ b/lib/dojo/robot.js @@ -5,85 +5,181 @@ */ -if(!dojo._hasResource["dojo.robot"]){ -dojo._hasResource["dojo.robot"]=true; +if(!dojo._hasResource["dojo.robot"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojo.robot"] = true; dojo.provide("dojo.robot"); dojo.experimental("dojo.robot"); dojo.require("doh.robot"); dojo.require("dojo.window"); + (function(){ -dojo.mixin(doh.robot,{_resolveNode:function(n){ -if(typeof n=="function"){ -n=n(); -} -return n?dojo.byId(n):null; -},_scrollIntoView:function(n){ -var d=dojo,dr=doh.robot,p=null; -d.forEach(dr._getWindowChain(n),function(w){ -d.withGlobal(w,function(){ -var p2=d.position(n,false),b=d._getPadBorderExtents(n),_1=null; -if(!p){ -p=p2; -}else{ -_1=p; -p={x:p.x+p2.x+b.l,y:p.y+p2.y+b.t,w:p.w,h:p.h}; -} -dojo.window.scrollIntoView(n,p); -p2=d.position(n,false); -if(!_1){ -p=p2; -}else{ -p={x:_1.x+p2.x+b.l,y:_1.y+p2.y+b.t,w:p.w,h:p.h}; -} -n=w.frameElement; -}); -}); -},_position:function(n){ -var d=dojo,p=null,M=Math.max,m=Math.min; -d.forEach(doh.robot._getWindowChain(n),function(w){ -d.withGlobal(w,function(){ -var p2=d.position(n,false),b=d._getPadBorderExtents(n); -if(!p){ -p=p2; -}else{ -var _2; -d.withGlobal(n.contentWindow,function(){ -_2=dojo.window.getBox(); -}); -p2.r=p2.x+_2.w; -p2.b=p2.y+_2.h; -p={x:M(p.x+p2.x,p2.x)+b.l,y:M(p.y+p2.y,p2.y)+b.t,r:m(p.x+p2.x+p.w,p2.r)+b.l,b:m(p.y+p2.y+p.h,p2.b)+b.t}; -p.w=p.r-p.x; -p.h=p.b-p.y; -} -n=w.frameElement; -}); +// users who use doh+dojo get the added convenience of dojo.mouseMoveAt, +// instead of computing the absolute coordinates of their elements themselves +dojo.mixin(doh.robot,{ + + _resolveNode: function(/*String||DOMNode||Function*/ n){ + if(typeof n == "function"){ + // if the user passed a function returning a node, evaluate it + n = n(); + } + return n? dojo.byId(n) : null; + }, + + _scrollIntoView: function(/*Node*/ n){ + // scrolls the passed node into view, scrolling all ancester frames/windows as well. + // Assumes parent iframes can be made fully visible given the current browser window size + var d = dojo, + dr = doh.robot, + p = null; + d.forEach(dr._getWindowChain(n), function(w){ + d.withGlobal(w, function(){ + // get the position of the node wrt its parent window + // if it is a parent frame, its padding and border extents will get added in + var p2 = d.position(n, false), + b = d._getPadBorderExtents(n), + oldp = null; + // if p2 is the position of the original passed node, store the position away as p + // otherwise, node is actually an iframe. in this case, add the iframe's position wrt its parent window and also the iframe's padding and border extents + if(!p){ + p = p2; + }else{ + oldp = p; + p = {x: p.x+p2.x+b.l, + y: p.y+p2.y+b.t, + w: p.w, + h: p.h}; + + } + // scroll the parent window so that the node translated into the parent window's coordinate space is in view + dojo.window.scrollIntoView(n,p); + // adjust position for the new scroll offsets + p2 = d.position(n, false); + if(!oldp){ + p = p2; + }else{ + p = {x: oldp.x+p2.x+b.l, + y: oldp.y+p2.y+b.t, + w: p.w, + h: p.h}; + } + // get the parent iframe so it can be scrolled too + n = w.frameElement; + }); + }); + }, + + _position: function(/*Node*/ n){ + // Returns the dojo.position of the passed node wrt the passed window's viewport, + // following any parent iframes containing the node and clipping the node to each iframe. + // precondition: _scrollIntoView already called + var d = dojo, p = null, M = Math.max, m = Math.min; + // p: the returned position of the node + d.forEach(doh.robot._getWindowChain(n), function(w){ + d.withGlobal(w, function(){ + // get the position of the node wrt its parent window + // if it is a parent frame, its padding and border extents will get added in + var p2 = d.position(n, false), b = d._getPadBorderExtents(n); + // if p2 is the position of the original passed node, store the position away as p + // otherwise, node is actually an iframe. in this case, add the iframe's position wrt its parent window and also the iframe's padding and border extents + if(!p){ + p = p2; + }else{ + var view; + d.withGlobal(n.contentWindow,function(){ + view=dojo.window.getBox(); + }); + p2.r = p2.x+view.w; + p2.b = p2.y+view.h; + p = {x: M(p.x+p2.x,p2.x)+b.l, // clip left edge of node wrt the iframe + y: M(p.y+p2.y,p2.y)+b.t, // top edge + r: m(p.x+p2.x+p.w,p2.r)+b.l, // right edge (to compute width) + b: m(p.y+p2.y+p.h,p2.b)+b.t}; // bottom edge (to compute height) + // save a few bytes by computing width and height from r and b + p.w = p.r-p.x; + p.h = p.b-p.y; + } + // the new node is now the old node's parent iframe + n=w.frameElement; + }); + }); + return p; + }, + + _getWindowChain : function(/*Node*/ n){ + // Returns an array of windows starting from the passed node's parent window and ending at dojo's window + var cW = dojo.window.get(n.ownerDocument); + var arr=[cW]; + var f = cW.frameElement; + return (cW == dojo.global || f == null)? arr : arr.concat(doh.robot._getWindowChain(f)); + }, + + scrollIntoView : function(/*String||DOMNode||Function*/ node, /*Number, optional*/ delay){ + // summary: + // Scroll the passed node into view, if it is not. + // + // node: + // The id of the node, or the node itself, to move the mouse to. + // If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes. + // This is useful if you need to move the mouse to an node that is not yet present. + // + // delay: + // Delay, in milliseconds, to wait before firing. + // The delay is a delta with respect to the previous automation call. + // + doh.robot.sequence(function(){ + doh.robot._scrollIntoView(doh.robot._resolveNode(node)); + }, delay); + }, + + mouseMoveAt : function(/*String||DOMNode||Function*/ node, /*Integer, optional*/ delay, /*Integer, optional*/ duration, /*Number, optional*/ offsetX, /*Number, optional*/ offsetY){ + // summary: + // Moves the mouse over the specified node at the specified relative x,y offset. + // + // description: + // Moves the mouse over the specified node at the specified relative x,y offset. + // If you do not specify an offset, mouseMove will default to move to the middle of the node. + // Example: to move the mouse over a ComboBox's down arrow node, call doh.mouseMoveAt(dijit.byId('setvaluetest').downArrowNode); + // + // node: + // The id of the node, or the node itself, to move the mouse to. + // If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes. + // This is useful if you need to move the mouse to an node that is not yet present. + // + // delay: + // Delay, in milliseconds, to wait before firing. + // The delay is a delta with respect to the previous automation call. + // For example, the following code ends after 600ms: + // doh.robot.mouseClick({left:true}, 100) // first call; wait 100ms + // doh.robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all + // + // duration: + // Approximate time Robot will spend moving the mouse + // The default is 100ms. + // + // offsetX: + // x offset relative to the node, in pixels, to move the mouse. The default is half the node's width. + // + // offsetY: + // y offset relative to the node, in pixels, to move the mouse. The default is half the node's height. + // + + doh.robot._assertRobot(); + duration = duration||100; + this.sequence(function(){ + node=doh.robot._resolveNode(node); + doh.robot._scrollIntoView(node); + var pos = doh.robot._position(node); + if(offsetY === undefined){ + offsetX=pos.w/2; + offsetY=pos.h/2; + } + var x = pos.x+offsetX; + var y = pos.y+offsetY; + doh.robot._mouseMove(x, y, false, duration); + }, delay, duration); + } }); -return p; -},_getWindowChain:function(n){ -var cW=dojo.window.get(n.ownerDocument); -var _3=[cW]; -var f=cW.frameElement; -return (cW==dojo.global||f==null)?_3:_3.concat(doh.robot._getWindowChain(f)); -},scrollIntoView:function(_4,_5){ -doh.robot.sequence(function(){ -doh.robot._scrollIntoView(doh.robot._resolveNode(_4)); -},_5); -},mouseMoveAt:function(_6,_7,_8,_9,_a){ -doh.robot._assertRobot(); -_8=_8||100; -this.sequence(function(){ -_6=doh.robot._resolveNode(_6); -doh.robot._scrollIntoView(_6); -var _b=doh.robot._position(_6); -if(_a===undefined){ -_9=_b.w/2; -_a=_b.h/2; -} -var x=_b.x+_9; -var y=_b.y+_a; -doh.robot._mouseMove(x,y,false,_8); -},_7,_8); -}}); + })(); + } -- cgit v1.2.3