PDA

View Full Version : [FIXED-101][3.x/2.x] Panel collapses bwrap with display:none



Condor
3 Jan 2009, 10:01 AM
This bug has been reported several times before, but nobody made a proper bugreport for it:

Ext.Panel.collapse() collapses the collapseEl element (bwrap) with display:none.
This can cause several problems in components (combobox zero listwidth, border layout region zero height/width etc.).

This problem also affects panels in an accordion layout, because it also uses collapse() to only show the panel header of collapsed items.

IMHO Ext.Panel should use the current hideMode to hide the collapseEl.

Example:

new Ext.Viewport({
layout: 'accordion',
layoutConfig: {
animate: true
},
items: [{
title: 'Panel 1'
},{
title: 'Panel 2',
layout: 'form',
hideMode: 'offsets', // <- not used by collapse()
items: {
fieldLabel: 'Combobox',
xtype: 'combo',
store: ['A', 'B', 'C'],
triggerAction: 'all',
editable: false
}
}]
});
(notice the wrong combobox listwidth on the second panel)

Unfortunately the actual fix would require a rather big rewrite, so I'll only provide a workaround:

Ext.override(Ext.Panel, {
onCollapse : function(doAnim, animArg){
this[this.collapseEl].setVisibilityMode(Ext.Element.VISIBILITY);
if(doAnim){
this[this.collapseEl].slideOut(this.slideAnchor,
Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
this.collapseDefaults));
}else{
this[this.collapseEl].hide();
this.afterCollapse();
}
},
afterCollapse : function(){
this[this.collapseEl].applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
this.collapsed = true;
this.el.addClass(this.collapsedCls);
this.afterEffect();
this.fireEvent('collapse', this);
},
onExpand : function(doAnim, animArg){
this[this.collapseEl].applyStyles({position: '', top: '', left: ''});
if(doAnim){
this[this.collapseEl].slideIn(this.slideAnchor,
Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
this.expandDefaults));
}else{
this[this.collapseEl].show();
this.afterExpand();
}
}
});
Ext.override(Ext.layout.Accordion, {
setItemSize : function(item, size){
if(this.fill && item){
var items = this.container.items.items;
var hh = 0;
for(var i = 0, len = items.length; i < len; i++){
var p = items[i];
if(p != item){
hh += (p.getSize().height - (p.collapsed ? 0 : p.bwrap.getHeight()));
}
}
size.height -= hh;
item.setSize(size);
}
}
});

mystix
4 Jan 2009, 7:20 PM
i was wondering why the workaround wasn't working. :)

there's a small typo in the afterCollapse override:


afterCollapse : function(){
this[this.collapseEl].applyStyles({position: 'aboslute', top: '-10000px', left: '-10000px'});
this.collapsed = true;
this.el.addClass(this.collapsedCls);
this.afterEffect();
this.fireEvent('collapse', this);
},

that should be absolute.

scosta
30 Apr 2009, 12:24 AM
I've found the case where fieldset doesn't get expanded once it's collapsed:


var panelContent = new Ext.Panel({
...
items: new Ext.form.FieldSet({
border: false,
labelAlign: 'top',
labelWidth: 100,
style: 'padding:10px;',
items: [
....
{
xtype: 'checkbox',
hideLabel: true,
anchor: '100%',
inputValue: 1,
checked: false,
listeners: {
check: function(checkBox, checked) {
var fckFieldset = Ext.getCmp('buggyFieldset');
if (checked && ('function' == typeof(fckFieldset.collapse))) {
fckFieldset.collapse();
} else if ('function' == typeof(fckFieldset.expand)) {
fckFieldset.expand();
}
}
}
}
,new Ext.form.FieldSet({
id: 'buggyFieldset'
style: 'padding:0px; margin:0px',
layoutConfig: {
labelSeparator: ''
},
collapsible: true,
collapsed: true,
autoHeight: true,
border: false,
items: new Ext.ux.form.FckEditor({
....
})
}),
new Ext.ux.form.FckEditor({
....
})
]
}),
...
});and this is what fixed this:



onExpand : function(doAnim, animArg){
//this[this.collapseEl].applyStyles({position: '', top: '', left: ''});
if(doAnim){
this[this.collapseEl].slideIn(this.slideAnchor,
Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
this.expandDefaults));
}else{
this[this.collapseEl].show();
this.afterExpand();
}
},
afterExpand : function() {
this[this.collapseEl].applyStyles({position: '', top: '', left: ''});
this.collapsed = false;
this.afterEffect();
this.fireEvent('expand', this);
}Ext.ux.form.FckEditor is my own ExtJs wrapper class for FCK Editor (extended textarea).

Condor
1 May 2009, 3:06 AM
Doesn't that kill the slideIn animation effect?

PierceSD
17 Jul 2009, 2:35 PM
+1 for fixing this issue...I just ran into it today.

I ended up solving the issue by not using collapsed: true in the initial config, but rather collapsing the panel after rendering, without animating. It seems to happen fast enough to cause no screen flicker. This is in a window with a form that has 6 collapsible fieldsets.

Condor
17 Jul 2009, 10:32 PM
I don't think this will be solved in the Ext 2.x branch.

However, it was fixed in Ext 3.0 (by deffering layout until the panel is expanded).
Unfortunately animation still uses display:none as Animal pointed out.

mystix
6 Aug 2009, 8:53 AM
[ moved to 3.x Bugs from 2.x Bugs ]
with reference to the following thread:
http://extjs.com/forum/showthread.php?t=76784

Animal
6 Aug 2009, 9:33 AM
It's not fixed in that the slideOut effect still uses display: none

Condor
6 Aug 2009, 9:56 AM
You should not consider my patch as the final solution. The problem needs to be handled much deeper down (IMHO animation effects should have the choice of using display, visibility or offsets).

Stefan B
13 Aug 2009, 11:15 PM
However, it was fixed in Ext 3.0 (by deffering layout until the panel is expanded).

Haven't tried in Ext 3.0 yet, but I don't believe deferring layout fixes all implications. It only helps getting the layout right on initial rendering of a panel. But think of things like updating the value of a progress bar that resides in a collapsed container. Its bar element will be sized relative to its main el size, which is zero because the container panel el has "display: none".

Condor's workaround helps here, but using "hideMode" settings for collapsing is the solid way to go.

omermx
5 Sep 2009, 1:04 PM
Thanks for providing a workaround for this! Wrong listWidth on my Combobox was driving me crazy!! :D

dtex-lab
5 Oct 2009, 4:22 AM
Please consider also this case:

http://www.extjs.com/forum/showthread.php?t=82013

Condor's workaround doesn't work on my test case.
ty

Stefan B
23 Oct 2009, 1:59 AM
Just realized that Condor's fix makes the panel slide in at the left side of the screen before it is positioned correctly in a border layout. Happens with Ext 3.0.2, did not test any other versions.

This is because the top/left values are empty when the positioning mode is reset. The position needs to be buffered instead and restore when the panel is expanded:


Ext.override(Ext.Panel, {
onCollapse : function(doAnim, animArg){
this[this.collapseEl].setVisibilityMode(Ext.Element.VISIBILITY);
if(doAnim){
this[this.collapseEl].slideOut(this.slideAnchor,
Ext.apply(this.createEffect(animArg||true, this.afterCollapse, this),
this.collapseDefaults));
}else{
this[this.collapseEl].hide();
this.afterCollapse();
}
},
afterCollapse : function(){
var collapseEl = this[this.collapseEl];
collapseEl.posBuffer = {top: collapseEl.dom.style.top, left: collapseEl.dom.style.left};
collapseEl.applyStyles({position: "absolute", top: "-10000px", left: "-10000px"});
this.collapsed = true;
this.el.addClass(this.collapsedCls);
this.afterEffect();
this.fireEvent('collapse', this);
},
onExpand : function(doAnim, animArg){
var collapseEl = this[this.collapseEl];
collapseEl.applyStyles({position: "", top: collapseEl.posBuffer.top, left: collapseEl.posBuffer.left});
if(doAnim){
this[this.collapseEl].slideIn(this.slideAnchor,
Ext.apply(this.createEffect(animArg||true, this.afterExpand, this),
this.expandDefaults));
}else{
this[this.collapseEl].show();
this.afterExpand();
}
}
});

There's another, slightly off-topic question here:
Since I think this is quite a dirty hack, I don't want to override Ext.Panel's prototype. Instead I tried to create interceptor methods in the panel's config, like so:


var p = new Panel({
/* ... */
onCollapse: Ext.Panel.prototype.onCollapse.createInterceptor(function(doAnim, animArg) {
this[this.collapseEl].setVisibilityMode(Ext.Element.VISIBILITY);
}),
afterCollapse: Ext.Panel.prototype.afterCollapse.createInterceptor(function(anim) {
var collapseEl = this[this.collapseEl];
collapseEl.posBuffer = {top: collapseEl.dom.style.top, left: collapseEl.dom.style.left};
collapseEl.applyStyles({position: "absolute", top: "-10000px", left: "-10000px"});
}),
onExpand: Ext.Panel.prototype.onExpand.createInterceptor(function(doAnim, animArg) {
var collapseEl = this[this.collapseEl];
collapseEl.applyStyles({position: "", top: collapseEl.posBuffer.top, left: this.collapseEl.posBuffer.left});
})
});

This doesn't work, FireBug says "this[this.collapseEl] is undefined".
What's wrong with that? Did I run into a scoping issue that I don't recognize?

Thanks,
Stefan

Stefan B
23 Oct 2009, 3:36 AM
Nevermind my question regarding interceptors. I just realized that the panel's initial config is applied to the border layout region as well, so that in fact i don't just override the relevant panel methods but also the region, which happens to have its own onCollapse, afterCollapse and onExpand methods.
Worked around this by creating the interceptors in the panel's "beforerender" handler.

Thanks,
Stefan

bbxx
23 Oct 2009, 2:50 PM
I have a container within a collapsed panel that does not render. But after I expand the panel and then resize my browser, it renders properly.

After initial expand:
http://teikena.com/temp/collapsed_normal.png

After resizing browser window:
http://teikena.com/temp/collapsed_resized.png

I tried condor's fix but it didn't work. Any ideas? It's just a few containers nested with hbox layout

Jamie Avins
11 Feb 2010, 3:52 PM
Fixed in svn-6047 for 3.2.x branch.

lorezyra
31 Jan 2011, 5:56 PM
Fixed in svn-6047 for 3.2.x branch.

Jamie Avins,
I'm using EXTjs 3.3.1 and have the HTMLeditor inside of a Ext.Window component. This buggy behavior still persists when I collapse the window. I have yet to try setting the config animateCollapse to false as suggested by another tread. I've observed that HtmlEditor.reset() method will restore any text that existed in the initial rendering of the component, but all changes from that point are lost.

Has the fix been applied to the EXTjs 3.3.x branch?


*Edit: tested on IE8 and FF3

Condor
31 Jan 2011, 11:33 PM
HtmlEditor really can't handle being display:none. Try configuring the window with hideMode:'offsets'.

skbach_pointyhat
7 May 2011, 10:46 AM
Still not fixed in 3.3.1

Issue perists, with a collapsed: true split panel, where the south region is a formpanel. collapsed: false renders correctly, but collapsed true renders nothing.