You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
8.5 KiB
236 lines
8.5 KiB
define([ |
|
"dojo/_base/array", // array.filter array.forEach |
|
"dojo/_base/declare", // declare |
|
"dojo/dom-class", // domClass.contains domClass.toggle |
|
"dojo/dom-geometry", // domGeometry.contentBox domGeometry.marginBox |
|
"dojo/dom-style", |
|
"dojo/_base/lang", // lang.mixin |
|
"dojo/query", // query |
|
"../registry", // registry.byId |
|
"../Viewport", |
|
"./utils" // marginBox2contextBox |
|
], function(array, declare, domClass, domGeometry, domStyle, lang, query, |
|
registry, Viewport, layoutUtils){ |
|
|
|
// module: |
|
// dijit/layout/_ContentPaneResizeMixin |
|
|
|
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){ |
|
// 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 viewport size changes so that I can re-layout. |
|
// This is more for subclasses of ContentPane than ContentPane itself, although it |
|
// could be useful for a ContentPane if it has a single child widget inheriting ContentPane's size. |
|
this.own(Viewport.on("resize", lang.hitch(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. |
|
|
|
if(!this.doLayout){ return; } |
|
|
|
var candidateWidgets = [], |
|
otherVisibleNodes = false; |
|
|
|
query("> *", this.containerNode).some(function(node){ |
|
var widget = registry.byNode(node); |
|
if(widget && widget.resize){ |
|
candidateWidgets.push(widget); |
|
}else if(!/script|link|style/i.test(node.nodeName) && node.offsetHeight){ |
|
otherVisibleNodes = true; |
|
} |
|
}); |
|
|
|
this._singleChild = candidateWidgets.length == 1 && !otherVisibleNodes ? |
|
candidateWidgets[0] : null; |
|
|
|
// 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. |
|
|
|
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 an isLayoutContainer widget, each of my children expects me to |
|
// call resize() or layout() on it. |
|
// |
|
// 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 |
|
|
|
delete this._needLayout; |
|
|
|
// For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is |
|
// never called directly, 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(); |
|
} |
|
|
|
// 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(); |
|
}, |
|
|
|
_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. |
|
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. |
|
var children = this.getChildren(), |
|
widget, |
|
i = 0; |
|
while(widget = children[i++]){ |
|
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) |
|
|
|
// Need to keep track of whether ContentPane has been shown (which is different than |
|
// whether or not it's currently visible). |
|
this._wasShown = true; |
|
|
|
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); |
|
} |
|
}); |
|
});
|
|
|