source: Dev/trunk/src/client/dijit/layout/_ContentPaneResizeMixin.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 8.6 KB
Line 
1define([
2        "dojo/_base/array", // array.filter array.forEach
3        "dojo/_base/declare", // declare
4        "dojo/dom-class", // domClass.contains domClass.toggle
5        "dojo/dom-geometry", // domGeometry.contentBox domGeometry.marginBox
6        "dojo/dom-style",
7        "dojo/_base/lang", // lang.mixin
8        "dojo/query", // query
9        "dojo/sniff", // has("ie")
10        "../registry", // registry.byId
11        "../Viewport",
12        "./utils" // marginBox2contextBox
13], function(array, declare, domClass, domGeometry, domStyle, lang, query, has,
14                        registry, Viewport, layoutUtils){
15
16        // module:
17        //              dijit/layout/_ContentPaneResizeMixin
18
19        return declare("dijit.layout._ContentPaneResizeMixin", null, {
20                // summary:
21                //              Resize() functionality of ContentPane.   If there's a single layout widget
22                //              child then it will call resize() with the same dimensions as the ContentPane.
23                //              Otherwise just calls resize on each child.
24                //
25                //              Also implements basic startup() functionality, where starting the parent
26                //              will start the children
27
28                // doLayout: Boolean
29                //              - false - don't adjust size of children
30                //              - true - if there is a single visible child widget, set it's size to however big the ContentPane is
31                doLayout: true,
32
33                // isLayoutContainer: [protected] Boolean
34                //              Indicates that this widget will call resize() on it's child widgets
35                //              when they become visible.
36                isLayoutContainer: true,
37
38                startup: function(){
39                        // summary:
40                        //              See `dijit/layout/_LayoutWidget.startup()` for description.
41                        //              Although ContentPane doesn't extend _LayoutWidget, it does implement
42                        //              the same API.
43
44                        if(this._started){
45                                return;
46                        }
47
48                        var parent = this.getParent();
49                        this._childOfLayoutWidget = parent && parent.isLayoutContainer;
50
51                        // I need to call resize() on my child/children (when I become visible), unless
52                        // I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
53                        this._needLayout = !this._childOfLayoutWidget;
54
55                        this.inherited(arguments);
56
57                        if(this._isShown()){
58                                this._onShow();
59                        }
60
61                        if(!this._childOfLayoutWidget){
62                                // Since my parent isn't a layout container, and my style *may be* width=height=100%
63                                // or something similar (either set directly or via a CSS class),
64                                // monitor when viewport size changes so that I can re-layout.
65                                // This is more for subclasses of ContentPane than ContentPane itself, although it
66                                // could be useful for a ContentPane if it has a single child widget inheriting ContentPane's size.
67                                this.own(Viewport.on("resize", lang.hitch(this, "resize")));
68                        }
69                },
70
71                _checkIfSingleChild: function(){
72                        // summary:
73                        //              Test if we have exactly one visible widget as a child,
74                        //              and if so assume that we are a container for that widget,
75                        //              and should propagate startup() and resize() calls to it.
76                        //              Skips over things like data stores since they aren't visible.
77
78                        var candidateWidgets = [],
79                                otherVisibleNodes = false;
80
81                        query("> *", this.containerNode).some(function(node){
82                                var widget = registry.byNode(node);
83                                if(widget && widget.resize){
84                                        candidateWidgets.push(widget);
85                                }else if(!/script|link|style/i.test(node.nodeName) && node.offsetHeight){
86                                        otherVisibleNodes = true;
87                                }
88                        });
89
90                        this._singleChild = candidateWidgets.length == 1 && !otherVisibleNodes ?
91                                candidateWidgets[0] : null;
92
93                        // So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
94                        domClass.toggle(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
95                },
96
97                resize: function(changeSize, resultSize){
98                        // summary:
99                        //              See `dijit/layout/_LayoutWidget.resize()` for description.
100                        //              Although ContentPane doesn't extend _LayoutWidget, it does implement
101                        //              the same API.
102
103                        this._resizeCalled = true;
104
105                        this._scheduleLayout(changeSize, resultSize);
106                },
107
108                _scheduleLayout: function(changeSize, resultSize){
109                        // summary:
110                        //              Resize myself, and call resize() on each of my child layout widgets, either now
111                        //              (if I'm currently visible) or when I become visible
112                        if(this._isShown()){
113                                this._layout(changeSize, resultSize);
114                        }else{
115                                this._needLayout = true;
116                                this._changeSize = changeSize;
117                                this._resultSize = resultSize;
118                        }
119                },
120
121                _layout: function(changeSize, resultSize){
122                        // summary:
123                        //              Resize myself according to optional changeSize/resultSize parameters, like a layout widget.
124                        //              Also, since I am an isLayoutContainer widget, each of my children expects me to
125                        //              call resize() or layout() on it.
126                        //
127                        //              Should be called on initialization and also whenever we get new content
128                        //              (from an href, or from set('content', ...))... but deferred until
129                        //              the ContentPane is visible
130
131                        delete this._needLayout;
132
133                        // For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
134                        // never called directly, so resize() is our trigger to do the initial href download (see [20099]).
135                        // However, don't load href for closed TitlePanes.
136                        if(!this._wasShown && this.open !== false){
137                                this._onShow();
138                        }
139
140                        // Set margin box size, unless it wasn't specified, in which case use current size.
141                        if(changeSize){
142                                domGeometry.setMarginBox(this.domNode, changeSize);
143                        }
144
145                        // Compute content box size of containerNode in case we [later] need to size our single child.
146                        var cn = this.containerNode;
147                        if(cn === this.domNode){
148                                // If changeSize or resultSize was passed to this method and this.containerNode ==
149                                // this.domNode then we can compute the content-box size without querying the node,
150                                // which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
151                                var mb = resultSize || {};
152                                lang.mixin(mb, changeSize || {}); // changeSize overrides resultSize
153                                if(!("h" in mb) || !("w" in mb)){
154                                        mb = lang.mixin(domGeometry.getMarginBox(cn), mb); // just use domGeometry.setMarginBox() to fill in missing values
155                                }
156                                this._contentBox = layoutUtils.marginBox2contentBox(cn, mb);
157                        }else{
158                                this._contentBox = domGeometry.getContentBox(cn);
159                        }
160
161                        this._layoutChildren();
162                },
163
164                _layoutChildren: function(){
165                        // Call _checkIfSingleChild() again in case app has manually mucked w/the content
166                        // of the ContentPane (rather than changing it through the set("content", ...) API.
167                        if(this.doLayout){
168                                this._checkIfSingleChild();
169                        }
170
171                        if(this._singleChild && this._singleChild.resize){
172                                var cb = this._contentBox || domGeometry.getContentBox(this.containerNode);
173
174                                // note: if widget has padding this._contentBox will have l and t set,
175                                // but don't pass them to resize() or it will doubly-offset the child
176                                this._singleChild.resize({w: cb.w, h: cb.h});
177                        }else{
178                                // All my child widgets are independently sized (rather than matching my size),
179                                // but I still need to call resize() on each child to make it layout.
180                                var children = this.getChildren(),
181                                        widget,
182                                        i = 0;
183                                while(widget = children[i++]){
184                                        if(widget.resize){
185                                                widget.resize();
186                                        }
187                                }
188                        }
189                },
190
191                _isShown: function(){
192                        // summary:
193                        //              Returns true if the content is currently shown.
194                        // description:
195                        //              If I am a child of a layout widget then it actually returns true if I've ever been visible,
196                        //              not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
197                        //              tree every call, and at least solves the performance problem on page load by deferring loading
198                        //              hidden ContentPanes until they are first shown
199
200                        if(this._childOfLayoutWidget){
201                                // If we are TitlePane, etc - we return that only *IF* we've been resized
202                                if(this._resizeCalled && "open" in this){
203                                        return this.open;
204                                }
205                                return this._resizeCalled;
206                        }else if("open" in this){
207                                return this.open;               // for TitlePane, etc.
208                        }else{
209                                var node = this.domNode, parent = this.domNode.parentNode;
210                                return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !domClass.contains(node, "dijitHidden") &&
211                                        parent && parent.style && (parent.style.display != 'none');
212                        }
213                },
214
215                _onShow: function(){
216                        // summary:
217                        //              Called when the ContentPane is made visible
218                        // description:
219                        //              For a plain ContentPane, this is called on initialization, from startup().
220                        //              If the ContentPane is a hidden pane of a TabContainer etc., then it's
221                        //              called whenever the pane is made visible.
222                        //
223                        //              Does layout/resize of child widget(s)
224
225                        // Need to keep track of whether ContentPane has been shown (which is different than
226                        // whether or not it's currently visible).
227                        this._wasShown = true;
228
229                        if(this._needLayout){
230                                // If a layout has been scheduled for when we become visible, do it now
231                                this._layout(this._changeSize, this._resultSize);
232                        }
233
234                        this.inherited(arguments);
235                }
236        });
237});
Note: See TracBrowser for help on using the repository browser.