630 lines
22 KiB
JavaScript
630 lines
22 KiB
JavaScript
|
dojo.provide("dijit.layout.BorderContainer");
|
||
|
|
||
|
dojo.require("dijit.layout._LayoutWidget");
|
||
|
dojo.require("dojo.cookie");
|
||
|
|
||
|
dojo.declare(
|
||
|
"dijit.layout.BorderContainer",
|
||
|
dijit.layout._LayoutWidget,
|
||
|
{
|
||
|
// summary:
|
||
|
// Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
|
||
|
//
|
||
|
// description:
|
||
|
// A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
|
||
|
// that contains a child widget marked region="center" and optionally children widgets marked
|
||
|
// region equal to "top", "bottom", "leading", "trailing", "left" or "right".
|
||
|
// Children along the edges will be laid out according to width or height dimensions and may
|
||
|
// include optional splitters (splitter="true") to make them resizable by the user. The remaining
|
||
|
// space is designated for the center region.
|
||
|
//
|
||
|
// NOTE: Splitters must not be more than 50 pixels in width.
|
||
|
//
|
||
|
// The outer size must be specified on the BorderContainer node. Width must be specified for the sides
|
||
|
// and height for the top and bottom, respectively. No dimensions should be specified on the center;
|
||
|
// it will fill the remaining space. Regions named "leading" and "trailing" may be used just like
|
||
|
// "left" and "right" except that they will be reversed in right-to-left environments.
|
||
|
//
|
||
|
// example:
|
||
|
// | <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
|
||
|
// | style="width: 400px; height: 300px;">
|
||
|
// | <div dojoType="ContentPane" region="top">header text</div>
|
||
|
// | <div dojoType="ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
|
||
|
// | <div dojoType="ContentPane" region="center">client area</div>
|
||
|
// | </div>
|
||
|
|
||
|
// design: String
|
||
|
// Which design is used for the layout:
|
||
|
// - "headline" (default) where the top and bottom extend
|
||
|
// the full width of the container
|
||
|
// - "sidebar" where the left and right sides extend from top to bottom.
|
||
|
design: "headline",
|
||
|
|
||
|
// gutters: Boolean
|
||
|
// Give each pane a border and margin.
|
||
|
// Margin determined by domNode.paddingLeft.
|
||
|
// When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
|
||
|
gutters: true,
|
||
|
|
||
|
// liveSplitters: Boolean
|
||
|
// Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
|
||
|
liveSplitters: true,
|
||
|
|
||
|
// persist: Boolean
|
||
|
// Save splitter positions in a cookie.
|
||
|
persist: false,
|
||
|
|
||
|
baseClass: "dijitBorderContainer",
|
||
|
|
||
|
// _splitterClass: String
|
||
|
// Optional hook to override the default Splitter widget used by BorderContainer
|
||
|
_splitterClass: "dijit.layout._Splitter",
|
||
|
|
||
|
postMixInProperties: function(){
|
||
|
// change class name to indicate that BorderContainer is being used purely for
|
||
|
// layout (like LayoutContainer) rather than for pretty formatting.
|
||
|
if(!this.gutters){
|
||
|
this.baseClass += "NoGutter";
|
||
|
}
|
||
|
this.inherited(arguments);
|
||
|
},
|
||
|
|
||
|
postCreate: function(){
|
||
|
this.inherited(arguments);
|
||
|
|
||
|
this._splitters = {};
|
||
|
this._splitterThickness = {};
|
||
|
},
|
||
|
|
||
|
startup: function(){
|
||
|
if(this._started){ return; }
|
||
|
dojo.forEach(this.getChildren(), this._setupChild, this);
|
||
|
this.inherited(arguments);
|
||
|
},
|
||
|
|
||
|
_setupChild: function(/*Widget*/child){
|
||
|
// Override _LayoutWidget._setupChild().
|
||
|
|
||
|
var region = child.region;
|
||
|
if(region){
|
||
|
this.inherited(arguments);
|
||
|
|
||
|
dojo.addClass(child.domNode, this.baseClass+"Pane");
|
||
|
|
||
|
var ltr = this.isLeftToRight();
|
||
|
if(region == "leading"){ region = ltr ? "left" : "right"; }
|
||
|
if(region == "trailing"){ region = ltr ? "right" : "left"; }
|
||
|
|
||
|
//FIXME: redundant?
|
||
|
this["_"+region] = child.domNode;
|
||
|
this["_"+region+"Widget"] = child;
|
||
|
|
||
|
// Create draggable splitter for resizing pane,
|
||
|
// or alternately if splitter=false but BorderContainer.gutters=true then
|
||
|
// insert dummy div just for spacing
|
||
|
if((child.splitter || this.gutters) && !this._splitters[region]){
|
||
|
var _Splitter = dojo.getObject(child.splitter ? this._splitterClass : "dijit.layout._Gutter");
|
||
|
var flip = {left:'right', right:'left', top:'bottom', bottom:'top', leading:'trailing', trailing:'leading'};
|
||
|
var splitter = new _Splitter({
|
||
|
container: this,
|
||
|
child: child,
|
||
|
region: region,
|
||
|
// oppNode: dojo.query('[region=' + flip[child.region] + ']', this.domNode)[0],
|
||
|
oppNode: this["_" + flip[child.region]],
|
||
|
live: this.liveSplitters
|
||
|
});
|
||
|
splitter.isSplitter = true;
|
||
|
this._splitters[region] = splitter.domNode;
|
||
|
dojo.place(this._splitters[region], child.domNode, "after");
|
||
|
|
||
|
// Splitters arent added as Contained children, so we need to call startup explicitly
|
||
|
splitter.startup();
|
||
|
}
|
||
|
child.region = region;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_computeSplitterThickness: function(region){
|
||
|
this._splitterThickness[region] = this._splitterThickness[region] ||
|
||
|
dojo.marginBox(this._splitters[region])[(/top|bottom/.test(region) ? 'h' : 'w')];
|
||
|
},
|
||
|
|
||
|
layout: function(){
|
||
|
// Implement _LayoutWidget.layout() virtual method.
|
||
|
for(var region in this._splitters){ this._computeSplitterThickness(region); }
|
||
|
this._layoutChildren();
|
||
|
},
|
||
|
|
||
|
addChild: function(/*Widget*/ child, /*Integer?*/ insertIndex){
|
||
|
// Override _LayoutWidget.addChild().
|
||
|
this.inherited(arguments);
|
||
|
if(this._started){
|
||
|
this._layoutChildren(); //OPT
|
||
|
}
|
||
|
},
|
||
|
|
||
|
removeChild: function(/*Widget*/ child){
|
||
|
// Override _LayoutWidget.removeChild().
|
||
|
var region = child.region;
|
||
|
var splitter = this._splitters[region];
|
||
|
if(splitter){
|
||
|
dijit.byNode(splitter).destroy();
|
||
|
delete this._splitters[region];
|
||
|
delete this._splitterThickness[region];
|
||
|
}
|
||
|
this.inherited(arguments);
|
||
|
delete this["_"+region];
|
||
|
delete this["_" +region+"Widget"];
|
||
|
if(this._started){
|
||
|
this._layoutChildren(child.region);
|
||
|
}
|
||
|
dojo.removeClass(child.domNode, this.baseClass+"Pane");
|
||
|
},
|
||
|
|
||
|
getChildren: function(){
|
||
|
// Override _LayoutWidget.getChildren() to only return real children, not the splitters.
|
||
|
return dojo.filter(this.inherited(arguments), function(widget){
|
||
|
return !widget.isSplitter;
|
||
|
});
|
||
|
},
|
||
|
|
||
|
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;
|
||
|
},
|
||
|
|
||
|
resize: function(newSize, currentSize){
|
||
|
// Overrides _LayoutWidget.resize().
|
||
|
|
||
|
// resetting potential padding to 0px to provide support for 100% width/height + padding
|
||
|
// TODO: this hack doesn't respect the box model and is a temporary fix
|
||
|
if (!this.cs || !this.pe){
|
||
|
var node = this.domNode;
|
||
|
this.cs = dojo.getComputedStyle(node);
|
||
|
this.pe = dojo._getPadExtents(node, this.cs);
|
||
|
this.pe.r = dojo._toPixelValue(node, this.cs.paddingRight);
|
||
|
this.pe.b = dojo._toPixelValue(node, this.cs.paddingBottom);
|
||
|
|
||
|
dojo.style(node, "padding", "0px");
|
||
|
}
|
||
|
|
||
|
this.inherited(arguments);
|
||
|
},
|
||
|
|
||
|
_layoutChildren: function(/*String?*/changedRegion){
|
||
|
// summary:
|
||
|
// This is the main routine for setting size/position of each child
|
||
|
|
||
|
if(!this._borderBox || !this._borderBox.h){
|
||
|
// We are currently hidden, or we haven't been sized by our parent yet.
|
||
|
// Abort. Someone will resize us later.
|
||
|
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 = layoutTopBottom && this._top.style;
|
||
|
topHeight = dojo.marginBox(this._top).h;
|
||
|
}
|
||
|
if(this._left){
|
||
|
leftStyle = layoutSides && this._left.style;
|
||
|
leftWidth = dojo.marginBox(this._left).w;
|
||
|
}
|
||
|
if(this._right){
|
||
|
rightStyle = layoutSides && this._right.style;
|
||
|
rightWidth = dojo.marginBox(this._right).w;
|
||
|
}
|
||
|
if(this._bottom){
|
||
|
bottomStyle = layoutTopBottom && this._bottom.style;
|
||
|
bottomHeight = dojo.marginBox(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
|
||
|
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 }
|
||
|
};
|
||
|
|
||
|
// 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{
|
||
|
// We've already sized the children by setting style.top/bottom/left/right...
|
||
|
// Now just need to call resize() on those children telling them their new size,
|
||
|
// so they can re-layout themselves
|
||
|
|
||
|
// Calculate which panes need a notification
|
||
|
var resizeList = {};
|
||
|
if(changedRegion){
|
||
|
resizeList[changedRegion] = resizeList.center = true;
|
||
|
if(/top|bottom/.test(changedRegion) && this.design != "sidebar"){
|
||
|
resizeList.left = resizeList.right = true;
|
||
|
}else if(/left|right/.test(changedRegion) && this.design == "sidebar"){
|
||
|
resizeList.top = resizeList.bottom = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dojo.forEach(this.getChildren(), function(child){
|
||
|
if(child.resize && (!changedRegion || child.region in resizeList)){
|
||
|
child.resize(null, dim[child.region]);
|
||
|
}
|
||
|
}, this);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
destroy: function(){
|
||
|
for(var region in this._splitters){
|
||
|
var splitter = this._splitters[region];
|
||
|
dijit.byNode(splitter).destroy();
|
||
|
dojo.destroy(splitter);
|
||
|
}
|
||
|
delete this._splitters;
|
||
|
delete this._splitterThickness;
|
||
|
this.inherited(arguments);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// This argument can be specified for the children of a BorderContainer.
|
||
|
// Since any widget can be specified as a LayoutContainer child, mix it
|
||
|
// into the base widget class. (This is a hack, but it's effective.)
|
||
|
dojo.extend(dijit._Widget, {
|
||
|
// region: String
|
||
|
// "top", "bottom", "leading", "trailing", "left", "right", "center".
|
||
|
// See the BorderContainer description for details on this parameter.
|
||
|
region: '',
|
||
|
|
||
|
// splitter: Boolean
|
||
|
// If true, puts a draggable splitter on this widget to resize when used
|
||
|
// inside a border container edge region.
|
||
|
splitter: false,
|
||
|
|
||
|
// minSize: Number
|
||
|
// Specifies a minimum size for this widget when resized by a splitter
|
||
|
minSize: 0,
|
||
|
|
||
|
// maxSize: Number
|
||
|
// Specifies a maximum size for this widget when resized by a splitter
|
||
|
maxSize: Infinity
|
||
|
});
|
||
|
|
||
|
dojo.require("dijit._Templated");
|
||
|
|
||
|
dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
|
||
|
{
|
||
|
// summary:
|
||
|
// A draggable spacer between two items in a `dijit.layout.BorderContainer`.
|
||
|
// description:
|
||
|
// This is instantiated by `dijit.layout.BorderContainer`. Users should not
|
||
|
// create it directly.
|
||
|
// tags:
|
||
|
// private
|
||
|
|
||
|
/*=====
|
||
|
// container: [const] dijit.layout.BorderContainer
|
||
|
// Pointer to the parent BorderContainer
|
||
|
container: null,
|
||
|
|
||
|
// child: [const] dijit.layout._LayoutWidget
|
||
|
// Pointer to the pane associated with this splitter
|
||
|
child: null,
|
||
|
|
||
|
// region: String
|
||
|
// Region of pane associated with this splitter.
|
||
|
// "top", "bottom", "left", "right".
|
||
|
region: null,
|
||
|
=====*/
|
||
|
|
||
|
// live: [const] Boolean
|
||
|
// If true, the child's size changes and the child widget is redrawn as you drag the splitter;
|
||
|
// otherwise, the size doesn't change until you drop the splitter (by mouse-up)
|
||
|
live: true,
|
||
|
|
||
|
templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag" tabIndex="0" waiRole="separator"><div class="dijitSplitterThumb"></div></div>',
|
||
|
|
||
|
postCreate: function(){
|
||
|
this.inherited(arguments);
|
||
|
this.horizontal = /top|bottom/.test(this.region);
|
||
|
dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
|
||
|
// dojo.addClass(this.child.domNode, "dijitSplitterPane");
|
||
|
// dojo.setSelectable(this.domNode, false); //TODO is this necessary?
|
||
|
|
||
|
this._factor = /top|left/.test(this.region) ? 1 : -1;
|
||
|
this._minSize = this.child.minSize;
|
||
|
|
||
|
// trigger constraints calculations
|
||
|
this.child.domNode._recalc = true;
|
||
|
this.connect(this.container, "resize", function(){ this.child.domNode._recalc = true; });
|
||
|
|
||
|
this._cookieName = this.container.id + "_" + this.region;
|
||
|
if(this.container.persist){
|
||
|
// restore old size
|
||
|
var persistSize = dojo.cookie(this._cookieName);
|
||
|
if(persistSize){
|
||
|
this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_computeMaxSize: function(){
|
||
|
var dim = this.horizontal ? 'h' : 'w',
|
||
|
thickness = this.container._splitterThickness[this.region];
|
||
|
var available = dojo.contentBox(this.container.domNode)[dim] -
|
||
|
(this.oppNode ? dojo.marginBox(this.oppNode)[dim] : 0) -
|
||
|
20 - thickness * 2;
|
||
|
this._maxSize = Math.min(this.child.maxSize, available);
|
||
|
},
|
||
|
|
||
|
_startDrag: function(e){
|
||
|
if(this.child.domNode._recalc){
|
||
|
this._computeMaxSize();
|
||
|
this.child.domNode._recalc = false;
|
||
|
}
|
||
|
|
||
|
if(!this.cover){
|
||
|
this.cover = dojo.doc.createElement('div');
|
||
|
dojo.addClass(this.cover, "dijitSplitterCover");
|
||
|
dojo.place(this.cover, this.child.domNode, "after");
|
||
|
}
|
||
|
dojo.addClass(this.cover, "dijitSplitterCoverActive");
|
||
|
|
||
|
// Safeguard in case the stop event was missed. Shouldn't be necessary if we always get the mouse up.
|
||
|
if(this.fake){ dojo.destroy(this.fake); }
|
||
|
if(!(this._resize = this.live)){ //TODO: disable live for IE6?
|
||
|
// create fake splitter to display at old position while we drag
|
||
|
(this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
|
||
|
dojo.addClass(this.domNode, "dijitSplitterShadow");
|
||
|
dojo.place(this.fake, this.domNode, "after");
|
||
|
}
|
||
|
dojo.addClass(this.domNode, "dijitSplitterActive");
|
||
|
|
||
|
//Performance: load data info local vars for onmousevent function closure
|
||
|
var factor = this._factor,
|
||
|
max = this._maxSize,
|
||
|
min = this._minSize || 20,
|
||
|
isHorizontal = this.horizontal,
|
||
|
axis = isHorizontal ? "pageY" : "pageX",
|
||
|
pageStart = e[axis],
|
||
|
splitterStyle = this.domNode.style,
|
||
|
dim = isHorizontal ? 'h' : 'w',
|
||
|
childStart = dojo.marginBox(this.child.domNode)[dim],
|
||
|
region = this.region,
|
||
|
splitterStart = parseInt(this.domNode.style[region], 10),
|
||
|
resize = this._resize,
|
||
|
mb = {},
|
||
|
childNode = this.child.domNode,
|
||
|
layoutFunc = dojo.hitch(this.container, this.container._layoutChildren),
|
||
|
de = dojo.doc.body;
|
||
|
|
||
|
this._handlers = (this._handlers || []).concat([
|
||
|
dojo.connect(de, "onmousemove", this._drag = function(e, forceResize){
|
||
|
var delta = e[axis] - pageStart,
|
||
|
childSize = factor * delta + childStart,
|
||
|
boundChildSize = Math.max(Math.min(childSize, max), min);
|
||
|
|
||
|
if(resize || forceResize){
|
||
|
mb[dim] = boundChildSize;
|
||
|
// TODO: inefficient; we set the marginBox here and then immediately layoutFunc() needs to query it
|
||
|
dojo.marginBox(childNode, mb);
|
||
|
layoutFunc(region);
|
||
|
}
|
||
|
splitterStyle[region] = factor * delta + splitterStart + (boundChildSize - childSize) + "px";
|
||
|
}),
|
||
|
dojo.connect(dojo.doc, "ondragstart", dojo.stopEvent),
|
||
|
dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent),
|
||
|
dojo.connect(de, "onmouseup", this, "_stopDrag")
|
||
|
]);
|
||
|
dojo.stopEvent(e);
|
||
|
},
|
||
|
|
||
|
_stopDrag: function(e){
|
||
|
try{
|
||
|
if(this.cover){
|
||
|
dojo.removeClass(this.cover, "dijitSplitterCoverActive");
|
||
|
}
|
||
|
if(this.fake){ dojo.destroy(this.fake); }
|
||
|
dojo.removeClass(this.domNode, "dijitSplitterActive");
|
||
|
dojo.removeClass(this.domNode, "dijitSplitterShadow");
|
||
|
this._drag(e); //TODO: redundant with onmousemove?
|
||
|
this._drag(e, true);
|
||
|
}finally{
|
||
|
this._cleanupHandlers();
|
||
|
if(this.oppNode){ this.oppNode._recalc = true; }
|
||
|
delete this._drag;
|
||
|
}
|
||
|
|
||
|
if(this.container.persist){
|
||
|
dojo.cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_cleanupHandlers: function(){
|
||
|
dojo.forEach(this._handlers, dojo.disconnect);
|
||
|
delete this._handlers;
|
||
|
},
|
||
|
|
||
|
_onKeyPress: function(/*Event*/ e){
|
||
|
if(this.child.domNode._recalc){
|
||
|
this._computeMaxSize();
|
||
|
this.child.domNode._recalc = false;
|
||
|
}
|
||
|
|
||
|
// should we apply typematic to this?
|
||
|
this._resize = true;
|
||
|
var horizontal = this.horizontal;
|
||
|
var tick = 1;
|
||
|
var dk = dojo.keys;
|
||
|
switch(e.charOrCode){
|
||
|
case horizontal ? dk.UP_ARROW : dk.LEFT_ARROW:
|
||
|
tick *= -1;
|
||
|
// break;
|
||
|
case horizontal ? dk.DOWN_ARROW : dk.RIGHT_ARROW:
|
||
|
break;
|
||
|
default:
|
||
|
// this.inherited(arguments);
|
||
|
return;
|
||
|
}
|
||
|
var childSize = dojo.marginBox(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
|
||
|
var mb = {};
|
||
|
mb[ this.horizontal ? "h" : "w"] = Math.max(Math.min(childSize, this._maxSize), this._minSize);
|
||
|
dojo.marginBox(this.child.domNode, mb);
|
||
|
if(this.oppNode){ this.oppNode._recalc = true; }
|
||
|
this.container._layoutChildren(this.region);
|
||
|
dojo.stopEvent(e);
|
||
|
},
|
||
|
|
||
|
destroy: function(){
|
||
|
this._cleanupHandlers();
|
||
|
delete this.child;
|
||
|
delete this.container;
|
||
|
delete this.cover;
|
||
|
delete this.fake;
|
||
|
this.inherited(arguments);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated ],
|
||
|
{
|
||
|
// summary:
|
||
|
// Just a spacer div to separate side pane from center pane.
|
||
|
// Basically a trick to lookup the gutter/splitter width from the theme.
|
||
|
// description:
|
||
|
// Instantiated by `dijit.layout.BorderContainer`. Users should not
|
||
|
// create directly.
|
||
|
// tags:
|
||
|
// private
|
||
|
|
||
|
templateString: '<div class="dijitGutter" waiRole="presentation"></div>',
|
||
|
|
||
|
postCreate: function(){
|
||
|
this.horizontal = /top|bottom/.test(this.region);
|
||
|
dojo.addClass(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
|
||
|
}
|
||
|
});
|