Custom overflowHandler implementation in ExtJS 4

I have a panel with two toolbars . How can I implement my own class to use as an overflowHandler that will move components to the second toolbar when the toolbar overflows for the first time?

I tried using the code Ext.layout.container.boxOverflow.Menu , but my second toolbar is just hiding.

Here is my code that was mixed with the toolbar overflow example from 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(); }); 
+6
source share
1 answer

We need to implement an overflowHandler for a toolbar layout that adds a second toolbar and wraps components from the first toolbar to the second when they cannot be displayed because the toolbar container is not wide enough. First, we need to override 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; } }); 

Next, we need to create the class Ext4.layout.container.boxOverflow.TBar2 (it has such a long name because ExtJS is looking for handleOverflow (which is an instance of String) in the hardcoded namespace Ext4.layout.container.boxOverflow).

 /** * @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; } }); 

Please note that I am using ExtJS 4 download (because there is ExtJD 2.3 in my web application), so you should probably use Ext. in your code Ext. instead of Ext4.

+3
source

Source: https://habr.com/ru/post/926581/


All Articles