/public/javascripts/dojo/release/dojo/dijit/layout/_LayoutWidget.js

http://enginey.googlecode.com/ · JavaScript · 268 lines · 128 code · 38 blank · 102 comment · 29 complexity · 9c2ed242f192a459cca98a97454eb0a2 MD5 · raw file

  1. /*
  2. Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dijit.layout._LayoutWidget"] = true;
  8. dojo.provide("dijit.layout._LayoutWidget");
  9. dojo.require("dijit._Widget");
  10. dojo.require("dijit._Container");
  11. dojo.declare("dijit.layout._LayoutWidget",
  12. [dijit._Widget, dijit._Container, dijit._Contained],
  13. {
  14. // summary
  15. // Mixin for widgets that contain a list of children like SplitContainer.
  16. // Widgets which mixin this code must define layout() to lay out the children
  17. // baseClass: String
  18. // This class name is applied to the widget's domNode
  19. // and also may be used to generate names for sub nodes,
  20. // like for example dijitTabContainer-content.
  21. baseClass: "dijitLayoutContainer",
  22. isLayoutContainer: true,
  23. postCreate: function(){
  24. dojo.addClass(this.domNode, "dijitContainer");
  25. dojo.addClass(this.domNode, this.baseClass);
  26. },
  27. startup: function(){
  28. // summary:
  29. // Called after all the widgets have been instantiated and their
  30. // dom nodes have been inserted somewhere under dojo.doc.body.
  31. //
  32. // Widgets should override this method to do any initialization
  33. // dependent on other widgets existing, and then call
  34. // this superclass method to finish things off.
  35. //
  36. // startup() in subclasses shouldn't do anything
  37. // size related because the size of the widget hasn't been set yet.
  38. if(this._started){ return; }
  39. dojo.forEach(this.getChildren(), function(child){ child.startup(); });
  40. // If I am a top level widget
  41. if(!this.getParent || !this.getParent()){
  42. // Do recursive sizing and layout of all my descendants
  43. // (passing in no argument to resize means that it has to glean the size itself)
  44. this.resize();
  45. // since my parent isn't a layout container, and my style is width=height=100% (or something similar),
  46. // then I need to watch when the window resizes, and size myself accordingly
  47. // (passing in no argument to resize means that it has to glean the size itself)
  48. this.connect(dojo.global, 'onresize', 'resize');
  49. }
  50. this.inherited(arguments);
  51. },
  52. resize: function(changeSize, resultSize){
  53. // summary:
  54. // Call this to resize a widget, or after it's size has changed.
  55. // description:
  56. // Change size mode:
  57. // When changeSize is specified, changes the marginBox of this widget
  58. // and forces it to relayout it's contents accordingly.
  59. // changeSize may specify height, width, or both.
  60. //
  61. // If resultSize is specified it indicates the size the widget will
  62. // become after changeSize has been applied.
  63. //
  64. // Notification mode:
  65. // When changeSize is null, indicates that the caller has already changed
  66. // the size of the widget, or perhaps it changed because the browser
  67. // window was resized. Tells widget to relayout it's contents accordingly.
  68. //
  69. // If resultSize is also specified it indicates the size the widget has
  70. // become.
  71. //
  72. // In either mode, this method also:
  73. // 1. Sets this._borderBox and this._contentBox to the new size of
  74. // the widget. Queries the current domNode size if necessary.
  75. // 2. Calls layout() to resize contents (and maybe adjust child widgets).
  76. //
  77. // changeSize: Object?
  78. // Sets the widget to this margin-box size and position.
  79. // May include any/all of the following properties:
  80. // | {w: int, h: int, l: int, t: int}
  81. //
  82. // resultSize: Object?
  83. // The margin-box size of this widget after applying changeSize (if
  84. // changeSize is specified). If caller knows this size and
  85. // passes it in, we don't need to query the browser to get the size.
  86. // | {w: int, h: int}
  87. var node = this.domNode;
  88. // set margin box size, unless it wasn't specified, in which case use current size
  89. if(changeSize){
  90. dojo.marginBox(node, changeSize);
  91. // set offset of the node
  92. if(changeSize.t){ node.style.top = changeSize.t + "px"; }
  93. if(changeSize.l){ node.style.left = changeSize.l + "px"; }
  94. }
  95. // If either height or width wasn't specified by the user, then query node for it.
  96. // But note that setting the margin box and then immediately querying dimensions may return
  97. // inaccurate results, so try not to depend on it.
  98. var mb = resultSize || {};
  99. dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
  100. if ( !("h" in mb) || !("w" in mb) ){
  101. mb = dojo.mixin(dojo.marginBox(node), mb); // just use dojo.marginBox() to fill in missing values
  102. }
  103. // Compute and save the size of my border box and content box
  104. // (w/out calling dojo.contentBox() since that may fail if size was recently set)
  105. var cs = dojo.getComputedStyle(node);
  106. var me = dojo._getMarginExtents(node, cs);
  107. var be = dojo._getBorderExtents(node, cs);
  108. var bb = this._borderBox = {
  109. w: mb.w - (me.w + be.w),
  110. h: mb.h - (me.h + be.h)
  111. };
  112. var pe = dojo._getPadExtents(node, cs);
  113. this._contentBox = {
  114. l: dojo._toPixelValue(node, cs.paddingLeft),
  115. t: dojo._toPixelValue(node, cs.paddingTop),
  116. w: bb.w - pe.w,
  117. h: bb.h - pe.h
  118. };
  119. // Callback for widget to adjust size of it's children
  120. this.layout();
  121. },
  122. layout: function(){
  123. // summary
  124. // Widgets override this method to size & position their contents/children.
  125. // When this is called this._contentBox is guaranteed to be set (see resize()).
  126. //
  127. // This is called after startup(), and also when the widget's size has been
  128. // changed.
  129. },
  130. _setupChild: function(/*Widget*/child){
  131. // summary: common setup for initial children or children which are added after startup
  132. if(child.baseClass){
  133. dojo.addClass(child.domNode, this.baseClass+"-"+child.baseClass);
  134. }
  135. },
  136. addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
  137. this.inherited(arguments);
  138. if(this._started){
  139. this._setupChild(child);
  140. }
  141. },
  142. removeChild: function(/*Widget*/ child){
  143. if(child.baseClass){
  144. dojo.removeClass(child.domNode, this.baseClass+"-"+child.baseClass);
  145. }
  146. this.inherited(arguments);
  147. }
  148. }
  149. );
  150. dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
  151. // summary:
  152. // Given the margin-box size of a node, return it's content box size.
  153. // Functions like dojo.contentBox() but is more reliable since it doesn't have
  154. // to wait for the browser to compute sizes.
  155. var cs = dojo.getComputedStyle(node);
  156. var me = dojo._getMarginExtents(node, cs);
  157. var pb = dojo._getPadBorderExtents(node, cs);
  158. return {
  159. l: dojo._toPixelValue(node, cs.paddingLeft),
  160. t: dojo._toPixelValue(node, cs.paddingTop),
  161. w: mb.w - (me.w + pb.w),
  162. h: mb.h - (me.h + pb.h)
  163. };
  164. };
  165. (function(){
  166. var capitalize = function(word){
  167. return word.substring(0,1).toUpperCase() + word.substring(1);
  168. };
  169. var size = function(widget, dim){
  170. // size the child
  171. widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
  172. // record child's size, but favor our own numbers when we have them.
  173. // the browser lies sometimes
  174. dojo.mixin(widget, dojo.marginBox(widget.domNode));
  175. dojo.mixin(widget, dim);
  176. };
  177. dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
  178. /**
  179. * summary
  180. * Layout a bunch of child dom nodes within a parent dom node
  181. * container:
  182. * parent node
  183. * dim:
  184. * {l, t, w, h} object specifying dimensions of container into which to place children
  185. * children:
  186. * an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
  187. */
  188. // copy dim because we are going to modify it
  189. dim = dojo.mixin({}, dim);
  190. dojo.addClass(container, "dijitLayoutContainer");
  191. // Move "client" elements to the end of the array for layout. a11y dictates that the author
  192. // needs to be able to put them in the document in tab-order, but this algorithm requires that
  193. // client be last.
  194. children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
  195. .concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
  196. // set positions/sizes
  197. dojo.forEach(children, function(child){
  198. var elm = child.domNode,
  199. pos = child.layoutAlign;
  200. // set elem to upper left corner of unused space; may move it later
  201. var elmStyle = elm.style;
  202. elmStyle.left = dim.l+"px";
  203. elmStyle.top = dim.t+"px";
  204. elmStyle.bottom = elmStyle.right = "auto";
  205. dojo.addClass(elm, "dijitAlign" + capitalize(pos));
  206. // set size && adjust record of remaining space.
  207. // note that setting the width of a <div> may affect it's height.
  208. if(pos == "top" || pos == "bottom"){
  209. size(child, { w: dim.w });
  210. dim.h -= child.h;
  211. if(pos=="top"){
  212. dim.t += child.h;
  213. }else{
  214. elmStyle.top = dim.t + dim.h + "px";
  215. }
  216. }else if(pos == "left" || pos == "right"){
  217. size(child, { h: dim.h });
  218. dim.w -= child.w;
  219. if(pos == "left"){
  220. dim.l += child.w;
  221. }else{
  222. elmStyle.left = dim.l + dim.w + "px";
  223. }
  224. }else if(pos == "client"){
  225. size(child, dim);
  226. }
  227. });
  228. };
  229. })();
  230. }