1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-menu.Menu-method-constructor'><span id='Ext-menu.Menu'>/**
2 </span></span> * @class Ext.menu.Menu
3 * @extends Ext.panel.Panel
5 * A menu object. This is the container to which you may add {@link Ext.menu.Item menu items}.
7 * Menus may contain either {@link Ext.menu.Item menu items}, or general {@link Ext.Component Components}.
8 * Menus may also contain {@link Ext.panel.AbstractPanel#dockedItems docked items} because it extends {@link Ext.panel.Panel}.
10 * To make a contained general {@link Ext.Component Component} line up with other {@link Ext.menu.Item menu items},
11 * specify `{@link Ext.menu.Item#iconCls iconCls}: 'no-icon'` _or_ `{@link Ext.menu.Item#indent indent}: true`.
12 * This reserves a space for an icon, and indents the Component in line with the other menu items.
13 * See {@link Ext.form.field.ComboBox}.{@link Ext.form.field.ComboBox#getListParent getListParent} for an example.
15 * By default, Menus are absolutely positioned, floating Components. By configuring a Menu with `{@link #floating}:false`,
16 * a Menu may be used as a child of a {@link Ext.container.Container Container}.
17 * {@img Ext.menu.Item/Ext.menu.Item.png Ext.menu.Item component}
19 Ext.create('Ext.menu.Menu', {
23 floating: false, // usually you want this set to True (default)
24 renderTo: Ext.getBody(), // usually rendered by it's containing component
26 text: 'regular item 1'
28 text: 'regular item 2'
30 text: 'regular item 3'
34 Ext.create('Ext.menu.Menu', {
38 floating: false, // usually you want this set to True (default)
39 renderTo: Ext.getBody(), // usually rendered by it's containing component
51 * @param {Object} config The config object
53 Ext.define('Ext.menu.Menu', {
54 extend: 'Ext.panel.Panel',
57 'Ext.layout.container.Fit',
58 'Ext.layout.container.VBox',
66 <span id='Ext-menu.Menu-cfg-allowOtherMenus'> /**
67 </span> * @cfg {Boolean} allowOtherMenus
68 * True to allow multiple menus to be displayed at the same time. Defaults to `false`.
71 allowOtherMenus: false,
73 <span id='Ext-menu.Menu-cfg-ariaRole'> /**
74 </span> * @cfg {String} ariaRole @hide
78 <span id='Ext-menu.Menu-cfg-autoRender'> /**
79 </span> * @cfg {Boolean} autoRender @hide
80 * floating is true, so autoRender always happens
83 <span id='Ext-menu.Menu-cfg-defaultAlign'> /**
84 </span> * @cfg {String} defaultAlign
85 * The default {@link Ext.core.Element#getAlignToXY Ext.core.Element#getAlignToXY} anchor position value for this menu
86 * relative to its element of origin. Defaults to `'tl-bl?'`.
89 defaultAlign: 'tl-bl?',
91 <span id='Ext-menu.Menu-cfg-floating'> /**
92 </span> * @cfg {Boolean} floating
93 * A Menu configured as `floating: true` (the default) will be rendered as an absolutely positioned,
94 * {@link Ext.Component#floating floating} {@link Ext.Component Component}. If configured as `floating: false`, the Menu may be
95 * used as a child item of another {@link Ext.container.Container Container}.
100 <span id='Ext-menu.Menu-cfg-constrain'> /**
101 </span> * @cfg {Boolean} @hide
102 * Menu performs its own size changing constraining, so ensure Component's constraining is not applied
106 <span id='Ext-menu.Menu-cfg-hidden'> /**
107 </span> * @cfg {Boolean} hidden
108 * True to initially render the Menu as hidden, requiring to be shown manually.
109 * Defaults to `true` when `floating: true`, and defaults to `false` when `floating: false`.
114 <span id='Ext-menu.Menu-cfg-ignoreParentClicks'> /**
115 </span> * @cfg {Boolean} ignoreParentClicks
116 * True to ignore clicks on any item in this menu that is a parent item (displays a submenu)
117 * so that the submenu is not dismissed when clicking the parent item. Defaults to `false`.
120 ignoreParentClicks: false,
124 <span id='Ext-menu.Menu-cfg-layout'> /**
125 </span> * @cfg {String/Object} layout @hide
128 <span id='Ext-menu.Menu-cfg-showSeparator'> /**
129 </span> * @cfg {Boolean} showSeparator True to show the icon separator. (defaults to true).
131 showSeparator : true,
133 <span id='Ext-menu.Menu-cfg-minWidth'> /**
134 </span> * @cfg {Number} minWidth
135 * The minimum width of the Menu. Defaults to `120`.
140 <span id='Ext-menu.Menu-cfg-plain'> /**
141 </span> * @cfg {Boolean} plain
142 * True to remove the incised line down the left side of the menu and to not
143 * indent general Component items. Defaults to `false`.
147 initComponent: function() {
149 prefix = Ext.baseCSSPrefix;
152 <span id='Ext-menu.Menu-event-click'> /**
153 </span> * @event click
154 * Fires when this menu is clicked
155 * @param {Ext.menu.Menu} menu The menu which has been clicked
156 * @param {Ext.Component} item The menu item that was clicked. `undefined` if not applicable.
157 * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}.
162 <span id='Ext-menu.Menu-event-mouseenter'> /**
163 </span> * @event mouseenter
164 * Fires when the mouse enters this menu
165 * @param {Ext.menu.Menu} menu The menu
166 * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}
171 <span id='Ext-menu.Menu-event-mouseleave'> /**
172 </span> * @event mouseleave
173 * Fires when the mouse leaves this menu
174 * @param {Ext.menu.Menu} menu The menu
175 * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}
180 <span id='Ext-menu.Menu-event-mouseover'> /**
181 </span> * @event mouseover
182 * Fires when the mouse is hovering over this menu
183 * @param {Ext.menu.Menu} menu The menu
184 * @param {Ext.Component} item The menu item that the mouse is over. `undefined` if not applicable.
185 * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}
190 Ext.menu.Manager.register(me);
193 var cls = [prefix + 'menu'];
195 cls.push(prefix + 'menu-plain');
197 me.cls = cls.join(' ');
200 var bodyCls = me.bodyCls ? [me.bodyCls] : [];
201 bodyCls.unshift(prefix + 'menu-body');
202 me.bodyCls = bodyCls.join(' ');
204 // Internal vbox layout, with scrolling overflow
205 // Placed in initComponent (rather than prototype) in order to support dynamic layout/scroller
206 // options if we wish to allow for such configurations on the Menu.
207 // e.g., scrolling speed, vbox align stretch, etc.
212 clearInnerCtOnLayout: true,
213 overflowHandler: 'Scroller'
216 // hidden defaults to false if floating is configured as false
217 if (me.floating === false && me.initialConfig.hidden !== true) {
221 me.callParent(arguments);
223 me.on('beforeshow', function() {
224 var hasItems = !!me.items.length;
225 // FIXME: When a menu has its show cancelled because of no items, it
226 // gets a visibility: hidden applied to it (instead of the default display: none)
227 // Not sure why, but we remove this style when we want to show again.
228 if (hasItems && me.rendered) {
229 me.el.setStyle('visibility', null);
235 afterRender: function(ct) {
237 prefix = Ext.baseCSSPrefix,
238 space = '&#160;';
240 me.callParent(arguments);
242 // TODO: Move this to a subTemplate When we support them in the future
243 if (me.showSeparator) {
244 me.iconSepEl = me.layout.getRenderTarget().insertFirst({
245 cls: prefix + 'menu-icon-separator',
250 me.focusEl = me.el.createChild({
251 cls: prefix + 'menu-focus',
258 mouseover: me.onMouseOver,
261 me.mouseMonitor = me.el.monitorMouseLeave(100, me.onMouseLeave, me);
263 if (me.showSeparator && ((!Ext.isStrict && Ext.isIE) || Ext.isIE6)) {
264 me.iconSepEl.setHeight(me.el.getHeight());
267 me.keyNav = Ext.create('Ext.menu.KeyNav', me);
270 afterLayout: function() {
272 me.callParent(arguments);
274 // For IE6 & IE quirks, we have to resize the el and body since position: absolute
275 // floating elements inherit their parent's width, making them the width of
276 // document.body instead of the width of their contents.
277 // This includes left/right dock items.
278 if ((!Ext.iStrict && Ext.isIE) || Ext.isIE6) {
279 var innerCt = me.layout.getRenderTarget(),
281 dis = me.dockedItems,
286 innerCtWidth = innerCt.getWidth();
288 newWidth = innerCtWidth + me.body.getBorderWidth('lr') + me.body.getPadding('lr');
290 // First set the body to the new width
291 me.body.setWidth(newWidth);
293 // Now we calculate additional width (docked items) and set the el's width
294 for (; i < l, di = dis.getAt(i); i++) {
295 if (di.dock == 'left' || di.dock == 'right') {
296 newWidth += di.getWidth();
299 me.el.setWidth(newWidth);
303 <span id='Ext-menu.Menu-method-canActivateItem'> /**
304 </span> * Returns whether a menu item can be activated or not.
307 canActivateItem: function(item) {
308 return item && !item.isDisabled() && item.isVisible() && (item.canActivate || item.getXTypes().indexOf('menuitem') < 0);
311 <span id='Ext-menu.Menu-method-deactivateActiveItem'> /**
312 </span> * Deactivates the current active item on the menu, if one exists.
314 deactivateActiveItem: function() {
318 me.activeItem.deactivate();
319 if (!me.activeItem.activated) {
320 delete me.activeItem;
323 if (me.focusedItem) {
324 me.focusedItem.blur();
325 if (!me.focusedItem.$focused) {
326 delete me.focusedItem;
332 getFocusEl: function() {
338 this.deactivateActiveItem();
339 this.callParent(arguments);
343 getItemFromEvent: function(e) {
344 return this.getChildByElement(e.getTarget());
347 lookupComponent: function(cmp) {
350 if (Ext.isString(cmp)) {
351 cmp = me.lookupItemFromString(cmp);
352 } else if (Ext.isObject(cmp)) {
353 cmp = me.lookupItemFromObject(cmp);
356 // Apply our minWidth to all of our child components so it's accounted
357 // for in our VBox layout
358 cmp.minWidth = cmp.minWidth || me.minWidth;
364 lookupItemFromObject: function(cmp) {
366 prefix = Ext.baseCSSPrefix;
368 if (!cmp.isComponent) {
370 cmp = Ext.create('Ext.menu.' + (Ext.isBoolean(cmp.checked) ? 'Check': '') + 'Item', cmp);
372 cmp = Ext.ComponentManager.create(cmp, cmp.xtype);
376 if (cmp.isMenuItem) {
380 if (!cmp.isMenuItem && !cmp.dock) {
382 prefix + 'menu-item',
383 prefix + 'menu-item-cmp'
385 intercept = Ext.Function.createInterceptor;
387 // Wrap focus/blur to control component focus
388 cmp.focus = intercept(cmp.focus, function() {
389 this.$focused = true;
391 cmp.blur = intercept(cmp.blur, function() {
392 this.$focused = false;
395 if (!me.plain && (cmp.indent === true || cmp.iconCls === 'no-icon')) {
396 cls.push(prefix + 'menu-item-indent');
402 cmp.cls = (cmp.cls ? cmp.cls : '') + ' ' + cls.join(' ');
404 cmp.isMenuItem = true;
410 lookupItemFromString: function(cmp) {
411 return (cmp == 'separator' || cmp == '-') ?
412 Ext.createWidget('menuseparator')
413 : Ext.createWidget('menuitem', {
421 onClick: function(e) {
430 if ((e.getTarget() == me.focusEl.dom) || e.within(me.layout.getRenderTarget())) {
431 item = me.getItemFromEvent(e) || me.activeItem;
434 if (item.getXTypes().indexOf('menuitem') >= 0) {
435 if (!item.menu || !me.ignoreParentClicks) {
442 me.fireEvent('click', me, item, e);
446 onDestroy: function() {
449 Ext.menu.Manager.unregister(me);
451 me.el.un(me.mouseMonitor);
455 me.callParent(arguments);
458 onMouseLeave: function(e) {
461 me.deactivateActiveItem();
467 me.fireEvent('mouseleave', me, e);
470 onMouseOver: function(e) {
472 fromEl = e.getRelatedTarget(),
473 mouseEnter = !me.el.contains(fromEl),
474 item = me.getItemFromEvent(e);
476 if (mouseEnter && me.parentMenu) {
477 me.parentMenu.setActiveItem(me.parentItem);
478 me.parentMenu.mouseMonitor.mouseenter();
486 me.setActiveItem(item);
487 if (item.activated && item.expandMenu) {
492 me.fireEvent('mouseenter', me, e);
494 me.fireEvent('mouseover', me, item, e);
497 setActiveItem: function(item) {
500 if (item && (item != me.activeItem && item != me.focusedItem)) {
501 me.deactivateActiveItem();
502 if (me.canActivateItem(item)) {
505 if (item.activated) {
506 me.activeItem = item;
507 me.focusedItem = item;
512 me.focusedItem = item;
515 item.el.scrollIntoView(me.layout.getRenderTarget());
519 <span id='Ext-menu.Menu-method-showBy'> /**
520 </span> * Shows the floating menu by the specified {@link Ext.Component Component} or {@link Ext.core.Element Element}.
521 * @param {Mixed component} The {@link Ext.Component} or {@link Ext.core.Element} to show the menu by.
522 * @param {String} position (optional) Alignment position as used by {@link Ext.core.Element#getAlignToXY Ext.core.Element.getAlignToXY}. Defaults to `{@link #defaultAlign}`.
523 * @param {Array} offsets (optional) Alignment offsets as used by {@link Ext.core.Element#getAlignToXY Ext.core.Element.getAlignToXY}. Defaults to `undefined`.
524 * @return {Menu} This Menu.
527 showBy: function(cmp, pos, off) {
530 if (me.floating && cmp) {
531 me.layout.autoSize = true;
534 // Component or Element
537 // Convert absolute to floatParent-relative coordinates if necessary.
538 var xy = me.el.getAlignToXY(cmp, pos || me.defaultAlign, off);
539 if (me.floatParent) {
540 var r = me.floatParent.getTargetEl().getViewRegion();
550 doConstrain : function() {
554 returnY = y, normalY, parentEl, scrollTop, viewHeight;
558 full = me.getHeight();
560 parentEl = Ext.fly(me.el.dom.parentNode);
561 scrollTop = parentEl.getScroll().top;
562 viewHeight = parentEl.getViewSize().height;
563 //Normalize y by the scroll position for the parent element. Need to move it into the coordinate space
565 normalY = y - scrollTop;
566 max = me.maxHeight ? me.maxHeight : viewHeight - normalY;
567 if (full > viewHeight) {
569 //Set returnY equal to (0,0) in view space by reducing y by the value of normalY
570 returnY = y - normalY;
571 } else if (max < full) {
572 returnY = y - (full - max);
576 max = me.getHeight();
578 // Always respect maxHeight
580 max = Math.min(me.maxHeight, max);
582 if (full > max && max > 0){
583 me.layout.autoSize = false;
585 if (me.showSeparator){
586 me.iconSepEl.setHeight(me.layout.getRenderTarget().dom.scrollHeight);
591 });</pre></pre></body></html>