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