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