]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * This is a base class for layouts that contain a single item that automatically expands to fill the layout's\r | |
3 | * container. This class is intended to be extended or created via the layout:'fit'\r | |
4 | * {@link Ext.container.Container#layout} config, and should generally not need to be created directly via the new keyword.\r | |
5 | *\r | |
6 | * Fit layout does not have any direct config options (other than inherited ones). To fit a panel to a container using\r | |
7 | * Fit layout, simply set `layout: 'fit'` on the container and add a single panel to it.\r | |
8 | *\r | |
9 | * @example\r | |
10 | * Ext.create('Ext.panel.Panel', {\r | |
11 | * title: 'Fit Layout',\r | |
12 | * width: 300,\r | |
13 | * height: 150,\r | |
14 | * layout:'fit',\r | |
15 | * items: {\r | |
16 | * title: 'Inner Panel',\r | |
17 | * html: 'This is the inner panel content',\r | |
18 | * bodyPadding: 20,\r | |
19 | * border: false\r | |
20 | * },\r | |
21 | * renderTo: Ext.getBody()\r | |
22 | * });\r | |
23 | *\r | |
24 | * If the container has multiple items, all of the items will all be equally sized. This is usually not\r | |
25 | * desired, so to avoid this, place only a **single** item in the container. This sizing of all items\r | |
26 | * can be used to provide a background {@link Ext.Img image} that is "behind" another item\r | |
27 | * such as a {@link Ext.view.View dataview} if you also absolutely position the items.\r | |
28 | */\r | |
29 | Ext.define('Ext.layout.container.Fit', {\r | |
30 | \r | |
31 | /* Begin Definitions */\r | |
32 | extend: 'Ext.layout.container.Container',\r | |
33 | alternateClassName: 'Ext.layout.FitLayout',\r | |
34 | \r | |
35 | alias: 'layout.fit',\r | |
36 | \r | |
37 | /* End Definitions */\r | |
38 | \r | |
39 | /**\r | |
40 | * @inheritdoc Ext.layout.container.Container#cfg-itemCls\r | |
41 | */\r | |
42 | itemCls: Ext.baseCSSPrefix + 'fit-item',\r | |
43 | type: 'fit',\r | |
44 | \r | |
45 | manageMargins: true,\r | |
46 | \r | |
47 | sizePolicies: {\r | |
48 | 0: { readsWidth: 1, readsHeight: 1, setsWidth: 0, setsHeight: 0 },\r | |
49 | 1: { readsWidth: 0, readsHeight: 1, setsWidth: 1, setsHeight: 0 },\r | |
50 | 2: { readsWidth: 1, readsHeight: 0, setsWidth: 0, setsHeight: 1 },\r | |
51 | 3: { readsWidth: 0, readsHeight: 0, setsWidth: 1, setsHeight: 1 }\r | |
52 | },\r | |
53 | \r | |
54 | getItemSizePolicy: function (item, ownerSizeModel) {\r | |
55 | // this layout's sizePolicy is derived from its owner's sizeModel:\r | |
56 | var sizeModel = ownerSizeModel || this.owner.getSizeModel(),\r | |
57 | mode = (sizeModel.width.shrinkWrap ? 0 : 1) | // jshint ignore:line\r | |
58 | (sizeModel.height.shrinkWrap ? 0 : 2);\r | |
59 | \r | |
60 | return this.sizePolicies[mode];\r | |
61 | },\r | |
62 | \r | |
63 | beginLayoutCycle: function (ownerContext, firstCycle) {\r | |
64 | var me = this,\r | |
65 | // determine these before the lastSizeModels get updated:\r | |
66 | resetHeight = me.lastHeightModel && me.lastHeightModel.calculated,\r | |
67 | resetWidth = me.lastWidthModel && me.lastWidthModel.calculated,\r | |
68 | resetSizes = resetWidth || resetHeight,\r | |
69 | maxChildMinHeight = 0, maxChildMinWidth = 0,\r | |
70 | c, childItems, i, item, length, margins, minHeight, minWidth, style, undef;\r | |
71 | \r | |
72 | me.callParent(arguments);\r | |
73 | \r | |
74 | // Clear any dimensions which we set before calculation, in case the current\r | |
75 | // settings affect the available size. This particularly effects self-sizing\r | |
76 | // containers such as fields, in which the target element is naturally sized,\r | |
77 | // and should not be stretched by a sized child item.\r | |
78 | if (resetSizes && ownerContext.targetContext.el.dom.tagName.toUpperCase() !== 'TD') {\r | |
79 | resetSizes = resetWidth = resetHeight = false;\r | |
80 | }\r | |
81 | \r | |
82 | childItems = ownerContext.childItems;\r | |
83 | length = childItems.length;\r | |
84 | \r | |
85 | for (i = 0; i < length; ++i) {\r | |
86 | item = childItems[i];\r | |
87 | \r | |
88 | // On the firstCycle, we determine the max of the minWidth/Height of the items\r | |
89 | // since these can cause the container to grow scrollbars despite our attempts\r | |
90 | // to fit the child to the container.\r | |
91 | if (firstCycle) {\r | |
92 | c = item.target;\r | |
93 | minHeight = c.minHeight;\r | |
94 | minWidth = c.minWidth;\r | |
95 | \r | |
96 | if (minWidth || minHeight) {\r | |
97 | margins = item.marginInfo || item.getMarginInfo();\r | |
98 | // if the child item has undefined minWidth/Height, these will become\r | |
99 | // NaN by adding the margins...\r | |
100 | minHeight += margins.height;\r | |
101 | minWidth += margins.height;\r | |
102 | \r | |
103 | // if the child item has undefined minWidth/Height, these comparisons\r | |
104 | // will evaluate to false... that is, "0 < NaN" == false...\r | |
105 | if (maxChildMinHeight < minHeight) {\r | |
106 | maxChildMinHeight = minHeight;\r | |
107 | }\r | |
108 | if (maxChildMinWidth < minWidth) {\r | |
109 | maxChildMinWidth = minWidth;\r | |
110 | }\r | |
111 | }\r | |
112 | }\r | |
113 | \r | |
114 | if (resetSizes) {\r | |
115 | style = item.el.dom.style;\r | |
116 | \r | |
117 | if (resetHeight) {\r | |
118 | style.height = '';\r | |
119 | }\r | |
120 | if (resetWidth) {\r | |
121 | style.width = '';\r | |
122 | }\r | |
123 | }\r | |
124 | }\r | |
125 | \r | |
126 | if (firstCycle) {\r | |
127 | ownerContext.maxChildMinHeight = maxChildMinHeight;\r | |
128 | ownerContext.maxChildMinWidth = maxChildMinWidth;\r | |
129 | }\r | |
130 | \r | |
131 | // Cache the overflowX/Y flags, but make them false in shrinkWrap mode (since we\r | |
132 | // won't be triggering overflow in that case) and false if we have no minSize (so\r | |
133 | // no child to trigger an overflow).\r | |
134 | c = ownerContext.target;\r | |
135 | ownerContext.overflowX = (!ownerContext.widthModel.shrinkWrap && \r | |
136 | ownerContext.maxChildMinWidth &&\r | |
137 | c.scrollFlags.x) || undef;\r | |
138 | \r | |
139 | ownerContext.overflowY = (!ownerContext.heightModel.shrinkWrap &&\r | |
140 | ownerContext.maxChildMinHeight &&\r | |
141 | c.scrollFlags.y) || undef;\r | |
142 | },\r | |
143 | \r | |
144 | calculate: function (ownerContext) {\r | |
145 | var me = this,\r | |
146 | childItems = ownerContext.childItems,\r | |
147 | length = childItems.length,\r | |
148 | containerSize = me.getContainerSize(ownerContext),\r | |
149 | info = {\r | |
150 | length: length,\r | |
151 | ownerContext: ownerContext,\r | |
152 | targetSize: containerSize\r | |
153 | },\r | |
154 | shrinkWrapWidth = ownerContext.widthModel.shrinkWrap,\r | |
155 | shrinkWrapHeight = ownerContext.heightModel.shrinkWrap,\r | |
156 | overflowX = ownerContext.overflowX,\r | |
157 | overflowY = ownerContext.overflowY,\r | |
158 | scrollbars, scrollbarSize, padding, i, contentWidth, contentHeight;\r | |
159 | \r | |
160 | ownerContext.state.info = info;\r | |
161 | if (overflowX || overflowY) {\r | |
162 | // If we have children that have minHeight/Width, we may be forced to overflow\r | |
163 | // and gain scrollbars. If so, we want to remove their space from the other\r | |
164 | // axis so that we fit things inside the scrollbars rather than under them.\r | |
165 | scrollbars = me.getScrollbarsNeeded(\r | |
166 | overflowX && containerSize.width, overflowY && containerSize.height,\r | |
167 | ownerContext.maxChildMinWidth, ownerContext.maxChildMinHeight);\r | |
168 | \r | |
169 | if (scrollbars) {\r | |
170 | scrollbarSize = Ext.getScrollbarSize();\r | |
171 | if (scrollbars & 1) { // jshint ignore:line\r | |
172 | // if we need the hscrollbar, remove its height\r | |
173 | containerSize.height -= scrollbarSize.height;\r | |
174 | }\r | |
175 | if (scrollbars & 2) { // jshint ignore:line\r | |
176 | // if we need the vscrollbar, remove its width\r | |
177 | containerSize.width -= scrollbarSize.width;\r | |
178 | }\r | |
179 | }\r | |
180 | }\r | |
181 | \r | |
182 | // If length === 0, it means we either have no child items, or the children are hidden\r | |
183 | if (length > 0) {\r | |
184 | // Size the child items to the container (if non-shrinkWrap):\r | |
185 | for (i = 0; i < length; ++i) {\r | |
186 | info.index = i;\r | |
187 | me.fitItem(childItems[i], info);\r | |
188 | }\r | |
189 | } else {\r | |
190 | info.contentWidth = info.contentHeight = 0;\r | |
191 | }\r | |
192 | \r | |
193 | if (shrinkWrapHeight || shrinkWrapWidth) {\r | |
194 | padding = ownerContext.targetContext.getPaddingInfo();\r | |
195 | \r | |
196 | if (shrinkWrapWidth) {\r | |
197 | if (overflowY && !containerSize.gotHeight) {\r | |
198 | // if we might overflow vertically and don't have the container height,\r | |
199 | // we don't know if we will need a vscrollbar or not, so we must wait\r | |
200 | // for that height so that we can determine the contentWidth...\r | |
201 | me.done = false;\r | |
202 | } else {\r | |
203 | contentWidth = info.contentWidth + padding.width;\r | |
204 | // the scrollbar flag (if set) will indicate that an overflow exists on\r | |
205 | // the horz(1) or vert(2) axis... if not set, then there could never be\r | |
206 | // an overflow...\r | |
207 | if (scrollbars & 2) { // jshint ignore:line\r | |
208 | // if we need the vscrollbar, add its width\r | |
209 | contentWidth += scrollbarSize.width;\r | |
210 | }\r | |
211 | if (!ownerContext.setContentWidth(contentWidth)) {\r | |
212 | me.done = false;\r | |
213 | }\r | |
214 | }\r | |
215 | }\r | |
216 | \r | |
217 | if (shrinkWrapHeight) {\r | |
218 | if (overflowX && !containerSize.gotWidth) {\r | |
219 | // if we might overflow horizontally and don't have the container width,\r | |
220 | // we don't know if we will need a hscrollbar or not, so we must wait\r | |
221 | // for that width so that we can determine the contentHeight...\r | |
222 | me.done = false;\r | |
223 | } else {\r | |
224 | contentHeight = info.contentHeight + padding.height;\r | |
225 | // the scrollbar flag (if set) will indicate that an overflow exists on\r | |
226 | // the horz(1) or vert(2) axis... if not set, then there could never be\r | |
227 | // an overflow...\r | |
228 | if (scrollbars & 1) { // jshint ignore:line\r | |
229 | // if we need the hscrollbar, add its height\r | |
230 | contentHeight += scrollbarSize.height;\r | |
231 | }\r | |
232 | if (!ownerContext.setContentHeight(contentHeight)) {\r | |
233 | me.done = false;\r | |
234 | }\r | |
235 | }\r | |
236 | }\r | |
237 | }\r | |
238 | },\r | |
239 | \r | |
240 | fitItem: function (itemContext, info) {\r | |
241 | var me = this;\r | |
242 | \r | |
243 | if (itemContext.invalid) {\r | |
244 | me.done = false;\r | |
245 | return;\r | |
246 | }\r | |
247 | \r | |
248 | info.margins = itemContext.getMarginInfo();\r | |
249 | info.needed = info.got = 0;\r | |
250 | \r | |
251 | me.fitItemWidth(itemContext, info);\r | |
252 | me.fitItemHeight(itemContext, info);\r | |
253 | \r | |
254 | // If not all required dimensions have been satisfied, we're not done.\r | |
255 | if (info.got !== info.needed) {\r | |
256 | me.done = false;\r | |
257 | }\r | |
258 | },\r | |
259 | \r | |
260 | fitItemWidth: function (itemContext, info) {\r | |
261 | var contentWidth, width;\r | |
262 | // Attempt to set only dimensions that are being controlled, not shrinkWrap dimensions\r | |
263 | if (info.ownerContext.widthModel.shrinkWrap) {\r | |
264 | // contentWidth must include the margins to be consistent with setItemWidth\r | |
265 | width = itemContext.getProp('width') + info.margins.width;\r | |
266 | // because we add margins, width will be NaN or a number (not undefined)\r | |
267 | \r | |
268 | contentWidth = info.contentWidth;\r | |
269 | if (contentWidth === undefined) {\r | |
270 | info.contentWidth = width;\r | |
271 | } else {\r | |
272 | info.contentWidth = Math.max(contentWidth, width);\r | |
273 | }\r | |
274 | } else if (itemContext.widthModel.calculated) {\r | |
275 | ++info.needed;\r | |
276 | if (info.targetSize.gotWidth) {\r | |
277 | ++info.got;\r | |
278 | this.setItemWidth(itemContext, info);\r | |
279 | } else {\r | |
280 | // Too early to position\r | |
281 | return;\r | |
282 | }\r | |
283 | }\r | |
284 | \r | |
285 | this.positionItemX(itemContext, info);\r | |
286 | },\r | |
287 | \r | |
288 | fitItemHeight: function (itemContext, info) {\r | |
289 | var contentHeight, height;\r | |
290 | if (info.ownerContext.heightModel.shrinkWrap) {\r | |
291 | // contentHeight must include the margins to be consistent with setItemHeight\r | |
292 | height = itemContext.getProp('height') + info.margins.height;\r | |
293 | // because we add margins, height will be NaN or a number (not undefined)\r | |
294 | \r | |
295 | contentHeight = info.contentHeight;\r | |
296 | if (contentHeight === undefined) {\r | |
297 | info.contentHeight = height;\r | |
298 | } else {\r | |
299 | info.contentHeight = Math.max(contentHeight, height);\r | |
300 | }\r | |
301 | } else if (itemContext.heightModel.calculated) {\r | |
302 | ++info.needed;\r | |
303 | if (info.targetSize.gotHeight) {\r | |
304 | ++info.got;\r | |
305 | this.setItemHeight(itemContext, info);\r | |
306 | } else {\r | |
307 | // Too early to position\r | |
308 | return;\r | |
309 | }\r | |
310 | }\r | |
311 | \r | |
312 | this.positionItemY(itemContext, info);\r | |
313 | },\r | |
314 | \r | |
315 | positionItemX: function (itemContext, info) {\r | |
316 | var margins = info.margins;\r | |
317 | \r | |
318 | // Adjust position to account for configured margins or if we have multiple items\r | |
319 | // (all items should overlap):\r | |
320 | if (info.index || margins.left) {\r | |
321 | itemContext.setProp('x', margins.left);\r | |
322 | }\r | |
323 | \r | |
324 | if (margins.width && info.ownerContext.widthModel.shrinkWrap) {\r | |
325 | // Need the margins for shrink-wrapping but old IE sometimes collapses the left margin into the padding\r | |
326 | itemContext.setProp('margin-right', margins.width);\r | |
327 | }\r | |
328 | },\r | |
329 | \r | |
330 | positionItemY: function (itemContext, info) {\r | |
331 | var margins = info.margins;\r | |
332 | \r | |
333 | if (info.index || margins.top) {\r | |
334 | itemContext.setProp('y', margins.top);\r | |
335 | }\r | |
336 | \r | |
337 | if (margins.height && info.ownerContext.heightModel.shrinkWrap) {\r | |
338 | // Need the margins for shrink-wrapping but old IE sometimes collapses the top margin into the padding\r | |
339 | itemContext.setProp('margin-bottom', margins.height);\r | |
340 | }\r | |
341 | },\r | |
342 | \r | |
343 | setItemHeight: function (itemContext, info) {\r | |
344 | itemContext.setHeight(info.targetSize.height - info.margins.height);\r | |
345 | },\r | |
346 | \r | |
347 | setItemWidth: function (itemContext, info) {\r | |
348 | itemContext.setWidth(info.targetSize.width - info.margins.width);\r | |
349 | }\r | |
350 | });\r |