layout - Implementación Custom overflowHandler en ExtJS 4
extjs4 extjs4.1 (1)
Necesitamos implementar overflowHandler para el diseño de la barra de herramientas, que agregará una segunda barra de herramientas y ajustará los componentes de la primera barra de herramientas a la segunda cuando no se puedan mostrar porque no hay suficiente ancho del contenedor de la barra de herramientas. Primero, debemos anular Ext.panel.Panel:
Ext4.override(Ext4.panel.Panel, {
bridgeToolbars: function () {
var toolbar;
this.callParent(arguments);
if (this.tbar2) {
if (Ext4.isArray(this.tbar2)) {
toolbar = {
xtype: ''toolbar'',
items: this.tbar2
};
} else if (!toolbar.xtype) {
toolbar.xtype = ''toolbar'';
}
toolbar.dock = ''top'';
toolbar.isTbar2 = true;
this.dockedItems = this.dockedItems.concat(toolbar);
this.tbar2 = null;
}
},
onRender: function () {
this.callParent(arguments);
var topBars = this.getDockedItems(''toolbar[dock="top"]''),
i,
len;
for (i = 0, len = topBars.length; i < len; i++) {
if (topBars[i].isTbar2) {
this.tbar2 = topBars[i];
break;
}
}
},
/**
* Creates, if not exists, and returns toolbar at passed position
* @param {Ext.panel.Panel} panel
* @param {String} position
* @return {Ext.toolbar.Toolbar}
*/
getDynamicTBar: function (position) {
var panel = this,
params,
tb;
position = position || ''top'';
if (position === ''tbar2'') {
tb = panel.tbar2;
params = {
dock: ''top'',
isTbar2: true,
layout: {
overflowHandler: ''Scroller''
}
};
} else {
tb = panel.getDockedItems(''toolbar[dock="'' + position + ''"]'');
params = {
dock: position
};
if (tb.length > 0) {
tb = tb[0];
}
}
if (!tb) {
tb = Ext4.create(''Ext4.toolbar.Toolbar'', params);
panel.addDocked(tb);
if (position === ''tbar2'') {
panel.tbar2 = tb;
}
}
return tb;
}
});
A continuación, tenemos que crear la clase Ext4.layout.container.boxOverflow.TBar2 (tiene un nombre tan largo porque ExtJS busca handleOverflow (que es una instancia de String) en el espacio de nombres Ext4.layout.container.boxOverflow codificado).
/**
* @class Ext4.layout.container.boxOverflow.TBar2
* Class for using as overflowHandler
* @extends Ext.layout.container.boxOverflow.None
*/
Ext4.define(''Ext4.layout.container.boxOverflow.TBar2'', {
extend: ''Ext4.layout.container.boxOverflow.None'',
/**
* @private
* @property {Boolean} initialized
*/
initialized: false,
constructor: function () {
/**
* @private
* @property {Array} tbar2Items
* List of moved components
*/
this.tbar2Items = [];
return this.callParent(arguments);
},
beginLayout: function (ownerContext) {
if (!this.initialized) {
this.layout.owner.ownerCt.on(''afterlayout'', this.createTBar2, this);
this.initialized = true;
}
this.callParent(arguments);
this.clearOverflow(ownerContext);
},
beginLayoutCycle: function (ownerContext, firstCycle) {
this.callParent(arguments);
if (!firstCycle) {
this.clearOverflow(ownerContext);
this.layout.cacheChildItems(ownerContext);
}
},
getOverflowCls: function () {
return Ext4.baseCSSPrefix + this.layout.direction + ''-box-overflow-body'';
},
/**
* @private
* @property {Object} _asLayoutRoot
*/
_asLayoutRoot: {
isRoot: true
},
clearOverflow: function () {
// If afterlayout is not processing and tbar2 already created,
// we can to move components from tbar2 to first toolbar, because now
// there isn''t any overflow
if (!this.processing && this.tbar2) {
this.tbar2.items.each(function (item) {
this.tbar1.add(item);
// change ui from saved property, or CSS will be incorrect
item.ui = item.origUI;
}, this);
this.tbar2.removeAll(false);
this.tbar2.hide();
}
this.tbar2Items.length = 0;
},
/**
* @private
* Creates tbar2 and does other routines
*/
createTBar2: function () {
// if afterlayout event is still processing,
// or we don''t need to handle toolbar overflow, just return from function
if (this.processing || !this.doTbar2) {
return;
}
this.processing = true;
this.doTbar2 = false;
var me = this,
ownerContext = this.mOwnerContext,
layout = me.layout,
owner = layout.owner,
names = layout.getNames(),
startProp = names.x,
sizeProp = names.width,
plan = ownerContext.state.boxPlan,
available = plan.targetSize[sizeProp],
childItems = ownerContext.childItems,
len = childItems.length,
childContext,
comp, i, props,
tbarOwner = owner.ownerCt;
me.tbar1 = owner;
// save components which will be moved
owner.suspendLayouts();
me.tbar2Items.length = 0;
for (i = 0; i < len; i++) {
childContext = childItems[i];
props = childContext.props;
if (props[startProp] + props[sizeProp] > available) {
comp = childContext.target;
me.tbar2Items.push(comp);
// save original ui property
comp.origUI = comp.ui;
owner.remove(comp, false);
}
}
owner.resumeLayouts();
// add tbar2 to the layout cycle (you can see very similar code in clearOverflow
// method of Ext.layout.container.boxOverflow.Menu)
tbarOwner.suspendLayouts();
me.tbar2 = tbarOwner.getDynamicTBar(''tbar2'');
me.tbar2.show();
// moving components
Ext4.each(me.tbar2Items, function (item, index) {
me.tbar2.insert(index, item);
item.ui = item.origUI;
});
tbarOwner.resumeLayouts(this._asLayoutRoot);
this.processing = false;
},
handleOverflow: function (ownerContext) {
// set flag and store context for later using
this.doTbar2 = true;
this.mOwnerContext = ownerContext;
}
});
Tenga en cuenta que utilizo el arranque ExtJS 4 (porque en mi aplicación web también existe ExtJD 2.3), por lo que en su código probablemente deba usar Ext.
en lugar de Ext4.
Tengo un panel con dos toolbars
. ¿Cómo puedo implementar una clase personalizada para usar como overflowHandler
, que moverá los componentes a la segunda barra de herramientas en el desbordamiento de la primera barra de herramientas?
Traté de usar el código de Ext.layout.container.boxOverflow.Menu
, pero mi segunda barra de herramientas simplemente se oculta.
Aquí está mi código, que se mezcló con el ejemplo de toolbar overflow
de ExtJS 4
distributive.
Ext.require([''Ext.window.Window'', ''Ext.toolbar.Toolbar'', ''Ext.menu.ColorPicker'', ''Ext.form.field.Date'']);
Ext.onReady(function(){
/**
* Override for implementing tbar2
*/
Ext.override(Ext.panel.Panel, {
bridgeToolbars : function () {
var toolbar;
this.callParent(arguments);
if (this.tbar2) {
if (Ext.isArray(this.tbar2)) {
toolbar = {
xtype : ''toolbar'',
items : this.tbar2
};
}
else if (!toolbar.xtype) {
toolbar.xtype = ''toolbar'';
}
toolbar.dock = ''top'';
toolbar.isTbar2 = true;
this.dockedItems = this.dockedItems.concat(toolbar);
this.tbar2 = null;
}
},
onRender : function () {
this.callParent(arguments);
var topBars = this.getDockedItems(''toolbar[dock="top"]''),
i,
len;
for (i = 0, len = topBars.length; i < len; i++) {
if (topBars[i].isTbar2) {
this.tbar2 = topBars[i];
break;
}
}
},
/**
* Lazy creates new toolbar and returns it
* @param {Ext.panel.Panel} panel
* @param {String} position
* @return {Ext.toolbar.Toolbar}
*/
getDynamicTBar : function (position) {
var panel = this,
params,
tb;
position = position || ''top'';
if (position === ''tbar2'') {
tb = panel.tbar2;
params = {dock : ''top'', isTbar2 : true};
}
else {
tb = panel.getDockedItems(''toolbar[dock="'' + position + ''"]'');
params = {dock : position};
if (tb.length > 0) {
tb = tb[0];
}
}
if (!tb) {
console.log(''created tb at '' + position);
tb = Ext.create(''Ext.toolbar.Toolbar'', params);
panel.addDocked(tb);
}
return tb;
}
});
Ext.define(''Ext.layout.container.boxOverflow.TBar2'', {
extend : ''Ext.layout.container.boxOverflow.None'',
constructor : function () {
this.tbar2Items = [];
return this.callParent(arguments);
},
beginLayout : function (ownerContext) {
this.callParent(arguments);
this.clearOverflow(ownerContext);
},
beginLayoutCycle : function (ownerContext, firstCycle) {
this.callParent(arguments);
if (!firstCycle) {
this.clearOverflow(ownerContext);
this.layout.cacheChildItems(ownerContext);
}
},
getOverflowCls : function () {
return Ext.baseCSSPrefix + this.layout.direction + ''-box-overflow-body'';
},
_asLayoutRoot : { isRoot : true },
clearOverflow : function () {
if (this.tbar2) {
this.tbar2.suspendLayouts();
this.tbar2.hide();
this.tbar2.resumeLayouts(this._asLayoutRoot);
}
this.tbar2Items.length = 0;
},
handleOverflow : function (ownerContext) {
var me = this,
layout = me.layout,
owner = layout.owner,
names = layout.getNames(),
startProp = names.x,
sizeProp = names.width,
plan = ownerContext.state.boxPlan,
available = plan.targetSize[sizeProp],
childItems = ownerContext.childItems,
len = childItems.length,
childContext,
comp, i, props,
tbarOwner = owner.ownerCt;
owner.suspendLayouts();
// Hide all items which are off the end, and store them to allow them to be restored
// before each layout operation.
me.tbar2Items.length = 0;
for (i = 0; i < len; i++) {
childContext = childItems[i];
props = childContext.props;
if (props[startProp] + props[sizeProp] > available) {
comp = childContext.target;
me.tbar2Items.push(comp);
owner.remove(comp, false);
}
}
owner.resumeLayouts();
if (!me.tbar2 && (tbarOwner instanceof Ext.panel.Panel)) {
me.tbar2 = tbarOwner.getDynamicTBar(''tbar2'');
}
me.tbar2.suspendLayouts();
me.tbar2.show();
Ext.each(me.tbar2Items, function(item, index) {
me.tbar2.add(item);
});
me.tbar2.resumeLayouts(me._asLayoutRoot);
}
});
var handleAction = function(action){
Ext.example.msg(''<b>Action</b>'', ''You clicked "'' + action + ''"'');
};
var colorMenu = Ext.create(''Ext.menu.ColorPicker'', {
handler: function(cm, color){
Ext.example.msg(''Color Selected'', ''<span style="color:#'' + color + '';">You choose {0}.</span>'', color);
}
});
var showDate = function(d, value) {
Ext.example.msg(''<b>Action date</b>'', ''You picked '' + Ext.Date.format(value, d.format));
};
var fromPicker = false;
Ext.create(''Ext.window.Window'', {
title: ''Standard'',
closable: false,
height:250,
width: 500,
bodyStyle: ''padding:10px'',
contentEl: ''content'',
autoScroll: true,
tbar: Ext.create(''Ext.toolbar.Toolbar'', {
layout: {
overflowHandler: ''TBar2''
},
items: [{
xtype:''splitbutton'',
text: ''Menu Button'',
iconCls: ''add16'',
handler: Ext.Function.pass(handleAction, ''Menu Button''),
menu: [{text: ''Menu Item 1'', handler: Ext.Function.pass(handleAction, ''Menu Item 1'')}]
},''-'',{
xtype:''splitbutton'',
text: ''Cut'',
iconCls: ''add16'',
handler: Ext.Function.pass(handleAction, ''Cut''),
menu: [{text: ''Cut menu'', handler: Ext.Function.pass(handleAction, ''Cut menu'')}]
},{
text: ''Copy'',
iconCls: ''add16'',
handler: Ext.Function.pass(handleAction, ''Copy'')
},{
text: ''Paste'',
iconCls: ''add16'',
menu: [{text: ''Paste menu'', handler: Ext.Function.pass(handleAction, ''Paste menu'')}]
},''-'',{
text: ''Format'',
iconCls: ''add16'',
handler: Ext.Function.pass(handleAction, ''Format'')
},''->'', {
fieldLabel: ''Action'',
labelWidth: 70,
width: 180,
xtype: ''datefield'',
labelSeparator: '''',
enableKeyEvents: true,
listeners: {
expand: function(){
fromPicker = true;
},
collapse: function(){
fromPicker = false;
},
change: function(d, newVal, oldVal) {
if (fromPicker || !d.isVisible()) {
showDate(d, newVal);
}
},
keypress: {
buffer: 500,
fn: function(field){
var value = field.getValue();
if (value !== null && field.isValid()) {
showDate(field, value);
}
}
}
}
}, {
text: ''Sell'',
iconCls: ''money-down'',
enableToggle: true,
toggleHandler: function(button, pressed) {
Ext.example.msg(''<b>Action</b>'', ''Right ToggleButton '' + (pressed ? ''Buy'' : ''Sell''));
button.setText(pressed ? ''Buy'' : ''Sell'')
button.setIconCls(pressed ? ''money-up'' : ''money-down'')
}
}, {
text: ''Choose a Color'',
menu: colorMenu // <-- submenu by reference
}]
})
}).show();
});