1 define("dijit/layout/_ContentPaneResizeMixin", [
2 "dojo/_base/array", // array.filter array.forEach
3 "dojo/_base/declare", // declare
4 "dojo/dom-attr", // domAttr.has
5 "dojo/dom-class", // domClass.contains domClass.toggle
6 "dojo/dom-geometry",// domGeometry.contentBox domGeometry.marginBox
7 "dojo/_base/lang", // lang.mixin
9 "dojo/_base/sniff", // has("ie")
10 "dojo/_base/window", // win.global
11 "../registry", // registry.byId
12 "./utils", // marginBox2contextBox
14 ], function(array, declare, domAttr, domClass, domGeometry, lang, query, has, win,
15 registry, layoutUtils, _Contained){
18 var _Contained = dijit._Contained;
22 // dijit/layout/_ContentPaneResizeMixin
24 // Resize() functionality of ContentPane. If there's a single layout widget
25 // child then it will call resize() with the same dimensions as the ContentPane.
26 // Otherwise just calls resize on each child.
29 return declare("dijit.layout._ContentPaneResizeMixin", null, {
31 // Resize() functionality of ContentPane. If there's a single layout widget
32 // child then it will call resize() with the same dimensions as the ContentPane.
33 // Otherwise just calls resize on each child.
35 // Also implements basic startup() functionality, where starting the parent
36 // will start the children
39 // - false - don't adjust size of children
40 // - true - if there is a single visible child widget, set it's size to
41 // however big the ContentPane is
44 // isLayoutContainer: [protected] Boolean
45 // Indicates that this widget will call resize() on it's child widgets
46 // when they become visible.
47 isLayoutContainer: true,
51 // See `dijit.layout._LayoutWidget.startup` for description.
52 // Although ContentPane doesn't extend _LayoutWidget, it does implement
55 if(this._started){ return; }
57 var parent = this.getParent();
58 this._childOfLayoutWidget = parent && parent.isLayoutContainer;
60 // I need to call resize() on my child/children (when I become visible), unless
61 // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
62 this._needLayout = !this._childOfLayoutWidget;
64 this.inherited(arguments);
70 if(!this._childOfLayoutWidget){
71 // If my parent isn't a layout container, since my style *may be* width=height=100%
72 // or something similar (either set directly or via a CSS class),
73 // monitor when my size changes so that I can re-layout.
74 // For browsers where I can't directly monitor when my size changes,
75 // monitor when the viewport changes size, which *may* indicate a size change for me.
76 this.connect(has("ie") ? this.domNode : win.global, 'onresize', function(){
77 // Using function(){} closure to ensure no arguments to resize.
78 this._needLayout = !this._childOfLayoutWidget;
84 _checkIfSingleChild: function(){
86 // Test if we have exactly one visible widget as a child,
87 // and if so assume that we are a container for that widget,
88 // and should propagate startup() and resize() calls to it.
89 // Skips over things like data stores since they aren't visible.
91 var childNodes = query("> *", this.containerNode).filter(function(node){
92 return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
94 childWidgetNodes = childNodes.filter(function(node){
95 return domAttr.has(node, "data-dojo-type") || domAttr.has(node, "dojoType") || domAttr.has(node, "widgetId");
97 candidateWidgets = array.filter(childWidgetNodes.map(registry.byNode), function(widget){
98 return widget && widget.domNode && widget.resize;
102 // all child nodes are widgets
103 childNodes.length == childWidgetNodes.length &&
105 // all but one are invisible (like dojo.data)
106 candidateWidgets.length == 1
108 this._singleChild = candidateWidgets[0];
110 delete this._singleChild;
113 // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
114 domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
117 resize: function(changeSize, resultSize){
119 // See `dijit.layout._LayoutWidget.resize` for description.
120 // Although ContentPane doesn't extend _LayoutWidget, it does implement
123 // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
124 // never called, so resize() is our trigger to do the initial href download (see [20099]).
125 // However, don't load href for closed TitlePanes.
126 if(!this._wasShown && this.open !== false){
130 this._resizeCalled = true;
132 this._scheduleLayout(changeSize, resultSize);
135 _scheduleLayout: function(changeSize, resultSize){
137 // Resize myself, and call resize() on each of my child layout widgets, either now
138 // (if I'm currently visible) or when I become visible
140 this._layout(changeSize, resultSize);
142 this._needLayout = true;
143 this._changeSize = changeSize;
144 this._resultSize = resultSize;
148 _layout: function(changeSize, resultSize){
150 // Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
151 // Also, since I am a Container widget, each of my children expects me to
152 // call resize() or layout() on them.
154 // Should be called on initialization and also whenever we get new content
155 // (from an href, or from set('content', ...))... but deferred until
156 // the ContentPane is visible
158 // Set margin box size, unless it wasn't specified, in which case use current size.
160 domGeometry.setMarginBox(this.domNode, changeSize);
163 // Compute content box size of containerNode in case we [later] need to size our single child.
164 var cn = this.containerNode;
165 if(cn === this.domNode){
166 // If changeSize or resultSize was passed to this method and this.containerNode ==
167 // this.domNode then we can compute the content-box size without querying the node,
168 // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
169 var mb = resultSize || {};
170 lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
171 if(!("h" in mb) || !("w" in mb)){
172 mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
174 this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
176 this._contentBox = domGeometry.getContentBox(cn);
179 this._layoutChildren();
181 delete this._needLayout;
184 _layoutChildren: function(){
185 // Call _checkIfSingleChild() again in case app has manually mucked w/the content
186 // of the ContentPane (rather than changing it through the set("content", ...) API.
188 this._checkIfSingleChild();
191 if(this._singleChild && this._singleChild.resize){
192 var cb = this._contentBox || domGeometry.getContentBox(this.containerNode);
194 // note: if widget has padding this._contentBox will have l and t set,
195 // but don't pass them to resize() or it will doubly-offset the child
196 this._singleChild.resize({w: cb.w, h: cb.h});
198 // All my child widgets are independently sized (rather than matching my size),
199 // but I still need to call resize() on each child to make it layout.
200 array.forEach(this.getChildren(), function(widget){
208 _isShown: function(){
210 // Returns true if the content is currently shown.
212 // If I am a child of a layout widget then it actually returns true if I've ever been visible,
213 // not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
214 // tree every call, and at least solves the performance problem on page load by deferring loading
215 // hidden ContentPanes until they are first shown
217 if(this._childOfLayoutWidget){
218 // If we are TitlePane, etc - we return that only *IF* we've been resized
219 if(this._resizeCalled && "open" in this){
222 return this._resizeCalled;
223 }else if("open" in this){
224 return this.open; // for TitlePane, etc.
226 var node = this.domNode, parent = this.domNode.parentNode;
227 return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
228 parent && parent.style && (parent.style.display != 'none');
234 // Called when the ContentPane is made visible
236 // For a plain ContentPane, this is called on initialization, from startup().
237 // If the ContentPane is a hidden pane of a TabContainer etc., then it's
238 // called whenever the pane is made visible.
240 // Does layout/resize of child widget(s)
242 if(this._needLayout){
243 // If a layout has been scheduled for when we become visible, do it now
244 this._layout(this._changeSize, this._resultSize);
247 this.inherited(arguments);
249 // Need to keep track of whether ContentPane has been shown (which is different than
250 // whether or not it's currently visible).
251 this._wasShown = true;