2 * @class Ext.layout.container.boxOverflow.Menu
3 * @extends Ext.layout.container.boxOverflow.None
6 Ext.define('Ext.layout.container.boxOverflow.Menu', {
8 /* Begin Definitions */
10 extend: 'Ext.layout.container.boxOverflow.None',
11 requires: ['Ext.toolbar.Separator', 'Ext.button.Button'],
12 alternateClassName: 'Ext.layout.boxOverflow.Menu',
17 * @cfg {String} afterCtCls
18 * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
19 * which must always be present at the rightmost edge of the Container
23 * @property noItemsMenuText
25 * HTML fragment to render into the toolbar overflow menu if there are no items to display
27 noItemsMenuText : '<div class="' + Ext.baseCSSPrefix + 'toolbar-no-items">(None)</div>',
29 constructor: function(layout) {
32 me.callParent(arguments);
34 // Before layout, we need to re-show all items which we may have hidden due to a previous overflow.
35 layout.beforeLayout = Ext.Function.createInterceptor(layout.beforeLayout, this.clearOverflow, this);
37 me.afterCtCls = me.afterCtCls || Ext.baseCSSPrefix + 'box-menu-' + layout.parallelAfter;
41 * Array of all items that are currently hidden and should go into the dropdown menu
46 onRemove: function(comp){
47 Ext.Array.remove(this.menuItems, comp);
50 handleOverflow: function(calculations, targetSize) {
53 methodName = 'get' + layout.parallelPrefixCap,
55 posArgs = [null, null];
57 me.callParent(arguments);
58 this.createMenu(calculations, targetSize);
59 newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
60 newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - me.afterCt[methodName]();
62 // Center the menuTrigger button.
63 // TODO: Should we emulate align: 'middle' like this, or should we 'stretchmax' the menuTrigger?
64 posArgs[layout.perpendicularSizeIndex] = (calculations.meta.maxSize - me.menuTrigger['get' + layout.perpendicularPrefixCap]()) / 2;
65 me.menuTrigger.setPosition.apply(me.menuTrigger, posArgs);
67 return { targetSize: newSize };
72 * Called by the layout, when it determines that there is no overflow.
73 * Also called as an interceptor to the layout's onLayout method to reshow
74 * previously hidden overflowing items.
76 clearOverflow: function(calculations, targetSize) {
78 newWidth = targetSize ? targetSize.width + (me.afterCt ? me.afterCt.getWidth() : 0) : 0,
81 length = items.length,
85 for (; i < length; i++) {
92 height: targetSize.height,
101 showTrigger: function() {
102 this.menuTrigger.show();
108 hideTrigger: function() {
109 if (this.menuTrigger !== undefined) {
110 this.menuTrigger.hide();
116 * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
118 beforeMenuShow: function(menu) {
120 items = me.menuItems,
126 var needsSep = function(group, prev){
127 return group.isXType('buttongroup') && !(prev instanceof Ext.toolbar.Separator);
133 for (; i < len; i++) {
136 // Do not show a separator as a first item
137 if (!i && (item instanceof Ext.toolbar.Separator)) {
140 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
144 me.addComponentToMenu(menu, item);
148 // put something so the menu isn't empty if no compatible items found
149 if (menu.items.length < 1) {
150 menu.add(me.noItemsMenuText);
156 * Returns a menu config for a given component. This config is used to create a menu item
157 * to be added to the expander menu
158 * @param {Ext.Component} component The component to create the config for
159 * @param {Boolean} hideOnClick Passed through to the menu item
161 createMenuConfig : function(component, hideOnClick) {
162 var config = Ext.apply({}, component.initialConfig),
163 group = component.toggleGroup;
165 Ext.copyTo(config, component, [
166 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
170 text : component.overflowText || component.text,
171 hideOnClick: hideOnClick,
175 if (group || component.enableToggle) {
178 checked: component.pressed,
180 checkchange: function(item, checked){
181 component.toggle(checked);
187 delete config.ownerCt;
195 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
196 * @param {Ext.menu.Menu} menu The menu to add to
197 * @param {Ext.Component} component The component to add
199 addComponentToMenu : function(menu, component) {
201 if (component instanceof Ext.toolbar.Separator) {
203 } else if (component.isComponent) {
204 if (component.isXType('splitbutton')) {
205 menu.add(me.createMenuConfig(component, true));
207 } else if (component.isXType('button')) {
208 menu.add(me.createMenuConfig(component, !component.menu));
210 } else if (component.isXType('buttongroup')) {
211 component.items.each(function(item){
212 me.addComponentToMenu(menu, item);
215 menu.add(Ext.create(Ext.getClassName(component), me.createMenuConfig(component)));
222 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
223 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
225 clearMenu : function() {
226 var menu = this.moreMenu;
227 if (menu && menu.items) {
228 menu.items.each(function(item) {
238 * Creates the overflow trigger and menu used when enableOverflow is set to true and the items
239 * in the layout are too wide to fit in the space available
241 createMenu: function(calculations, targetSize) {
244 startProp = layout.parallelBefore,
245 sizeProp = layout.parallelPrefix,
246 available = targetSize[sizeProp],
247 boxes = calculations.boxes,
252 if (!me.menuTrigger) {
253 me.createInnerElements();
258 * @type Ext.menu.Menu
259 * The expand menu - holds items for every item that cannot be shown
260 * because the container is currently not large enough.
262 me.menu = Ext.create('Ext.menu.Menu', {
266 beforeshow: me.beforeMenuShow
272 * @property menuTrigger
273 * @type Ext.button.Button
274 * The expand button which triggers the overflow menu to be shown
276 me.menuTrigger = Ext.create('Ext.button.Button', {
277 ownerCt : me.layout.owner, // To enable the Menu to ascertain a valid zIndexManager owner in the same tree
278 iconCls : Ext.baseCSSPrefix + layout.owner.getXType() + '-more-icon',
279 ui : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',
281 getSplitCls: function() { return '';},
286 available -= me.afterCt.getWidth();
288 // Hide all items which are off the end, and store them to allow them to be restored
289 // before each layout operation.
290 me.menuItems.length = 0;
291 for (; i < len; i++) {
293 if (box[startProp] + box[sizeProp] > available) {
294 me.menuItems.push(box.component);
295 box.component.hide();
302 * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
303 * @param {Ext.container.Container} container The Container attached to this Layout instance
304 * @param {Ext.core.Element} target The target Element
306 createInnerElements: function() {
308 target = me.layout.getRenderTarget();
311 target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
312 this.afterCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + this.afterCtCls}, 'before');
319 destroy: function() {
320 Ext.destroy(this.menu, this.menuTrigger);