]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/layout/container/Fit.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / layout / container / Fit.js
CommitLineData
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
29Ext.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