Skip to content

Commit

Permalink
Convert !BorderContainer to use dijit.layout.layoutChildren() rather …
Browse files Browse the repository at this point in the history
…than custom layout code. Refs #11030, fixes #12078 !strict.
  • Loading branch information
wkeese committed Dec 13, 2010
1 parent b45a665 commit d12334a
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 198 deletions.
218 changes: 29 additions & 189 deletions layout/BorderContainer.js
Expand Up @@ -90,9 +90,8 @@ dojo.declare(
if(region == "leading"){ region = ltr ? "left" : "right"; }
if(region == "trailing"){ region = ltr ? "right" : "left"; }

//FIXME: redundant?
this["_"+region] = child.domNode;
this["_"+region+"Widget"] = child;
this["_"+region] = child.domNode; //FIXME: redundant?

// Create draggable splitter for resizing pane,
// or alternately if splitter=false but BorderContainer.gutters=true then
Expand All @@ -107,8 +106,9 @@ dojo.declare(
live: this.liveSplitters
});
splitter.isSplitter = true;
this._splitters[region] = splitter.domNode;
dojo.place(this._splitters[region], child.domNode, "after");
this._splitters[region] = splitter;

dojo.place(this._splitters[region].domNode, child.domNode, "after");

// Splitters arent added as Contained children, so we need to call startup explicitly
splitter.startup();
Expand All @@ -119,7 +119,7 @@ dojo.declare(

_computeSplitterThickness: function(/*String*/ region){
this._splitterThickness[region] = this._splitterThickness[region] ||
dojo._getMarginSize(this._splitters[region])[(/top|bottom/.test(region) ? 'h' : 'w')];
dojo._getMarginSize(this._splitters[region].domNode)[(/top|bottom/.test(region) ? 'h' : 'w')];
},

layout: function(){
Expand All @@ -142,7 +142,7 @@ dojo.declare(
var region = child.region;
var splitter = this._splitters[region];
if(splitter){
dijit.byNode(splitter).destroy();
splitter.destroy();
delete this._splitters[region];
delete this._splitterThickness[region];
}
Expand Down Expand Up @@ -176,8 +176,7 @@ dojo.declare(
getSplitter: function(/*String*/region){
// summary:
// Returns the widget responsible for rendering the splitter associated with region
var splitter = this._splitters[region];
return splitter ? dijit.byNode(splitter) : null;
return this._splitters[region];
},

resize: function(newSize, currentSize){
Expand All @@ -198,7 +197,7 @@ dojo.declare(
this.inherited(arguments);
},

_layoutChildren: function(/*String?*/changedRegion, /*Number?*/ changedRegionSize){
_layoutChildren: function(/*String?*/ changedRegion, /*Number?*/ changedRegionSize){
// summary:
// This is the main routine for setting size/position of each child.
// description:
Expand All @@ -220,193 +219,34 @@ dojo.declare(
return;
}

var sidebarLayout = (this.design == "sidebar");
var topHeight = 0, bottomHeight = 0, leftWidth = 0, rightWidth = 0;
var topStyle = {}, leftStyle = {}, rightStyle = {}, bottomStyle = {},
centerStyle = (this._center && this._center.style) || {};

var changedSide = /left|right/.test(changedRegion);

var layoutSides = !changedRegion || (!changedSide && !sidebarLayout);
var layoutTopBottom = !changedRegion || (changedSide && sidebarLayout);

// Ask browser for width/height of side panes.
// Would be nice to cache this but height can change according to width
// (because words wrap around). I don't think width will ever change though
// (except when the user drags a splitter).
if(this._top){
topStyle = (changedRegion == "top" || layoutTopBottom) && this._top.style;
topHeight = changedRegion == "top" ? changedRegionSize : dojo._getMarginSize(this._top).h;
}
if(this._left){
leftStyle = (changedRegion == "left" || layoutSides) && this._left.style;
leftWidth = changedRegion == "left" ? changedRegionSize : dojo._getMarginSize(this._left).w;
}
if(this._right){
rightStyle = (changedRegion == "right" || layoutSides) && this._right.style;
rightWidth = changedRegion == "right" ? changedRegionSize : dojo._getMarginSize(this._right).w;
}
if(this._bottom){
bottomStyle = (changedRegion == "bottom" || layoutTopBottom) && this._bottom.style;
bottomHeight = changedRegion == "bottom" ? changedRegionSize : dojo._getMarginSize(this._bottom).h;
}

var splitters = this._splitters;
var topSplitter = splitters.top, bottomSplitter = splitters.bottom,
leftSplitter = splitters.left, rightSplitter = splitters.right;
var splitterThickness = this._splitterThickness;
var topSplitterThickness = splitterThickness.top || 0,
leftSplitterThickness = splitterThickness.left || 0,
rightSplitterThickness = splitterThickness.right || 0,
bottomSplitterThickness = splitterThickness.bottom || 0;

// Check for race condition where CSS hasn't finished loading, so
// the splitter width == the viewport width (#5824)
if(leftSplitterThickness > 50 || rightSplitterThickness > 50){
setTimeout(dojo.hitch(this, function(){
// Results are invalid. Clear them out.
this._splitterThickness = {};

for(var region in this._splitters){
this._computeSplitterThickness(region);
}
this._layoutChildren();
}), 50);
return false;
}

var pe = this.pe;

var splitterBounds = {
left: (sidebarLayout ? leftWidth + leftSplitterThickness: 0) + pe.l + "px",
right: (sidebarLayout ? rightWidth + rightSplitterThickness: 0) + pe.r + "px"
};

if(topSplitter){
dojo.mixin(topSplitter.style, splitterBounds);
topSplitter.style.top = topHeight + pe.t + "px";
}

if(bottomSplitter){
dojo.mixin(bottomSplitter.style, splitterBounds);
bottomSplitter.style.bottom = bottomHeight + pe.b + "px";
}

splitterBounds = {
top: (sidebarLayout ? 0 : topHeight + topSplitterThickness) + pe.t + "px",
bottom: (sidebarLayout ? 0 : bottomHeight + bottomSplitterThickness) + pe.b + "px"
};

if(leftSplitter){
dojo.mixin(leftSplitter.style, splitterBounds);
leftSplitter.style.left = leftWidth + pe.l + "px";
}

if(rightSplitter){
dojo.mixin(rightSplitter.style, splitterBounds);
rightSplitter.style.right = rightWidth + pe.r + "px";
}

dojo.mixin(centerStyle, {
top: pe.t + topHeight + topSplitterThickness + "px",
left: pe.l + leftWidth + leftSplitterThickness + "px",
right: pe.r + rightWidth + rightSplitterThickness + "px",
bottom: pe.b + bottomHeight + bottomSplitterThickness + "px"
});

var bounds = {
top: sidebarLayout ? pe.t + "px" : centerStyle.top,
bottom: sidebarLayout ? pe.b + "px" : centerStyle.bottom
};
dojo.mixin(leftStyle, bounds);
dojo.mixin(rightStyle, bounds);
leftStyle.left = pe.l + "px"; rightStyle.right = pe.r + "px"; topStyle.top = pe.t + "px"; bottomStyle.bottom = pe.b + "px";
if(sidebarLayout){
topStyle.left = bottomStyle.left = leftWidth + leftSplitterThickness + pe.l + "px";
topStyle.right = bottomStyle.right = rightWidth + rightSplitterThickness + pe.r + "px";
}else{
topStyle.left = bottomStyle.left = pe.l + "px";
topStyle.right = bottomStyle.right = pe.r + "px";
}

// More calculations about sizes of panes
var containerHeight = this._borderBox.h - pe.t - pe.b,
middleHeight = containerHeight - ( topHeight + topSplitterThickness + bottomHeight + bottomSplitterThickness),
sidebarHeight = sidebarLayout ? containerHeight : middleHeight;

var containerWidth = this._borderBox.w - pe.l - pe.r,
middleWidth = containerWidth - (leftWidth + leftSplitterThickness + rightWidth + rightSplitterThickness),
sidebarWidth = sidebarLayout ? middleWidth : containerWidth;

// New margin-box size of each pane
// Generate list of my children in the order that I want layoutChildren()
// to process them (i.e. from the outside to the inside)
var splitters = this._splitters,
candidates =
(this.design == "sidebar") ?
[this._leftWidget, splitters.left, this._rightWidget, splitters.right,
this._topWidget, splitters.top, this._bottomWidget, splitters.bottom, this._centerWidget] :
[this._topWidget, splitters.top, this._bottomWidget, splitters.bottom,
this._leftWidget, splitters.left, this._rightWidget, splitters.right, this._centerWidget],
children = dojo.filter(candidates, function(w){ return w; }); // in case there's no left/top/etc. pane

// Compute the box in which to lay out my children
var dim = {
top: { w: sidebarWidth, h: topHeight },
bottom: { w: sidebarWidth, h: bottomHeight },
left: { w: leftWidth, h: sidebarHeight },
right: { w: rightWidth, h: sidebarHeight },
center: { h: middleHeight, w: middleWidth }
l: this.pe.l,
t: this.pe.t,
w: this._borderBox.w - this.pe.w,
h: this._borderBox.h - this.pe.h
};

if(changedRegion){
// Respond to splitter drag event by changing changedRegion's width or height
var child = this["_" + changedRegion + "Widget"],
mb = {};
mb[ /top|bottom/.test(changedRegion) ? "h" : "w"] = changedRegionSize;
child.resize ? child.resize(mb, dim[child.region]) : dojo.marginBox(child.domNode, mb);
}

// Nodes in IE<8 don't respond to t/l/b/r, and TEXTAREA doesn't respond in any browser
var janky = dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.some(this.getChildren(), function(child){
return child.domNode.tagName == "TEXTAREA" || child.domNode.tagName == "INPUT";
});
if(janky){
// Set the size of the children the old fashioned way, by setting
// CSS width and height

var resizeWidget = function(widget, changes, result){
if(widget){
(widget.resize ? widget.resize(changes, result) : dojo.marginBox(widget.domNode, changes));
}
};

if(leftSplitter){ leftSplitter.style.height = sidebarHeight; }
if(rightSplitter){ rightSplitter.style.height = sidebarHeight; }
resizeWidget(this._leftWidget, {h: sidebarHeight}, dim.left);
resizeWidget(this._rightWidget, {h: sidebarHeight}, dim.right);

if(topSplitter){ topSplitter.style.width = sidebarWidth; }
if(bottomSplitter){ bottomSplitter.style.width = sidebarWidth; }
resizeWidget(this._topWidget, {w: sidebarWidth}, dim.top);
resizeWidget(this._bottomWidget, {w: sidebarWidth}, dim.bottom);

resizeWidget(this._centerWidget, dim.center);
}else{
// Calculate which panes need a notification that their size has been changed
// (we've already set style.top/bottom/left/right on those other panes).
var notifySides = !changedRegion || (/top|bottom/.test(changedRegion) && this.design != "sidebar"),
notifyTopBottom = !changedRegion || (/left|right/.test(changedRegion) && this.design == "sidebar"),
notifyList = {
center: true,
left: notifySides,
right: notifySides,
top: notifyTopBottom,
bottom: notifyTopBottom
};

// Send notification to those panes that have changed size
dojo.forEach(this.getChildren(), function(child){
if(child.resize && notifyList[child.region]){
child.resize(null, dim[child.region]);
}
}, this);
}
// Layout the children, possibly changing size due to a splitter drag
dijit.layout.layoutChildren(this.domNode, dim, children,
changedRegion ? this["_"+changedRegion+"Widget"].id : null, changedRegionSize);
},

destroy: function(){
for(var region in this._splitters){
var splitter = this._splitters[region];
dijit.byNode(splitter).destroy();
dojo.destroy(splitter);
splitter.destroy();
}
delete this._splitters;
delete this._splitterThickness;
Expand Down Expand Up @@ -548,7 +388,7 @@ dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
dim = isHorizontal ? 'h' : 'w',
childStart = dojo.marginBox(this.child.domNode)[dim],
region = this.region,
splitterStart = parseInt(this.domNode.style[region], 10),
splitterStart = parseInt(this.domNode.style[region == "top" || region == "bottom" ? "top" : "left"], 10),
resize = this._resize,
childNode = this.child.domNode,
layoutFunc = dojo.hitch(this.container, this.container._layoutChildren),
Expand Down
39 changes: 30 additions & 9 deletions layout/_LayoutWidget.js
Expand Up @@ -210,15 +210,25 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
dojo.mixin(widget, dim);
};

dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
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 like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]
// 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);
Expand All @@ -227,14 +237,14 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){

// 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.
children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
.concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));
// 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.layoutAlign;
pos = (child.region || child.layoutAlign);

// set elem to upper left corner of unused space; may move it later
var elmStyle = elm.style;
Expand All @@ -244,25 +254,36 @@ dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){

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"){
size(child, { w: dim.w });
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"){
size(child, { h: dim.h });
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"){
}else if(pos == "client" || pos == "center"){
size(child, dim);
}
});
Expand Down

0 comments on commit d12334a

Please sign in to comment.