PDA

View Full Version : [OPEN] [FIXED-255][3.x] buttonAlign center/right on IE



Condor
3 Sep 2009, 3:07 AM
There have been several fixes to Panel buttons since Ext 3.0.0, but there are still some instances where the buttons are displayed incorrectly.

Try the following example on IE 6 strict or IE 6/7/8 quirks:

Ext.onReady(function(){
new Ext.Window({
title: 'buttonAlign: center',
x: 0,
width: 350,
height: 100,
buttonAlign: 'center',
buttons: [{
text: 'Button 1'
},{
text: 'Button 2'
}]
}).show();
new Ext.Window({
title: 'buttonAlign: right',
x: 300,
width: 300,
height: 100,
buttonAlign: 'right',
buttons: [{
text: 'Button 1'
},{
text: 'Button 2'
}]
}).show();
});
In the first window the buttons are moved to the overflow and in the second window the footer height is calculated incorrectly which results in a undersized body.

I was looking into a solution, but ended up doing a rather big rewrite (which cleans up the code quite nicely I must say):

// Add support for buttonLayout config option to Toolbar
Ext.override(Ext.layout.ToolbarLayout, {
onLayout : function(ct, target){
if(!this.leftTr){
target.addClass('x-toolbar-layout-ct');
target.insertHtml('beforeEnd',
'<table cellspacing="0" class="x-toolbar-ct"><tbody>' +
'<tr>' +
'<td class="x-toolbar-left" align="' + (ct.buttonAlign == 'center' ? 'center' : 'left') + '">' +
'<table cellspacing="0"><tbody>' +
'<tr class="x-toolbar-left-row"></tr>' +
'</tbody></table>' +
'</td>' +
'<td class="x-toolbar-right" align="right">' +
'<table cellspacing="0" class="x-toolbar-right-ct"><tbody>' +
'<tr>' +
'<td>' +
'<table cellspacing="0"><tbody>' +
'<tr class="x-toolbar-right-row"></tr>' +
'</tbody></table>' +
'</td>' +
'<td>' +
'<table cellspacing="0"><tbody>' +
'<tr class="x-toolbar-extras-row"></tr>' +
'</tbody></table>' +
'</td>' +
'</tr>' +
'</tbody></table>' +
'</td>' +
'</tr>' +
'</tbody></table>');
this.leftTr = target.child('tr.x-toolbar-left-row', true);
this.rightTr = target.child('tr.x-toolbar-right-row', true);
this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
}
var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr;
var pos = 0;
var items = ct.items.items;
for(var i = 0, len = items.length, c; i < len; i++, pos++) {
c = items[i];
if(c.isFill){
side = this.rightTr;
pos = -1;
}else if(!c.rendered){
c.render(this.insertCell(c, side, pos));
}else{
if(!c.xtbHidden && !this.isValidParent(c, side.childNodes[pos])){
var td = this.insertCell(c, side, pos);
td.appendChild(c.getDomPositionEl().dom);
c.container = Ext.get(td);
}
}
}
this.cleanup(this.leftTr);
this.cleanup(this.rightTr);
this.cleanup(this.extrasTr);
this.fitToSize(target);
}
});
Ext.override(Ext.Panel, {
initComponent : function(){
Ext.Panel.superclass.initComponent.call(this);
this.addEvents(
'bodyresize',
'titlechange',
'iconchange',
'collapse',
'expand',
'beforecollapse',
'beforeexpand',
'beforeclose',
'close',
'activate',
'deactivate'
);
if(this.unstyled){
this.baseCls = 'x-plain';
}
this.toolbars = [];
if(this.tbar){
this.elements += ',tbar';
if(Ext.isArray(this.tbar)){
this.tbar = {
items: this.tbar
};
}
if (!this.tbar.events) {
this.topToolbar = this.createComponent(this.tbar, 'toolbar');
} else {
this.topToolbar = this.tbar;
}
this.topToolbar.ownerCt = this;
this.toolbars.push(this.topToolbar);
delete this.tbar;
}
if(this.bbar){
this.elements += ',bbar';
if(Ext.isArray(this.bbar)){
this.bbar = {
items: this.bbar
};
}
if (!this.bbar.events) {
this.bottomToolbar = this.createComponent(this.bbar, 'toolbar');
} else {
this.bottomToolbar = this.bbar;
}
this.bottomToolbar.ownerCt = this;
this.toolbars.push(this.bottomToolbar);
delete this.bbar;
}
if(this.header === true){
this.elements += ',header';
delete this.header;
}else if(this.headerCfg || (this.title && this.header !== false)){
this.elements += ',header';
}
if(this.footerCfg || this.footer === true){
this.elements += ',footer';
delete this.footer;
}
// treat buttons as fbar alias
if(this.buttons){
this.fbar = this.buttons;
delete this.buttons;
}
// treat fbar as a regular toolbar in the footer
if(this.fbar){
this.elements += ',footer';
if(Ext.isArray(this.fbar)){
this.fbar = {
items: this.fbar
};
}
Ext.apply(this.fbar, {
//enableOverflow: false <- no longer required IMHO
toolbarCls: 'x-panel-fbar',
buttonAlign: this.buttonAlign,
defaults: Ext.apply({
minWidth: this.minButtonWidth
}, this.fbar.defaults)
});
if (!this.fbar.events) {
this.fbar = this.createComponent(this.fbar, 'toolbar');
}
this.fbar.ownerCt = this;
this.toolbars.push(this.fbar);
// keep buttons array for backward compatibility
this.buttons = this.fbar.items.items;
}
if(this.autoLoad){
this.on('render', this.doAutoLoad, this, {delay:10});
}
},
onRender : function(ct, position){
Ext.Panel.superclass.onRender.call(this, ct, position);
this.createClasses();
var el = this.el,
d = el.dom,
bw,
ts;
if(this.header && this.collapsible && !this.hideCollapseTool){
this.tools = this.tools ? this.tools.slice(0) : [];
this.tools[this.collapseFirst?'unshift':'push']({
id: 'toggle',
handler : this.toggleCollapse,
scope: this
});
}
if(this.tools){
ts = this.tools;
this.elements += (this.header !== false) ? ',header' : '';
}
this.tools = {};
el.addClass(this.baseCls);
if(d.firstChild){
this.header = el.down('.'+this.headerCls);
this.bwrap = el.down('.'+this.bwrapCls);
var cp = this.bwrap ? this.bwrap : el;
this.tbar = cp.down('.'+this.tbarCls);
this.body = cp.down('.'+this.bodyCls);
this.bbar = cp.down('.'+this.bbarCls);
this.footer = cp.down('.'+this.footerCls);
this.fromMarkup = true;
}
if (this.preventBodyReset === true) {
el.addClass('x-panel-reset');
}
if(this.cls){
el.addClass(this.cls);
}
if(this.buttons){
this.elements += ',footer';
}
if(this.frame){
el.insertHtml('afterBegin', String.format(Ext.Element.boxMarkup, this.baseCls));
this.createElement('header', d.firstChild.firstChild.firstChild);
this.createElement('bwrap', d);
bw = this.bwrap.dom;
var ml = d.childNodes[1], bl = d.childNodes[2];
bw.appendChild(ml);
bw.appendChild(bl);
var mc = bw.firstChild.firstChild.firstChild;
this.createElement('tbar', mc);
this.createElement('body', mc);
this.createElement('bbar', mc);
this.createElement('footer', bw.lastChild.firstChild.firstChild);
if(!this.footer){
this.bwrap.dom.lastChild.className += ' x-panel-nofooter';
}
}else{
this.createElement('header', d);
this.createElement('bwrap', d);
bw = this.bwrap.dom;
this.createElement('tbar', bw);
this.createElement('body', bw);
this.createElement('bbar', bw);
this.createElement('footer', bw);
if(!this.header){
this.body.addClass(this.bodyCls + '-noheader');
if(this.tbar){
this.tbar.addClass(this.tbarCls + '-noheader');
}
}
}
if(Ext.isDefined(this.padding)){
this.body.setStyle('padding', this.body.addUnits(this.padding));
}
if(this.border === false){
this.el.addClass(this.baseCls + '-noborder');
this.body.addClass(this.bodyCls + '-noborder');
if(this.header){
this.header.addClass(this.headerCls + '-noborder');
}
if(this.footer){
this.footer.addClass(this.footerCls + '-noborder');
}
if(this.tbar){
this.tbar.addClass(this.tbarCls + '-noborder');
}
if(this.bbar){
this.bbar.addClass(this.bbarCls + '-noborder');
}
}
if(this.bodyBorder === false){
this.body.addClass(this.bodyCls + '-noborder');
}
this.bwrap.enableDisplayMode('block');
if(this.header){
this.header.unselectable();
if(this.headerAsText){
this.header.dom.innerHTML =
'<span class="' + this.headerTextCls + '">'+this.header.dom.innerHTML+'</span>';
if(this.iconCls){
this.setIconClass(this.iconCls);
}
}
}
if(this.floating){
this.makeFloating(this.floating);
}
if(this.collapsible && this.titleCollapse && this.header){
this.mon(this.header, 'click', this.toggleCollapse, this);
this.header.setStyle('cursor', 'pointer');
}
if(ts){
this.addTool.apply(this, ts);
}
if(this.fbar){
// the extra wrapper isn't required anymore
this.footer.addClass('x-panel-btns');
this.fbar.render(this.footer);
}
if(this.tbar && this.topToolbar){
this.topToolbar.render(this.tbar);
}
if(this.bbar && this.bottomToolbar){
this.bottomToolbar.render(this.bbar);
}
},
onResize : function(w, h){
if(Ext.isDefined(w) || Ext.isDefined(h)){
if(!this.collapsed){
if(Ext.isNumber(w)){
w = this.adjustBodyWidth(w - this.getFrameWidth());
if(this.tbar){
this.tbar.setWidth(w);
if(this.topToolbar){
this.topToolbar.setSize(w);
}
}
if(this.bbar){
this.bbar.setWidth(w);
if(this.bottomToolbar){
this.bottomToolbar.setSize(w);
}
}
// doesn't this look better!
if(this.footer){
this.footer.setWidth(w);
if(this.fbar){
this.fbar.setSize(w - this.footer.getFrameWidth('lr'));
}
}
this.body.setWidth(w);
}else if(w == 'auto'){
this.body.setWidth(w);
}
if(Ext.isNumber(h)){
h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
this.body.setHeight(h);
}else if(h == 'auto'){
this.body.setHeight(h);
}
if(this.disabled && this.el._mask){
this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
}
}else{
this.queuedBodySize = {width: w, height: h};
if(!this.queuedExpand && this.allowQueuedExpand !== false){
this.queuedExpand = true;
this.on('expand', function(){
delete this.queuedExpand;
this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
this.doLayout();
}, this, {single:true});
}
}
this.onBodyResize(w, h);
}
this.syncShadow();
},
addButton : function(config, handler, scope){
// make sure the fbar exists
if(!this.fbar){
this.elements += ',footer';
this.fbar = this.createComponent({
items: [],
toolbarCls: 'x-panel-fbar',
buttonAlign: this.buttonAlign,
defaults: {
minWidth: this.minButtonWidth
}
}, 'toolbar');
this.fbar.ownerCt = this;
this.toolbars.push(this.fbar);
this.buttons = this.fbar.items.items;
}
// now also supports '->' etc.
if(handler){
if(Ext.isString(config)){
config = {text: config};
}
config = Ext.apply({
handler: handler,
scope: scope
}, config)
}
return this.fbar.add(config);
}
});
with:

.x-toolbar-left {
width: 100%;
}
and all x-panel-btns-[left|center|right] rules can be removed.

The only problem with this solution is that minButtonWidth is also applied to buttons that are specified as Button instances with a minWidth.
That could be solved by changing applyDefaults (this is an adaptation from a feature request):

Ext.override(Ext.Container, {
// support optional defaults parameter (for descendants)
applyDefaults : function(c, defaults){
defaults = defaults || this.defaults;
if(defaults){
if(Ext.isString(c)){
c = Ext.ComponentMgr.get(c);
}
if(!c.events){
Ext.applyIf(c, defaults);
}else{
// apply to both initialConfig and component if not in initialConfig
var ic = c.initialConfig || {};
for(var p in defaults){
if(!Ext.isDefined(ic[p])){
c[p] = ic[p] = defaults[p];
}
}
}
}
return c;
}
});
Ext.override(Ext.Toolbar, {
applyDefaults : function(c){
if(Ext.isString(c)){
return c;
}
var defaults = Ext.apply({}, c.defaults, this.internalDefaults);
return Ext.Toolbar.superclass.applyDefaults.call(this, c, defaults);
}
});
Ext.override(Ext.ButtonGroup, {
applyDefaults : function(c){
var defaults = Ext.apply({}, c.defaults, this.internalDefaults);
return Ext.ButtonGroup.superclass.applyDefaults.call(this, c, defaults);
}
});

evant
20 Sep 2009, 9:55 PM
I've added a similar fix to SVN, seems to work well. Target 3.1 with this one since it's a reasonably large change.