ExtJS 4中的自定义overflowHandler实现

时间:2012-09-29 14:47:27

标签: layout extjs extjs4 extjs4.1

我有两个toolbars的面板。如何实现自定义类以使用overflowHandler,这会将组件移动到第一个工具栏溢出的第二个工具栏上?

我尝试使用Ext.layout.container.boxOverflow.Menu的代码,但我的第二个工具栏只是隐藏了。

这是我的代码,与toolbar overflow分配中的ExtJS 4示例混合在一起。

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

1 个答案:

答案 0 :(得分:3)

我们需要为工具栏布局实现overflowHandler,这将添加第二个工具栏并将组件从第一个工具栏包装到第二个工具栏,因为工具栏的容器宽度不够而无法显示它们。 首先,我们需要覆盖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;
    }
});

接下来,我们需要创建类Ext4.layout.container.boxOverflow.TBar2(它有很长的名称,因为ExtJS在硬编码的Ext4.layout.container.boxOverflow命名空间中搜索handleOverflow(它是String的实例))。

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

});

请注意我使用ExtJS 4引导(因为在我的网络应用中也有ExtJD 2.3),所以在你的代码中你必须使用Ext.而不是Ext4.

相关问题