summaryrefslogtreecommitdiff
path: root/lib/dijit/layout/_LayoutWidget.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/layout/_LayoutWidget.js')
-rw-r--r--lib/dijit/layout/_LayoutWidget.js411
1 files changed, 299 insertions, 112 deletions
diff --git a/lib/dijit/layout/_LayoutWidget.js b/lib/dijit/layout/_LayoutWidget.js
index ec7be37b7..cbbf71009 100644
--- a/lib/dijit/layout/_LayoutWidget.js
+++ b/lib/dijit/layout/_LayoutWidget.js
@@ -1,126 +1,313 @@
/*
- 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.layout._LayoutWidget"]){
-dojo._hasResource["dijit.layout._LayoutWidget"]=true;
+if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.layout._LayoutWidget"] = true;
dojo.provide("dijit.layout._LayoutWidget");
dojo.require("dijit._Widget");
dojo.require("dijit._Container");
dojo.require("dijit._Contained");
-dojo.declare("dijit.layout._LayoutWidget",[dijit._Widget,dijit._Container,dijit._Contained],{baseClass:"dijitLayoutContainer",isLayoutContainer:true,postCreate:function(){
-dojo.addClass(this.domNode,"dijitContainer");
-this.inherited(arguments);
-},startup:function(){
-if(this._started){
-return;
-}
-this.inherited(arguments);
-var _1=this.getParent&&this.getParent();
-if(!(_1&&_1.isLayoutContainer)){
-this.resize();
-this.connect(dojo.isIE?this.domNode:dojo.global,"onresize",function(){
-this.resize();
-});
-}
-},resize:function(_2,_3){
-var _4=this.domNode;
-if(_2){
-dojo.marginBox(_4,_2);
-if(_2.t){
-_4.style.top=_2.t+"px";
-}
-if(_2.l){
-_4.style.left=_2.l+"px";
-}
-}
-var mb=_3||{};
-dojo.mixin(mb,_2||{});
-if(!("h" in mb)||!("w" in mb)){
-mb=dojo.mixin(dojo.marginBox(_4),mb);
-}
-var cs=dojo.getComputedStyle(_4);
-var me=dojo._getMarginExtents(_4,cs);
-var be=dojo._getBorderExtents(_4,cs);
-var bb=(this._borderBox={w:mb.w-(me.w+be.w),h:mb.h-(me.h+be.h)});
-var pe=dojo._getPadExtents(_4,cs);
-this._contentBox={l:dojo._toPixelValue(_4,cs.paddingLeft),t:dojo._toPixelValue(_4,cs.paddingTop),w:bb.w-pe.w,h:bb.h-pe.h};
-this.layout();
-},layout:function(){
-},_setupChild:function(_5){
-dojo.addClass(_5.domNode,this.baseClass+"-child");
-if(_5.baseClass){
-dojo.addClass(_5.domNode,this.baseClass+"-"+_5.baseClass);
-}
-},addChild:function(_6,_7){
-this.inherited(arguments);
-if(this._started){
-this._setupChild(_6);
-}
-},removeChild:function(_8){
-dojo.removeClass(_8.domNode,this.baseClass+"-child");
-if(_8.baseClass){
-dojo.removeClass(_8.domNode,this.baseClass+"-"+_8.baseClass);
-}
-this.inherited(arguments);
-}});
-dijit.layout.marginBox2contentBox=function(_9,mb){
-var cs=dojo.getComputedStyle(_9);
-var me=dojo._getMarginExtents(_9,cs);
-var pb=dojo._getPadBorderExtents(_9,cs);
-return {l:dojo._toPixelValue(_9,cs.paddingLeft),t:dojo._toPixelValue(_9,cs.paddingTop),w:mb.w-(me.w+pb.w),h:mb.h-(me.h+pb.h)};
+
+
+dojo.declare("dijit.layout._LayoutWidget",
+ [dijit._Widget, dijit._Container, dijit._Contained],
+ {
+ // summary:
+ // Base class for a _Container widget which is responsible for laying out its children.
+ // Widgets which mixin this code must define layout() to manage placement and sizing of the children.
+
+ // baseClass: [protected extension] String
+ // This class name is applied to the widget's domNode
+ // and also may be used to generate names for sub nodes,
+ // for example dijitTabContainer-content.
+ baseClass: "dijitLayoutContainer",
+
+ // isLayoutContainer: [protected] Boolean
+ // Indicates that this widget is going to call resize() on its
+ // children widgets, setting their size, when they become visible.
+ isLayoutContainer: true,
+
+ buildRendering: function(){
+ this.inherited(arguments);
+ dojo.addClass(this.domNode, "dijitContainer");
+ },
+
+ startup: function(){
+ // summary:
+ // Called after all the widgets have been instantiated and their
+ // dom nodes have been inserted somewhere under dojo.doc.body.
+ //
+ // Widgets should override this method to do any initialization
+ // dependent on other widgets existing, and then call
+ // this superclass method to finish things off.
+ //
+ // startup() in subclasses shouldn't do anything
+ // size related because the size of the widget hasn't been set yet.
+
+ if(this._started){ return; }
+
+ // Need to call inherited first - so that child widgets get started
+ // up correctly
+ this.inherited(arguments);
+
+ // If I am a not being controlled by a parent layout widget...
+ var parent = this.getParent && this.getParent()
+ if(!(parent && parent.isLayoutContainer)){
+ // Do recursive sizing and layout of all my descendants
+ // (passing in no argument to resize means that it has to glean the size itself)
+ this.resize();
+
+ // Since my parent isn't a layout container, and my style *may be* width=height=100%
+ // or something similar (either set directly or via a CSS class),
+ // monitor when my size changes so that I can re-layout.
+ // For browsers where I can't directly monitor when my size changes,
+ // monitor when the viewport changes size, which *may* indicate a size change for me.
+ this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
+ // Using function(){} closure to ensure no arguments to resize.
+ this.resize();
+ });
+ }
+ },
+
+ resize: function(changeSize, resultSize){
+ // summary:
+ // Call this to resize a widget, or after its size has changed.
+ // description:
+ // Change size mode:
+ // When changeSize is specified, changes the marginBox of this widget
+ // and forces it to relayout its contents accordingly.
+ // changeSize may specify height, width, or both.
+ //
+ // If resultSize is specified it indicates the size the widget will
+ // become after changeSize has been applied.
+ //
+ // Notification mode:
+ // When changeSize is null, indicates that the caller has already changed
+ // the size of the widget, or perhaps it changed because the browser
+ // window was resized. Tells widget to relayout its contents accordingly.
+ //
+ // If resultSize is also specified it indicates the size the widget has
+ // become.
+ //
+ // In either mode, this method also:
+ // 1. Sets this._borderBox and this._contentBox to the new size of
+ // the widget. Queries the current domNode size if necessary.
+ // 2. Calls layout() to resize contents (and maybe adjust child widgets).
+ //
+ // changeSize: Object?
+ // Sets the widget to this margin-box size and position.
+ // May include any/all of the following properties:
+ // | {w: int, h: int, l: int, t: int}
+ //
+ // resultSize: Object?
+ // The margin-box size of this widget after applying changeSize (if
+ // changeSize is specified). If caller knows this size and
+ // passes it in, we don't need to query the browser to get the size.
+ // | {w: int, h: int}
+
+ var node = this.domNode;
+
+ // set margin box size, unless it wasn't specified, in which case use current size
+ if(changeSize){
+ dojo.marginBox(node, changeSize);
+
+ // set offset of the node
+ if(changeSize.t){ node.style.top = changeSize.t + "px"; }
+ if(changeSize.l){ node.style.left = changeSize.l + "px"; }
+ }
+
+ // If either height or width wasn't specified by the user, then query node for it.
+ // But note that setting the margin box and then immediately querying dimensions may return
+ // inaccurate results, so try not to depend on it.
+ var mb = resultSize || {};
+ dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
+ if( !("h" in mb) || !("w" in mb) ){
+ mb = dojo.mixin(dojo.marginBox(node), mb); // just use dojo.marginBox() to fill in missing values
+ }
+
+ // Compute and save the size of my border box and content box
+ // (w/out calling dojo.contentBox() since that may fail if size was recently set)
+ var cs = dojo.getComputedStyle(node);
+ var me = dojo._getMarginExtents(node, cs);
+ var be = dojo._getBorderExtents(node, cs);
+ var bb = (this._borderBox = {
+ w: mb.w - (me.w + be.w),
+ h: mb.h - (me.h + be.h)
+ });
+ var pe = dojo._getPadExtents(node, cs);
+ this._contentBox = {
+ l: dojo._toPixelValue(node, cs.paddingLeft),
+ t: dojo._toPixelValue(node, cs.paddingTop),
+ w: bb.w - pe.w,
+ h: bb.h - pe.h
+ };
+
+ // Callback for widget to adjust size of its children
+ this.layout();
+ },
+
+ layout: function(){
+ // summary:
+ // Widgets override this method to size and position their contents/children.
+ // When this is called this._contentBox is guaranteed to be set (see resize()).
+ //
+ // This is called after startup(), and also when the widget's size has been
+ // changed.
+ // tags:
+ // protected extension
+ },
+
+ _setupChild: function(/*dijit._Widget*/child){
+ // summary:
+ // Common setup for initial children and children which are added after startup
+ // tags:
+ // protected extension
+
+ var cls = this.baseClass + "-child "
+ + (child.baseClass ? this.baseClass + "-" + child.baseClass : "");
+ dojo.addClass(child.domNode, cls);
+ },
+
+ addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
+ // Overrides _Container.addChild() to call _setupChild()
+ this.inherited(arguments);
+ if(this._started){
+ this._setupChild(child);
+ }
+ },
+
+ removeChild: function(/*dijit._Widget*/ child){
+ // Overrides _Container.removeChild() to remove class added by _setupChild()
+ var cls = this.baseClass + "-child"
+ + (child.baseClass ?
+ " " + this.baseClass + "-" + child.baseClass : "");
+ dojo.removeClass(child.domNode, cls);
+
+ this.inherited(arguments);
+ }
+ }
+);
+
+dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
+ // summary:
+ // Given the margin-box size of a node, return its content box size.
+ // Functions like dojo.contentBox() but is more reliable since it doesn't have
+ // to wait for the browser to compute sizes.
+ var cs = dojo.getComputedStyle(node);
+ var me = dojo._getMarginExtents(node, cs);
+ var pb = dojo._getPadBorderExtents(node, cs);
+ return {
+ l: dojo._toPixelValue(node, cs.paddingLeft),
+ t: dojo._toPixelValue(node, cs.paddingTop),
+ w: mb.w - (me.w + pb.w),
+ h: mb.h - (me.h + pb.h)
+ };
};
+
(function(){
-var _a=function(_b){
-return _b.substring(0,1).toUpperCase()+_b.substring(1);
-};
-var _c=function(_d,_e){
-_d.resize?_d.resize(_e):dojo.marginBox(_d.domNode,_e);
-dojo.mixin(_d,dojo.marginBox(_d.domNode));
-dojo.mixin(_d,_e);
-};
-dijit.layout.layoutChildren=function(_f,dim,_10){
-dim=dojo.mixin({},dim);
-dojo.addClass(_f,"dijitLayoutContainer");
-_10=dojo.filter(_10,function(_11){
-return _11.layoutAlign!="client";
-}).concat(dojo.filter(_10,function(_12){
-return _12.layoutAlign=="client";
-}));
-dojo.forEach(_10,function(_13){
-var elm=_13.domNode,pos=_13.layoutAlign;
-var _14=elm.style;
-_14.left=dim.l+"px";
-_14.top=dim.t+"px";
-_14.bottom=_14.right="auto";
-dojo.addClass(elm,"dijitAlign"+_a(pos));
-if(pos=="top"||pos=="bottom"){
-_c(_13,{w:dim.w});
-dim.h-=_13.h;
-if(pos=="top"){
-dim.t+=_13.h;
-}else{
-_14.top=dim.t+dim.h+"px";
-}
-}else{
-if(pos=="left"||pos=="right"){
-_c(_13,{h:dim.h});
-dim.w-=_13.w;
-if(pos=="left"){
-dim.l+=_13.w;
-}else{
-_14.left=dim.l+dim.w+"px";
-}
-}else{
-if(pos=="client"){
-_c(_13,dim);
-}
-}
-}
-});
-};
+ var capitalize = function(word){
+ return word.substring(0,1).toUpperCase() + word.substring(1);
+ };
+
+ var size = function(widget, dim){
+ // size the child
+ var newSize = widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);
+
+ // record child's size
+ if(newSize){
+ // if the child returned it's new size then use that
+ dojo.mixin(widget, newSize);
+ }else{
+ // otherwise, call marginBox(), but favor our own numbers when we have them.
+ // the browser lies sometimes
+ dojo.mixin(widget, dojo.marginBox(widget.domNode));
+ dojo.mixin(widget, dim);
+ }
+ };
+
+ dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Widget[]*/ children,
+ /*String?*/ changedRegionId, /*Number?*/ changedRegionSize){
+ // summary
+ // Layout a bunch of child dom nodes within a parent dom node
+ // container:
+ // parent node
+ // dim:
+ // {l, t, w, h} object specifying dimensions of container into which to place children
+ // children:
+ // an array of Widgets or at least objects containing:
+ // * domNode: pointer to DOM node to position
+ // * region or layoutAlign: position to place DOM node
+ // * resize(): (optional) method to set size of node
+ // * id: (optional) Id of widgets, referenced from resize object, below.
+ // changedRegionId:
+ // If specified, the slider for the region with the specified id has been dragged, and thus
+ // the region's height or width should be adjusted according to changedRegionSize
+ // changedRegionSize:
+ // See changedRegionId.
+
+ // copy dim because we are going to modify it
+ dim = dojo.mixin({}, dim);
+
+ dojo.addClass(container, "dijitLayoutContainer");
+
+ // Move "client" elements to the end of the array for layout. a11y dictates that the author
+ // needs to be able to put them in the document in tab-order, but this algorithm requires that
+ // client be last. TODO: move these lines to LayoutContainer? Unneeded other places I think.
+ children = dojo.filter(children, function(item){ return item.region != "center" && item.layoutAlign != "client"; })
+ .concat(dojo.filter(children, function(item){ return item.region == "center" || item.layoutAlign == "client"; }));
+
+ // set positions/sizes
+ dojo.forEach(children, function(child){
+ var elm = child.domNode,
+ pos = (child.region || child.layoutAlign);
+
+ // set elem to upper left corner of unused space; may move it later
+ var elmStyle = elm.style;
+ elmStyle.left = dim.l+"px";
+ elmStyle.top = dim.t+"px";
+ elmStyle.position = "absolute";
+
+ dojo.addClass(elm, "dijitAlign" + capitalize(pos));
+
+ // Size adjustments to make to this child widget
+ var sizeSetting = {};
+
+ // Check for optional size adjustment due to splitter drag (height adjustment for top/bottom align
+ // panes and width adjustment for left/right align panes.
+ if(changedRegionId && changedRegionId == child.id){
+ sizeSetting[child.region == "top" || child.region == "bottom" ? "h" : "w"] = changedRegionSize;
+ }
+
+ // set size && adjust record of remaining space.
+ // note that setting the width of a <div> may affect its height.
+ if(pos == "top" || pos == "bottom"){
+ sizeSetting.w = dim.w;
+ size(child, sizeSetting);
+ dim.h -= child.h;
+ if(pos == "top"){
+ dim.t += child.h;
+ }else{
+ elmStyle.top = dim.t + dim.h + "px";
+ }
+ }else if(pos == "left" || pos == "right"){
+ sizeSetting.h = dim.h;
+ size(child, sizeSetting);
+ dim.w -= child.w;
+ if(pos == "left"){
+ dim.l += child.w;
+ }else{
+ elmStyle.left = dim.l + dim.w + "px";
+ }
+ }else if(pos == "client" || pos == "center"){
+ size(child, dim);
+ }
+ });
+ };
+
})();
+
}