UNPKG

dojo

Version:

Dojo core is a powerful, lightweight library that makes common tasks quicker and easier. Animate elements, manipulate the DOM, and query with easy CSS syntax, all without sacrificing performance.

171 lines (156 loc) 6.65 kB
define([ "./_base/array", "./dom", "./dom-geometry", "./_base/kernel", "./_base/lang", "./_base/window", "doh/_browserRunner", "doh/robot", "./window" ], function(array, dom, geom, kernel, lang, win, doh, robot, winUtils){ kernel.experimental("dojo.robot"); // users who use doh+dojo get the added convenience of robot.mouseMoveAt(), // instead of computing the absolute coordinates of their elements themselves lang.mixin(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 ? dom.byId(n) : null; }, _scrollIntoView: function(/*Node*/ n){ // scrolls the passed node into view, scrolling all ancestor frames/windows as well. // Assumes parent iframes can be made fully visible given the current browser window size var p = null; array.forEach(robot._getWindowChain(n), function(w){ // 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 = geom.position(n, false), b = geom.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 winUtils.scrollIntoView(n,p); // adjust position for the new scroll offsets p2 = geom.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 geom.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 p = null, max = Math.max, min = Math.min; // p: the returned position of the node array.forEach(robot._getWindowChain(n), function(w){ // 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 = geom.position(n, false), b = geom.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 = winUtils.getBox(n.contentWindow.document); p2.r = p2.x+view.w; p2.b = p2.y+view.h; p = {x: max(p.x+p2.x,p2.x)+b.l, // clip left edge of node wrt the iframe y: max(p.y+p2.y,p2.y)+b.t, // top edge r: min(p.x+p2.x+p.w,p2.r)+b.l, // right edge (to compute width) b: min(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 = winUtils.get(n.ownerDocument); var arr = [cW]; var f = cW.frameElement; return (cW == win.global || !f) ? arr : arr.concat(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. robot.sequence(function(){ robot._scrollIntoView(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: // | robot.mouseClick({left:true}, 100) // first call; wait 100ms // | 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. robot._assertRobot(); // Schedule an action to scroll the node into view, then calculate it's center point var point = {}; this.sequence(function(){ node = robot._resolveNode(node); robot._scrollIntoView(node); var pos = robot._position(node); if(offsetY === undefined){ offsetX = pos.w/2; offsetY = pos.h/2; } point.x = pos.x+offsetX; point.y = pos.y+offsetY; }, delay); // Schedule a bunch of actions to move the mouse from the current position to point. // These actions won't run until after the above callback. this.mouseMoveTo(point, 0, duration, false); } }); return robot; });