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 handleOverflow: function(calculations, targetSize) {
49 methodName = 'get' + layout.parallelPrefixCap,
51 posArgs = [null, null];
53 me.callParent(arguments);
54 this.createMenu(calculations, targetSize);
55 newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
56 newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - me.afterCt[methodName]();
58 // Center the menuTrigger button.
59 // TODO: Should we emulate align: 'middle' like this, or should we 'stretchmax' the menuTrigger?
60 posArgs[layout.perpendicularSizeIndex] = (calculations.meta.maxSize - me.menuTrigger['get' + layout.perpendicularPrefixCap]()) / 2;
61 me.menuTrigger.setPosition.apply(me.menuTrigger, posArgs);
63 return { targetSize: newSize };
68 * Called by the layout, when it determines that there is no overflow.
69 * Also called as an interceptor to the layout's onLayout method to reshow
70 * previously hidden overflowing items.
72 clearOverflow: function(calculations, targetSize) {
74 newWidth = targetSize ? targetSize.width + (me.afterCt ? me.afterCt.getWidth() : 0) : 0,
77 length = items.length,
81 for (; i < length; i++) {
88 height: targetSize.height,
97 showTrigger: function() {
98 this.menuTrigger.show();
104 hideTrigger: function() {
105 if (this.menuTrigger != undefined) {
106 this.menuTrigger.hide();
112 * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
114 beforeMenuShow: function(menu) {
116 items = me.menuItems,
122 var needsSep = function(group, prev){
123 return group.isXType('buttongroup') && !(prev instanceof Ext.toolbar.Separator);
129 for (; i < len; i++) {
132 // Do not show a separator as a first item
133 if (!i && (item instanceof Ext.toolbar.Separator)) {
136 if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
140 me.addComponentToMenu(menu, item);
144 // put something so the menu isn't empty if no compatible items found
145 if (menu.items.length < 1) {
146 menu.add(me.noItemsMenuText);
152 * Returns a menu config for a given component. This config is used to create a menu item
153 * to be added to the expander menu
154 * @param {Ext.Component} component The component to create the config for
155 * @param {Boolean} hideOnClick Passed through to the menu item
157 createMenuConfig : function(component, hideOnClick) {
158 var config = Ext.apply({}, component.initialConfig),
159 group = component.toggleGroup;
161 Ext.copyTo(config, component, [
162 'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
166 text : component.overflowText || component.text,
167 hideOnClick: hideOnClick,
171 if (group || component.enableToggle) {
174 checked: component.pressed,
176 checkchange: function(item, checked){
177 component.toggle(checked);
183 delete config.ownerCt;
191 * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
192 * @param {Ext.menu.Menu} menu The menu to add to
193 * @param {Ext.Component} component The component to add
195 addComponentToMenu : function(menu, component) {
197 if (component instanceof Ext.toolbar.Separator) {
199 } else if (component.isComponent) {
200 if (component.isXType('splitbutton')) {
201 menu.add(me.createMenuConfig(component, true));
203 } else if (component.isXType('button')) {
204 menu.add(me.createMenuConfig(component, !component.menu));
206 } else if (component.isXType('buttongroup')) {
207 component.items.each(function(item){
208 me.addComponentToMenu(menu, item);
211 menu.add(Ext.create(Ext.getClassName(component), me.createMenuConfig(component)));
218 * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
219 * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
221 clearMenu : function() {
222 var menu = this.moreMenu;
223 if (menu && menu.items) {
224 menu.items.each(function(item) {
234 * Creates the overflow trigger and menu used when enableOverflow is set to true and the items
235 * in the layout are too wide to fit in the space available
237 createMenu: function(calculations, targetSize) {
240 startProp = layout.parallelBefore,
241 sizeProp = layout.parallelPrefix,
242 available = targetSize[sizeProp],
243 boxes = calculations.boxes,
248 if (!me.menuTrigger) {
249 me.createInnerElements();
254 * @type Ext.menu.Menu
255 * The expand menu - holds items for every item that cannot be shown
256 * because the container is currently not large enough.
258 me.menu = Ext.create('Ext.menu.Menu', {
262 beforeshow: me.beforeMenuShow
268 * @property menuTrigger
269 * @type Ext.button.Button
270 * The expand button which triggers the overflow menu to be shown
272 me.menuTrigger = Ext.create('Ext.button.Button', {
273 ownerCt : me.layout.owner, // To enable the Menu to ascertain a valid zIndexManager owner in the same tree
274 iconCls : Ext.baseCSSPrefix + layout.owner.getXType() + '-more-icon',
275 ui : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',
277 getSplitCls: function() { return '';},
282 available -= me.afterCt.getWidth();
284 // Hide all items which are off the end, and store them to allow them to be restored
285 // before each layout operation.
286 me.menuItems.length = 0;
287 for (; i < len; i++) {
289 if (box[startProp] + box[sizeProp] > available) {
290 me.menuItems.push(box.component);
291 box.component.hide();
298 * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
299 * @param {Ext.container.Container} container The Container attached to this Layout instance
300 * @param {Ext.core.Element} target The target Element
302 createInnerElements: function() {
304 target = me.layout.getRenderTarget();
307 target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
308 this.afterCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + this.afterCtCls}, 'before');
315 destroy: function() {
316 Ext.destroy(this.menu, this.menuTrigger);