TabPanel Context Menu can be used for dynamic TabPanels. This feature is available in some IDEs, document editors, and internet browsers. I split the code to three files and did not use MVC pattern, sad but true.

The plugin has the following manipulation functionality:

  • Close tab under mouse pointer;
  • Close all tabs;
  • Close all tabs except the one, which is under mouse pointer;
  • Switch the TabBar‘s position to top, right, bottom or left.

You can also add permit-to-close mechanisms for the tabs, which are not allowed to be closed.

app/ux/tab/contextMenu/Plugin.js

Ext.define('app.ux.tab.contextMenu.Plugin', {
    extend: 'Ext.plugin.Abstract',
    alias: 'plugin.contextmenu',
    requires: [
        'app.ux.tab.contextMenu.Menu'
    ],
    init: function (tabPanel) {
        var tabBar = tabPanel.getTabBar();
        tabBar.on('add', this.onTabAdd, this);
    },

    onTabAdd: function (tabBar, tab) {
        if (tab.renderd) {
            this.addContextMenuToTab(tab);
        } else {
            tab.on('afterrender', this.addContextMenuToTab, this, {single: true});
        }
    },

    addContextMenuToTab: function (tab) {
        var contextMenu = this.getContextMenu();
        tab.getEl().on('contextmenu', function (e) {
            e.preventDefault();
            contextMenu.setTab(tab);
            contextMenu.showAt(e.getX(), e.getY());
        }, this);
    },

    getContextMenu: function () {
        if (!this.contextMenu) {
            this.contextMenu = Ext.create('app.ux.tab.contextMenu.Menu', {
                tabPanel: this.getCmp()
            });
        }
        return this.contextMenu;
    }
});

 

app/ux/tab/contextMenu/Menu.js

Ext.define('app.ux.tab.contextMenu.Menu', {
    extend: 'Ext.menu.Menu',
    requires: [
        'app.ux.tab.contextMenu.TabPlacementMenu'
    ],

    tabPanel: false,
    tab: false,

    initComponent: function () {
        this.items = [
            this.getCloseTab(),
            this.getCloseAllTabs(),
            this.getCloseOtherTabs(),
            '-', {
                xtype: 'menuitem',
                text: "Tab Placement",
                menu: this.getTabPlacementMenu()
            }
        ];
        this.getTabPanel().on('afterlayout', this.onTabPanelAfterLayout, this);
        this.callParent();
    },

    getCloseTab: function () {
        if (!this.closeTab) {
            this.closeTab = Ext.create('Ext.menu.Item', {
                text: "Close",
                handler: this.closeTabHandler,
                scope: this
            });
        }
        return this.closeTab;
    },

    getCloseAllTabs: function () {
        if (!this.closeAllTabs) {
            this.closeAllTabs = Ext.create('Ext.menu.Item', {
                text: "Close All",
                handler: this.closeAllTabsHandler,
                scope: this
            });
        }
        return this.closeAllTabs;
    },

    getCloseOtherTabs: function () {
        if (!this.closeOtherTabs) {
            this.closeOtherTabs = Ext.create('Ext.menu.Item', {
                text: "Close Others",
                handler: this.closeOtherTabsHandler,
                scope: this
            });
        }
        return this.closeOtherTabs;
    },

    getTabPlacementMenu: function () {
        if (!this.tabPlacementMenu) {
            this.tabPlacementMenu = Ext.create('app.ux.tab.contextMenu.TabPlacementMenu', {
                tabPanel: this.tabPanel
            });
        }
        return this.tabPlacementMenu;
    },

    getTabPanel: function () {
        return this.tabPanel;
    },

    setTab: function (tab) {
        this.tab = tab;
        return this;
    },

    getTab: function (tab) {
        return this.tab;
    },

    onTabPanelAfterLayout: function (tabPanel) {
        this.getTabPlacementMenu().setTabPosition(tabPanel.getTabPosition());
    },

    closeTabHandler: function () {
        this.getTabPanel().getTabBar().closeTab(this.getTab());
    },

    closeAllTabsHandler: function () {
        this.getTabPanel().removeAll();
    },

    closeOtherTabsHandler: function () {
        var tabBar = this.getTabPanel().getTabBar(),
            tabs = tabBar.query('tab');
        Ext.Array.each(tabs, function (tab) {
            if (tab.getId() != this.getTab().getId()) {
                tabBar.closeTab(tab);
            }

        }, this);
    }
});

 

app/ux/tab/contextMenu/TabPlacementMenu.js

Ext.define('app.ux.tab.contextMenu.TabPlacementMenu', {
    extend: 'Ext.menu.Menu',

    tabPanel: false,

    initComponent: function () {
        this.items = [
            this.getTopPlacementItem(),
            this.getRightPlacementItem(),
            this.getBottomPlacementItem(),
            this.getLeftPlacementItem()
        ];

        this.callParent();
    },

    getTopPlacementItem: function () {
        if (!this.topPlacementItem) {
            this.topPlacementItem = Ext.create('Ext.menu.Item', {
                text: "Top",
                glyph: 'xf062@FontAwesome',
                position: 'top',
                handler: this.changePositionHandler,
                scope: this
            });
        }
        return this.topPlacementItem;
    },

    getRightPlacementItem: function () {
        if (!this.rightPlacementItem) {
            this.rightPlacementItem = Ext.create('Ext.menu.Item', {
                text: "Right",
                glyph: 'xf061@FontAwesome',
                position: 'right',
                handler: this.changePositionHandler,
                scope: this
            });
        }
        return this.rightPlacementItem;
    },

    getBottomPlacementItem: function () {
        if (!this.bottomPlacementItem) {
            this.bottomPlacementItem = Ext.create('Ext.menu.Item', {
                text: "Bottom",
                glyph: 'xf063@FontAwesome',
                position: 'bottom',
                handler: this.changePositionHandler,
                scope: this
            });
        }
        return this.bottomPlacementItem;
    },

    getLeftPlacementItem: function () {
        if (!this.leftPlacementItem) {
            this.leftPlacementItem = Ext.create('Ext.menu.Item', {
                text: "Left",
                glyph: 'xf060@FontAwesome',
                position: 'left',
                handler: this.changePositionHandler,
                scope: this
            });
        }
        return this.leftPlacementItem;
    },

    getTabPanel: function () {
        return this.tabPanel;
    },

    changePositionHandler: function (menuItem) {
        this.getTabPanel().setTabPosition(menuItem.position)
    },

    setTabPosition: function (tabPosition) {
        this.items.each(function(menuItem) {
            menuItem.setDisabled(menuItem.position == tabPosition);
        }, this);
    }
});

 

Sample Usage: