webui-aria2/js/libs/dijit/layout/_ContentPaneResizeMixin.js.uncompressed.js
2012-05-01 19:52:07 +08:00

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;
}
});
});