PDA

View Full Version : [FIXED-r5761][3.x] Nested hbox in borderlayout does not set child container height



jay@moduscreate.com
9 Dec 2009, 5:59 AM
Fx 3.5 for OS X & Windows (see below)

With this example, the first of the hbox children is being set to 70px high, instead of 130, which is what the panel that uses the hbox layout is configured for.

This *was* working before, but is no longer.


Ext.onReady(function() {
var leftHalf = {
xtype : 'container',
layout : 'form',
flex : 1,
labelWidth : 60,
defaultType : 'textfield',
defaults : { anchor: '-10' },
items : [
{
xtype : 'hidden',
name : 'id'
},
{
fieldLabel : 'Name',
name : 'name',
allowBLank : false,
maxLength : 255
},
{
xtype : 'datefield',
fieldLabel : 'Activated',
name : 'dateActive'
},
{
fieldLabel : 'Other Field'
},
{
fieldLabel : 'Other Field'
},
{
fieldLabel : 'Other Field'
}
]
};

var rightHalf = {
xtype : 'container',
title : 'Description',
flex : 1,
layout : 'form',
labelWidth : 70,
items : {
xtype : 'textarea',
fieldLabel : 'Description',
name : 'description',
anchor : '100% 100%'
}
} ;

var northRegion = {
layout : 'hbox',
region : 'north',
height : 130,
bodyStyle : 'background-color: #DFE8F6; padding: 10px',
layoutConfig : { align : 'stretch' },
border : false,
items : [
leftHalf,
rightHalf
]
};


new Ext.Viewport ({
layout : 'fit',
items : {
layout : 'border',
items : [
northRegion,
{
region : 'center',
style : 'padding: 10px;',
html : 'Center region'
}

]
}
})

});





http://extjsinaction.com/tmp/screenshot.tmp.jpg

in windows too
http://extjsinaction.com/tmp/extia.windows.jpg

Much more complex layout (in the Ext JS in action application):

http://extjsinaction.com/tmp/extia.tmp.jpg

BlueCamel
9 Dec 2009, 6:24 AM
I've seen this too. FF 3.5.5 on Linux.

Animal
9 Dec 2009, 6:37 AM
It's a bug in getViewSize which I've been working on. It's not quite right there. It should not subtract padding if it finds a valid dimension value from getStyle(). I'm subracting padding (10px top and bottom) where it has already been done.

I will work out a fix, and PM Jamie with it.

jay@moduscreate.com
9 Dec 2009, 6:42 AM
Interesting. I wonder why things worked, and nolonger do so. :(

Testing testing testing :)

Animal
9 Dec 2009, 6:47 AM
And BoxLayout does this again!

We need to make it more consistent.

getViewSize returns the content area within the padding. That's the theory.

Perhaps there should be two modes. A second parameter, contentBox could be true to indicate within the padding, or false to mean just within the border.

And the layouts need to be clear on what they are asking for.

Animal
9 Dec 2009, 7:00 AM
This will work in that example:



Ext.override(Ext.Element, {
/**
* <p>Returns the dimensions of the element available to lay content out in.<p>
* <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
* example:<pre><code>
var vpSize = Ext.getBody().getViewSize();

// all Windows created afterwards will have a default value of 90% height and 95% width
Ext.Window.override({
width: vpSize.width * 0.9,
height: vpSize.height * 0.95
});
// To handle window resizing you would have to hook onto onWindowResize.
</code></pre>
* @param {Boolean} contentBox True to return the W3 content box <i>within</i> the padding area of the element. False
* or omitted to return the full area of the element within the border. See <a href="http://www.w3.org/TR/CSS2/box.html">http://www.w3.org/TR/CSS2/box.html</a>
* @return {Object} An object containing the elements's area: <code>{width: &lt;element width>, height: &lt;element height>}</code>
*/
getViewSize : function(contentBox){
var doc = document,
me = this,
d = me.dom,
extdom = Ext.lib.Dom,
isBB, w, h, tbBorder = 0, lrBorder = 0,
tbPadding = 0, lrPadding = 0;
if (d == doc || d == doc.body) {
return { width: extdom.getViewWidth(), height: extdom.getViewHeight() };
}
isBB = me.isBorderBox();
tbBorder = me.getBorderWidth('tb');
lrBorder = me.getBorderWidth('lr');
tbPadding = me.getPadding('tb');
lrPadding = me.getPadding('lr');

// Width calcs
// Try the style first, then clientWidth, then offsetWidth
if (w = me.getStyle('width').match(/(\d+)px/)){
if ((w = parseInt(w[1], 10)) && isBB){
// Style includes the padding and border if isBB
w -= (lrBorder + lrPadding);
}
contentBox || (w += lrPadding);
} else {
if (!(w = d.clientWidth) && (w = d.offsetWidth)){
// offsetWidth includes any border
w -= lrBorder;
}
if (w && contentBox) w -= lrPadding;
}

// Height calcs
// Try the style first, then clientHeight, then offsetHeight
if (h = me.getStyle('height').match(/(\d+)px/)){
if ((h = parseInt(h[1], 10)) && isBB){
// Style includes the padding and border if isBB
h -= (tbBorder + tbPadding);
}
contentBox || (h += tbPadding);
} else {
if (!(h = d.clientHeight) && (h = d.offsetHeight)){
// offsetHeight includes any border
h -= tbBorder;
}
if (h && contentBox) h -= tbPadding;
}

return {
width : w,
height : h
};
}
});


We need to implement that, and then check all usage of getViewSize, and see whether the layout is requiring the full element dimensions of just the content box.

Animal
9 Dec 2009, 7:43 AM
This will illustrate your required layout fully working (without the overnest ;) )

Drop this into examples/layout



<html>
<head>
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base-debug.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript">
Ext.override(Ext.Element, {
/**
* <p>Returns the dimensions of the element available to lay content out in.<p>
* <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
* example:<pre><code>
var vpSize = Ext.getBody().getViewSize();

// all Windows created afterwards will have a default value of 90% height and 95% width
Ext.Window.override({
width: vpSize.width * 0.9,
height: vpSize.height * 0.95
});
// To handle window resizing you would have to hook onto onWindowResize.
</code></pre>
* @param {Boolean} contentBox True to return the W3 content box <i>within</i> the padding area of the element. False
* or omitted to return the full area of the element within the border. See <a href="http://www.w3.org/TR/CSS2/box.html">http://www.w3.org/TR/CSS2/box.html</a>
* @return {Object} An object containing the elements's area: <code>{width: &lt;element width>, height: &lt;element height>}</code>
*/
getViewSize : function(contentBox){
var doc = document,
me = this,
d = me.dom,
extdom = Ext.lib.Dom,
isBB, w, h, tbBorder = 0, lrBorder = 0,
tbPadding = 0, lrPadding = 0;
if (d == doc || d == doc.body) {
return { width: extdom.getViewWidth(), height: extdom.getViewHeight() };
}
isBB = me.isBorderBox();
tbBorder = me.getBorderWidth('tb');
lrBorder = me.getBorderWidth('lr');
tbPadding = me.getPadding('tb');
lrPadding = me.getPadding('lr');

// Width calcs
// Try the style first, then clientWidth, then offsetWidth
if (w = me.getStyle('width').match(/(\d+)px/)){
if ((w = parseInt(w[1], 10)) && isBB){
// Style includes the padding and border if isBB
w -= (lrBorder + lrPadding);
}
contentBox || (w += lrPadding);
} else {
if (!(w = d.clientWidth) && (w = d.offsetWidth)){
// offsetWidth includes any border
w -= lrBorder;
}
if (w && contentBox) w -= lrPadding;
}

// Height calcs
// Try the style first, then clientHeight, then offsetHeight
if (h = me.getStyle('height').match(/(\d+)px/)){
if ((h = parseInt(h[1], 10)) && isBB){
// Style includes the padding and border if isBB
h -= (tbBorder + tbPadding);
}
contentBox || (h += tbPadding);
} else {
if (!(h = d.clientHeight) && (h = d.offsetHeight)){
// offsetHeight includes any border
h -= tbBorder;
}
if (h && contentBox) h -= tbPadding;
}

return {
width : w,
height : h
};
}
});

Ext.onReady(function(){

var leftHalf = {
xtype : 'container',
layout : 'form',
flex : 1,
labelWidth : 90,
defaultType : 'textfield',
defaults : { anchor: '-10' },
items : [
{
xtype : 'hidden',
name : 'id'
},
{
fieldLabel : 'Name',
name : 'name',
allowBLank : false,
maxLength : 255
},
{
xtype : 'datefield',
fieldLabel : 'Activated',
name : 'dateActive'
},
{
fieldLabel : 'Other Field'
},
{
fieldLabel : 'Other Field'
},
{
fieldLabel : 'Other Field'
}
]
};

var rightHalf = {
xtype : 'container',
title : 'Description',
flex : 1,
layout : 'form',
labelWidth : 70,
items : {
xtype : 'textarea',
fieldLabel : 'Description',
name : 'description',
anchor : '100% 100%'
}
} ;

var northRegion = {
layout : 'hbox',
region : 'north',
height : 150,
bodyStyle : 'background-color: #DFE8F6; padding: 10px',
layoutConfig : { align : 'stretch' },
border : false,
items : [
leftHalf,
rightHalf
]
};

new Ext.Viewport ({
layout : 'border',
items : [
northRegion,
{
region : 'center',
style : 'padding: 10px;',
html : 'Center region'
}

]
});

});
</script>
</head>
<body></body>
</html>

jay@moduscreate.com
9 Dec 2009, 7:51 AM
Thanks for your time Nige.

The the overnesting is a left-over artifact from stripped down of the example.

In the Extjs in action app, i need to nest a panel within a fit-layout viewport to get the following effect.
http://extjsinaction.com/tmp/extia.tmp.jpg

Animal
9 Dec 2009, 7:59 AM
So the suggested code fixes it for you?

I PM'd Jamie to let him know that we need to integrate this.

Condor
9 Dec 2009, 8:16 AM
There is an unusual case that you don't handle:

If the element is hidden with display:none the result should be {width: 0, height: 0}, but due to padding calculations the resulting width and/or height could actually be negative.

You should probably use:

...
if (w && contentBox) w -= lrPadding;
...
if (h && contentBox) h -= tbPadding;
...

Animal
9 Dec 2009, 8:21 AM
Yes. I'll add that.

There are other places in Ext.Element which need to use these techniques.

getWidth and getHeight make incorrect assumptions.

clientHeight does not include borders. But offsetHeight does.

aw1zard2
9 Dec 2009, 8:58 AM
Does it correct the width when validation is used with the hbox?

Or I guess more importantly should it?

I had to correct the width on my hbox forms cause it was cutting off the validation icon if it was used.

:)

Animal
9 Dec 2009, 9:02 AM
No. It's at a lower level than that. It's operating on DOM elements, not Components.

Animal
9 Dec 2009, 11:52 AM
I can confirm that testcase works (without any overrides) with the latest update just committed by Jamie.

(And the code got smaller, and there are several deprecated functions which will be slated for removal)

jay@moduscreate.com
9 Dec 2009, 12:05 PM
Awesome!! Confirmed it works perfectly.
http://tdg-i.com/img/screencasts/2009-12-09_1504.png