Ext


Go Back   Ext JS Forums > Ext JS Community Forums (2.0) > Ext 2.x: User Extensions and Plugins

Reply
 
Thread Tools
  #41  
Old 04-27-2009, 08:25 AM
tobiu's Avatar
tobiu tobiu is online now
Ext User
 
Join Date: May 2007
Location: Cologne (Germany)
Posts: 472
tobiu is on a distinguished road
Send a message via ICQ to tobiu Send a message via Skype™ to tobiu
Default

since we have filtering of tabs and a way to display subTabs,
the triggerMenu is no longer only a scrollerMenu,
but can be used to faster navigate to subTabs in general.

so, it should be possible to show the menu always, even if the scrollers are not displayed.
i started with adding a config value
alwaysShowTrigger : true
and changed the code quite a bit again.
in the init-function, i extracted the creation of the trigger to the method createMenuTrigger(), since the trigger has to be created in 2 ways:

1) in this class (independend from the scrollerMenu)
2) as a sequence on scrollerCreation in the tabPanel-scope.

in general, it is already working, but i found some margin-problems again.
the problem is, that tabPanels do not have a method for removeScrollers.
so, when scrollers get hidden, the margin-right of the tabStrip wont fit and the menu might be over the right edge of the last tab.

the code also should be beautified a bit more.
i'm sorry, but i dont have more time for this right now.
if anyone would like to always show the menu, feel free to improve the code here.

so, this is a NOT STABLE version!!
the stable-one is some postings above this.

kind regards, tobiu

Ext.ns('Ext.ux');

/**
 * @class Ext.ux.TabScrollerMenu
 * @extends Ext.menu.Menu
 * @author
 *     Jay Garcia (http://tdg-i.com/59/how-to-add-a-tab-scroller-menu),
 *     Ed Spencer (http://edspencer.net),
 *     Tobias Uhlig (info@internetsachen.com)
 *     ExtJS - Team (who did the modified version of 3.0rc1?)
 */
Ext.ux.TabScrollerMenu = Ext.extend(Ext.menu.Menu, {

   /**
    * @property alwaysShowTrigger
    * @type boolean
    * Show the trigger even if all tabs are displayed
    */
    alwaysShowTrigger : true,
    
   /**
    * @property pageSize
    * @type int
    * The number of tab links to show per submenu
    */
    pageSize : 10,

   /**
    * @property maxTextLength
    * @type int
    * The maximum length of submenu text to display before truncation
    */
    maxTextLength  : 30,
    menuPrefixText : 'Tabs',

   /**
    * @property hasFilter
    * @type Boolean
    * True to include an optional filter textbox which removes any non-matching menu items
    * Needs Ext.ux.menu.TextFilterItem
    */
    hasFilter       : true,
    filterEmptyText : "Tabs filtern...",

   /**
    * Sets up plugin, creates a clickable element to trigger this menu to be displayed
    * @param {Ext.TabPanel} tabPanel The TabPanel to attach this plugin to
    */
    init: function(tabPanel) {
        this.tabPanel = tabPanel;
        this.createMenuItems();

        var menuRef = this;

        if(this.alwaysShowTrigger === true){
            this.tabPanel.on('render', function() {
                var tabMenuTrigger = menuRef.createMenuTrigger();
                tabMenuTrigger.show();
            });

        } else {
            //creates the menu trigger element in the TabPanel header / footer
            this.tabPanel.createScrollers = this.tabPanel.createScrollers.createSequence(function() {

                var tabMenuTrigger = menuRef.createMenuTrigger();

                this.scrollLeft.show = this.scrollLeft.show.createSequence(function() {
        	        tabMenuTrigger.show();
        	    });
        	    
        	    this.scrollLeft.hide = this.scrollLeft.hide.createSequence(function() {
        		tabMenuTrigger.hide();
        	    });
            });
        }
        
        this.tabPanel.createScrollers = this.tabPanel.createScrollers.createSequence(function() {
            var pos = this.tabPosition == 'bottom' ? 'footer' : 'header';
            Ext.fly(this[pos].child('.x-tab-scroller-right')).applyStyles({right: '18px'});
            
            Ext.get(this.strip.dom.parentNode).applyStyles({
                'margin-right': '36px'
            });
        });
        
        this.tabPanel.on('add',    menuRef.createMenuItems, menuRef);
        this.tabPanel.on('remove', menuRef.createMenuItems, menuRef);
    },

    createMenuTrigger: function() {
        var pos = this.tabPosition == 'bottom' ? 'footer' : 'header';

        //create the menu trigger
        var tabMenuTrigger = this.tabPanel[pos].insertFirst({cls: "x-tab-panel-menu"});
        if(pos == 'footer')tabMenuTrigger.applyStyles({'margin-top': '1px'});
        tabMenuTrigger.setHeight(this.tabPanel.stripWrap.dom.offsetHeight);
        tabMenuTrigger.on('click', function() { this.show(tabMenuTrigger); }, this);
        tabMenuTrigger.addClassOnOver('x-tab-panel-menu-over');
        
        var stripWidth = parseInt(this.tabPanel.strip.dom.parentNode.style.width) - 36;
        Ext.get(this.tabPanel.strip.dom.parentNode).applyStyles({
            'margin-right': '18px',
            'width'       : stripWidth + 'px'
        });
        
        return tabMenuTrigger;
    },

   /**
    * Creates a menu item for each tab in the TabPanel (paginated if there are more than
    * the requested page size).  Optionally removes current menu items first
    * @param {Boolean} clearExisting True to remove all current menu items first (defaults to true)
    */
    createMenuItems: function(clearExisting) {
        var clearExisting = clearExisting ? clearExisting : true;
        if (clearExisting) { this.removeAll(); }
        this.createFilterMenu();

        var numberOfItems = this.tabPanel.items.length;

        if (numberOfItems > this.pageSize) {
            var numberOfPages = Math.ceil(numberOfItems / this.pageSize);

            //create each submenu
            for (var i=0; i < numberOfPages; i++) {
                var subMenuItems = [];

                //create each submenu item
                for (var j = 0; j <= this.pageSize - 1; j++){
                    var currentItem = this.tabPanel.items.items[j + (i * this.pageSize)];
                    if (currentItem) {
                        subMenuItems.push(this.createSubMenuItem(currentItem));
                    };
                };

                //calculate text label for this submenu
                var lowerNumber = 1 + (this.pageSize * i);
                var higherNumber = Math.min(((i + 1) * this.pageSize), numberOfItems);
                var subMenuText  = String.format(this.menuPrefixText + ' {0} - {1}', lowerNumber, higherNumber);

                this.addMenuItem({text: subMenuText, menu: subMenuItems, iconCls: 'page_copy'});
            }
        } else {
            //can put all items in the same 'page'
            this.tabPanel.items.each(function(item) {
                this.addMenuItem(this.createSubMenuItem(item));
            }, this);
        }
    },

   /**
    * Returns a config object for a tab, suitable for placement inside a submenu
    * @param {Object} panel The panel instance to create this submenu item from
    * @param function handler The handler of the top-Level menu item
    * @return {Object} An object suitable for addition to a submenu
    */
    createSubMenuItem: function(panel, handler) {
        var text        = Ext.util.Format.stripTags(panel.title);
        var menuHandler = handler  ? handler  : this.tabPanel.setActiveTab.createDelegate(this.tabPanel, [panel]);

        var menuItem = {
             disabled : panel.disabled
            ,iconCls  : panel.iconCls
            ,handler  : menuHandler
            ,rawText  : panel.title
            ,scope    : this
            ,text     : Ext.util.Format.ellipsis(text, this.maxTextLength)
        };

        if(panel.tabPosition){
            var parentMenu = this;
            
            if(!panel.parentHandler){
                panel.on({
                     add    : function(){parentMenu.createMenuItems();}
                    ,remove : function(){parentMenu.createMenuItems();}
                });
            }
            panel.parentHandler = true;
            
            var subMenuItems = [];
            
            panel.items.each(function(item) {
                var subHandler = menuHandler.createSequence(item.ownerCt.setActiveTab.createDelegate(item.ownerCt, [item]));
                subMenuItems.push(this.createSubMenuItem(item, subHandler));
            }, this);
            menuItem.menu = subMenuItems;
        }
        return menuItem;
    },

    // public
    getPageSize : function() {
        return this.pageSize;
    },
    // public
    setPageSize : function(pageSize) {
        this.pageSize = pageSize;
    },
    // public
    getMaxTextLength : function() {
        return this.maxTextLength
    },
    // public
    setMaxTextLength : function(maxText) {
        this.maxText = maxTextLength;
    },
    // public
    getMenuPrefixText : function() {
        return this.menuPrefixText;
    },
    // public
    setMenuPrefixText : function(t) {
        this.menuPrefixText = t;
    },

   /**
    * Adds a filter menu item with a TextField if this.hasFilter is true
    * @return {Ext.menu.MenuItem/Null} The filter menu item
    */
    createFilterMenu: function() {
        if (this.hasFilter) {
            this.filterMenu = this.addItem(
                new Ext.ux.menu.TextFilterItem({
                    name : 'filter',
                    emptyText : this.filterEmptyText,
                    listeners: {
                        keyup: {
                            scope: this,
                            fn: function(e, input) {
                                if(e.getKey() == 40){ // down
                                    var m = this;
                                    if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
                                        m.tryActivate(0, 1);
                                    }
                                } else {
                                    this.filterItems(input.value);
                                }
                            }
                        }
                    }
                })
            );
          return this.filterMenu;
        }
    },

   /**
    * Iterates over each submenu item, hiding it if it does not match the filter text
    * Also hides the menu item itself if all submenu items are hidden
    */
    filterItems: function(filterText) {
        var filterRegex = new RegExp(filterText, ['i']);

        this.items.each(function(topMenu) {
            //don't filter on the filterMenu itself...
            if (topMenu != this.filterMenu) {
                if (topMenu.menu) {
                    var hideMenu = true;

                    //if we have submenu items, iterate over each and hide if necessary
                    topMenu.menu.items.each(function(subMenuItem) {
                        if (filterRegex.test(subMenuItem.rawText)) {
                          subMenuItem.show();
                          hideMenu = false;
                        } else
                            subMenuItem.hide();
                    });

                    //if we've hidden everything, hide the whole menu
                    hideMenu ? topMenu.hide() : topMenu.show();
                } else {
                    //if we don't have submenu items, iterate over top level menus and hide if necessary
                    filterRegex.test(topMenu.rawText) ? topMenu.show() : topMenu.hide();
                }
            }
        }, this);
        this.getEl().sync();
    }
});
Reply With Quote
Reply

Thread Tools

Posting Rules

Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

All times are GMT -5. The time now is 01:50 PM.

© 2006-2009 Ext, LLC
Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.