PDA

View Full Version : [CLOSED] Ext.Element -> getWidth + fix



tobiu
13 Jul 2010, 5:42 AM
hi team,

this might be the biggest bugfix i posted so far, since it will resolve quite a bunch of issues.
in the past i had several problems with rendering hidden items and width calculations, most were tabbed forms with deferredRender: false.

+ i had comboBoxes that were 17px (the width of the trigger) to wide
+ errorIcons displayed over the fieldLabel
+ sliders with the thumb always at zero

and many more issues. this all went down to the point, that the width-calculations returned 0 if rendered hidden. i used hideMode: offsets quite a lot because of this. the solution i found also works with the default display-mode.

so, here it is:



Ext.override(Ext.Element, {
getWidth : function(contentWidth){
var me = this,
dom = me.dom,
hidden = Ext.isIE && me.isStyle('display', 'none'),
w = Math.max(dom.offsetWidth || parseInt(dom.style.width, 10), hidden ? 0 : dom.clientWidth) || 0;

w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
return w < 0 ? 0 : w;
}
});


i had to write "Math" instead of "MATH", since i can not access the attribute with an override.

here is a small usecase, showing my sliderField usecase with normal hideMode:display.
tested in ff3.6, ie8 and chrome. the fix for getHeight should work the same way.



Ext.onReady(function(){

Ext.override(Ext.Element, {
getWidth : function(contentWidth){
var me = this,
dom = me.dom,
hidden = Ext.isIE && me.isStyle('display', 'none'),
w = Math.max(dom.offsetWidth || parseInt(dom.style.width, 10), hidden ? 0 : dom.clientWidth) || 0;

w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
return w < 0 ? 0 : w;
}
});

new Ext.form.FormPanel({
renderTo: document.body,
width:600,
height:250,
layout:'fit',
border:false,
labelWidth : 100,
items : [{
xtype: 'tabpanel',
activeTab: 0,
deferredRender: false,
layoutOnTabChange: true,
plain:true,
defaults:{autoScroll: true},
items:[{
title: 'Tab 1',
html: "My content was added during construction."
},{
title: 'Tab 2',
layout: 'form',
items: [{
fieldLabel: 'Sliderfield',
maxValue : 500,
minValue : 0,
value : 250,
width : 200,
xtype : 'sliderfield'
}]
}
]
}]
});
});



kind regards,
tobiu

Jamie Avins
13 Jul 2010, 11:34 AM
Its an interesting workaround for the problem but I don't think we can generalize it to the extent where it's included in Element.

tobiu
14 Jul 2010, 4:50 AM
hi jamie,

please don't underestimate the override, it fixes many other tickets as well.
for example the triggerField-issue of ticket 1110:
http://www.sencha.com/forum/showthread.php?103405


kind regards,
tobias

tobiu
14 Jul 2010, 7:32 AM
hi jamie,

i build a new version of the fix:



Ext.override(Ext.Element, {
getWidth : function(contentWidth){
var me = this,
dom = me.dom,
w = dom.offsetWidth|| 0;

w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");

if(w <= 0){
w = parseInt(dom.style.width, 10) || 0;

while(dom.parentNode){
if(dom.parentNode.style){
w += (parseInt(dom.parentNode.style.marginLeft, 10) || 0);
w += (parseInt(dom.parentNode.style.paddingLeft, 10) || 0);
}
dom = dom.parentNode;
}
}
return w;
}
});


i removed the max (clientWidth, offsetWidth) check and improved the new routine a bit more:
it checks all parentNodes for margins and paddings.

since this might increase the needed execution-time, it is only used when the width is 0.
otherwise it could replace the whole old mechanism.

the advantage of this version is:
you can use tabpanels with


,deferredRender : false
,layoutOnTabChange : false


and hideMode -> display. so, basically we don't need layoutOnTabchange anymore if the fix works as i think it does.

here an example:



Ext.onReady(function(){

Ext.override(Ext.Element, {
getWidth : function(contentWidth){
var me = this,
dom = me.dom,
w = dom.offsetWidth|| 0;

w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");

if(w <= 0){
w = parseInt(dom.style.width, 10) || 0;

while(dom.parentNode){
if(dom.parentNode.style){
w += (parseInt(dom.parentNode.style.marginLeft, 10) || 0);
w += (parseInt(dom.parentNode.style.paddingLeft, 10) || 0);
}
dom = dom.parentNode;
}
console.log(w);
}
return w;
}
});

var tabs = new Ext.FormPanel({
labelWidth : 75
,border : false
,items: {
xtype : 'tabpanel'
,activeTab : 0
,deferredRender : false
//,layoutOnTabChange : true
,id : 'tp'
,anchor : '100% 100%'
,style : 'margin-bottom:10px;'
,defaults:{
autoScroll : true
,bodyStyle :'padding:10px;'
}
,items:[{
title : 'Personal Details',
layout : 'form',
id : 'tab1'
,items: [{
anchor : '-20'
,autoHeight : true
,title : 'Customer'
,checkboxName : 'checkAnimation'
,checkboxToggle : true
,xtype : 'fieldset'
,defaults: {
anchor : '-22'
,width : 230
,msgTarget : 'side'
},
defaultType: 'textfield',
items :[{
fieldLabel: 'First Name',
allowBlank: false,
name: 'first',
id: 'focus1'
},{
fieldLabel: 'Last Name',
allowBlank: false,
name: 'last'
},{
fieldLabel: 'Company',
name: 'company',
value: 'Ext JS'
}, {
fieldLabel: 'Email',
name: 'email',
vtype:'email'
},{
fieldLabel: 'Business',
name: 'business'
},{
fieldLabel: 'Mobile',
name: 'mobile'
},{
fieldLabel: 'Fax',
name: 'fax'
}]
}]
},{
title : 'Phone Numbers'
,layout : 'form'
,id : 'tab2'
,defaults : {
width : 230
,anchor : '-22'
,msgTarget : 'side'
}
,defaultType: 'textfield',

items: [{
fieldLabel: 'Home',
allowBlank: false,
name: 'home',
value: '(888) 555-1212'
}, {
fieldLabel: 'Email',
allowBlank: false,
name: 'email',
vtype:'email'
},{
fieldLabel: 'Business',
name: 'business'
},{
fieldLabel: 'Mobile',
name: 'mobile'
},{
fieldLabel: 'Fax',
name: 'fax',
style:'margin-bottom:10px;'
}]
}]
}
});

var myWindow = new Ext.Window({
height : 400
,border : false
,layout : 'fit'
,title : 'a window'
,width : 400
,items : tabs
,buttons: [{
text: 'Step 1',
handler : function(){
Ext.getCmp('focus1').focus();
Ext.getCmp('tp').setActiveTab(1);
}
},{
text: 'Step 2',
handler : function(){
Ext.getCmp('tp').setActiveTab(0);
}
}]
});

myWindow.show();
});


try it out with and without the fix.


kind regards,
tobiu

Jamie Avins
14 Jul 2010, 9:25 AM
I understand the logic behind what you are doing, but the potential impact to existing applications doing this implementation is too large for us to include it.

steffenk
15 Jul 2010, 6:21 AM
Hi,

i tested the patch with a big application of mine, and it has no side effects, all is working as expected.

tobiu
20 Jul 2010, 8:10 AM
after further testing, i prefer



Ext.override(Ext.Element, {
getWidth : function(contentWidth){
var me = this,
dom = me.dom,
hidden = Ext.isIE && me.isStyle('display', 'none'),
w = Math.max(dom.offsetWidth || parseInt(dom.style.width, 10), hidden ? 0 : dom.clientWidth) || 0;

w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");

return w < 0 ? 0 : w;
}
});


again ;)


for details, just ask.

Orgoth
22 Aug 2011, 4:41 AM
Problem sems still present or i have done something wrong ;)

tried with and without the workaround, no difference

first test at dev.sencha.com

2759827599

second test with our app + override

2760027601

used: Ext 3.4.0

at the moment iam analysing getWidth
the hidden elements get zero as width

log visible elements


after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");14ext-gen1014
after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");445ext-gen1012
after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");14ext-gen1021
after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");445ext-gen1019

log hidden elements


after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");0ext-gen1063
after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");0ext-gen1061
after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");0ext-gen1070
after w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");0ext-gen1068


Ext.override ( Ext.Element, { getWidth : function( contentWidth )
{
var me = this,
dom = me.dom,
hidden = Ext.isIE && me.isStyle ( 'display', 'none' ),
w = Math.max ( dom.offsetWidth || parseInt ( dom.style.width, 10 ), hidden ? 0 : dom.clientWidth ) || 0;
w = !contentWidth ? w : w - me.getBorderWidth ( "lr" ) - me.getPadding ( "lr" );
return w < 0 ? 0 : w;
}
} );
var baseurl = '';
Ext.namespace ( "Sys" );
Ext.namespace ( "Sys.cache" );
Ext.namespace ( "Sys.dialog" );


var PowerPoints = [new Ext.Panel ( {
title: 'Ambulante Leistungen',
layout : 'form',
defaultType: 'sliderfield',
border : false,
autoScroll: true,
padding: '5',
items: [
{
fieldLabel : 'Ärztliche Behandlung ambulant (Art und Höhe)',
name: 'Im_203',
id: 'Im_203',
ctCls: 'custom-slider',
increment: 8,
minValue: 0,
maxValue: 100,
value: 0,
overlap: false
},
{
fieldLabel : 'Gebührenordnung für Ärzte, ambulant',
name: 'Im_1',
id: 'Im_1',
ctCls: 'custom-slider',
increment: 7,
minValue: 0,
maxValue: 100,
value: 0,
overlap: false
}
]
} ),new Ext.Panel ( {
title: 'Stationäre Leistungen',
layout : 'form',
defaultType: 'sliderfield',
border : false,
autoScroll: true,
padding: '5',
items: [
{
fieldLabel : 'Stationäre Pflegeklasse',
name: 'Im_19',
id: 'Im_19',
ctCls: 'custom-slider',
increment: 4,
minValue: 0,
maxValue: 100,
value: 0,
overlap: false
},
{
fieldLabel : 'Haushaltshilfe',
name: 'Im_280',
id: 'Im_280',
ctCls: 'custom-slider',
increment: 5,
minValue: 0,
maxValue: 100,
value: 0,
overlap: false
},
{
fieldLabel : 'Ärztliche Behandlung stationär (Art und Höhe)',
name: 'Im_20',
id: 'Im_20',
ctCls: 'custom-slider',
increment: 2,
minValue: 0,
maxValue: 100,
value: 0,
overlap: false
}
]
} )]
Sys.dialog.facts = function( config )
{
if ( !config )
{
config = {};
}


config.maximizable = true;
config.modal = false;
config.resizable = true;
config.layout='fit';


config.width = 400;
config.height = 600;


config.title = 'Einstellung der Wichtigkeit';
config.id = 'dialog-importance-preference';


config.buttons = [
{
text: 'Speichern',
handler: function()
{
var val = this.form.getForm ().getValues ();
Ext.Ajax.request ( {
url: baseurl + 'important/save',
method: 'POST',
params: val,
success: function( a )
{
msg = Ext.util.JSON.decode ( a.responseText );
if ( msg.success )
{
// Sys.gridStore.reload ()
}
else
{
Ext.Msg.alert ( 'Failure', msg.message );
}
},
failure: function( form, action )
{
switch ( action.failureType )
{
case Ext.form.Action.CLIENT_INVALID:
Ext.Msg.alert ( 'Failure', 'Form fields may not be submitted with invalid values' );
break;
case Ext.form.Action.CONNECT_FAILURE:
Ext.Msg.alert ( 'Failure', 'Ajax communication failed' );
break;
case Ext.form.Action.SERVER_INVALID:
Ext.Msg.alert ( 'Failure', action.result.message );
}
},
scope:this
} );
},
scope: this
},
{
text: 'Schließen',
handler: function()
{
this.close ();
},
scope: this
}
];
config.items = this.form = new Ext.form.FormPanel ( {
url: baseurl + 'calculate/doRequest',
border:false,
labelAlign:'top',
layout: 'fit',
items:[
{
split:true,
border:false,
layout:'accordion',
items: [ config.powerPoints ]
}
]
} );


config.tbar = [
{
text: 'Regler zurücksetzen',
handler: function()
{
var list = this.form.getForm ().items.items;
for ( i = 0; i < list.length; i++ )
{
list[i].setValue ( 100 );
}
},
scope: this
}
];


config.listeners = {
show: function()
{
//Sys.util.spot.show('dialog-importance-preference');
},
hide: function()
{
//Sys.util.spot.hide();
},
scope: this
};


Sys.dialog.facts.superclass.constructor.call ( this, config );


}
Ext.extend ( Sys.dialog.facts, Ext.Window, {} );
Sys.dialog.Facts = new Sys.dialog.facts ( {
powerPoints: PowerPoints
} );
Sys.dialog.Facts.show ();

Edit:
visible elements
function Ext.Element.getWidth()
dom.offsetWidth == 14
dom.style.width == ""
dom.clientWidth == 14

hidden elements
function Ext.Element.getWidth()
dom.offsetWidth == 0
dom.style.width == ""
dom.clientWidth == 0

szalansun
8 Oct 2012, 9:38 PM
Ext.override(Ext.Element, { getWidth : function (contentWidth) {
var me = this, dom = me.dom, hidden = Ext.isIE && me.isStyle('display', 'none');
var outerWidth = me.getBorderWidth("lr") + me.getPadding("lr");
var styleWidth = parseInt(dom.style.width, 10) + outerWidth;
var w = Math.max(dom.offsetWidth || styleWidth, hidden ? 0 : dom.clientWidth) || 0;
w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");

return w < 0 ? 0 : w;
}
});