|
|||||||
![]() |
|
|
Thread Tools |
|
#41
|
||||
|
||||
|
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 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();
}
});
|
![]() |
| Thread Tools | |
|
|