PDA

View Full Version : [FIXED][3.1] vbox w. formpanel child layout bug



ExtMore
21 Dec 2009, 8:28 AM
Ext version tested:


Ext 3.1.0 w. no overrides



Adapter used:


ext



css used:


only default ext-all.css





Browser versions tested against:


IE8 v. 8.0.6001.18865
FF 3.5.6 (firebug 1.4.5installed)
Safari 4.0.4
Opera 9.64



Operating System:


Windows Vista



Description:


I have a form panel in a vbox layout. When the page loads the form panel is laid out incorrectly. When resizing the browser window the vbox children are laid out correctly. See attached screen shots.



Test Case:



<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title id='title'>vbox problem</title>

<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

<!-- overrides to base library -->


<!-- ** Javascript ** -->
<!-- base library -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>


<!-- overrides to base library -->

<!-- extensions -->

<!-- page specific -->

<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';

Ext.onReady(function() {
new Ext.Viewport({
layout: "vbox",
layoutConfig: { align: "stretch" },
items: [
{
layout: 'form',
title: "Top",
frame: true,
labelWidth: 70,
defaults: { anchor: "100%" },
defaultType: 'textfield',
items: [{fieldLabel: "field"}, {fieldLabel: "field"}, {fieldLabel: "field"},
{fieldLabel: "field"}, {fieldLabel: "field"}, {fieldLabel: "field"}]
},
{
title: "Bottom",
flex: 1
}
]
});
});
</script>
</head>
<body>
</body>
</html>
Steps to reproduce the problem:


Save the test case in a subdirectory under the SDK examples directory. Then load the page. Then resize the browser window.



The result that was expected:


Second screenshot (vbox-problem-after-resize.jpg)



The result that occurs instead:


First screenshot (vbox-problem-before-resize.jpg)



Screenshot or Video:


attached



Debugging already done:


none



Possible fix:


not provided

realjax
22 Dec 2009, 2:12 AM
Same problem here with 3.1
Workaround in my case was to set a height on the form, this was not needed for 3.0.3.

rblon
22 Dec 2009, 2:34 AM
I have the same problem, see this thread (http://www.extjs.com/forum/showthread.php?t=88316). The workaround suggested by realjax "solves" it.

ExtMore
22 Dec 2009, 2:37 AM
Same problem here with 3.1
Workaround in my case was to set a height on the form, this was not needed for 3.0.3.

True, it is new behaviour. It seems the layout optimization done in 3.1 is a bit too aggressive.

Also, another workaround is to give the ViewPort an id, say "myviewport", and then call doLayout() after the "new Ext.ViewPort(...)", like this:



Ext.getCmp('myviewport').doLayout(false, true);

meroy
24 Dec 2009, 3:07 AM
I was going through @Animal's first layout 2.0 code (zip #11 from when I did QA at the time) and saw that this was working. The following is what makes this work with 3.1


0500
diff -ru svn.ext-5819/src/widgets/layout/BoxLayout.js svn.ext-5819-c/src/widgets/layout/BoxLayout.js
--- svn.ext-5819/src/widgets/layout/BoxLayout.js 2009-12-22 03:42:34.000000000 -
+++ svn.ext-5819-c/src/widgets/layout/BoxLayout.js 2009-12-24 05:52:00.000000000 -0500
@@ -228,6 +228,12 @@
c = cs[i];
cm = c.margins;
totalFlex += c.flex || 0;
+
+ // autoHeight Containers must be fully laid out to acquire a height
+ if (c.doLayout && !c.height && !c.hasLayout) {
+ c.doLayout();
+ }
+
ch = c.getHeight();
margin = cm.top + cm.bottom;
extraHeight += ch + margin;
@@ -347,6 +353,12 @@
Ext.each(cs, function(c){
cm = c.margins;
totalFlex += c.flex || 0;
+
+ // autoWidth Containers must be fully laid out to acquire a width
+ if (c.doLayout && !c.width && !c.hasLayout) {
+ c.doLayout();
+ }
+
cw = c.getWidth();
margin = cm.left + cm.right;
extraWidth += cw + margin;

ExtMore
24 Dec 2009, 4:35 AM
I was going through @Animal's first layout 2.0 code (zip #11 from when I did QA at the time) and saw that this was working. The following is what makes this work with 3.1


I can verify that the patch fixes the test case and some of the issues I have in my application after upgrading to 3.1. Thanks for pointing this out!

I still have a problem with a (deeply nested) formpanel not showing at all before a browser window resize. But that's probably another (but related) problem. I'll cook up a minimal test case for that.

But now it's CHRISTMAS!

Merry Christmas to all in this wonderful community! :)

Animal
24 Dec 2009, 4:58 AM
Add the red bit:



// Do height calculations
for (i = 0 ; i < csLen; i++) {
c = cs[i];
cm = c.margins;
totalFlex += c.flex || 0;

// autoHeight Containers must be fully laid out to acquire a height
if (c.doLayout && !c.height && !c.hasLayout) {
c.doLayout();
}

ch = c.getHeight();
margin = cm.top + cm.bottom;
extraHeight += ch + margin;
flexHeight += margin + (c.flex ? 0 : ch);
}
...

meroy
24 Dec 2009, 5:06 AM
Add the red bit:


It's there. I will highlight the bits in red. You have more surrounding code to help make it obvious on where to add this in BoxLayout.js. This will help some folks out there. Thanks.

rblon
30 Dec 2009, 1:07 AM
thanks for this fix - or at least I hope it will work as I am not sure how to apply it...
Currently I am only using ext-base(-debug).js and ext-all(-debug).js. I guess I would need to change BoxLayout.js and then run JSBuilder2? Would it also be possible using an override? What would be the override code?

Condor
30 Dec 2009, 1:52 AM
As an override:

Ext.override(Ext.layout.VBoxLayout, {
onLayout : function(ct, target){
Ext.layout.VBoxLayout.superclass.onLayout.call(this, ct, target);
var cs = this.getItems(ct), cm, ch, margin, cl, diff, aw,
size = target.getViewSize(true),
w = size.width,
h = size.height - this.scrollOffset,
l = this.padding.left, t = this.padding.top,
isStart = this.pack == 'start',
stretchWidth = w - (this.padding.left + this.padding.right),
extraHeight = 0,
maxWidth = 0,
totalFlex = 0,
flexHeight = 0,
usedHeight = 0,
idx = 0,
heights = [],
restore = [],
c,
csLen = cs.length, i;
for (i = 0 ; i < csLen; i++) {
c = cs[i];
cm = c.margins;
margin = cm.top + cm.bottom;
maxWidth = Math.max(maxWidth, c.getWidth() + cm.left + cm.right);
}
var innerCtWidth = maxWidth + this.padding.left + this.padding.right;
switch(this.align){
case 'stretch':
this.innerCt.setSize(w, h);
break;
case 'stretchmax':
case 'left':
this.innerCt.setSize(innerCtWidth, h);
break;
case 'center':
this.innerCt.setSize(w = Math.max(w, innerCtWidth), h);
break;
}
var availableWidth = Math.max(0, w - this.padding.left - this.padding.right);
for (i = 0 ; i < csLen; i++) {
c = cs[i];
cm = c.margins;
if(this.align == 'stretch'){
c.setWidth((stretchWidth - (cm.left + cm.right)).constrain(
c.minWidth || 0, c.maxWidth || 1000000));
}else if(this.align == 'stretchmax'){
c.setWidth((maxWidth - (cm.left + cm.right)).constrain(
c.minWidth || 0, c.maxWidth || 1000000));
}else if(isStart && c.flex){
c.setWidth();
}
}
for (i = 0 ; i < csLen; i++) {
c = cs[i];
cm = c.margins;
totalFlex += c.flex || 0;
if (c.doLayout && !c.height && !c.hasLayout) {
c.doLayout();
}
ch = c.getHeight();
margin = cm.top + cm.bottom;
extraHeight += ch + margin;
flexHeight += margin + (c.flex ? 0 : ch);
}
extraHeight = h - extraHeight - this.padding.top - this.padding.bottom;
var availHeight = Math.max(0, h - this.padding.top - this.padding.bottom - flexHeight),
leftOver = availHeight;
for (i = 0 ; i < csLen; i++) {
c = cs[i];
if(isStart && c.flex){
ch = Math.floor(availHeight * (c.flex / totalFlex));
leftOver -= ch;
heights.push(ch);
}
}
if(this.pack == 'center'){
t += extraHeight ? extraHeight / 2 : 0;
}else if(this.pack == 'end'){
t += extraHeight;
}
idx = 0;
for (i = 0 ; i < csLen; i++) {
c = cs[i];
cm = c.margins;
t += cm.top;
aw = availableWidth;
cl = l + cm.left
if(this.align == 'center'){
if((diff = availableWidth - (c.getWidth() + cm.left + cm.right)) > 0){
cl += (diff/2);
aw -= diff;
}
}
c.setPosition(cl, t);
if(isStart && c.flex){
ch = Math.max(0, heights[idx++] + (leftOver-- > 0 ? 1 : 0));
c.setSize(aw, ch);
}else{
ch = c.getHeight();
}
t += ch + cm.bottom;
}
}
});
Ext.override(Ext.layout.HBoxLayout, {
onLayout : function(ct, target){
Ext.layout.HBoxLayout.superclass.onLayout.call(this, ct, target);
var cs = this.getItems(ct), cm, cw, margin, ch, diff,
size = target.getViewSize(true),
w = size.width - this.scrollOffset,
h = size.height,
l = this.padding.left, t = this.padding.top,
isStart = this.pack == 'start',
isRestore = ['stretch', 'stretchmax'].indexOf(this.align) == -1,
stretchHeight = h - (this.padding.top + this.padding.bottom),
extraWidth = 0,
maxHeight = 0,
totalFlex = 0,
flexWidth = 0,
usedWidth = 0;
Ext.each(cs, function(c){
cm = c.margins;
totalFlex += c.flex || 0;
if (c.doLayout && !c.height && !c.hasLayout) {
c.doLayout();
}
cw = c.getWidth();
margin = cm.left + cm.right;
extraWidth += cw + margin;
flexWidth += margin + (c.flex ? 0 : cw);
maxHeight = Math.max(maxHeight, c.getHeight() + cm.top + cm.bottom);
});
extraWidth = w - extraWidth - this.padding.left - this.padding.right;
var innerCtHeight = maxHeight + this.padding.top + this.padding.bottom;
switch(this.align){
case 'stretch':
this.innerCt.setSize(w, h);
break;
case 'stretchmax':
case 'top':
this.innerCt.setSize(w, innerCtHeight);
break;
case 'middle':
this.innerCt.setSize(w, h = Math.max(h, innerCtHeight));
break;
}
var availWidth = Math.max(0, w - this.padding.left - this.padding.right - flexWidth),
leftOver = availWidth,
widths = [],
restore = [],
idx = 0,
availableHeight = Math.max(0, h - this.padding.top - this.padding.bottom);
Ext.each(cs, function(c){
if(isStart && c.flex){
cw = Math.floor(availWidth * (c.flex / totalFlex));
leftOver -= cw;
widths.push(cw);
}
});
if(this.pack == 'center'){
l += extraWidth ? extraWidth / 2 : 0;
}else if(this.pack == 'end'){
l += extraWidth;
}
Ext.each(cs, function(c){
cm = c.margins;
l += cm.left;
c.setPosition(l, t + cm.top);
if(isStart && c.flex){
cw = Math.max(0, widths[idx++] + (leftOver-- > 0 ? 1 : 0));
if(isRestore){
restore.push(c.getHeight());
}
c.setSize(cw, availableHeight);
}else{
cw = c.getWidth();
}
l += cw + cm.right;
});
idx = 0;
Ext.each(cs, function(c){
cm = c.margins;
ch = c.getHeight();
if(isStart && c.flex){
ch = restore[idx++];
}
if(this.align == 'stretch'){
c.setHeight((stretchHeight - (cm.top + cm.bottom)).constrain(
c.minHeight || 0, c.maxHeight || 1000000));
}else if(this.align == 'stretchmax'){
c.setHeight((maxHeight - (cm.top + cm.bottom)).constrain(
c.minHeight || 0, c.maxHeight || 1000000));
}else{
if(this.align == 'middle'){
diff = availableHeight - (ch + cm.top + cm.bottom);
ch = t + cm.top + (diff/2);
if(diff > 0){
c.setPosition(c.x, ch);
}
}
if(isStart && c.flex){
c.setHeight(ch);
}
}
}, this);
}
});

rblon
30 Dec 2009, 2:25 AM
thx vm Condor - the override works for me

marcing
4 Jan 2010, 10:58 AM
Hi Condor,

I attached a scenario where override is ineffective:

http://www.extjs.com/forum/showthread.php?p=424089

Cheers,
Marcin

mbajema
19 Jan 2010, 8:51 AM
I still have a problem with a (deeply nested) formpanel not showing at all before a browser window resize. But that's probably another (but related) problem. I'll cook up a minimal test case for that.


Hey ExtMore,

Did you ever find a solution to the second problem you noted? I'm not finding a new test case in the forums. I'm having the same problem.

Thanks.

Jamie Avins
19 Jan 2010, 10:14 AM
Fixed in 3.1.1 beta.

ExtMore
20 Jan 2010, 11:24 AM
Hey ExtMore,

Did you ever find a solution to the second problem you noted? I'm not finding a new test case in the forums. I'm having the same problem.

Thanks.

No test case -- I am afraid that Christmas took focus there.. :)

But I seem to remember that there were some layout related overrides floating around in the forum, and one of them fixed my issue.

I am now running on 3.1.1-beta with no overrides, and the problem has been solved. Are you on 3.1.1-beta?

So far I am quite happy with 3.1.1-beta.