257 lines
9.2 KiB
JavaScript
257 lines
9.2 KiB
JavaScript
//>>built
|
|
define("dijit/layout/_ContentPaneResizeMixin", [
|
|
"dojo/_base/array", // array.filter array.forEach
|
|
"dojo/_base/declare", // declare
|
|
"dojo/dom-attr", // domAttr.has
|
|
"dojo/dom-class", // domClass.contains domClass.toggle
|
|
"dojo/dom-geometry",// domGeometry.contentBox domGeometry.marginBox
|
|
"dojo/_base/lang", // lang.mixin
|
|
"dojo/query", // query
|
|
"dojo/_base/sniff", // has("ie")
|
|
"dojo/_base/window", // win.global
|
|
"../registry", // registry.byId
|
|
"./utils", // marginBox2contextBox
|
|
"../_Contained"
|
|
], function(array, declare, domAttr, domClass, domGeometry, lang, query, has, win,
|
|
registry, layoutUtils, _Contained){
|
|
|
|
/*=====
|
|
var _Contained = dijit._Contained;
|
|
=====*/
|
|
|
|
// module:
|
|
// dijit/layout/_ContentPaneResizeMixin
|
|
// summary:
|
|
// Resize() functionality of ContentPane. If there's a single layout widget
|
|
// child then it will call resize() with the same dimensions as the ContentPane.
|
|
// Otherwise just calls resize on each child.
|
|
|
|
|
|
return declare("dijit.layout._ContentPaneResizeMixin", null, {
|
|
// summary:
|
|
// Resize() functionality of ContentPane. If there's a single layout widget
|
|
// child then it will call resize() with the same dimensions as the ContentPane.
|
|
// Otherwise just calls resize on each child.
|
|
//
|
|
// Also implements basic startup() functionality, where starting the parent
|
|
// will start the children
|
|
|
|
// doLayout: Boolean
|
|
// - false - don't adjust size of children
|
|
// - true - if there is a single visible child widget, set it's size to
|
|
// however big the ContentPane is
|
|
doLayout: true,
|
|
|
|
// isLayoutContainer: [protected] Boolean
|
|
// Indicates that this widget will call resize() on it's child widgets
|
|
// when they become visible.
|
|
isLayoutContainer: true,
|
|
|
|
startup: function(){
|
|
// summary:
|
|
// See `dijit.layout._LayoutWidget.startup` for description.
|
|
// Although ContentPane doesn't extend _LayoutWidget, it does implement
|
|
// the same API.
|
|
|
|
if(this._started){ return; }
|
|
|
|
var parent = this.getParent();
|
|
this._childOfLayoutWidget = parent && parent.isLayoutContainer;
|
|
|
|
// I need to call resize() on my child/children (when I become visible), unless
|
|
// I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
|
|
this._needLayout = !this._childOfLayoutWidget;
|
|
|
|
this.inherited(arguments);
|
|
|
|
if(this._isShown()){
|
|
this._onShow();
|
|
}
|
|
|
|
if(!this._childOfLayoutWidget){
|
|
// If my parent isn't a layout container, since 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(has("ie") ? this.domNode : win.global, 'onresize', function(){
|
|
// Using function(){} closure to ensure no arguments to resize.
|
|
this._needLayout = !this._childOfLayoutWidget;
|
|
this.resize();
|
|
});
|
|
}
|
|
},
|
|
|
|
_checkIfSingleChild: function(){
|
|
// summary:
|
|
// Test if we have exactly one visible widget as a child,
|
|
// and if so assume that we are a container for that widget,
|
|
// and should propagate startup() and resize() calls to it.
|
|
// Skips over things like data stores since they aren't visible.
|
|
|
|
var childNodes = query("> *", this.containerNode).filter(function(node){
|
|
return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
|
|
}),
|
|
childWidgetNodes = childNodes.filter(function(node){
|
|
return domAttr.has(node, "data-dojo-type") || domAttr.has(node, "dojoType") || domAttr.has(node, "widgetId");
|
|
}),
|
|
candidateWidgets = array.filter(childWidgetNodes.map(registry.byNode), function(widget){
|
|
return widget && widget.domNode && widget.resize;
|
|
});
|
|
|
|
if(
|
|
// all child nodes are widgets
|
|
childNodes.length == childWidgetNodes.length &&
|
|
|
|
// all but one are invisible (like dojo.data)
|
|
candidateWidgets.length == 1
|
|
){
|
|
this._singleChild = candidateWidgets[0];
|
|
}else{
|
|
delete this._singleChild;
|
|
}
|
|
|
|
// So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
|
|
domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
|
|
},
|
|
|
|
resize: function(changeSize, resultSize){
|
|
// summary:
|
|
// See `dijit.layout._LayoutWidget.resize` for description.
|
|
// Although ContentPane doesn't extend _LayoutWidget, it does implement
|
|
// the same API.
|
|
|
|
// For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
|
|
// never called, so resize() is our trigger to do the initial href download (see [20099]).
|
|
// However, don't load href for closed TitlePanes.
|
|
if(!this._wasShown && this.open !== false){
|
|
this._onShow();
|
|
}
|
|
|
|
this._resizeCalled = true;
|
|
|
|
this._scheduleLayout(changeSize, resultSize);
|
|
},
|
|
|
|
_scheduleLayout: function(changeSize, resultSize){
|
|
// summary:
|
|
// Resize myself, and call resize() on each of my child layout widgets, either now
|
|
// (if I'm currently visible) or when I become visible
|
|
if(this._isShown()){
|
|
this._layout(changeSize, resultSize);
|
|
}else{
|
|
this._needLayout = true;
|
|
this._changeSize = changeSize;
|
|
this._resultSize = resultSize;
|
|
}
|
|
},
|
|
|
|
_layout: function(changeSize, resultSize){
|
|
// summary:
|
|
// Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
|
|
// Also, since I am a Container widget, each of my children expects me to
|
|
// call resize() or layout() on them.
|
|
//
|
|
// Should be called on initialization and also whenever we get new content
|
|
// (from an href, or from set('content', ...))... but deferred until
|
|
// the ContentPane is visible
|
|
|
|
// Set margin box size, unless it wasn't specified, in which case use current size.
|
|
if(changeSize){
|
|
domGeometry.setMarginBox(this.domNode, changeSize);
|
|
}
|
|
|
|
// Compute content box size of containerNode in case we [later] need to size our single child.
|
|
var cn = this.containerNode;
|
|
if(cn === this.domNode){
|
|
// If changeSize or resultSize was passed to this method and this.containerNode ==
|
|
// this.domNode then we can compute the content-box size without querying the node,
|
|
// which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
|
|
var mb = resultSize || {};
|
|
lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
|
|
if(!("h" in mb) || !("w" in mb)){
|
|
mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
|
|
}
|
|
this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
|
|
}else{
|
|
this._contentBox = domGeometry.getContentBox(cn);
|
|
}
|
|
|
|
this._layoutChildren();
|
|
|
|
delete this._needLayout;
|
|
},
|
|
|
|
_layoutChildren: function(){
|
|
// Call _checkIfSingleChild() again in case app has manually mucked w/the content
|
|
// of the ContentPane (rather than changing it through the set("content", ...) API.
|
|
if(this.doLayout){
|
|
this._checkIfSingleChild();
|
|
}
|
|
|
|
if(this._singleChild && this._singleChild.resize){
|
|
var cb = this._contentBox || domGeometry.getContentBox(this.containerNode);
|
|
|
|
// note: if widget has padding this._contentBox will have l and t set,
|
|
// but don't pass them to resize() or it will doubly-offset the child
|
|
this._singleChild.resize({w: cb.w, h: cb.h});
|
|
}else{
|
|
// All my child widgets are independently sized (rather than matching my size),
|
|
// but I still need to call resize() on each child to make it layout.
|
|
array.forEach(this.getChildren(), function(widget){
|
|
if(widget.resize){
|
|
widget.resize();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
_isShown: function(){
|
|
// summary:
|
|
// Returns true if the content is currently shown.
|
|
// description:
|
|
// If I am a child of a layout widget then it actually returns true if I've ever been visible,
|
|
// not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
|
|
// tree every call, and at least solves the performance problem on page load by deferring loading
|
|
// hidden ContentPanes until they are first shown
|
|
|
|
if(this._childOfLayoutWidget){
|
|
// If we are TitlePane, etc - we return that only *IF* we've been resized
|
|
if(this._resizeCalled && "open" in this){
|
|
return this.open;
|
|
}
|
|
return this._resizeCalled;
|
|
}else if("open" in this){
|
|
return this.open; // for TitlePane, etc.
|
|
}else{
|
|
var node = this.domNode, parent = this.domNode.parentNode;
|
|
return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
|
|
parent && parent.style && (parent.style.display != 'none');
|
|
}
|
|
},
|
|
|
|
_onShow: function(){
|
|
// summary:
|
|
// Called when the ContentPane is made visible
|
|
// description:
|
|
// For a plain ContentPane, this is called on initialization, from startup().
|
|
// If the ContentPane is a hidden pane of a TabContainer etc., then it's
|
|
// called whenever the pane is made visible.
|
|
//
|
|
// Does layout/resize of child widget(s)
|
|
|
|
if(this._needLayout){
|
|
// If a layout has been scheduled for when we become visible, do it now
|
|
this._layout(this._changeSize, this._resultSize);
|
|
}
|
|
|
|
this.inherited(arguments);
|
|
|
|
// Need to keep track of whether ContentPane has been shown (which is different than
|
|
// whether or not it's currently visible).
|
|
this._wasShown = true;
|
|
}
|
|
});
|
|
|
|
});
|