Pregunta

Tengo panel con dos toolbars.¿Cómo puedo implementar la clase personalizada para usar como overflowHandler, que moverá los componentes a la segunda barra de herramientas en el desbordamiento de la barra de herramientas?

Intenté usar el código de Ext.layout.container.boxOverflow.Menu, pero mi segunda barra de herramientas simplemente se esconde.

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();
});

¿Fue útil?

Solución

Necesitamos implementar el desbordamiento para el diseño de la barra de herramientas, que agregará una segunda barra de herramientas y envuelva los componentes de la primera barra de herramientas a la segunda cuando no se pueden mostrar porque no hay suficiente ancho del contenedor de la barra de herramientas. Primero, necesitamos 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;
    }
});

Siguiente, necesitamos crear class ext4.layout.container.boxoverflow.tbar2 (tiene un nombre tan largo porque Extjs busca MANDANOBERFLOW (que es instancia de cadena) en el espacio de nombres con codificación dura).

/**
 * @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 Extjs 4 BootStrapping (porque en mi aplicación web también hay extjd 2.3), por lo que en su código, probablemente, debe usar Ext. en lugar de Ext4.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top