Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Menu.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-layout-container-boxOverflow-Menu'>/**
19 </span> * @class Ext.layout.container.boxOverflow.Menu
20  * @extends Ext.layout.container.boxOverflow.None
21  * @private
22  */
23 Ext.define('Ext.layout.container.boxOverflow.Menu', {
24
25     /* Begin Definitions */
26
27     extend: 'Ext.layout.container.boxOverflow.None',
28     requires: ['Ext.toolbar.Separator', 'Ext.button.Button'],
29     alternateClassName: 'Ext.layout.boxOverflow.Menu',
30     
31     /* End Definitions */
32
33 <span id='Ext-layout-container-boxOverflow-Menu-cfg-afterCtCls'>    /**
34 </span>     * @cfg {String} afterCtCls
35      * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
36      * which must always be present at the rightmost edge of the Container
37      */
38
39 <span id='Ext-layout-container-boxOverflow-Menu-property-noItemsMenuText'>    /**
40 </span>     * @property noItemsMenuText
41      * @type String
42      * HTML fragment to render into the toolbar overflow menu if there are no items to display
43      */
44     noItemsMenuText : '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'toolbar-no-items&quot;&gt;(None)&lt;/div&gt;',
45
46     constructor: function(layout) {
47         var me = this;
48
49         me.callParent(arguments);
50
51         // Before layout, we need to re-show all items which we may have hidden due to a previous overflow.
52         layout.beforeLayout = Ext.Function.createInterceptor(layout.beforeLayout, this.clearOverflow, this);
53
54         me.afterCtCls = me.afterCtCls || Ext.baseCSSPrefix + 'box-menu-' + layout.parallelAfter;
55 <span id='Ext-layout-container-boxOverflow-Menu-property-menuItems'>        /**
56 </span>         * @property menuItems
57          * @type Array
58          * Array of all items that are currently hidden and should go into the dropdown menu
59          */
60         me.menuItems = [];
61     },
62     
63     onRemove: function(comp){
64         Ext.Array.remove(this.menuItems, comp);
65     },
66
67     handleOverflow: function(calculations, targetSize) {
68         var me = this,
69             layout = me.layout,
70             methodName = 'get' + layout.parallelPrefixCap,
71             newSize = {},
72             posArgs = [null, null];
73
74         me.callParent(arguments);
75         this.createMenu(calculations, targetSize);
76         newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
77         newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - me.afterCt[methodName]();
78
79         // Center the menuTrigger button.
80         // TODO: Should we emulate align: 'middle' like this, or should we 'stretchmax' the menuTrigger?
81         posArgs[layout.perpendicularSizeIndex] = (calculations.meta.maxSize - me.menuTrigger['get' + layout.perpendicularPrefixCap]()) / 2;
82         me.menuTrigger.setPosition.apply(me.menuTrigger, posArgs);
83
84         return { targetSize: newSize };
85     },
86
87 <span id='Ext-layout-container-boxOverflow-Menu-method-clearOverflow'>    /**
88 </span>     * @private
89      * Called by the layout, when it determines that there is no overflow.
90      * Also called as an interceptor to the layout's onLayout method to reshow
91      * previously hidden overflowing items.
92      */
93     clearOverflow: function(calculations, targetSize) {
94         var me = this,
95             newWidth = targetSize ? targetSize.width + (me.afterCt ? me.afterCt.getWidth() : 0) : 0,
96             items = me.menuItems,
97             i = 0,
98             length = items.length,
99             item;
100
101         me.hideTrigger();
102         for (; i &lt; length; i++) {
103             items[i].show();
104         }
105         items.length = 0;
106
107         return targetSize ? {
108             targetSize: {
109                 height: targetSize.height,
110                 width : newWidth
111             }
112         } : null;
113     },
114
115 <span id='Ext-layout-container-boxOverflow-Menu-method-showTrigger'>    /**
116 </span>     * @private
117      */
118     showTrigger: function() {
119         this.menuTrigger.show();
120     },
121
122 <span id='Ext-layout-container-boxOverflow-Menu-method-hideTrigger'>    /**
123 </span>     * @private
124      */
125     hideTrigger: function() {
126         if (this.menuTrigger !== undefined) {
127             this.menuTrigger.hide();
128         }
129     },
130
131 <span id='Ext-layout-container-boxOverflow-Menu-method-beforeMenuShow'>    /**
132 </span>     * @private
133      * Called before the overflow menu is shown. This constructs the menu's items, caching them for as long as it can.
134      */
135     beforeMenuShow: function(menu) {
136         var me = this,
137             items = me.menuItems,
138             i = 0,
139             len   = items.length,
140             item,
141             prev;
142
143         var needsSep = function(group, prev){
144             return group.isXType('buttongroup') &amp;&amp; !(prev instanceof Ext.toolbar.Separator);
145         };
146
147         me.clearMenu();
148         menu.removeAll();
149
150         for (; i &lt; len; i++) {
151             item = items[i];
152
153             // Do not show a separator as a first item
154             if (!i &amp;&amp; (item instanceof Ext.toolbar.Separator)) {
155                 continue;
156             }
157             if (prev &amp;&amp; (needsSep(item, prev) || needsSep(prev, item))) {
158                 menu.add('-');
159             }
160
161             me.addComponentToMenu(menu, item);
162             prev = item;
163         }
164
165         // put something so the menu isn't empty if no compatible items found
166         if (menu.items.length &lt; 1) {
167             menu.add(me.noItemsMenuText);
168         }
169     },
170     
171 <span id='Ext-layout-container-boxOverflow-Menu-method-createMenuConfig'>    /**
172 </span>     * @private
173      * Returns a menu config for a given component. This config is used to create a menu item
174      * to be added to the expander menu
175      * @param {Ext.Component} component The component to create the config for
176      * @param {Boolean} hideOnClick Passed through to the menu item
177      */
178     createMenuConfig : function(component, hideOnClick) {
179         var config = Ext.apply({}, component.initialConfig),
180             group  = component.toggleGroup;
181
182         Ext.copyTo(config, component, [
183             'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
184         ]);
185
186         Ext.apply(config, {
187             text       : component.overflowText || component.text,
188             hideOnClick: hideOnClick,
189             destroyMenu: false
190         });
191
192         if (group || component.enableToggle) {
193             Ext.apply(config, {
194                 group  : group,
195                 checked: component.pressed,
196                 listeners: {
197                     checkchange: function(item, checked){
198                         component.toggle(checked);
199                     }
200                 }
201             });
202         }
203
204         delete config.ownerCt;
205         delete config.xtype;
206         delete config.id;
207         return config;
208     },
209
210 <span id='Ext-layout-container-boxOverflow-Menu-method-addComponentToMenu'>    /**
211 </span>     * @private
212      * Adds the given Toolbar item to the given menu. Buttons inside a buttongroup are added individually.
213      * @param {Ext.menu.Menu} menu The menu to add to
214      * @param {Ext.Component} component The component to add
215      */
216     addComponentToMenu : function(menu, component) {
217         var me = this;
218         if (component instanceof Ext.toolbar.Separator) {
219             menu.add('-');
220         } else if (component.isComponent) {
221             if (component.isXType('splitbutton')) {
222                 menu.add(me.createMenuConfig(component, true));
223
224             } else if (component.isXType('button')) {
225                 menu.add(me.createMenuConfig(component, !component.menu));
226
227             } else if (component.isXType('buttongroup')) {
228                 component.items.each(function(item){
229                      me.addComponentToMenu(menu, item);
230                 });
231             } else {
232                 menu.add(Ext.create(Ext.getClassName(component), me.createMenuConfig(component)));
233             }
234         }
235     },
236
237 <span id='Ext-layout-container-boxOverflow-Menu-method-clearMenu'>    /**
238 </span>     * @private
239      * Deletes the sub-menu of each item in the expander menu. Submenus are created for items such as
240      * splitbuttons and buttongroups, where the Toolbar item cannot be represented by a single menu item
241      */
242     clearMenu : function() {
243         var menu = this.moreMenu;
244         if (menu &amp;&amp; menu.items) {
245             menu.items.each(function(item) {
246                 if (item.menu) {
247                     delete item.menu;
248                 }
249             });
250         }
251     },
252
253 <span id='Ext-layout-container-boxOverflow-Menu-method-createMenu'>    /**
254 </span>     * @private
255      * Creates the overflow trigger and menu used when enableOverflow is set to true and the items
256      * in the layout are too wide to fit in the space available
257      */
258     createMenu: function(calculations, targetSize) {
259         var me = this,
260             layout = me.layout,
261             startProp = layout.parallelBefore,
262             sizeProp = layout.parallelPrefix,
263             available = targetSize[sizeProp],
264             boxes = calculations.boxes,
265             i = 0,
266             len = boxes.length,
267             box;
268
269         if (!me.menuTrigger) {
270             me.createInnerElements();
271
272 <span id='Ext-layout-container-boxOverflow-Menu-property-menu'>            /**
273 </span>             * @private
274              * @property menu
275              * @type Ext.menu.Menu
276              * The expand menu - holds items for every item that cannot be shown
277              * because the container is currently not large enough.
278              */
279             me.menu = Ext.create('Ext.menu.Menu', {
280                 listeners: {
281                     scope: me,
282                     beforeshow: me.beforeMenuShow
283                 }
284             });
285
286 <span id='Ext-layout-container-boxOverflow-Menu-property-menuTrigger'>            /**
287 </span>             * @private
288              * @property menuTrigger
289              * @type Ext.button.Button
290              * The expand button which triggers the overflow menu to be shown
291              */
292             me.menuTrigger = Ext.create('Ext.button.Button', {
293                 ownerCt : me.layout.owner, // To enable the Menu to ascertain a valid zIndexManager owner in the same tree
294                 iconCls : me.layout.owner.menuTriggerCls,
295                 ui      : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',
296                 menu    : me.menu,
297                 getSplitCls: function() { return '';},
298                 renderTo: me.afterCt
299             });
300         }
301         me.showTrigger();
302         available -= me.afterCt.getWidth();
303
304         // Hide all items which are off the end, and store them to allow them to be restored
305         // before each layout operation.
306         me.menuItems.length = 0;
307         for (; i &lt; len; i++) {
308             box = boxes[i];
309             if (box[startProp] + box[sizeProp] &gt; available) {
310                 me.menuItems.push(box.component);
311                 box.component.hide();
312             }
313         }
314     },
315
316 <span id='Ext-layout-container-boxOverflow-Menu-method-createInnerElements'>    /**
317 </span>     * @private
318      * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
319      * @param {Ext.container.Container} container The Container attached to this Layout instance
320      * @param {Ext.Element} target The target Element
321      */
322     createInnerElements: function() {
323         var me = this,
324             target = me.layout.getRenderTarget();
325
326         if (!this.afterCt) {
327             target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
328             this.afterCt  = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + this.afterCtCls}, 'before');
329         }
330     },
331
332 <span id='Ext-layout-container-boxOverflow-Menu-method-destroy'>    /**
333 </span>     * @private
334      */
335     destroy: function() {
336         Ext.destroy(this.menu, this.menuTrigger);
337     }
338 });</pre>
339 </body>
340 </html>