From 81bea17aefb26859f825b9293c7c99192874806e Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 8 Nov 2011 20:40:44 +0400 Subject: upgrade Dojo to 1.6.1 --- lib/dijit/_base/place.js | 449 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 357 insertions(+), 92 deletions(-) (limited to 'lib/dijit/_base/place.js') diff --git a/lib/dijit/_base/place.js b/lib/dijit/_base/place.js index ddc38fd08..a098f2fa4 100644 --- a/lib/dijit/_base/place.js +++ b/lib/dijit/_base/place.js @@ -1,111 +1,376 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit._base.place"]){ -dojo._hasResource["dijit._base.place"]=true; +if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit._base.place"] = true; dojo.provide("dijit._base.place"); dojo.require("dojo.window"); dojo.require("dojo.AdapterRegistry"); -dijit.getViewport=function(){ -return dojo.window.getBox(); -}; -dijit.placeOnScreen=function(_1,_2,_3,_4){ -var _5=dojo.map(_3,function(_6){ -var c={corner:_6,pos:{x:_2.x,y:_2.y}}; -if(_4){ -c.pos.x+=_6.charAt(1)=="L"?_4.x:-_4.x; -c.pos.y+=_6.charAt(0)=="T"?_4.y:-_4.y; -} -return c; -}); -return dijit._place(_1,_5); + + +dijit.getViewport = function(){ + // summary: + // Returns the dimensions and scroll position of the viewable area of a browser window + + return dojo.window.getBox(); }; -dijit._place=function(_7,_8,_9){ -var _a=dojo.window.getBox(); -if(!_7.parentNode||String(_7.parentNode.tagName).toLowerCase()!="body"){ -dojo.body().appendChild(_7); -} -var _b=null; -dojo.some(_8,function(_c){ -var _d=_c.corner; -var _e=_c.pos; -if(_9){ -_9(_7,_c.aroundCorner,_d); + +/*===== +dijit.__Position = function(){ + // x: Integer + // horizontal coordinate in pixels, relative to document body + // y: Integer + // vertical coordinate in pixels, relative to document body + + thix.x = x; + this.y = y; } -var _f=_7.style; -var _10=_f.display; -var _11=_f.visibility; -_f.visibility="hidden"; -_f.display=""; -var mb=dojo.marginBox(_7); -_f.display=_10; -_f.visibility=_11; -var _12=Math.max(_a.l,_d.charAt(1)=="L"?_e.x:(_e.x-mb.w)),_13=Math.max(_a.t,_d.charAt(0)=="T"?_e.y:(_e.y-mb.h)),_14=Math.min(_a.l+_a.w,_d.charAt(1)=="L"?(_12+mb.w):_e.x),_15=Math.min(_a.t+_a.h,_d.charAt(0)=="T"?(_13+mb.h):_e.y),_16=_14-_12,_17=_15-_13,_18=(mb.w-_16)+(mb.h-_17); -if(_b==null||_18<_b.overflow){ -_b={corner:_d,aroundCorner:_c.aroundCorner,x:_12,y:_13,w:_16,h:_17,overflow:_18}; +=====*/ + + +dijit.placeOnScreen = function( + /* DomNode */ node, + /* dijit.__Position */ pos, + /* String[] */ corners, + /* dijit.__Position? */ padding){ + // summary: + // Positions one of the node's corners at specified position + // such that node is fully visible in viewport. + // description: + // NOTE: node is assumed to be absolutely or relatively positioned. + // pos: + // Object like {x: 10, y: 20} + // corners: + // Array of Strings representing order to try corners in, like ["TR", "BL"]. + // Possible values are: + // * "BL" - bottom left + // * "BR" - bottom right + // * "TL" - top left + // * "TR" - top right + // padding: + // set padding to put some buffer around the element you want to position. + // example: + // Try to place node's top right corner at (10,20). + // If that makes node go (partially) off screen, then try placing + // bottom left corner at (10,20). + // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"]) + + var choices = dojo.map(corners, function(corner){ + var c = { corner: corner, pos: {x:pos.x,y:pos.y} }; + if(padding){ + c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x; + c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y; + } + return c; + }); + + return dijit._place(node, choices); } -return !_18; -}); -_7.style.left=_b.x+"px"; -_7.style.top=_b.y+"px"; -if(_b.overflow&&_9){ -_9(_7,_b.aroundCorner,_b.corner); + +dijit._place = function(/*DomNode*/ node, choices, layoutNode, /*Object*/ aroundNodeCoords){ + // summary: + // Given a list of spots to put node, put it at the first spot where it fits, + // of if it doesn't fit anywhere then the place with the least overflow + // choices: Array + // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } + // Above example says to put the top-left corner of the node at (10,20) + // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size) + // for things like tooltip, they are displayed differently (and have different dimensions) + // based on their orientation relative to the parent. This adjusts the popup based on orientation. + // It also passes in the available size for the popup, which is useful for tooltips to + // tell them that their width is limited to a certain amount. layoutNode() may return a value expressing + // how much the popup had to be modified to fit into the available space. This is used to determine + // what the best placement is. + // aroundNodeCoords: Object + // Size of aroundNode, ex: {w: 200, h: 50} + + // get {x: 10, y: 10, w: 100, h:100} type obj representing position of + // viewport over document + var view = dojo.window.getBox(); + + // This won't work if the node is inside a
, + // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong + // and also it might get cutoff) + if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ + dojo.body().appendChild(node); + } + + var best = null; + dojo.some(choices, function(choice){ + var corner = choice.corner; + var pos = choice.pos; + var overflow = 0; + + // calculate amount of space available given specified position of node + var spaceAvailable = { + w: corner.charAt(1) == 'L' ? (view.l + view.w) - pos.x : pos.x - view.l, + h: corner.charAt(1) == 'T' ? (view.t + view.h) - pos.y : pos.y - view.t + }; + + // configure node to be displayed in given position relative to button + // (need to do this in order to get an accurate size for the node, because + // a tooltip's size changes based on position, due to triangle) + if(layoutNode){ + var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords); + overflow = typeof res == "undefined" ? 0 : res; + } + + // get node's size + var style = node.style; + var oldDisplay = style.display; + var oldVis = style.visibility; + style.visibility = "hidden"; + style.display = ""; + var mb = dojo.marginBox(node); + style.display = oldDisplay; + style.visibility = oldVis; + + // coordinates and size of node with specified corner placed at pos, + // and clipped by viewport + var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)), + startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)), + endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x), + endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y), + width = endX - startX, + height = endY - startY; + + overflow += (mb.w - width) + (mb.h - height); + + if(best == null || overflow < best.overflow){ + best = { + corner: corner, + aroundCorner: choice.aroundCorner, + x: startX, + y: startY, + w: width, + h: height, + overflow: overflow, + spaceAvailable: spaceAvailable + }; + } + + return !overflow; + }); + + // In case the best position is not the last one we checked, need to call + // layoutNode() again. + if(best.overflow && layoutNode){ + layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords); + } + + // And then position the node. Do this last, after the layoutNode() above + // has sized the node, due to browser quirks when the viewport is scrolled + // (specifically that a Tooltip will shrink to fit as though the window was + // scrolled to the left). + // + // In RTL mode, set style.right rather than style.left so in the common case, + // window resizes move the popup along with the aroundNode. + var l = dojo._isBodyLtr(), + s = node.style; + s.top = best.y + "px"; + s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px"; + + return best; } -return _b; -}; -dijit.placeOnScreenAroundNode=function(_19,_1a,_1b,_1c){ -_1a=dojo.byId(_1a); -var _1d=_1a.style.display; -_1a.style.display=""; -var _1e=dojo.position(_1a,true); -_1a.style.display=_1d; -return dijit._placeOnScreenAroundRect(_19,_1e.x,_1e.y,_1e.w,_1e.h,_1b,_1c); -}; -dijit.placeOnScreenAroundRectangle=function(_1f,_20,_21,_22){ -return dijit._placeOnScreenAroundRect(_1f,_20.x,_20.y,_20.width,_20.height,_21,_22); + +dijit.placeOnScreenAroundNode = function( + /* DomNode */ node, + /* DomNode */ aroundNode, + /* Object */ aroundCorners, + /* Function? */ layoutNode){ + + // summary: + // Position node adjacent or kitty-corner to aroundNode + // such that it's fully visible in viewport. + // + // description: + // Place node such that corner of node touches a corner of + // aroundNode, and that node is fully visible. + // + // aroundCorners: + // Ordered list of pairs of corners to try matching up. + // Each pair of corners is represented as a key/value in the hash, + // where the key corresponds to the aroundNode's corner, and + // the value corresponds to the node's corner: + // + // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...} + // + // The following strings are used to represent the four corners: + // * "BL" - bottom left + // * "BR" - bottom right + // * "TL" - top left + // * "TR" - top right + // + // layoutNode: Function(node, aroundNodeCorner, nodeCorner) + // For things like tooltip, they are displayed differently (and have different dimensions) + // based on their orientation relative to the parent. This adjusts the popup based on orientation. + // + // example: + // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'}); + // This will try to position node such that node's top-left corner is at the same position + // as the bottom left corner of the aroundNode (ie, put node below + // aroundNode, with left edges aligned). If that fails it will try to put + // the bottom-right corner of node where the top right corner of aroundNode is + // (ie, put node above aroundNode, with right edges aligned) + // + + // get coordinates of aroundNode + aroundNode = dojo.byId(aroundNode); + var aroundNodePos = dojo.position(aroundNode, true); + + // place the node around the calculated rectangle + return dijit._placeOnScreenAroundRect(node, + aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h, // rectangle + aroundCorners, layoutNode); }; -dijit._placeOnScreenAroundRect=function(_23,x,y,_24,_25,_26,_27){ -var _28=[]; -for(var _29 in _26){ -_28.push({aroundCorner:_29,corner:_26[_29],pos:{x:x+(_29.charAt(1)=="L"?0:_24),y:y+(_29.charAt(0)=="T"?0:_25)}}); + +/*===== +dijit.__Rectangle = function(){ + // x: Integer + // horizontal offset in pixels, relative to document body + // y: Integer + // vertical offset in pixels, relative to document body + // width: Integer + // width in pixels + // height: Integer + // height in pixels + + this.x = x; + this.y = y; + this.width = width; + this.height = height; } -return dijit._place(_23,_28,_27); +=====*/ + + +dijit.placeOnScreenAroundRectangle = function( + /* DomNode */ node, + /* dijit.__Rectangle */ aroundRect, + /* Object */ aroundCorners, + /* Function */ layoutNode){ + + // summary: + // Like dijit.placeOnScreenAroundNode(), except that the "around" + // parameter is an arbitrary rectangle on the screen (x, y, width, height) + // instead of a dom node. + + return dijit._placeOnScreenAroundRect(node, + aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle + aroundCorners, layoutNode); +}; + +dijit._placeOnScreenAroundRect = function( + /* DomNode */ node, + /* Number */ x, + /* Number */ y, + /* Number */ width, + /* Number */ height, + /* Object */ aroundCorners, + /* Function */ layoutNode){ + + // summary: + // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates + // of a rectangle to place node adjacent to. + + // TODO: combine with placeOnScreenAroundRectangle() + + // Generate list of possible positions for node + var choices = []; + for(var nodeCorner in aroundCorners){ + choices.push( { + aroundCorner: nodeCorner, + corner: aroundCorners[nodeCorner], + pos: { + x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width), + y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height) + } + }); + } + + return dijit._place(node, choices, layoutNode, {w: width, h: height}); }; -dijit.placementRegistry=new dojo.AdapterRegistry(); -dijit.placementRegistry.register("node",function(n,x){ -return typeof x=="object"&&typeof x.offsetWidth!="undefined"&&typeof x.offsetHeight!="undefined"; -},dijit.placeOnScreenAroundNode); -dijit.placementRegistry.register("rect",function(n,x){ -return typeof x=="object"&&"x" in x&&"y" in x&&"width" in x&&"height" in x; -},dijit.placeOnScreenAroundRectangle); -dijit.placeOnScreenAroundElement=function(_2a,_2b,_2c,_2d){ -return dijit.placementRegistry.match.apply(dijit.placementRegistry,arguments); + +dijit.placementRegistry= new dojo.AdapterRegistry(); +dijit.placementRegistry.register("node", + function(n, x){ + return typeof x == "object" && + typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined"; + }, + dijit.placeOnScreenAroundNode); +dijit.placementRegistry.register("rect", + function(n, x){ + return typeof x == "object" && + "x" in x && "y" in x && "width" in x && "height" in x; + }, + dijit.placeOnScreenAroundRectangle); + +dijit.placeOnScreenAroundElement = function( + /* DomNode */ node, + /* Object */ aroundElement, + /* Object */ aroundCorners, + /* Function */ layoutNode){ + + // summary: + // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object + // for the "around" argument and finds a proper processor to place a node. + + return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments); }; -dijit.getPopupAroundAlignment=function(_2e,_2f){ -var _30={}; -dojo.forEach(_2e,function(pos){ -switch(pos){ -case "after": -_30[_2f?"BR":"BL"]=_2f?"BL":"BR"; -break; -case "before": -_30[_2f?"BL":"BR"]=_2f?"BR":"BL"; -break; -case "below": -_30[_2f?"BL":"BR"]=_2f?"TL":"TR"; -_30[_2f?"BR":"BL"]=_2f?"TR":"TL"; -break; -case "above": -default: -_30[_2f?"TL":"TR"]=_2f?"BL":"BR"; -_30[_2f?"TR":"TL"]=_2f?"BR":"BL"; -break; -} -}); -return _30; + +dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){ + // summary: + // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement. + // + // position: String[] + // This variable controls the position of the drop down. + // It's an array of strings with the following values: + // + // * before: places drop down to the left of the target node/widget, or to the right in + // the case of RTL scripts like Hebrew and Arabic + // * after: places drop down to the right of the target node/widget, or to the left in + // the case of RTL scripts like Hebrew and Arabic + // * above: drop down goes above target node + // * below: drop down goes below target node + // + // The list is positions is tried, in order, until a position is found where the drop down fits + // within the viewport. + // + // leftToRight: Boolean + // Whether the popup will be displaying in leftToRight mode. + // + var align = {}; + dojo.forEach(position, function(pos){ + switch(pos){ + case "after": + align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR"; + break; + case "before": + align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL"; + break; + case "below-alt": + leftToRight = !leftToRight; + // fall through + case "below": + // first try to align left borders, next try to align right borders (or reverse for RTL mode) + align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR"; + align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL"; + break; + case "above-alt": + leftToRight = !leftToRight; + // fall through + case "above": + default: + // first try to align left borders, next try to align right borders (or reverse for RTL mode) + align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR"; + align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL"; + break; + } + }); + return align; }; + } -- cgit v1.2.3