Upgrade to ExtJS 3.3.0 - Released 10/06/2010
[extjs.git] / docs / source / MenuOverflow.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.0
11  * Copyright(c) 2006-2010 Ext JS, Inc.
12  * licensing@extjs.com
13  * http://www.extjs.com/license
14  */
15 <div id="cls-Ext.layout.boxOverflow.Menu"></div>/**
16  * @class Ext.layout.boxOverflow.Menu
17  * @extends Ext.layout.boxOverflow.None
18  * Description
19  */
20 Ext.layout.boxOverflow.Menu = Ext.extend(Ext.layout.boxOverflow.None, {
21     <div id="cfg-Ext.layout.boxOverflow.Menu-null"></div>/**
22      * @cfg afterCls
23      * @type String
24      * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
25      * which must always be present at the rightmost edge of the Container
26      */
27     afterCls: 'x-strip-right',
28     
29     <div id="prop-Ext.layout.boxOverflow.Menu-noItemsMenuText"></div>/**
30      * @property noItemsMenuText
31      * @type String
32      * HTML fragment to render into the toolbar overflow menu if there are no items to display
33      */
34     noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
35     
36     constructor: function(layout) {
37         Ext.layout.boxOverflow.Menu.superclass.constructor.apply(this, arguments);
38         
39         <div id="prop-Ext.layout.boxOverflow.Menu-menuItems"></div>/**
40          * @property menuItems
41          * @type Array
42          * Array of all items that are currently hidden and should go into the dropdown menu
43          */
44         this.menuItems = [];
45     },
46     
47     /**
48      * @private
49      * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
50      * @param {Ext.Container} container The Container attached to this Layout instance
51      * @param {Ext.Element} target The target Element
52      */
53     createInnerElements: function() {
54         if (!this.afterCt) {
55             this.afterCt  = this.layout.innerCt.insertSibling({cls: this.afterCls},  'before');
56         }
57     },
58     
59     /**
60      * @private
61      */
62     clearOverflow: function(calculations, targetSize) {
63         var newWidth = targetSize.width + (this.afterCt ? this.afterCt.getWidth() : 0),
64             items    = this.menuItems;
65         
66         this.hideTrigger();
67         
68         for (var index = 0, length = items.length; index < length; index++) {
69             items.pop().component.show();
70         }
71         
72         return {
73             targetSize: {
74                 height: targetSize.height,
75                 width : newWidth
76             }
77         };
78     },
79     
80     /**
81      * @private
82      */
83     showTrigger: function() {
84         this.createMenu();
85         this.menuTrigger.show();
86     },
87     
88     /**
89      * @private
90      */
91     hideTrigger: function() {
92         if (this.menuTrigger != undefined) {
93             this.menuTrigger.hide();
94         }
95     },
96     
97     /**
98      * @private
99      * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
100      */
101     beforeMenuShow: function(menu) {
102         var items = this.menuItems,
103             len   = items.length,
104             item,
105             prev;
106
107         var needsSep = function(group, item){
108             return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
109         };
110         
111         this.clearMenu();
112         menu.removeAll();
113         
114         for (var i = 0; i < len; i++) {
115             item = items[i].component;
116             
117             if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
118                 menu.add('-');
119             }
120             
121             this.addComponentToMenu(menu, item);
122             prev = item;
123         }
124
125         // put something so the menu isn't empty if no compatible items found
126         if (menu.items.length < 1) {
127             menu.add(this.noItemsMenuText);
128         }
129     },
130     
131     /**
132      * @private
133      * Returns a menu config for a given component. This config is used to create a menu item
134      * to be added to the expander menu
135      * @param {Ext.Component} component The component to create the config for
136      * @param {Boolean} hideOnClick Passed through to the menu item
137      */
138     createMenuConfig : function(component, hideOnClick){
139         var config = Ext.apply({}, component.initialConfig),
140             group  = component.toggleGroup;
141
142         Ext.copyTo(config, component, [
143             'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
144         ]);
145
146         Ext.apply(config, {
147             text       : component.overflowText || component.text,
148             hideOnClick: hideOnClick
149         });
150
151         if (group || component.enableToggle) {
152             Ext.apply(config, {
153                 group  : group,
154                 checked: component.pressed,
155                 listeners: {
156                     checkchange: function(item, checked){
157                         component.toggle(checked);
158                     }
159                 }
160             });
161         }
162
163         delete config.ownerCt;
164         delete config.xtype;
165         delete config.id;
166
167         return config;
168     },
169
170     /**
171      * @private
172      * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
173      * @param {Ext.menu.Menu} menu The menu to add to
174      * @param {Ext.Component} component The component to add
175      */
176     addComponentToMenu : function(menu, component) {
177         if (component instanceof Ext.Toolbar.Separator) {
178             menu.add('-');
179
180         } else if (Ext.isFunction(component.isXType)) {
181             if (component.isXType('splitbutton')) {
182                 menu.add(this.createMenuConfig(component, true));
183
184             } else if (component.isXType('button')) {
185                 menu.add(this.createMenuConfig(component, !component.menu));
186
187             } else if (component.isXType('buttongroup')) {
188                 component.items.each(function(item){
189                      this.addComponentToMenu(menu, item);
190                 }, this);
191             }
192         }
193     },
194     
195     /**
196      * @private
197      * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
198      * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
199      */
200     clearMenu : function(){
201         var menu = this.moreMenu;
202         if (menu && menu.items) {
203             menu.items.each(function(item){
204                 delete item.menu;
205             });
206         }
207     },
208     
209     /**
210      * @private
211      * Creates the overflow trigger and menu used when enableOverflow is set to true and the items
212      * in the layout are too wide to fit in the space available
213      */
214     createMenu: function() {
215         if (!this.menuTrigger) {
216             this.createInnerElements();
217             
218             /**
219              * @private
220              * @property menu
221              * @type Ext.menu.Menu
222              * The expand menu - holds items for every item that cannot be shown
223              * because the container is currently not large enough.
224              */
225             this.menu = new Ext.menu.Menu({
226                 ownerCt : this.layout.container,
227                 listeners: {
228                     scope: this,
229                     beforeshow: this.beforeMenuShow
230                 }
231             });
232
233             /**
234              * @private
235              * @property menuTrigger
236              * @type Ext.Button
237              * The expand button which triggers the overflow menu to be shown
238              */
239             this.menuTrigger = new Ext.Button({
240                 iconCls : 'x-toolbar-more-icon',
241                 cls     : 'x-toolbar-more',
242                 menu    : this.menu,
243                 renderTo: this.afterCt
244             });
245         }
246     },
247     
248     /**
249      * @private
250      */
251     destroy: function() {
252         Ext.destroy(this.menu, this.menuTrigger);
253     }
254 });
255
256 Ext.layout.boxOverflow.menu = Ext.layout.boxOverflow.Menu;
257
258
259 <div id="cls-Ext.layout.boxOverflow.HorizontalMenu"></div>/**
260  * @class Ext.layout.boxOverflow.HorizontalMenu
261  * @extends Ext.layout.boxOverflow.Menu
262  * Description
263  */
264 Ext.layout.boxOverflow.HorizontalMenu = Ext.extend(Ext.layout.boxOverflow.Menu, {
265     
266     constructor: function() {
267         Ext.layout.boxOverflow.HorizontalMenu.superclass.constructor.apply(this, arguments);
268         
269         var me = this,
270             layout = me.layout,
271             origFunction = layout.calculateChildBoxes;
272         
273         layout.calculateChildBoxes = function(visibleItems, targetSize) {
274             var calcs = origFunction.apply(layout, arguments),
275                 meta  = calcs.meta,
276                 items = me.menuItems;
277             
278             //calculate the width of the items currently hidden solely because there is not enough space
279             //to display them
280             var hiddenWidth = 0;
281             for (var index = 0, length = items.length; index < length; index++) {
282                 hiddenWidth += items[index].width;
283             }
284             
285             meta.minimumWidth += hiddenWidth;
286             meta.tooNarrow = meta.minimumWidth > targetSize.width;
287             
288             return calcs;
289         };        
290     },
291     
292     handleOverflow: function(calculations, targetSize) {
293         this.showTrigger();
294         
295         var newWidth    = targetSize.width - this.afterCt.getWidth(),
296             boxes       = calculations.boxes,
297             usedWidth   = 0,
298             recalculate = false;
299         
300         //calculate the width of all visible items and any spare width
301         for (var index = 0, length = boxes.length; index < length; index++) {
302             usedWidth += boxes[index].width;
303         }
304         
305         var spareWidth = newWidth - usedWidth,
306             showCount  = 0;
307         
308         //see if we can re-show any of the hidden components
309         for (var index = 0, length = this.menuItems.length; index < length; index++) {
310             var hidden = this.menuItems[index],
311                 comp   = hidden.component,
312                 width  = hidden.width;
313             
314             if (width < spareWidth) {
315                 comp.show();
316                 
317                 spareWidth -= width;
318                 showCount ++;
319                 recalculate = true;
320             } else {
321                 break;
322             }
323         }
324                 
325         if (recalculate) {
326             this.menuItems = this.menuItems.slice(showCount);
327         } else {
328             for (var i = boxes.length - 1; i >= 0; i--) {
329                 var item  = boxes[i].component,
330                     right = boxes[i].left + boxes[i].width;
331
332                 if (right >= newWidth) {
333                     this.menuItems.unshift({
334                         component: item,
335                         width    : boxes[i].width
336                     });
337
338                     item.hide();
339                 } else {
340                     break;
341                 }
342             }
343         }
344         
345         if (this.menuItems.length == 0) {
346             this.hideTrigger();
347         }
348         
349         return {
350             targetSize: {
351                 height: targetSize.height,
352                 width : newWidth
353             },
354             recalculate: recalculate
355         };
356     }
357 });
358
359 Ext.layout.boxOverflow.menu.hbox = Ext.layout.boxOverflow.HorizontalMenu;</pre>    
360 </body>
361 </html>