place.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. if (!dojo._hasResource["dijit._base.place"]) { // _hasResource checks added by
  2. // build. Do not use
  3. // _hasResource directly in your
  4. // code.
  5. dojo._hasResource["dijit._base.place"] = true;
  6. dojo.provide("dijit._base.place");
  7. // ported from dojo.html.util
  8. dijit.getViewport = function() {
  9. // summary
  10. // Returns the dimensions and scroll position of the viewable area of a
  11. // browser window
  12. var _window = dojo.global;
  13. var _document = dojo.doc;
  14. // get viewport size
  15. var w = 0, h = 0;
  16. if (dojo.isMozilla) {
  17. // mozilla
  18. // _window.innerHeight includes the height taken by the scroll bar
  19. // clientHeight is ideal but has DTD issues:
  20. // #4539: FF reverses the roles of body.clientHeight/Width and
  21. // documentElement.clientHeight/Width based on the DTD!
  22. // check DTD to see whether body or documentElement returns the
  23. // viewport dimensions using this algorithm:
  24. var minw, minh, maxw, maxh;
  25. if (_document.body.clientWidth > _document.documentElement.clientWidth) {
  26. minw = _document.documentElement.clientWidth;
  27. maxw = _document.body.clientWidth;
  28. } else {
  29. maxw = _document.documentElement.clientWidth;
  30. minw = _document.body.clientWidth;
  31. }
  32. if (_document.body.clientHeight > _document.documentElement.clientHeight) {
  33. minh = _document.documentElement.clientHeight;
  34. maxh = _document.body.clientHeight;
  35. } else {
  36. maxh = _document.documentElement.clientHeight;
  37. minh = _document.body.clientHeight;
  38. }
  39. w = (maxw > _window.innerWidth) ? minw : maxw;
  40. h = (maxh > _window.innerHeight) ? minh : maxh;
  41. } else if (!dojo.isOpera && _window.innerWidth) {
  42. // in opera9, dojo.body().clientWidth should be used, instead
  43. // of window.innerWidth/document.documentElement.clientWidth
  44. // so we have to check whether it is opera
  45. w = _window.innerWidth;
  46. h = _window.innerHeight;
  47. } else if (dojo.isIE && _document.documentElement
  48. && _document.documentElement.clientHeight) {
  49. w = _document.documentElement.clientWidth;
  50. h = _document.documentElement.clientHeight;
  51. } else if (dojo.body().clientWidth) {
  52. // IE5, Opera
  53. w = dojo.body().clientWidth;
  54. h = dojo.body().clientHeight;
  55. }
  56. // get scroll position
  57. var scroll = dojo._docScroll();
  58. return {
  59. w : w,
  60. h : h,
  61. l : scroll.x,
  62. t : scroll.y
  63. }; // object
  64. };
  65. dijit.placeOnScreen = function(
  66. /* DomNode */node,
  67. /* Object */pos,
  68. /* Object */corners,
  69. /* boolean? */tryOnly) {
  70. // summary:
  71. // Keeps 'node' in the visible area of the screen while trying to
  72. // place closest to pos.x, pos.y. The input coordinates are
  73. // expected to be the desired document position.
  74. //
  75. // Set which corner(s) you want to bind to, such as
  76. //
  77. // placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
  78. //
  79. // The desired x/y will be treated as the topleft(TL)/topright(TR) or
  80. // BottomLeft(BL)/BottomRight(BR) corner of the node. Each corner is
  81. // tested
  82. // and if a perfect match is found, it will be used. Otherwise, it goes
  83. // through
  84. // all of the specified corners, and choose the most appropriate one.
  85. //
  86. // NOTE: node is assumed to be absolutely or relatively positioned.
  87. var choices = dojo.map(corners, function(corner) {
  88. return {
  89. corner : corner,
  90. pos : pos
  91. };
  92. });
  93. return dijit._place(node, choices);
  94. }
  95. dijit._place = function(/* DomNode */node, /* Array */choices, /* Function */
  96. layoutNode) {
  97. // summary:
  98. // Given a list of spots to put node, put it at the first spot where it
  99. // fits,
  100. // of if it doesn't fit anywhere then the place with the least overflow
  101. // choices: Array
  102. // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
  103. // Above example says to put the top-left corner of the node at (10,20)
  104. // layoutNode: Function(node, orient)
  105. // for things like tooltip, they are displayed differently (and have
  106. // different dimensions)
  107. // based on their orientation relative to the parent. This adjusts the
  108. // popup based on orientation.
  109. // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
  110. // viewport over document
  111. var view = dijit.getViewport();
  112. // This won't work if the node is inside a <div style="position:
  113. // relative">,
  114. // so reattach it to document.body. (Otherwise, the positioning will be
  115. // wrong
  116. // and also it might get cutoff)
  117. if (!node.parentNode
  118. || String(node.parentNode.tagName).toLowerCase() != "body") {
  119. dojo.body().appendChild(node);
  120. }
  121. var best = null;
  122. for (var i = 0; i < choices.length; i++) {
  123. var corner = choices[i].corner;
  124. var pos = choices[i].pos;
  125. // configure node to be displayed in given position relative to
  126. // button
  127. // (need to do this in order to get an accurate size for the node,
  128. // because
  129. // a tooltips size changes based on position, due to triangle)
  130. if (layoutNode) {
  131. layoutNode(corner);
  132. }
  133. // get node's size
  134. var oldDisplay = node.style.display;
  135. var oldVis = node.style.visibility;
  136. node.style.visibility = "hidden";
  137. node.style.display = "";
  138. var mb = dojo.marginBox(node);
  139. node.style.display = oldDisplay;
  140. node.style.visibility = oldVis;
  141. // coordinates and size of node with specified corner placed at pos,
  142. // and clipped by viewport
  143. var startX = (corner.charAt(1) == 'L' ? pos.x : Math.max(view.l,
  144. pos.x - mb.w)), startY = (corner.charAt(0) == 'T'
  145. ? pos.y
  146. : Math.max(view.t, pos.y - mb.h)), endX = (corner.charAt(1) == 'L'
  147. ? Math.min(view.l + view.w, startX + mb.w)
  148. : pos.x), endY = (corner.charAt(0) == 'T' ? Math.min(view.t
  149. + view.h, startY + mb.h) : pos.y), width = endX
  150. - startX, height = endY - startY, overflow = (mb.w - width)
  151. + (mb.h - height);
  152. if (best == null || overflow < best.overflow) {
  153. best = {
  154. corner : corner,
  155. aroundCorner : choices[i].aroundCorner,
  156. x : startX,
  157. y : startY,
  158. w : width,
  159. h : height,
  160. overflow : overflow
  161. };
  162. }
  163. if (overflow == 0) {
  164. break;
  165. }
  166. }
  167. node.style.left = best.x + "px";
  168. node.style.top = best.y + "px";
  169. return best;
  170. }
  171. dijit.placeOnScreenAroundElement = function(
  172. /* DomNode */node,
  173. /* DomNode */aroundNode,
  174. /* Object */aroundCorners,
  175. /* Function */layoutNode) {
  176. // summary
  177. // Like placeOnScreen, except it accepts aroundNode instead of x,y
  178. // and attempts to place node around it. Uses margin box dimensions.
  179. //
  180. // aroundCorners
  181. // specify Which corner of aroundNode should be
  182. // used to place the node => which corner(s) of node to use (see the
  183. // corners parameter in dijit.placeOnScreen)
  184. // e.g. {'TL': 'BL', 'BL': 'TL'}
  185. //
  186. // layoutNode: Function(node, orient)
  187. // for things like tooltip, they are displayed differently (and have
  188. // different dimensions)
  189. // based on their orientation relative to the parent. This adjusts the
  190. // popup based on orientation.
  191. // get coordinates of aroundNode
  192. aroundNode = dojo.byId(aroundNode);
  193. var oldDisplay = aroundNode.style.display;
  194. aroundNode.style.display = "";
  195. // #3172: use the slightly tighter border box instead of marginBox
  196. var aroundNodeW = aroundNode.offsetWidth; // mb.w;
  197. var aroundNodeH = aroundNode.offsetHeight; // mb.h;
  198. var aroundNodePos = dojo.coords(aroundNode, true);
  199. aroundNode.style.display = oldDisplay;
  200. // Generate list of possible positions for node
  201. var choices = [];
  202. for (var nodeCorner in aroundCorners) {
  203. choices.push({
  204. aroundCorner : nodeCorner,
  205. corner : aroundCorners[nodeCorner],
  206. pos : {
  207. x : aroundNodePos.x
  208. + (nodeCorner.charAt(1) == 'L'
  209. ? 0
  210. : aroundNodeW),
  211. y : aroundNodePos.y
  212. + (nodeCorner.charAt(0) == 'T'
  213. ? 0
  214. : aroundNodeH)
  215. }
  216. });
  217. }
  218. return dijit._place(node, choices, layoutNode);
  219. }
  220. }