PDA

View Full Version : Borderlayout split region won't shrink on IE8 when region contains a container



wepac
25 Jun 2012, 4:23 AM
Hi there,

I've been banging my head off a wall for several hours on this. I'm having problems with a split region refusing to shrink on IE8 only (fine on other browsers).

The structure of the components is:


viewport with a border layout, with...

west tree panel
center container also with a border layout, with...

center container with fit layout - 'upperSlot', with...

a panel containing an iframe

south container with fit layout - 'lowerSlot', with...

a panel containing an iframe





It's the nested border layout that's causing problems on IE8 - it's fine on Firefox and Chrome. I can drag the split bar to make the south region bigger, but when you try to make it smaller, IE8 ignores it. You can drag the bar, but no resize takes place when you let go.

I've put together a small self-contained example. Any suggestions very much appreciated. This is killing me!!



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

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

<!-- ExtJS library: all widgets -->
<script type="text/javascript" src="ext-3.4.0/ext-all-debug.js"></script>


<script type="text/javascript">
Ext.BLANK_IMAGE_URL = "ext-3.4.0/resources/images/default/s.gif";
</script>
</head>
<body>

<script type="text/javascript">

var parametersPanel = new Ext.Panel({
title: 'Parameters Panel',
layout: 'fit',
html: '<iframe style="width: 100%; height: 100%;" src="http://news.ycombinator.com/"></iframe>'
});

var resultsPanel = new Ext.Panel({
title: 'Results Panel',
layout: 'fit',
html: '<iframe style="width: 100%; height: 100%;" src="http://news.bbc.co.uk/"></iframe>'
});

var upperSlot = new Ext.Container({
region: 'center',
layout: 'fit',
items: [ parametersPanel ]
});

var lowerSlot = new Ext.Container({
region: 'south',
layout: 'fit',
split: true,
height: 500,
items: [ resultsPanel ]
});

var centerContainer = {
region: 'center',
xtype: 'container',
layout: 'border',
items:[
upperSlot,
lowerSlot
]
};

var viewport = new Ext.Viewport({
layout: 'border',
items: [
{
region: 'west',
collapsible: true,
title: 'Navigation',
xtype: 'treepanel',
width: 200,
autoScroll: true,
split: true,
loader: new Ext.tree.TreeLoader(),
root: new Ext.tree.AsyncTreeNode({
expanded: true,
children: [
{
text: 'Show both panels',
leaf: true
}, {
text: 'Show results panel only',
leaf: true
}
]
}),
rootVisible: false,
listeners: {
click: function(n) {
//Ext.Msg.alert('Navigation Tree Click', 'You clicked: "' + n.attributes.text + '"');
if(n.attributes.text === 'Show both panels'){

upperSlot.removeAll(false);
lowerSlot.removeAll(false);
upperSlot.add(parametersPanel);
lowerSlot.add(resultsPanel);
lowerSlot.show();
viewport.doLayout();

}else{
upperSlot.removeAll(false);
lowerSlot.removeAll(false);
upperSlot.add(resultsPanel);
lowerSlot.hide();
viewport.doLayout();
}
}
}
},
centerContainer
]
});

</script>


</body>
</html>


(I'm using nested containers to allow me to switch panels into the upper and lower slots as needed, because regions are fixed at initial creation time.)

As can be seen the regions contain iframes. I don't know if this is a factor or not, but this is a part of what I'm trying to get working.

Thanks in advance for any help.

wepac
26 Jun 2012, 6:12 AM
OK I found a workaround.

Here's the code:



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

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

<!-- ExtJS library: all widgets -->
<script type="text/javascript" src="ext-3.4.0/ext-all-debug.js"></script>


<script type="text/javascript">
Ext.BLANK_IMAGE_URL = "ext-3.4.0/resources/images/default/s.gif";
</script>
</head>
<body>

<script type="text/javascript">

var parametersPanel = new Ext.Panel({
title: 'Parameters Panel',
layout: 'fit',
html: '<iframe style="width: 100%; height: 100%;" src="http://news.ycombinator.com/"></iframe>'
});

var resultsPanel = new Ext.Panel({
id: 'resultsPanel',
title: 'Results Panel',
layout: 'fit',
html: '<iframe style="width: 100%; height: 100%;" src="http://news.bbc.co.uk/"></iframe>'
});

var upperSlot = new Ext.Container({
region: 'center',
layout: 'fit',
items: [ parametersPanel ]
});

var lowerSlot = new Ext.Container({
region: 'south',
layout: 'fit',
split: true,
height: 500,
listeners: {
// Workaround for problem in IE with nested containers - need to manually adjust the size of the
// child panel.
//
// Otherwise, when the split bar is dropped, ExtJS will update the height of the child container
// (using dom.style.height = ...) but, unlike in Chrome & Firefox, the height update **won't** be
// reflected in the dom.offsetHeight and dom.clientHeight. This ultimately results in a 2nd resize,
// when layout occurs, which then sizes the container back to its original size - because the layout
// code asks for the size of the child component, and the getSize() code relies on
// offsetHeight and clientHeight being correct.
//
// Note that on IE8, without manually setting the height of the child component as below, the resize
// listener will be fired twice when the split bar is dragged to make the panel smaller. The first time
// is when the split bar sets the height of the child component, the 2nd time is when the layout code
// detects that the size isn't correct (according to offsetHeight and clientHeight) and resizes it back.
//
// By contrast, on Chrome and Firefox the resize listener is fired only once, without any workaround in
// place.
//
// Horrible.
//
resize: function(component, adjWidth, adjHeight, rawWidth, rawHeight) {
if(Ext.isIE) { component.get(0).setHeight(adjHeight); }
}
},
items: [ resultsPanel ]
});

var centerContainer = {
region: 'center',
xtype: 'container',
layout: 'border',
items:[
upperSlot,
lowerSlot
]
};

var viewport = new Ext.Viewport({
layout: 'border',
items: [
{
region: 'west',
collapsible: true,
title: 'Navigation',
xtype: 'treepanel',
width: 200,
autoScroll: true,
split: true,
loader: new Ext.tree.TreeLoader(),
root: new Ext.tree.AsyncTreeNode({
expanded: true,
children: [
{
text: 'Show both panels',
leaf: true
}, {
text: 'Show results panel only',
leaf: true
}
]
}),
rootVisible: false,
listeners: {
click: function(n) {
//Ext.Msg.alert('Navigation Tree Click', 'You clicked: "' + n.attributes.text + '"');
if(n.attributes.text === 'Show both panels'){

upperSlot.removeAll(false);
lowerSlot.removeAll(false);
upperSlot.add(parametersPanel);
lowerSlot.add(resultsPanel);
lowerSlot.show();
viewport.doLayout();

}else{
upperSlot.removeAll(false);
lowerSlot.removeAll(false);
upperSlot.add(resultsPanel);
lowerSlot.hide();
viewport.doLayout();
}
}
}
},
centerContainer
]
});

</script>


</body>
</html>


Compare the two snippets above in this thread to see the difference - the workaround is to add a resize handler to the lower-slot container that, on IE only, manually sets the size of the contained panel.

Without doing this the container that forms the lower slot lies about its size, after it has been resized. To see the 'bug' in action:


Use the code at the top of this thread (without the workaround) and load the page in IE8
In ext-3.4.0/ext-all-debug.js set a breakpoint on line 15177.
Drag the split bar to make the lower slot smaller
Use the console to call this.panel.getSize() and you'll see that it's not the size that you've just set
You'll also find the the layout that takes place on line 15182 sets the height of the lower slot container back to its pre-resize height