]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @class Ext.layout.container.Auto\r | |
3 | *\r | |
4 | * The AutoLayout is the default layout manager delegated by {@link Ext.container.Container} to\r | |
5 | * render any child Components when no `{@link Ext.container.Container#layout layout}` is configured into\r | |
6 | * a `{@link Ext.container.Container Container}.` AutoLayout provides only a passthrough of any layout calls\r | |
7 | * to any child containers.\r | |
8 | *\r | |
9 | * @example\r | |
10 | * Ext.create('Ext.Panel', {\r | |
11 | * width: 500,\r | |
12 | * height: 280,\r | |
13 | * title: 'AutoLayout Panel',\r | |
14 | * layout: 'auto',\r | |
15 | * renderTo: document.body,\r | |
16 | * items: [{\r | |
17 | * xtype: 'panel',\r | |
18 | * title: 'Top Inner Panel',\r | |
19 | * width: '75%',\r | |
20 | * height: 90\r | |
21 | * }, {\r | |
22 | * xtype: 'panel',\r | |
23 | * title: 'Bottom Inner Panel',\r | |
24 | * width: '75%',\r | |
25 | * height: 90\r | |
26 | * }]\r | |
27 | * });\r | |
28 | */\r | |
29 | Ext.define('Ext.layout.container.Auto', {\r | |
30 | \r | |
31 | /* Begin Definitions */\r | |
32 | \r | |
33 | alias: ['layout.auto', 'layout.autocontainer'],\r | |
34 | \r | |
35 | extend: 'Ext.layout.container.Container',\r | |
36 | \r | |
37 | /* End Definitions */\r | |
38 | \r | |
39 | type: 'autocontainer',\r | |
40 | \r | |
41 | childEls: [\r | |
42 | 'outerCt',\r | |
43 | 'innerCt'\r | |
44 | ],\r | |
45 | \r | |
46 | /**\r | |
47 | * @cfg {Boolean} [reserveScrollbar=false]\r | |
48 | * Set to `true` to leave space for a vertical scrollbar (if the OS shows space-consuming scrollbars) regardless\r | |
49 | * of whether a scrollbar is needed.\r | |
50 | *\r | |
51 | * This is useful if content height changes during application usage, but you do not want the calculated width\r | |
52 | * of child items to change when a scrollbar appears or disappears. The scrollbar will appear in the reserved space,\r | |
53 | * and the calculated width of child Components will not change.\r | |
54 | *\r | |
55 | * @example\r | |
56 | * Ext.define('Employee', {\r | |
57 | * extend: 'Ext.data.Model',\r | |
58 | * fields: [\r | |
59 | * {name: 'rating', type: 'int'},\r | |
60 | * {name: 'salary', type: 'float'},\r | |
61 | * {name: 'name'}\r | |
62 | * ]\r | |
63 | * });\r | |
64 | *\r | |
65 | * function createFakeData(count) {\r | |
66 | * var firstNames = ['Screech', 'Kelly', 'Zach', 'Jessie', 'Lisa', 'A.C.', 'Richard'],\r | |
67 | * lastNames = ['Powers', 'Kapowski', 'Morris', 'Spano', 'Turtle', 'Slater', 'Belding'],\r | |
68 | * ratings = [1, 2, 3, 4, 5],\r | |
69 | * salaries = [100, 400, 900, 1500, 1000000];\r | |
70 | *\r | |
71 | * var data = [];\r | |
72 | * for (var i = 0; i < (count || 25); i++) {\r | |
73 | * var ratingId = Math.floor(Math.random() * ratings.length),\r | |
74 | * salaryId = Math.floor(Math.random() * salaries.length),\r | |
75 | * firstNameId = Math.floor(Math.random() * firstNames.length),\r | |
76 | * lastNameId = Math.floor(Math.random() * lastNames.length),\r | |
77 | *\r | |
78 | * rating = ratings[ratingId],\r | |
79 | * salary = salaries[salaryId],\r | |
80 | * name = Ext.String.format("{0} {1}", firstNames[firstNameId], lastNames[lastNameId]);\r | |
81 | *\r | |
82 | * data.push({\r | |
83 | * rating: rating,\r | |
84 | * salary: salary,\r | |
85 | * name: name\r | |
86 | * });\r | |
87 | * }\r | |
88 | * store.loadData(data);\r | |
89 | * }\r | |
90 | *\r | |
91 | * // create the Data Store\r | |
92 | * var store = Ext.create('Ext.data.Store', {\r | |
93 | * id: 'store',\r | |
94 | * model: 'Employee',\r | |
95 | * proxy: {\r | |
96 | * type: 'memory'\r | |
97 | * }\r | |
98 | * });\r | |
99 | * createFakeData(10);\r | |
100 | *\r | |
101 | * var grid = Ext.create('Ext.grid.Panel', {\r | |
102 | * title: 'Grid loaded with varying number of records',\r | |
103 | * anchor: '100%',\r | |
104 | * store: store,\r | |
105 | * columns: [{\r | |
106 | * xtype: 'rownumberer',\r | |
107 | * width: 40,\r | |
108 | * sortable: false\r | |
109 | * },{\r | |
110 | * text: 'Name',\r | |
111 | * flex: 1,\r | |
112 | * sortable: true,\r | |
113 | * dataIndex: 'name'\r | |
114 | * },{\r | |
115 | * text: 'Rating',\r | |
116 | * width: 125,\r | |
117 | * sortable: true,\r | |
118 | * dataIndex: 'rating'\r | |
119 | * },{\r | |
120 | * text: 'Salary',\r | |
121 | * width: 125,\r | |
122 | * sortable: true,\r | |
123 | * dataIndex: 'salary',\r | |
124 | * align: 'right',\r | |
125 | * renderer: Ext.util.Format.usMoney\r | |
126 | * }]\r | |
127 | * });\r | |
128 | *\r | |
129 | * Ext.create('Ext.panel.Panel', {\r | |
130 | * renderTo: document.body,\r | |
131 | * width: 800,\r | |
132 | * height: 600,\r | |
133 | * layout: {\r | |
134 | * type: 'anchor',\r | |
135 | * reserveScrollbar: true // There will be a gap even when there's no scrollbar\r | |
136 | * },\r | |
137 | * scrollable: true,\r | |
138 | * items: grid,\r | |
139 | * tbar: {\r | |
140 | * defaults: {\r | |
141 | * handler: function(b) {\r | |
142 | * createFakeData(b.count);\r | |
143 | * }\r | |
144 | * },\r | |
145 | * items: [{\r | |
146 | * text: '10 Items',\r | |
147 | * count: 10\r | |
148 | * },{\r | |
149 | * text: '100 Items',\r | |
150 | * count: 100\r | |
151 | * },{\r | |
152 | * text: '300 Items',\r | |
153 | * count: 300\r | |
154 | * },{\r | |
155 | * text: '1000 Items',\r | |
156 | * count: 1000\r | |
157 | * },{\r | |
158 | * text: '5000 Items',\r | |
159 | * count: 5000\r | |
160 | * }]\r | |
161 | * }\r | |
162 | * });\r | |
163 | *\r | |
164 | */\r | |
165 | reserveScrollbar: false,\r | |
166 | \r | |
167 | /**\r | |
168 | * @property {Boolean} [managePadding=true]\r | |
169 | * indicates that this layout will correct cross browser padding differences when the\r | |
170 | * container has overflow.\r | |
171 | * \r | |
172 | * In some browsers the right and/or bottom padding of a container is lost when\r | |
173 | * the container has overflow. If managePadding is true the layout will apply the\r | |
174 | * padding to an inner wrapping element instead of the container element that has the\r | |
175 | * overflow so that paddding will be included in the scrollable area.\r | |
176 | * Note: padding will not be managed if it is configured on the container using\r | |
177 | * a style config or css class. In order to be managed, padding must be added to the\r | |
178 | * container using the appropriate {@link Ext.Component#contentPaddingProperty\r | |
179 | * contentPaddingProperty}. For {@link Ext.panel.Panel Panels} use \r | |
180 | * {@link Ext.panel.Panel#bodyPadding}, and for\r | |
181 | * {@link Ext.container.Container Containers}, use\r | |
182 | * {@link Ext.Component#padding padding}\r | |
183 | */\r | |
184 | managePadding: true,\r | |
185 | \r | |
186 | /**\r | |
187 | * @property {Boolean} [manageOverflow=false]\r | |
188 | * true to rerun the layout if scrollbars are needed.\r | |
189 | */\r | |
190 | manageOverflow: false,\r | |
191 | \r | |
192 | // auto layout does not care about the dimensions of individual child items since\r | |
193 | // it does not size them, and it measures them as a whole when in shrinkWrap mode.\r | |
194 | needsItemSize: false,\r | |
195 | setsItemSize: false,\r | |
196 | \r | |
197 | // Begin with no previous adjustments\r | |
198 | lastOverflowAdjust: {\r | |
199 | width: 0,\r | |
200 | height: 0\r | |
201 | },\r | |
202 | \r | |
203 | outerCtCls: Ext.baseCSSPrefix + 'autocontainer-outerCt',\r | |
204 | innerCtCls: Ext.baseCSSPrefix + 'autocontainer-innerCt',\r | |
205 | \r | |
206 | // Auto layout's renderTpl wraps the content in an outerCt which is used to accomplish\r | |
207 | // the following 3 goals:\r | |
208 | // \r | |
209 | // 1. When the container has a shrink wrapped width and/or height, the outerCt is used\r | |
210 | // to measure the size of the content.\r | |
211 | // 2. When the container has overflow some browsers lose the container's right and/or\r | |
212 | // bottom padding. To fix this, the padding is rendered to the outerCt instead of\r | |
213 | // the container target element. This ensures that the padding is included in the \r | |
214 | // container's scrollWidth/scrollHeight. In Old IE when a table is used, the padding\r | |
215 | // is rendered to the innerCt td element.\r | |
216 | // 3. The outerCt contains the margins of its children, that is to say, it prevents\r | |
217 | // them from collapsing.\r | |
218 | renderTpl: [\r | |
219 | // An outerCt with display:table shrink-wraps contents, and contains child\r | |
220 | // margins. The table-cell innerCt is required in order to support percentage\r | |
221 | // heights on child elements.\r | |
222 | '<div id="{ownerId}-outerCt" data-ref="outerCt" class="{outerCtCls}" role="presentation">',\r | |
223 | '<div id="{ownerId}-innerCt" data-ref="innerCt" style="{%this.renderPadding(out, values)%}" ',\r | |
224 | // If raw HTML is used as the component's content, avoid setting\r | |
225 | // presentation role so as not to mask the content from screen readers\r | |
226 | '<tpl if="!$comp.html">role="presentation"</tpl>',\r | |
227 | 'class="{innerCtCls}">',\r | |
228 | '{%this.renderBody(out,values)%}',\r | |
229 | '</div>',\r | |
230 | '</div>'\r | |
231 | ],\r | |
232 | \r | |
233 | beginLayout: function(ownerContext) {\r | |
234 | this.callParent(arguments);\r | |
235 | this.initContextItems(ownerContext);\r | |
236 | },\r | |
237 | \r | |
238 | beforeLayoutCycle: function(ownerContext){\r | |
239 | var comp = this.owner,\r | |
240 | inheritedState = comp.inheritedState,\r | |
241 | inheritedStateInner = comp.inheritedStateInner;\r | |
242 | \r | |
243 | if (!inheritedState || inheritedState.invalid) {\r | |
244 | inheritedState = comp.getInherited(); // fixes both\r | |
245 | inheritedStateInner = comp.inheritedStateInner;\r | |
246 | }\r | |
247 | if (ownerContext.widthModel.shrinkWrap) {\r | |
248 | inheritedStateInner.inShrinkWrapTable = true;\r | |
249 | } else {\r | |
250 | delete inheritedStateInner.inShrinkWrapTable;\r | |
251 | }\r | |
252 | },\r | |
253 | \r | |
254 | beginLayoutCycle: function(ownerContext) {\r | |
255 | var me = this,\r | |
256 | outerCt = me.outerCt,\r | |
257 | lastOuterCtWidth = me.lastOuterCtWidth || '',\r | |
258 | lastOuterCtHeight = me.lastOuterCtHeight || '',\r | |
259 | lastOuterCtTableLayout = me.lastOuterCtTableLayout || '',\r | |
260 | state = ownerContext.state,\r | |
261 | overflowXStyle, outerCtWidth, outerCtHeight, outerCtTableLayout,\r | |
262 | inheritedStateInner;\r | |
263 | \r | |
264 | me.callParent(arguments);\r | |
265 | \r | |
266 | // Default to "shrink wrap styles".\r | |
267 | outerCtWidth = outerCtHeight = outerCtTableLayout = '';\r | |
268 | \r | |
269 | if (!ownerContext.widthModel.shrinkWrap) {\r | |
270 | // if we're not shrink wrapping width, we need to get the innerCt out of the\r | |
271 | // way to avoid any shrink wrapping effect on child items\r | |
272 | \r | |
273 | // fill the available width within the container\r | |
274 | outerCtWidth = '100%';\r | |
275 | inheritedStateInner = me.owner.inheritedStateInner;\r | |
276 | // expand no further than the available width, even if contents are wider\r | |
277 | // unless there is a potential for horizontal overflow, then allow\r | |
278 | // the outerCt to expand to the width of the contents\r | |
279 | overflowXStyle = me.getOverflowXStyle(ownerContext);\r | |
280 | outerCtTableLayout = (inheritedStateInner.inShrinkWrapTable ||\r | |
281 | overflowXStyle === 'auto' || \r | |
282 | overflowXStyle === 'scroll') ? '' : 'fixed';\r | |
283 | }\r | |
284 | \r | |
285 | if (!ownerContext.heightModel.shrinkWrap && \r | |
286 | !Ext.supports.PercentageHeightOverflowBug) {\r | |
287 | // if we're not shrink wrapping height, we need to get the outerCt out of the\r | |
288 | // way so that percentage height children will be sized correctly. We do this\r | |
289 | // by giving the outerCt a height of '100%' unless the browser is affected by\r | |
290 | // the "percentage height overflow bug", in which case the outerCt will get a\r | |
291 | // pixel height set during the calculate phase after we know the targetEl size.\r | |
292 | outerCtHeight = '100%';\r | |
293 | }\r | |
294 | \r | |
295 | // if the outerCt width changed since last time (becuase of a widthModel change)\r | |
296 | // or if we set a pixel width on the outerCt last time to work around a browser-\r | |
297 | // specific bug, we need to set the width of the outerCt\r | |
298 | if ((outerCtWidth !== lastOuterCtWidth) || me.hasOuterCtPxWidth) {\r | |
299 | outerCt.setStyle('width', outerCtWidth);\r | |
300 | me.lastOuterCtWidth = outerCtWidth;\r | |
301 | me.hasOuterCtPxWidth = false;\r | |
302 | }\r | |
303 | \r | |
304 | // Set the outerCt table-layout property if different from last time.\r | |
305 | if (outerCtTableLayout !== lastOuterCtTableLayout) {\r | |
306 | outerCt.setStyle('table-layout', outerCtTableLayout);\r | |
307 | me.lastOuterCtTableLayout = outerCtTableLayout;\r | |
308 | }\r | |
309 | \r | |
310 | // if the outerCt height changed since last time (becuase of a heightModel change)\r | |
311 | // or if we set a pixel height on the outerCt last time to work around a browser-\r | |
312 | // specific bug, we need to set the height of the outerCt\r | |
313 | if ((outerCtHeight !== lastOuterCtHeight) || me.hasOuterCtPxHeight) {\r | |
314 | outerCt.setStyle('height', outerCtHeight);\r | |
315 | me.lastOuterCtHeight = outerCtHeight;\r | |
316 | me.hasOuterCtPxHeight = false;\r | |
317 | }\r | |
318 | \r | |
319 | if (me.hasInnerCtPxHeight) {\r | |
320 | me.innerCt.setStyle('height', '');\r | |
321 | me.hasInnerCtPxHeight = false;\r | |
322 | }\r | |
323 | \r | |
324 | // Begin with the scrollbar adjustment that we used last time - this is more likely\r | |
325 | // to be correct than beginning with no adjustment at all, but only if it is not\r | |
326 | // already defined - it may have already been set by invalidate()\r | |
327 | state.overflowAdjust = state.overflowAdjust || me.lastOverflowAdjust;\r | |
328 | },\r | |
329 | \r | |
330 | calculate: function(ownerContext) {\r | |
331 | var me = this,\r | |
332 | state = ownerContext.state,\r | |
333 | containerSize = me.getContainerSize(ownerContext, true),\r | |
334 | // If subclass has a calculateItems method, call it and cache the result\r | |
335 | calculatedItems = state.calculatedItems ||\r | |
336 | (state.calculatedItems = me.calculateItems ?\r | |
337 | me.calculateItems(ownerContext, containerSize) : true);\r | |
338 | \r | |
339 | me.setCtSizeIfNeeded(ownerContext, containerSize);\r | |
340 | \r | |
341 | if (calculatedItems && ownerContext.hasDomProp('containerChildrenSizeDone')) {\r | |
342 | \r | |
343 | me.calculateContentSize(ownerContext);\r | |
344 | \r | |
345 | if (containerSize.gotAll) {\r | |
346 | if (me.manageOverflow && !ownerContext.state.secondPass && !me.reserveScrollbar) {\r | |
347 | me.calculateOverflow(ownerContext, containerSize);\r | |
348 | }\r | |
349 | return;\r | |
350 | }\r | |
351 | }\r | |
352 | \r | |
353 | me.done = false;\r | |
354 | },\r | |
355 | \r | |
356 | calculateContentSize: function (ownerContext) {\r | |
357 | var me = this,\r | |
358 | containerDimensions = ((ownerContext.widthModel.shrinkWrap ? 1 : 0) | // jshint ignore:line\r | |
359 | (ownerContext.heightModel.shrinkWrap ? 2 : 0)),\r | |
360 | calcWidth = (containerDimensions & 1) || undefined, // jshint ignore:line\r | |
361 | calcHeight = (containerDimensions & 2) || undefined, // jshint ignore:line\r | |
362 | needed = 0,\r | |
363 | props = ownerContext.props;\r | |
364 | \r | |
365 | if (calcWidth) {\r | |
366 | if (isNaN(props.contentWidth)) {\r | |
367 | ++needed;\r | |
368 | } else {\r | |
369 | calcWidth = undefined;\r | |
370 | }\r | |
371 | }\r | |
372 | if (calcHeight) {\r | |
373 | if (isNaN(props.contentHeight)) {\r | |
374 | ++needed;\r | |
375 | } else {\r | |
376 | calcHeight = undefined;\r | |
377 | }\r | |
378 | }\r | |
379 | \r | |
380 | if (needed) {\r | |
381 | if (calcWidth && !ownerContext.setContentWidth(me.measureContentWidth(ownerContext))) {\r | |
382 | me.done = false;\r | |
383 | }\r | |
384 | if (calcHeight && !ownerContext.setContentHeight(me.measureContentHeight(ownerContext))) {\r | |
385 | me.done = false;\r | |
386 | }\r | |
387 | \r | |
388 | //if (me.done) {\r | |
389 | // var el = ownerContext.targetContext.el.dom;\r | |
390 | // Ext.log(this.owner.id, '.contentSize: ', contentWidth, 'x', contentHeight,\r | |
391 | // ' => scrollSize: ', el.scrollWidth, 'x', el.scrollHeight);\r | |
392 | //}\r | |
393 | }\r | |
394 | },\r | |
395 | \r | |
396 | /**\r | |
397 | * Handles overflow processing for a container. In addition to the ownerContext\r | |
398 | * passed to the {@link #calculate} method, this method also needs the containerSize\r | |
399 | * (the object returned by {@link #getContainerSize}).\r | |
400 | * @protected\r | |
401 | * \r | |
402 | * @param {Ext.layout.ContextItem} ownerContext\r | |
403 | */\r | |
404 | calculateOverflow: function (ownerContext) {\r | |
405 | var me = this,\r | |
406 | width, height, scrollbarSize, scrollbars, xauto, yauto, targetEl;\r | |
407 | \r | |
408 | // Determine the dimensions that have overflow:auto applied. If these come by\r | |
409 | // way of component config, this does not require a DOM read:\r | |
410 | xauto = (me.getOverflowXStyle(ownerContext) === 'auto');\r | |
411 | yauto = (me.getOverflowYStyle(ownerContext) === 'auto');\r | |
412 | \r | |
413 | if (xauto || yauto) {\r | |
414 | scrollbarSize = Ext.getScrollbarSize();\r | |
415 | targetEl = ownerContext.overflowContext.el.dom;\r | |
416 | scrollbars = 0;\r | |
417 | \r | |
418 | if (targetEl.scrollWidth > targetEl.clientWidth) {\r | |
419 | // has horizontal scrollbar\r | |
420 | scrollbars |= 1; // jshint ignore:line\r | |
421 | }\r | |
422 | \r | |
423 | if (targetEl.scrollHeight > targetEl.clientHeight) {\r | |
424 | // has vertical scrollbar\r | |
425 | scrollbars |= 2; // jshint ignore:line\r | |
426 | }\r | |
427 | \r | |
428 | width = (yauto && (scrollbars & 2)) ? scrollbarSize.width : 0; // jshint ignore:line\r | |
429 | height = (xauto && (scrollbars & 1)) ? scrollbarSize.height : 0; // jshint ignore:line\r | |
430 | \r | |
431 | if (width !== me.lastOverflowAdjust.width || height !== me.lastOverflowAdjust.height) {\r | |
432 | me.done = false;\r | |
433 | \r | |
434 | // we pass overflowAdjust and overflowState in as state for the next\r | |
435 | // cycle (these are discarded if one of our ownerCt's invalidates):\r | |
436 | ownerContext.invalidate({\r | |
437 | state: {\r | |
438 | overflowAdjust: {\r | |
439 | width: width,\r | |
440 | height: height\r | |
441 | },\r | |
442 | overflowState: scrollbars,\r | |
443 | secondPass: true\r | |
444 | }\r | |
445 | });\r | |
446 | }\r | |
447 | }\r | |
448 | },\r | |
449 | \r | |
450 | completeLayout: function(ownerContext) {\r | |
451 | this.lastOverflowAdjust = ownerContext.state.overflowAdjust;\r | |
452 | },\r | |
453 | \r | |
454 | doRenderBody: function (out, renderData) {\r | |
455 | // Careful! This method is bolted on to the renderTpl so all we get for context is\r | |
456 | // the renderData! The "this" pointer is the renderTpl instance!\r | |
457 | var me = renderData.$layout,\r | |
458 | XTemplate = Ext.XTemplate,\r | |
459 | beforeBodyTpl = me.beforeBodyTpl,\r | |
460 | afterBodyTpl = me.afterBodyTpl;\r | |
461 | \r | |
462 | if (beforeBodyTpl) {\r | |
463 | XTemplate.getTpl(me, 'beforeBodyTpl').applyOut(renderData, out);\r | |
464 | }\r | |
465 | this.renderItems(out, renderData);\r | |
466 | this.renderContent(out, renderData);\r | |
467 | if (afterBodyTpl) {\r | |
468 | XTemplate.getTpl(me, 'afterBodyTpl').applyOut(renderData, out);\r | |
469 | }\r | |
470 | },\r | |
471 | \r | |
472 | doRenderPadding: function(out, renderData) {\r | |
473 | // Careful! This method is bolted on to the renderTpl so all we get for context is\r | |
474 | // the renderData! The "this" pointer is the renderTpl instance!\r | |
475 | \r | |
476 | var me = renderData.$layout,\r | |
477 | owner = renderData.$layout.owner,\r | |
478 | padding = owner[owner.contentPaddingProperty];\r | |
479 | \r | |
480 | if (me.managePadding && padding) {\r | |
481 | out.push('padding:', owner.unitizeBox(padding));\r | |
482 | }\r | |
483 | },\r | |
484 | \r | |
485 | finishedLayout: function (ownerContext) {\r | |
486 | var innerCt = this.innerCt;\r | |
487 | \r | |
488 | this.callParent(arguments);\r | |
489 | \r | |
490 | if (Ext.isIE8) {\r | |
491 | // IE8 needs a repaint to render percentage sized child items.\r | |
492 | innerCt.repaint();\r | |
493 | }\r | |
494 | \r | |
495 | if (Ext.isOpera) {\r | |
496 | // Opera also needs a repaint to render percentage sized child items. but \r | |
497 | // the normal repaint() method doesn't seem to do the trick, but tweaking\r | |
498 | // the position property in combination with reading scrollWidth does.\r | |
499 | innerCt.setStyle('position', 'relative');\r | |
500 | innerCt.dom.scrollWidth; // jshint ignore:line\r | |
501 | innerCt.setStyle('position', '');\r | |
502 | }\r | |
503 | },\r | |
504 | \r | |
505 | /**\r | |
506 | * Returns the container size (that of the target). Only the fixed-sized dimensions can\r | |
507 | * be returned because the shrinkWrap dimensions are based on the contentWidth/Height\r | |
508 | * as determined by the container layout.\r | |
509 | *\r | |
510 | * If the {@link #calculateOverflow} method is used and if {@link #manageOverflow} is\r | |
511 | * true, this will adjust the width/height by the size of scrollbars.\r | |
512 | * \r | |
513 | * @param {Ext.layout.ContextItem} ownerContext The owner's context item.\r | |
514 | * @param {Boolean} [inDom=false] True if the container size must be in the DOM.\r | |
515 | * @return {Object} The size\r | |
516 | * @return {Number} return.width The width\r | |
517 | * @return {Number} return.height The height\r | |
518 | * @protected\r | |
519 | */\r | |
520 | getContainerSize : function(ownerContext, inDom) {\r | |
521 | // Subtle But Important:\r | |
522 | // \r | |
523 | // We don't want to call getProp/hasProp et.al. unless we in fact need that value\r | |
524 | // for our results! If we call it and don't need it, the layout manager will think\r | |
525 | // we depend on it and will schedule us again should it change.\r | |
526 | \r | |
527 | var size = this.callParent(arguments),\r | |
528 | overflowAdjust = ownerContext.state.overflowAdjust;\r | |
529 | \r | |
530 | if (overflowAdjust) {\r | |
531 | size.width -= overflowAdjust.width;\r | |
532 | size.height -= overflowAdjust.height;\r | |
533 | }\r | |
534 | \r | |
535 | return size;\r | |
536 | },\r | |
537 | \r | |
538 | getRenderData: function () {\r | |
539 | var me = this,\r | |
540 | data = me.callParent();\r | |
541 | \r | |
542 | data.innerCtCls = me.innerCtCls;\r | |
543 | data.outerCtCls = me.outerCtCls;\r | |
544 | \r | |
545 | return data;\r | |
546 | },\r | |
547 | \r | |
548 | // Overridden method from Ext.layout.container.Container.\r | |
549 | // Used in the beforeLayout method to render all items into.\r | |
550 | getRenderTarget: function() {\r | |
551 | return this.innerCt;\r | |
552 | },\r | |
553 | \r | |
554 | // Overridden method from Ext.layout.container.Container.\r | |
555 | // Used by Container classes to insert special DOM elements which must exist in addition to the child components\r | |
556 | getElementTarget: function() {\r | |
557 | return this.innerCt;\r | |
558 | },\r | |
559 | \r | |
560 | /**\r | |
561 | * Returns the overflow-x style of the render target.\r | |
562 | * Note: If overflow is configured on a container using style or css class this method\r | |
563 | * will read the dom the first time it is called. It is therefore preferable for\r | |
564 | * performance reasons to use the {@link Ext.Component#scrollable scrollable config when\r | |
565 | * horizontal overflow is desired.\r | |
566 | * @protected\r | |
567 | * @param {Ext.layout.ContextItem} ownerContext\r | |
568 | * @return {String}\r | |
569 | */\r | |
570 | getOverflowXStyle: function(ownerContext) {\r | |
571 | return ownerContext.overflowXStyle ||\r | |
572 | (ownerContext.overflowXStyle = this.owner.scrollFlags.overflowX || ownerContext.overflowContext.getStyle('overflow-x'));\r | |
573 | },\r | |
574 | \r | |
575 | /**\r | |
576 | * Returns the overflow-y style of the render target.\r | |
577 | * Note: If overflow is configured on a container using style or css class this method\r | |
578 | * will read the dom the first time it is called. It is therefore preferable for\r | |
579 | * performance reasons to use the {@link Ext.Component#scrollable scrollable config when\r | |
580 | * vertical overflow is desired.\r | |
581 | * @protected\r | |
582 | * @param {Ext.layout.ContextItem} ownerContext\r | |
583 | * @return {String}\r | |
584 | */\r | |
585 | getOverflowYStyle: function(ownerContext) {\r | |
586 | return ownerContext.overflowYStyle || \r | |
587 | (ownerContext.overflowYStyle = this.owner.scrollFlags.overflowY || ownerContext.overflowContext.getStyle('overflow-y'));\r | |
588 | },\r | |
589 | \r | |
590 | initContextItems: function(ownerContext) {\r | |
591 | var me = this,\r | |
592 | target = ownerContext.target,\r | |
593 | overflowEl = me.owner.getOverflowEl();\r | |
594 | \r | |
595 | ownerContext.outerCtContext = ownerContext.getEl('outerCt', me);\r | |
596 | ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);\r | |
597 | ownerContext.overflowContext = (overflowEl === ownerContext.el) ? ownerContext :\r | |
598 | ownerContext.getEl(overflowEl);\r | |
599 | \r | |
600 | if (target[target.contentPaddingProperty] !== undefined) {\r | |
601 | // If padding was defined using the contentPaddingProperty, we render the\r | |
602 | // the padding to the innerCt or outerCt (depending on the template that is\r | |
603 | // being used), so we need to set the paddingContext accordingly.\r | |
604 | // Otherwise we leave paddingContext as set by Container layout (defaults to\r | |
605 | // the targetContext)\r | |
606 | ownerContext.paddingContext = ownerContext.innerCtContext;\r | |
607 | }\r | |
608 | },\r | |
609 | \r | |
610 | initLayout: function() {\r | |
611 | var me = this,\r | |
612 | scrollbarWidth = Ext.getScrollbarSize().width,\r | |
613 | owner = me.owner;\r | |
614 | \r | |
615 | me.callParent();\r | |
616 | \r | |
617 | // Create a default lastOverflowAdjust based upon scrolling configuration.\r | |
618 | // If the Container is to overflow, or we *always* reserve space for a scrollbar\r | |
619 | // then reserve space for a vertical scrollbar\r | |
620 | if (scrollbarWidth && me.manageOverflow && !me.hasOwnProperty('lastOverflowAdjust')) {\r | |
621 | if (owner.scrollable || me.reserveScrollbar) {\r | |
622 | me.lastOverflowAdjust = {\r | |
623 | width: scrollbarWidth,\r | |
624 | height: 0\r | |
625 | };\r | |
626 | }\r | |
627 | }\r | |
628 | },\r | |
629 | \r | |
630 | measureContentHeight: function (ownerContext) {\r | |
631 | // contentHeight includes padding, but not border, framing or margins\r | |
632 | var contentHeight = this.outerCt.getHeight(),\r | |
633 | target = ownerContext.target;\r | |
634 | \r | |
635 | if (this.managePadding && (target[target.contentPaddingProperty] === undefined)) {\r | |
636 | // if padding was not configured using the appropriate contentPaddingProperty\r | |
637 | // then the padding will not be on the paddingContext, and therfore not included\r | |
638 | // in the outerCt measurement, so we need to read the padding from the\r | |
639 | // targetContext\r | |
640 | contentHeight += ownerContext.targetContext.getPaddingInfo().height;\r | |
641 | }\r | |
642 | return contentHeight;\r | |
643 | },\r | |
644 | \r | |
645 | measureContentWidth: function (ownerContext) {\r | |
646 | var dom, style, old, contentWidth, target;\r | |
647 | \r | |
648 | // In the newer Chrome versions, it won't measure the\r | |
649 | // width correctly without repainting the inner\r | |
650 | // cell in some circumstances.\r | |
651 | if (this.chromeCellMeasureBug) {\r | |
652 | dom = this.innerCt.dom;\r | |
653 | style = dom.style;\r | |
654 | old = style.display;\r | |
655 | \r | |
656 | if (old === 'table-cell') {\r | |
657 | style.display = '';\r | |
658 | dom.offsetWidth; // jshint ignore:line\r | |
659 | style.display = old;\r | |
660 | } \r | |
661 | }\r | |
662 | \r | |
663 | if (Ext.isSafari) {\r | |
664 | // EXTJS-12041: Safari needs a reflow of the outerCt to measure content width\r | |
665 | // correctly in some cases. The circumstances which make this happen are\r | |
666 | // very difficult to isolate, so we have to resort to always triggering a\r | |
667 | // reflow before measuring. We switch between table-cell and table in hopes\r | |
668 | // of minimizing the impact of the reflow on surrounding elements\r | |
669 | dom = this.outerCt.dom;\r | |
670 | style = dom.style;\r | |
671 | style.display = 'table-cell';\r | |
672 | dom.offsetWidth; // jshint ignore:line\r | |
673 | dom.style.display = '';\r | |
674 | }\r | |
675 | \r | |
676 | // contentWidth includes padding, but not border, framing or margins\r | |
677 | contentWidth = this.outerCt.getWidth();\r | |
678 | target = ownerContext.target;\r | |
679 | \r | |
680 | if (this.managePadding && (target[target.contentPaddingProperty] === undefined)) {\r | |
681 | // if padding was not configured using the appropriate contentPaddingProperty\r | |
682 | // then the padding will not be on the paddingContext, and therfore not included\r | |
683 | // in the outerCt measurement, so we need to read the padding from the\r | |
684 | // targetContext\r | |
685 | contentWidth += ownerContext.targetContext.getPaddingInfo().width;\r | |
686 | }\r | |
687 | return contentWidth;\r | |
688 | },\r | |
689 | \r | |
690 | /**\r | |
691 | * This method sets the height and/or width of the outerCt/innerCt to adjust for the\r | |
692 | * following browser-specific issues:\r | |
693 | * \r | |
694 | * 1. In some browsers a percentage-height element ignores the horizontal scrollbar\r | |
695 | * of its parent (see Ext.supports.PercentageHeightOverflowBug). If the browser is\r | |
696 | * affected by this bug the outerCt needs a pixel height in order to support\r | |
697 | * percentage-height children when not shrink-wrapping height. If the browser is not\r | |
698 | * affected by this bug, a height of 100% is assigned to the outerCt (see\r | |
699 | * beginLayoutCycle).\r | |
700 | * \r | |
701 | * 2. IE8 mode has a bug with percentage height children. if the innerCt has\r | |
702 | * a height of 100%, has padding, and has a child item with a percentage height, that\r | |
703 | * child item will be sized as a percentage of the parent's height plus padding height.\r | |
704 | * In other words, a child with height:50% would have its height caclulated thusly:\r | |
705 | * (parentHeight + parentPaddingHeight) * 0.5\r | |
706 | * To fix this, we have to give the innerCt a pixel height.\r | |
707 | * \r | |
708 | * @protected\r | |
709 | * @param {Ext.layout.ContextItem} ownerContext\r | |
710 | * @param {Object} containerSize\r | |
711 | */\r | |
712 | setCtSizeIfNeeded: function(ownerContext, containerSize) {\r | |
713 | var me = this,\r | |
714 | height = containerSize.height,\r | |
715 | padding = ownerContext.paddingContext.getPaddingInfo(),\r | |
716 | targetEl = me.getTarget(),\r | |
717 | overflowXStyle = me.getOverflowXStyle(ownerContext),\r | |
718 | canOverflowX = (overflowXStyle === 'auto' || overflowXStyle === 'scroll'),\r | |
719 | scrollbarSize = Ext.getScrollbarSize(),\r | |
720 | needsOuterHeight, needsInnerHeight;\r | |
721 | \r | |
722 | if (height && !ownerContext.heightModel.shrinkWrap) {\r | |
723 | if (Ext.supports.PercentageHeightOverflowBug) {\r | |
724 | // set a pixel height on the outerCt if the browser ignores horizontal\r | |
725 | // scrollbar when rendering percentage-height elements\r | |
726 | needsOuterHeight = true;\r | |
727 | }\r | |
728 | if (Ext.isIE8) {\r | |
729 | // When not shrink wrapping, we set a pixel height on the innerCt to\r | |
730 | // support percentage height children in IE8.\r | |
731 | needsInnerHeight = true;\r | |
732 | }\r | |
733 | \r | |
734 | if ((needsOuterHeight || needsInnerHeight) && canOverflowX && \r | |
735 | (targetEl.dom.scrollWidth > targetEl.dom.clientWidth)) {\r | |
736 | // adjust the height for scrollbar size since it's not accounted for\r | |
737 | // in the containerSize.\r | |
738 | // IE8 does not tolerate negative sizes\r | |
739 | height = Math.max(height - scrollbarSize.height, 0);\r | |
740 | }\r | |
741 | \r | |
742 | if (needsOuterHeight) {\r | |
743 | ownerContext.outerCtContext.setProp('height', height + padding.height);\r | |
744 | me.hasOuterCtPxHeight = true;\r | |
745 | }\r | |
746 | \r | |
747 | if (needsInnerHeight) {\r | |
748 | ownerContext.innerCtContext.setProp('height', height);\r | |
749 | me.hasInnerCtPxHeight = true;\r | |
750 | }\r | |
751 | }\r | |
752 | },\r | |
753 | \r | |
754 | setupRenderTpl: function (renderTpl) {\r | |
755 | this.callParent(arguments);\r | |
756 | \r | |
757 | renderTpl.renderPadding = this.doRenderPadding;\r | |
758 | },\r | |
759 | \r | |
760 | getContentTarget: function(){\r | |
761 | return this.innerCt;\r | |
762 | },\r | |
763 | \r | |
764 | getScrollerEl: function() {\r | |
765 | return this.outerCt;\r | |
766 | }\r | |
767 | \r | |
768 | }, function(){\r | |
769 | this.prototype.chromeCellMeasureBug = Ext.isChrome && Ext.chromeVersion >= 26;\r | |
770 | });\r |