]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/layout/component/Component.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / layout / component / Component.js
CommitLineData
6527f429
DM
1/**\r
2 * This class is intended to be extended or created via the {@link Ext.Component#componentLayout layout}\r
3 * configuration property. See {@link Ext.Component#componentLayout} for additional details.\r
4 * @private\r
5 */\r
6Ext.define('Ext.layout.component.Component', {\r
7 extend: 'Ext.layout.Layout',\r
8\r
9 type: 'component',\r
10\r
11 isComponentLayout: true,\r
12\r
13 nullBox: {},\r
14\r
15 usesContentHeight: true,\r
16 usesContentWidth: true,\r
17 usesHeight: true,\r
18 usesWidth: true,\r
19\r
20 widthCache: {},\r
21 heightCache: {},\r
22\r
23 beginLayoutCycle: function (ownerContext, firstCycle) {\r
24 var me = this,\r
25 owner = me.owner,\r
26 ownerCtContext = ownerContext.ownerCtContext,\r
27 heightModel = ownerContext.heightModel,\r
28 widthModel = ownerContext.widthModel,\r
29 body = owner.el.dom === document.body,\r
30 lastBox = owner.lastBox || me.nullBox,\r
31 lastSize = owner.el.lastBox || me.nullBox,\r
32 dirty = !body,\r
33 isTopLevel = ownerContext.isTopLevel,\r
34 ownerLayout, v, width, height;\r
35\r
36 me.callParent([ownerContext, firstCycle]);\r
37\r
38 if (firstCycle) {\r
39 if (me.usesContentWidth) {\r
40 ++ownerContext.consumersContentWidth;\r
41 }\r
42 if (me.usesContentHeight) {\r
43 ++ownerContext.consumersContentHeight;\r
44 }\r
45 if (me.usesWidth) {\r
46 ++ownerContext.consumersWidth;\r
47 }\r
48 if (me.usesHeight) {\r
49 ++ownerContext.consumersHeight;\r
50 }\r
51\r
52 if (ownerCtContext && !ownerCtContext.hasRawContent) {\r
53 ownerLayout = owner.ownerLayout;\r
54\r
55 if (ownerLayout) {\r
56 if (ownerLayout.usesWidth) {\r
57 ++ownerContext.consumersWidth;\r
58 }\r
59 if (ownerLayout.usesHeight) {\r
60 ++ownerContext.consumersHeight;\r
61 }\r
62 }\r
63 }\r
64 }\r
65\r
66 // we want to publish configured dimensions as early as possible and since this is\r
67 // a write phase...\r
68\r
69 if (widthModel.configured) {\r
70 // If the owner.el is the body, owner.width is not dirty (we don't want to write\r
71 // it to the body el). For other el's, the width may already be correct in the\r
72 // DOM (e.g., it is rendered in the markup initially). If the width is not\r
73 // correct in the DOM, this is only going to be the case on the first cycle.\r
74 width = owner[widthModel.names.width];\r
75 if (isTopLevel && widthModel.calculatedFrom) {\r
76 width = lastBox.width;\r
77 }\r
78\r
79 if (!body) {\r
80 dirty = me.setWidthInDom ||\r
81 (firstCycle ? width !== lastSize.width : widthModel.constrained);\r
82 }\r
83\r
84 \r
85 ownerContext.setWidth(width, dirty);\r
86 } else if (isTopLevel) {\r
87 if (widthModel.calculated) {\r
88 v = lastBox.width;\r
89 ownerContext.setWidth(v, /*dirty=*/v !== lastSize.width);\r
90 }\r
91\r
92 v = lastBox.x;\r
93 ownerContext.setProp('x', v, /*dirty=*/v !== lastSize.x);\r
94 }\r
95\r
96 if (heightModel.configured) {\r
97 height = owner[heightModel.names.height];\r
98 if (isTopLevel && heightModel.calculatedFrom) {\r
99 height = lastBox.height;\r
100 }\r
101\r
102 if (!body) {\r
103 dirty = firstCycle ? height !== lastSize.height\r
104 : heightModel.constrained;\r
105 }\r
106\r
107 ownerContext.setHeight(height, dirty);\r
108 } else if (isTopLevel) {\r
109 if (heightModel.calculated) {\r
110 v = lastBox.height;\r
111 ownerContext.setHeight(v, v !== lastSize.height);\r
112 }\r
113\r
114 v = lastBox.y;\r
115 ownerContext.setProp('y', v, /*dirty=*/v !== lastSize.y);\r
116 }\r
117 },\r
118\r
119 finishedLayout: function(ownerContext) {\r
120 var me = this,\r
121 elementChildren = ownerContext.children,\r
122 owner = me.owner,\r
123 len, i, elContext, lastBox, props;\r
124\r
125 // NOTE: In the code below we cannot use getProp because that will generate a layout dependency\r
126\r
127 // Set lastBox on managed child Elements.\r
128 // So that ContextItem.constructor can snag the lastBox for use by its undo method.\r
129 if (elementChildren) {\r
130 len = elementChildren.length;\r
131 for (i = 0; i < len; i++) {\r
132 elContext = elementChildren[i];\r
133 elContext.el.lastBox = elContext.props;\r
134 }\r
135 }\r
136\r
137 // Cache the size from which we are changing so that notifyOwner can notify the owningComponent with all essential information\r
138 ownerContext.previousSize = me.lastComponentSize;\r
139\r
140 // Cache the currently layed out size\r
141 me.lastComponentSize = owner.el.lastBox = props = ownerContext.props;\r
142 \r
143 // lastBox is a copy of the defined props to allow save/restore of these (panel\r
144 // collapse needs this)\r
145 lastBox = owner.lastBox || (owner.lastBox = {});\r
146 lastBox.x = props.x;\r
147 lastBox.y = props.y;\r
148 lastBox.width = props.width;\r
149 lastBox.height = props.height;\r
150 lastBox.invalid = false;\r
151 \r
152 me.callParent([ownerContext]);\r
153 },\r
154 \r
155 notifyOwner: function(ownerContext) {\r
156 var me = this,\r
157 currentSize = me.lastComponentSize,\r
158 prevSize = ownerContext.previousSize;\r
159\r
160 me.owner.afterComponentLayout(currentSize.width, currentSize.height, \r
161 prevSize ? prevSize.width : undefined, prevSize ? prevSize.height : undefined);\r
162 },\r
163\r
164 /**\r
165 * Returns the owner component's resize element.\r
166 * @return {Ext.dom.Element}\r
167 */\r
168 getTarget : function() {\r
169 return this.owner.el;\r
170 },\r
171\r
172 /**\r
173 * Returns the element into which rendering must take place. Defaults to the owner Component's encapsulating element.\r
174 *\r
175 * May be overridden in Component layout managers which implement an inner element.\r
176 * @return {Ext.dom.Element}\r
177 */\r
178 getRenderTarget : function() {\r
179 return this.owner.el;\r
180 },\r
181\r
182 cacheTargetInfo: function(ownerContext) {\r
183 var me = this,\r
184 targetInfo = me.targetInfo,\r
185 target;\r
186\r
187 if (!targetInfo) {\r
188 target = ownerContext.getEl('getTarget', me);\r
189\r
190 me.targetInfo = targetInfo = {\r
191 padding: target.getPaddingInfo(),\r
192 border: target.getBorderInfo()\r
193 };\r
194 }\r
195\r
196 return targetInfo;\r
197 },\r
198\r
199 measureAutoDimensions: function (ownerContext, dimensions) {\r
200 // Subtle But Important:\r
201 // \r
202 // We don't want to call getProp/hasProp et.al. unless we in fact need that value\r
203 // for our results! If we call it and don't need it, the layout manager will think\r
204 // we depend on it and will schedule us again should it change.\r
205\r
206 var me = this,\r
207 owner = me.owner,\r
208 containerLayout = owner.layout,\r
209 heightModel = ownerContext.heightModel,\r
210 widthModel = ownerContext.widthModel,\r
211 boxParent = ownerContext.boxParent,\r
212 isBoxParent = ownerContext.isBoxParent,\r
213 target = ownerContext.target,\r
214 props = ownerContext.props,\r
215 isContainer,\r
216 ret = {\r
217 gotWidth: false,\r
218 gotHeight: false,\r
219 isContainer: (isContainer = !ownerContext.hasRawContent)\r
220 },\r
221 hv = dimensions || 3,\r
222 zeroWidth, zeroHeight,\r
223 needed = 0,\r
224 got = 0,\r
225 ready, size, temp, key, cache;\r
226\r
227 // Note: this method is called *a lot*, so we have to be careful not to waste any\r
228 // time or make useless calls or, especially, read the DOM when we can avoid it.\r
229\r
230 //---------------------------------------------------------------------\r
231 // Width\r
232\r
233 if (widthModel.shrinkWrap && ownerContext.consumersContentWidth) {\r
234 ++needed;\r
235 zeroWidth = !(hv & 1); // jshint ignore:line\r
236\r
237 if (isContainer) {\r
238 // as a componentLayout for a container, we rely on the container layout to\r
239 // produce contentWidth...\r
240 if (zeroWidth) {\r
241 ret.contentWidth = 0;\r
242 ret.gotWidth = true;\r
243 ++got;\r
244 } else if ((ret.contentWidth = ownerContext.getProp('contentWidth')) !== undefined) {\r
245 ret.gotWidth = true;\r
246 ++got;\r
247 }\r
248 } else {\r
249 size = props.contentWidth;\r
250\r
251 if (typeof size === 'number') { // if (already determined)\r
252 ret.contentWidth = size;\r
253 ret.gotWidth = true;\r
254 ++got;\r
255 } else {\r
256 if (zeroWidth) {\r
257 ready = true;\r
258 } else if (!ownerContext.hasDomProp('containerChildrenSizeDone')) {\r
259 ready = false;\r
260 } else if (isBoxParent || !boxParent || boxParent.widthModel.shrinkWrap) {\r
261 // if we have no boxParent, we are ready, but a shrinkWrap boxParent\r
262 // artificially provides width early in the measurement process so\r
263 // we are ready to go in that case as well...\r
264 ready = true;\r
265 } else {\r
266 // lastly, we have a boxParent that will be given a width, so we\r
267 // can wait for that width to be set in order to properly measure\r
268 // whatever is inside...\r
269 ready = boxParent.hasDomProp('width');\r
270 }\r
271\r
272 if (ready) {\r
273 if (zeroWidth) {\r
274 temp = 0;\r
275 } else if (containerLayout && containerLayout.measureContentWidth) {\r
276 // Allow the container layout to do the measurement since it\r
277 // may have a better idea of how to do it even with no items:\r
278 temp = containerLayout.measureContentWidth(ownerContext);\r
279 } else {\r
280 if (target.cacheWidth) {\r
281 // if all instances of a given xtype/UI are the same size, only read the DOM once\r
282 // to measure the first instance. Thereafter, retrieve the width from the cache.\r
283 key = target.xtype + '-' + target.ui;\r
284 cache = me.widthCache;\r
285 temp = cache[key] || (cache[key] = me.measureContentWidth(ownerContext));\r
286 } else {\r
287 temp = me.measureContentWidth(ownerContext);\r
288 }\r
289 }\r
290\r
291 if (!isNaN(ret.contentWidth = temp)) {\r
292 ownerContext.setContentWidth(temp, true);\r
293 ret.gotWidth = true;\r
294 ++got;\r
295 }\r
296 }\r
297 }\r
298 }\r
299 } else if (widthModel.natural && ownerContext.consumersWidth) {\r
300 ++needed;\r
301 size = props.width;\r
302 // zeroWidth does not apply\r
303\r
304 if (typeof size === 'number') { // if (already determined)\r
305 ret.width = size;\r
306 ret.gotWidth = true;\r
307 ++got;\r
308 } else {\r
309 if (isBoxParent || !boxParent) {\r
310 ready = true;\r
311 } else {\r
312 // lastly, we have a boxParent that will be given a width, so we\r
313 // can wait for that width to be set in order to properly measure\r
314 // whatever is inside...\r
315 ready = boxParent.hasDomProp('width');\r
316 }\r
317\r
318 if (ready) {\r
319 if (!isNaN(ret.width = me.measureOwnerWidth(ownerContext))) {\r
320 ownerContext.setWidth(ret.width, false);\r
321 ret.gotWidth = true;\r
322 ++got;\r
323 }\r
324 }\r
325 }\r
326 }\r
327\r
328 //---------------------------------------------------------------------\r
329 // Height\r
330\r
331 if (heightModel.shrinkWrap && ownerContext.consumersContentHeight) {\r
332 ++needed;\r
333 zeroHeight = !(hv & 2); // jshint ignore:line\r
334\r
335 if (isContainer) {\r
336 // don't ask unless we need to know...\r
337 if (zeroHeight) {\r
338 ret.contentHeight = 0;\r
339 ret.gotHeight = true;\r
340 ++got;\r
341 } else if ((ret.contentHeight = ownerContext.getProp('contentHeight')) !== undefined) {\r
342 ret.gotHeight = true;\r
343 ++got;\r
344 }\r
345 } else {\r
346 size = props.contentHeight;\r
347\r
348 if (typeof size === 'number') { // if (already determined)\r
349 ret.contentHeight = size;\r
350 ret.gotHeight = true;\r
351 ++got;\r
352 } else {\r
353 if (zeroHeight) {\r
354 ready = true;\r
355 } else if (!ownerContext.hasDomProp('containerChildrenSizeDone')) {\r
356 ready = false;\r
357 } else if (owner.noWrap) {\r
358 ready = true;\r
359 } else if (!widthModel.shrinkWrap) {\r
360 // fixed width, so we need the width to determine the height...\r
361 ready = (ownerContext.bodyContext || ownerContext).hasDomProp('width');// && (!ownerContext.bodyContext || ownerContext.bodyContext.hasDomProp('width'));\r
362 } else if (isBoxParent || !boxParent || boxParent.widthModel.shrinkWrap) {\r
363 // if we have no boxParent, we are ready, but an autoWidth boxParent\r
364 // artificially provides width early in the measurement process so\r
365 // we are ready to go in that case as well...\r
366 ready = true;\r
367 } else {\r
368 // lastly, we have a boxParent that will be given a width, so we\r
369 // can wait for that width to be set in order to properly measure\r
370 // whatever is inside...\r
371 ready = boxParent.hasDomProp('width');\r
372 }\r
373\r
374 if (ready) {\r
375 if (zeroHeight) {\r
376 temp = 0;\r
377 } else if (containerLayout && containerLayout.measureContentHeight) {\r
378 // Allow the container layout to do the measurement since it\r
379 // may have a better idea of how to do it even with no items:\r
380 temp = containerLayout.measureContentHeight(ownerContext);\r
381 } else {\r
382 if (target.cacheHeight) {\r
383 // if all instances of a given xtype/UI are the same size, only read the DOM once\r
384 // to measure the first instance. Thereafter, retrieve the height from the cache.\r
385 key = target.xtype + '-' + target.ui;\r
386 cache = me.heightCache;\r
387 temp = cache[key] || (cache[key] = me.measureContentHeight(ownerContext));\r
388 } else {\r
389 temp = me.measureContentHeight(ownerContext);\r
390 }\r
391 }\r
392\r
393 if (!isNaN(ret.contentHeight = temp)) {\r
394 ownerContext.setContentHeight(temp, true);\r
395 ret.gotHeight = true;\r
396 ++got;\r
397 }\r
398 }\r
399 }\r
400 }\r
401 } else if (heightModel.natural && ownerContext.consumersHeight) {\r
402 ++needed;\r
403 size = props.height;\r
404 // zeroHeight does not apply\r
405\r
406 if (typeof size === 'number') { // if (already determined)\r
407 ret.height = size;\r
408 ret.gotHeight = true;\r
409 ++got;\r
410 } else {\r
411 if (isBoxParent || !boxParent) {\r
412 ready = true;\r
413 } else {\r
414 // lastly, we have a boxParent that will be given a width, so we\r
415 // can wait for that width to be set in order to properly measure\r
416 // whatever is inside...\r
417 ready = boxParent.hasDomProp('width');\r
418 }\r
419\r
420 if (ready) {\r
421 if (!isNaN(ret.height = me.measureOwnerHeight(ownerContext))) {\r
422 ownerContext.setHeight(ret.height, false);\r
423 ret.gotHeight = true;\r
424 ++got;\r
425 }\r
426 }\r
427 }\r
428 }\r
429\r
430 if (boxParent) {\r
431 ownerContext.onBoxMeasured();\r
432 }\r
433\r
434 ret.gotAll = got === needed;\r
435 // see if we can avoid calling this method by storing something on ownerContext.\r
436 return ret;\r
437 },\r
438\r
439 measureContentWidth: function (ownerContext) {\r
440 // contentWidth includes padding, but not border, framing or margins\r
441 return ownerContext.el.getWidth() - ownerContext.getFrameInfo().width;\r
442 },\r
443\r
444 measureContentHeight: function (ownerContext) {\r
445 // contentHeight includes padding, but not border, framing or margins\r
446 return ownerContext.el.getHeight() - ownerContext.getFrameInfo().height;\r
447 },\r
448\r
449 measureOwnerHeight: function (ownerContext) {\r
450 return ownerContext.el.getHeight();\r
451 },\r
452\r
453 measureOwnerWidth: function (ownerContext) {\r
454 return ownerContext.el.getWidth();\r
455 }\r
456});\r