From 1354d17270961fff662d40f90521223f8fd0d73b Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 14 Aug 2012 18:59:10 +0400 Subject: update dojo to 1.7.3 --- lib/dijit/place.js.uncompressed.js | 369 +++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 lib/dijit/place.js.uncompressed.js (limited to 'lib/dijit/place.js.uncompressed.js') diff --git a/lib/dijit/place.js.uncompressed.js b/lib/dijit/place.js.uncompressed.js new file mode 100644 index 000000000..5283da478 --- /dev/null +++ b/lib/dijit/place.js.uncompressed.js @@ -0,0 +1,369 @@ +define("dijit/place", [ + "dojo/_base/array", // array.forEach array.map array.some + "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position + "dojo/dom-style", // domStyle.getComputedStyle + "dojo/_base/kernel", // kernel.deprecated + "dojo/_base/window", // win.body + "dojo/window", // winUtils.getBox + "." // dijit (defining dijit.place to match API doc) +], function(array, domGeometry, domStyle, kernel, win, winUtils, dijit){ + + // module: + // dijit/place + // summary: + // Code to place a popup relative to another node + + + function _place(/*DomNode*/ node, choices, layoutNode, 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 = winUtils.getBox(); + + // This won't work if the node is inside a
, + // so reattach it to win.doc.body. (Otherwise, the positioning will be wrong + // and also it might get cutoff) + if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ + win.body().appendChild(node); + } + + var best = null; + array.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: { + 'L': view.l + view.w - pos.x, + 'R': pos.x - view.l, + 'M': view.w + }[corner.charAt(1)], + h: { + 'T': view.t + view.h - pos.y, + 'B': pos.y - view.t, + 'M': view.h + }[corner.charAt(0)] + }; + + // 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; + if(style.display == "none"){ + style.visibility = "hidden"; + style.display = ""; + } + var mb = domGeometry. getMarginBox(node); + style.display = oldDisplay; + style.visibility = oldVis; + + // coordinates and size of node with specified corner placed at pos, + // and clipped by viewport + var + startXpos = { + 'L': pos.x, + 'R': pos.x - mb.w, + 'M': Math.max(view.l, Math.min(view.l + view.w, pos.x + (mb.w >> 1)) - mb.w) // M orientation is more flexible + }[corner.charAt(1)], + startYpos = { + 'T': pos.y, + 'B': pos.y - mb.h, + 'M': Math.max(view.t, Math.min(view.t + view.h, pos.y + (mb.h >> 1)) - mb.h) + }[corner.charAt(0)], + startX = Math.max(view.l, startXpos), + startY = Math.max(view.t, startYpos), + endX = Math.min(view.l + view.w, startXpos + mb.w), + endY = Math.min(view.t + view.h, startYpos + mb.h), + 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 = domGeometry.isBodyLtr(), + s = node.style; + s.top = best.y + "px"; + s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px"; + s[l ? "right" : "left"] = "auto"; // needed for FF or else tooltip goes to far left + + return best; + } + + /*===== + dijit.place.__Position = function(){ + // x: Integer + // horizontal coordinate in pixels, relative to document body + // y: Integer + // vertical coordinate in pixels, relative to document body + + this.x = x; + this.y = y; + }; + =====*/ + + /*===== + dijit.place.__Rectangle = function(){ + // x: Integer + // horizontal offset in pixels, relative to document body + // y: Integer + // vertical offset in pixels, relative to document body + // w: Integer + // width in pixels. Can also be specified as "width" for backwards-compatibility. + // h: Integer + // height in pixels. Can also be specified as "height" from backwards-compatibility. + + this.x = x; + this.y = y; + this.w = w; + this.h = h; + }; + =====*/ + + return (dijit.place = { + // summary: + // Code to place a DOMNode relative to another DOMNode. + // Load using require(["dijit/place"], function(place){ ... }). + + at: function(node, pos, corners, 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. + // node: DOMNode + // The node to position + // pos: dijit.place.__Position + // Object like {x: 10, y: 20} + // corners: String[] + // 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: dijit.place.__Position? + // optional param to 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). + // | place(node, {x: 10, y: 20}, ["TR", "BL"]) + var choices = array.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 _place(node, choices); + }, + + around: function( + /*DomNode*/ node, + /*DomNode || dijit.place.__Rectangle*/ anchor, + /*String[]*/ positions, + /*Boolean*/ leftToRight, + /*Function?*/ layoutNode){ + + // summary: + // Position node adjacent or kitty-corner to anchor + // 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. + // + // anchor: + // Either a DOMNode or a __Rectangle (object with x, y, width, height). + // + // positions: + // Ordered list of positions to try matching up. + // * before: places drop down to the left of the anchor node/widget, or to the right in the case + // of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down + // with the top of the anchor, or the bottom of the drop down with bottom of the anchor. + // * after: places drop down to the right of the anchor node/widget, or to the left in the case + // of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down + // with the top of the anchor, or the bottom of the drop down with bottom of the anchor. + // * before-centered: centers drop down to the left of the anchor node/widget, or to the right + // in the case of RTL scripts like Hebrew and Arabic + // * after-centered: centers drop down to the right of the anchor node/widget, or to the left + // in the case of RTL scripts like Hebrew and Arabic + // * above-centered: drop down is centered above anchor node + // * above: drop down goes above anchor node, left sides aligned + // * above-alt: drop down goes above anchor node, right sides aligned + // * below-centered: drop down is centered above anchor node + // * below: drop down goes below anchor node + // * below-alt: drop down goes below anchor node, right sides aligned + // + // 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. + // + // leftToRight: + // True if widget is LTR, false if widget is RTL. Affects the behavior of "above" and "below" + // positions slightly. + // + // example: + // | placeAroundNode(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) + // + + // if around is a DOMNode (or DOMNode id), convert to coordinates + var aroundNodePos = (typeof anchor == "string" || "offsetWidth" in anchor) + ? domGeometry.position(anchor, true) + : anchor; + + // Adjust anchor positioning for the case that a parent node has overflw hidden, therefore cuasing the anchor not to be completely visible + if(anchor.parentNode){ + var parent = anchor.parentNode; + while(parent && parent.nodeType == 1 && parent.nodeName != "BODY"){ //ignoring the body will help performance + var parentPos = domGeometry.position(parent, true); + var parentStyleOverflow = domStyle.getComputedStyle(parent).overflow; + if(parentStyleOverflow == "hidden" || parentStyleOverflow == "auto" || parentStyleOverflow == "scroll"){ + var bottomYCoord = Math.min(aroundNodePos.y + aroundNodePos.h, parentPos.y + parentPos.h); + var rightXCoord = Math.min(aroundNodePos.x + aroundNodePos.w, parentPos.x + parentPos.w); + aroundNodePos.x = Math.max(aroundNodePos.x, parentPos.x); + aroundNodePos.y = Math.max(aroundNodePos.y, parentPos.y); + aroundNodePos.h = bottomYCoord - aroundNodePos.y; + aroundNodePos.w = rightXCoord - aroundNodePos.x; + } + parent = parent.parentNode; + } + } + + var x = aroundNodePos.x, + y = aroundNodePos.y, + width = "w" in aroundNodePos ? aroundNodePos.w : (aroundNodePos.w = aroundNodePos.width), + height = "h" in aroundNodePos ? aroundNodePos.h : (kernel.deprecated("place.around: dijit.place.__Rectangle: { x:"+x+", y:"+y+", height:"+aroundNodePos.height+", width:"+width+" } has been deprecated. Please use { x:"+x+", y:"+y+", h:"+aroundNodePos.height+", w:"+width+" }", "", "2.0"), aroundNodePos.h = aroundNodePos.height); + + // Convert positions arguments into choices argument for _place() + var choices = []; + function push(aroundCorner, corner){ + choices.push({ + aroundCorner: aroundCorner, + corner: corner, + pos: { + x: { + 'L': x, + 'R': x + width, + 'M': x + (width >> 1) + }[aroundCorner.charAt(1)], + y: { + 'T': y, + 'B': y + height, + 'M': y + (height >> 1) + }[aroundCorner.charAt(0)] + } + }) + } + array.forEach(positions, function(pos){ + var ltr = leftToRight; + switch(pos){ + case "above-centered": + push("TM", "BM"); + break; + case "below-centered": + push("BM", "TM"); + break; + case "after-centered": + ltr = !ltr; + // fall through + case "before-centered": + push(ltr ? "ML" : "MR", ltr ? "MR" : "ML"); + break; + case "after": + ltr = !ltr; + // fall through + case "before": + push(ltr ? "TL" : "TR", ltr ? "TR" : "TL"); + push(ltr ? "BL" : "BR", ltr ? "BR" : "BL"); + break; + case "below-alt": + ltr = !ltr; + // fall through + case "below": + // first try to align left borders, next try to align right borders (or reverse for RTL mode) + push(ltr ? "BL" : "BR", ltr ? "TL" : "TR"); + push(ltr ? "BR" : "BL", ltr ? "TR" : "TL"); + break; + case "above-alt": + ltr = !ltr; + // fall through + case "above": + // first try to align left borders, next try to align right borders (or reverse for RTL mode) + push(ltr ? "TL" : "TR", ltr ? "BL" : "BR"); + push(ltr ? "TR" : "TL", ltr ? "BR" : "BL"); + break; + default: + // To assist dijit/_base/place, accept arguments of type {aroundCorner: "BL", corner: "TL"}. + // Not meant to be used directly. + push(pos.aroundCorner, pos.corner); + } + }); + + var position = _place(node, choices, layoutNode, {w: width, h: height}); + position.aroundNodePos = aroundNodePos; + + return position; + } + }); +}); -- cgit v1.2.3