1 | define([ |
---|
2 | "./_base/array", |
---|
3 | "./dom", |
---|
4 | "./dom-geometry", |
---|
5 | "./_base/kernel", |
---|
6 | "./_base/lang", |
---|
7 | "./_base/window", |
---|
8 | "doh/_browserRunner", |
---|
9 | "doh/robot", |
---|
10 | "./window" |
---|
11 | ], function(array, dom, geom, kernel, lang, win, doh, robot, winUtils){ |
---|
12 | |
---|
13 | kernel.experimental("dojo.robot"); |
---|
14 | |
---|
15 | // users who use doh+dojo get the added convenience of robot.mouseMoveAt(), |
---|
16 | // instead of computing the absolute coordinates of their elements themselves |
---|
17 | lang.mixin(robot, { |
---|
18 | |
---|
19 | _resolveNode: function(/*String||DOMNode||Function*/ n){ |
---|
20 | if(typeof n == "function"){ |
---|
21 | // if the user passed a function returning a node, evaluate it |
---|
22 | n = n(); |
---|
23 | } |
---|
24 | return n ? dom.byId(n) : null; |
---|
25 | }, |
---|
26 | |
---|
27 | _scrollIntoView: function(/*Node*/ n){ |
---|
28 | // scrolls the passed node into view, scrolling all ancestor frames/windows as well. |
---|
29 | // Assumes parent iframes can be made fully visible given the current browser window size |
---|
30 | var p = null; |
---|
31 | array.forEach(robot._getWindowChain(n), function(w){ |
---|
32 | // get the position of the node wrt its parent window |
---|
33 | // if it is a parent frame, its padding and border extents will get added in |
---|
34 | var p2 = geom.position(n, false), |
---|
35 | b = geom.getPadBorderExtents(n), |
---|
36 | oldp = null; |
---|
37 | // if p2 is the position of the original passed node, store the position away as p |
---|
38 | // 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 |
---|
39 | if(!p){ |
---|
40 | p = p2; |
---|
41 | }else{ |
---|
42 | oldp = p; |
---|
43 | p = {x: p.x+p2.x+b.l, |
---|
44 | y: p.y+p2.y+b.t, |
---|
45 | w: p.w, |
---|
46 | h: p.h}; |
---|
47 | |
---|
48 | } |
---|
49 | // scroll the parent window so that the node translated into the parent window's coordinate space is in view |
---|
50 | winUtils.scrollIntoView(n,p); |
---|
51 | // adjust position for the new scroll offsets |
---|
52 | p2 = geom.position(n, false); |
---|
53 | if(!oldp){ |
---|
54 | p = p2; |
---|
55 | }else{ |
---|
56 | p = {x: oldp.x+p2.x+b.l, |
---|
57 | y: oldp.y+p2.y+b.t, |
---|
58 | w: p.w, |
---|
59 | h: p.h}; |
---|
60 | } |
---|
61 | // get the parent iframe so it can be scrolled too |
---|
62 | n = w.frameElement; |
---|
63 | }); |
---|
64 | }, |
---|
65 | |
---|
66 | _position: function(/*Node*/ n){ |
---|
67 | // Returns the geom.position of the passed node wrt the passed window's viewport, |
---|
68 | // following any parent iframes containing the node and clipping the node to each iframe. |
---|
69 | // precondition: _scrollIntoView already called |
---|
70 | var p = null, max = Math.max, min = Math.min; |
---|
71 | // p: the returned position of the node |
---|
72 | array.forEach(robot._getWindowChain(n), function(w){ |
---|
73 | // get the position of the node wrt its parent window |
---|
74 | // if it is a parent frame, its padding and border extents will get added in |
---|
75 | var p2 = geom.position(n, false), b = geom.getPadBorderExtents(n); |
---|
76 | // if p2 is the position of the original passed node, store the position away as p |
---|
77 | // 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 |
---|
78 | if(!p){ |
---|
79 | p = p2; |
---|
80 | }else{ |
---|
81 | var view = winUtils.getBox(n.contentWindow.document); |
---|
82 | p2.r = p2.x+view.w; |
---|
83 | p2.b = p2.y+view.h; |
---|
84 | p = {x: max(p.x+p2.x,p2.x)+b.l, // clip left edge of node wrt the iframe |
---|
85 | y: max(p.y+p2.y,p2.y)+b.t, // top edge |
---|
86 | r: min(p.x+p2.x+p.w,p2.r)+b.l, // right edge (to compute width) |
---|
87 | b: min(p.y+p2.y+p.h,p2.b)+b.t}; // bottom edge (to compute height) |
---|
88 | // save a few bytes by computing width and height from r and b |
---|
89 | p.w = p.r-p.x; |
---|
90 | p.h = p.b-p.y; |
---|
91 | } |
---|
92 | // the new node is now the old node's parent iframe |
---|
93 | n=w.frameElement; |
---|
94 | }); |
---|
95 | return p; |
---|
96 | }, |
---|
97 | |
---|
98 | _getWindowChain : function(/*Node*/ n){ |
---|
99 | // Returns an array of windows starting from the passed node's parent window and ending at dojo's window |
---|
100 | var cW = winUtils.get(n.ownerDocument); |
---|
101 | var arr = [cW]; |
---|
102 | var f = cW.frameElement; |
---|
103 | return (cW == win.global || !f) ? arr : arr.concat(robot._getWindowChain(f)); |
---|
104 | }, |
---|
105 | |
---|
106 | scrollIntoView : function(/*String||DOMNode||Function*/ node, /*Number, optional*/ delay){ |
---|
107 | // summary: |
---|
108 | // Scroll the passed node into view, if it is not. |
---|
109 | // node: |
---|
110 | // The id of the node, or the node itself, to move the mouse to. |
---|
111 | // If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes. |
---|
112 | // This is useful if you need to move the mouse to an node that is not yet present. |
---|
113 | // delay: |
---|
114 | // Delay, in milliseconds, to wait before firing. |
---|
115 | // The delay is a delta with respect to the previous automation call. |
---|
116 | |
---|
117 | robot.sequence(function(){ |
---|
118 | robot._scrollIntoView(robot._resolveNode(node)); |
---|
119 | }, delay); |
---|
120 | }, |
---|
121 | |
---|
122 | mouseMoveAt : function(/*String||DOMNode||Function*/ node, /*Integer, optional*/ delay, /*Integer, optional*/ duration, /*Number, optional*/ offsetX, /*Number, optional*/ offsetY){ |
---|
123 | // summary: |
---|
124 | // Moves the mouse over the specified node at the specified relative x,y offset. |
---|
125 | // description: |
---|
126 | // Moves the mouse over the specified node at the specified relative x,y offset. |
---|
127 | // If you do not specify an offset, mouseMove will default to move to the middle of the node. |
---|
128 | // Example: to move the mouse over a ComboBox's down arrow node, call doh.mouseMoveAt(dijit.byId('setvaluetest').downArrowNode); |
---|
129 | // node: |
---|
130 | // The id of the node, or the node itself, to move the mouse to. |
---|
131 | // If you pass an id or a function that returns a node, the node will not be evaluated until the movement executes. |
---|
132 | // This is useful if you need to move the mouse to an node that is not yet present. |
---|
133 | // delay: |
---|
134 | // Delay, in milliseconds, to wait before firing. |
---|
135 | // The delay is a delta with respect to the previous automation call. |
---|
136 | // For example, the following code ends after 600ms: |
---|
137 | // | robot.mouseClick({left:true}, 100) // first call; wait 100ms |
---|
138 | // | robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all |
---|
139 | // duration: |
---|
140 | // Approximate time Robot will spend moving the mouse |
---|
141 | // The default is 100ms. |
---|
142 | // offsetX: |
---|
143 | // x offset relative to the node, in pixels, to move the mouse. The default is half the node's width. |
---|
144 | // offsetY: |
---|
145 | // y offset relative to the node, in pixels, to move the mouse. The default is half the node's height. |
---|
146 | |
---|
147 | robot._assertRobot(); |
---|
148 | |
---|
149 | // Schedule an action to scroll the node into view, then calculate it's center point |
---|
150 | var point = {}; |
---|
151 | this.sequence(function(){ |
---|
152 | node = robot._resolveNode(node); |
---|
153 | robot._scrollIntoView(node); |
---|
154 | var pos = robot._position(node); |
---|
155 | if(offsetY === undefined){ |
---|
156 | offsetX = pos.w/2; |
---|
157 | offsetY = pos.h/2; |
---|
158 | } |
---|
159 | point.x = pos.x+offsetX; |
---|
160 | point.y = pos.y+offsetY; |
---|
161 | }, delay); |
---|
162 | |
---|
163 | // Schedule a bunch of actions to move the mouse from the current position to point. |
---|
164 | // These actions won't run until after the above callback. |
---|
165 | this.mouseMoveTo(point, 0, duration, false); |
---|
166 | } |
---|
167 | }); |
---|
168 | |
---|
169 | return robot; |
---|
170 | }); |
---|