]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/menu/Item.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / menu / Item.js
CommitLineData
6527f429
DM
1/**\r
2 * A base class for all menu items that require menu-related functionality such as click handling,\r
3 * sub-menus, icons, etc.\r
4 *\r
5 * @example\r
6 * Ext.create('Ext.menu.Menu', {\r
7 * width: 100,\r
8 * height: 100,\r
9 * floating: false, // usually you want this set to True (default)\r
10 * renderTo: Ext.getBody(), // usually rendered by it's containing component\r
11 * items: [{\r
12 * text: 'icon item',\r
13 * iconCls: 'add16'\r
14 * },{\r
15 * text: 'text item'\r
16 * },{\r
17 * text: 'plain item',\r
18 * plain: true\r
19 * }]\r
20 * });\r
21 */\r
22Ext.define('Ext.menu.Item', {\r
23 extend: 'Ext.Component',\r
24 alias: 'widget.menuitem',\r
25 alternateClassName: 'Ext.menu.TextItem',\r
26\r
27 /**\r
28 * @property {Boolean} isMenuItem\r
29 * `true` in this class to identify an object as an instantiated Menu Item, or subclass thereof.\r
30 */\r
31 isMenuItem: true,\r
32\r
33 mixins: [\r
34 'Ext.mixin.Queryable'\r
35 ],\r
36\r
37 /**\r
38 * @property {Boolean} activated\r
39 * Whether or not this item is currently activated\r
40 */\r
41 activated: false,\r
42\r
43 /**\r
44 * @property {Ext.menu.Menu} parentMenu\r
45 * The parent Menu of this item.\r
46 */\r
47\r
48 /**\r
49 * @cfg {String} activeCls\r
50 * The CSS class added to the menu item when the item is focused.\r
51 */\r
52 activeCls: Ext.baseCSSPrefix + 'menu-item-active',\r
53\r
54 /**\r
55 * @cfg {Boolean} canActivate\r
56 * Whether or not this menu item can be focused.\r
57 * @deprecated 5.1.0 Use the {@link #focusable} config.\r
58 */\r
59\r
60 /**\r
61 * @cfg {Number} clickHideDelay\r
62 * The delay in milliseconds to wait before hiding the menu after clicking the menu item.\r
63 * This only has an effect when `hideOnClick: true`.\r
64 */\r
65 clickHideDelay: 0,\r
66\r
67 /**\r
68 * @cfg {Boolean} destroyMenu\r
69 * Whether or not to destroy any associated sub-menu when this item is destroyed.\r
70 */\r
71 destroyMenu: true,\r
72\r
73 /**\r
74 * @cfg {String} disabledCls\r
75 * The CSS class added to the menu item when the item is disabled.\r
76 */\r
77 disabledCls: Ext.baseCSSPrefix + 'menu-item-disabled',\r
78\r
79 /**\r
80 * @cfg {String} [href='#']\r
81 * The href attribute to use for the underlying anchor link.\r
82 */\r
83\r
84 /**\r
85 * @cfg {String} hrefTarget\r
86 * The target attribute to use for the underlying anchor link.\r
87 */\r
88\r
89 /**\r
90 * @cfg {Boolean} hideOnClick\r
91 * Whether to not to hide the owning menu when this item is clicked.\r
92 */\r
93 hideOnClick: true,\r
94\r
95 /**\r
96 * @cfg {String} [icon=Ext#BLANK_IMAGE_URL]\r
97 * @inheritdoc Ext.panel.Header#icon\r
98 */\r
99\r
100 /**\r
101 * @cfg {String} iconCls\r
102 * @inheritdoc Ext.panel.Header#cfg-iconCls\r
103 */\r
104\r
105 /**\r
106 * @cfg {Number/String} glyph\r
107 * @inheritdoc Ext.panel.Header#glyph\r
108 */\r
109\r
110 /**\r
111 * @cfg {Ext.menu.Menu/Object} menu\r
112 * Either an instance of {@link Ext.menu.Menu} or a config object for an {@link Ext.menu.Menu}\r
113 * which will act as a sub-menu to this item.\r
114 */\r
115\r
116 /**\r
117 * @property {Ext.menu.Menu} menu The sub-menu associated with this item, if one was configured.\r
118 */\r
119\r
120 /**\r
121 * @cfg {String} menuAlign\r
122 * The default {@link Ext.util.Positionable#getAlignToXY Ext.util.Positionable.getAlignToXY} anchor position value for this\r
123 * item's sub-menu relative to this item's position.\r
124 */\r
125 menuAlign: 'tl-tr?',\r
126\r
127 /**\r
128 * @cfg {Number} menuExpandDelay\r
129 * The delay in milliseconds before this item's sub-menu expands after this item is moused over.\r
130 */\r
131 menuExpandDelay: 200,\r
132\r
133 /**\r
134 * @cfg {Number} menuHideDelay\r
135 * The delay in milliseconds before this item's sub-menu hides after this item is moused out.\r
136 */\r
137 menuHideDelay: 200,\r
138\r
139 /**\r
140 * @cfg {Boolean} plain\r
141 * Whether or not this item is plain text/html with no icon or visual submenu indication.\r
142 */\r
143\r
144 /**\r
145 * @cfg {String/Object} tooltip\r
146 * The tooltip for the button - can be a string to be used as innerHTML (html tags are accepted) or\r
147 * QuickTips config object.\r
148 */\r
149\r
150 /**\r
151 * @cfg {String} tooltipType\r
152 * The type of tooltip to use. Either 'qtip' for QuickTips or 'title' for title attribute.\r
153 */\r
154 tooltipType: 'qtip',\r
155 \r
156 focusable: true,\r
157 ariaRole: 'menuitem',\r
158 ariaEl: 'itemEl',\r
159\r
160 baseCls: Ext.baseCSSPrefix + 'menu-item',\r
161 arrowCls: Ext.baseCSSPrefix + 'menu-item-arrow',\r
162 baseIconCls: Ext.baseCSSPrefix + 'menu-item-icon',\r
163 textCls: Ext.baseCSSPrefix + 'menu-item-text',\r
164 indentCls: Ext.baseCSSPrefix + 'menu-item-indent',\r
165 indentNoSeparatorCls: Ext.baseCSSPrefix + 'menu-item-indent-no-separator',\r
166 indentRightIconCls: Ext.baseCSSPrefix + 'menu-item-indent-right-icon',\r
167 indentRightArrowCls: Ext.baseCSSPrefix + 'menu-item-indent-right-arrow',\r
168 linkCls: Ext.baseCSSPrefix + 'menu-item-link',\r
169 linkHrefCls: Ext.baseCSSPrefix + 'menu-item-link-href',\r
170\r
171 childEls: [\r
172 'itemEl', 'iconEl', 'textEl', 'arrowEl'\r
173 ],\r
174 \r
175 renderTpl:\r
176 '<tpl if="plain">' +\r
177 '{text}' +\r
178 '<tpl else>' +\r
179 '<a id="{id}-itemEl" data-ref="itemEl"' +\r
180 ' class="{linkCls}<tpl if="hasHref"> {linkHrefCls}</tpl>{childElCls}"' +\r
181 ' href="{href}" ' +\r
182 '<tpl if="hrefTarget"> target="{hrefTarget}"</tpl>' +\r
183 ' hidefocus="true"' +\r
184 // For most browsers the text is already unselectable but Opera needs an explicit unselectable="on".\r
185 ' unselectable="on"' +\r
186 '<tpl if="tabIndex != null">' +\r
187 ' tabindex="{tabIndex}"' +\r
188 '</tpl>' +\r
189 '<tpl foreach="ariaAttributes"> {$}="{.}"</tpl>' +\r
190 '>' +\r
191 '<span id="{id}-textEl" data-ref="textEl" class="{textCls} {textCls}-{ui} {indentCls}{childElCls}" unselectable="on">{text}</span>' +\r
192 '<tpl if="hasIcon">' +\r
193 '<div role="presentation" id="{id}-iconEl" data-ref="iconEl" class="{baseIconCls}-{ui} {baseIconCls}' +\r
194 '{[values.rightIcon ? "-right" : ""]} {iconCls}' +\r
195 '{childElCls} {glyphCls}" style="<tpl if="icon">background-image:url({icon});</tpl>' +\r
196 '<tpl if="glyph && glyphFontFamily">font-family:{glyphFontFamily};</tpl>">' +\r
197 '<tpl if="glyph">&#{glyph};</tpl>' +\r
198 '</div>' +\r
199 '</tpl>' +\r
200 '<tpl if="showCheckbox">' +\r
201 '<div role="presentation" id="{id}-checkEl" data-ref="checkEl" class="{baseIconCls}-{ui} {baseIconCls}' +\r
202 '{[(values.hasIcon && !values.rightIcon) ? "-right" : ""]} ' +\r
203 '{groupCls} {checkboxCls}{childElCls}">' +\r
204 '</div>' +\r
205 '</tpl>' +\r
206 '<tpl if="hasMenu">' +\r
207 '<div role="presentation" id="{id}-arrowEl" data-ref="arrowEl" class="{arrowCls} {arrowCls}-{ui}{childElCls}"></div>' +\r
208 '</tpl>' +\r
209 '</a>' +\r
210 '</tpl>',\r
211\r
212 maskOnDisable: false,\r
213\r
214 iconAlign: 'left',\r
215\r
216 /**\r
217 * @cfg {String} text\r
218 * The text/html to display in this item.\r
219 */\r
220\r
221 /**\r
222 * @cfg {Function/String} handler\r
223 * A function called when the menu item is clicked (can be used instead of {@link #click} event).\r
224 * @cfg {Ext.menu.Item} handler.item The item that was clicked\r
225 * @cfg {Ext.event.Event} handler.e The underlying {@link Ext.event.Event}.\r
226 * @declarativeHandler\r
227 */\r
228\r
229 /**\r
230 * @event activate\r
231 * Fires when this item is activated\r
232 * @param {Ext.menu.Item} item The activated item\r
233 */\r
234\r
235 /**\r
236 * @event click\r
237 * Fires when this item is clicked\r
238 * @param {Ext.menu.Item} item The item that was clicked\r
239 * @param {Ext.event.Event} e The underlying {@link Ext.event.Event}.\r
240 */\r
241\r
242 /**\r
243 * @event deactivate\r
244 * Fires when this item is deactivated\r
245 * @param {Ext.menu.Item} item The deactivated item\r
246 */\r
247\r
248 /**\r
249 * @event textchange\r
250 * Fired when the item's text is changed by the {@link #setText} method.\r
251 * @param {Ext.menu.Item} this\r
252 * @param {String} oldText\r
253 * @param {String} newText\r
254 */\r
255\r
256 /**\r
257 * @event iconchange\r
258 * Fired when the item's icon is changed by the {@link #setIcon} or {@link #setIconCls} methods.\r
259 * @param {Ext.menu.Item} this\r
260 * @param {String} oldIcon\r
261 * @param {String} newIcon\r
262 */\r
263\r
264 initComponent: function() {\r
265 var me = this,\r
266 cls = me.cls ? [me.cls] : [],\r
267 menu;\r
268\r
269 // During deprecation period of canActivate config, copy it into focusable config.\r
270 if (me.hasOwnProperty('canActivate')) {\r
271 me.focusable = me.canActivate;\r
272 }\r
273\r
274 if (me.plain) {\r
275 cls.push(Ext.baseCSSPrefix + 'menu-item-plain');\r
276 }\r
277\r
278 if (cls.length) {\r
279 me.cls = cls.join(' ');\r
280 }\r
281\r
282 if (me.menu) {\r
283 menu = me.menu;\r
284 me.menu = null;\r
285 me.setMenu(menu);\r
286 }\r
287\r
288 me.callParent(arguments);\r
289 },\r
290\r
291 canFocus: function() {\r
292 var me = this;\r
293 \r
294 // This is an override of the implementation in Focusable.\r
295 // We do not refuse focus if the Item is disabled.\r
296 // http://www.w3.org/TR/2013/WD-wai-aria-practices-20130307/#menu\r
297 // "Disabled menu items receive focus but have no action when Enter or Left Arrow/Right Arrow is pressed."\r
298 // Test that deprecated canActivate config has not been set to false.\r
299 return me.focusable && me.rendered && me.canActivate !== false &&\r
300 !me.destroying && !me.destroyed &&\r
301 me.isVisible(true);\r
302 },\r
303\r
304 onFocus: function(e) {\r
305 var me = this;\r
306\r
307 me.callParent([e]);\r
308\r
309 if (!me.disabled) {\r
310 if (!me.plain) {\r
311 me.addCls(me.activeCls);\r
312 }\r
313\r
314 me.activated = true;\r
315 if (me.hasListeners.activate) {\r
316 me.fireEvent('activate', me);\r
317 }\r
318 }\r
319 },\r
320\r
321 onFocusLeave: function(e) {\r
322 var me = this;\r
323\r
324 me.callParent([e]);\r
325\r
326 if (me.activated) {\r
327 if (!me.plain) {\r
328 me.removeCls(me.activeCls);\r
329 }\r
330 me.doHideMenu();\r
331 me.activated = false;\r
332 if (me.hasListeners.deactivate) {\r
333 me.fireEvent('deactivate', me);\r
334 }\r
335 }\r
336 },\r
337\r
338 doHideMenu: function() {\r
339 var menu = this.menu;\r
340\r
341 this.cancelDeferExpand();\r
342 if (menu && menu.isVisible()) {\r
343 menu.hide();\r
344 }\r
345 },\r
346\r
347 /**\r
348 * @private\r
349 * Hides the entire floating menu tree that we are within.\r
350 * Walks up the refOwner axis hiding each Menu instance it find until it hits\r
351 * a non-floating ancestor.\r
352 */\r
353 deferHideParentMenus: function() {\r
354 for (var menu = this.getRefOwner(); menu && ((menu.isMenu && menu.floating) || menu.isMenuItem); menu = menu.getRefOwner()) {\r
355 if (menu.isMenu) {\r
356 menu.hide();\r
357 }\r
358 }\r
359 },\r
360\r
361 expandMenu: function(event, delay) {\r
362 var me = this;\r
363\r
364 if (me.activated && me.menu) {\r
365\r
366 // hideOnClick makes no sense when there's a child menu\r
367 me.hideOnClick = false;\r
368\r
369 me.cancelDeferHide();\r
370\r
371 // Allow configuration of zero to perform immediate expansion.\r
372 delay = delay == null ? me.menuExpandDelay : delay;\r
373 if (delay === 0) {\r
374 me.doExpandMenu(event);\r
375 } else {\r
376 me.cancelDeferExpand();\r
377 // Delay can't be 0 by this point\r
378 me.expandMenuTimer = Ext.defer(me.doExpandMenu, delay, me, [event]);\r
379 }\r
380 }\r
381 },\r
382\r
383 doExpandMenu: function(clickEvent) {\r
384 var me = this,\r
385 menu = me.menu;\r
386\r
387 if (!menu.isVisible()) {\r
388 me.parentMenu.activeChild = menu;\r
389 menu.ownerCmp = me;\r
390 menu.parentMenu = me.parentMenu;\r
391 menu.constrainTo = document.body;\r
392\r
393 // Pointer-invoked menus do not auto focus, key invoked ones do.\r
394 menu.autoFocus = !clickEvent || !clickEvent.pointerType;\r
395 menu.showBy(me, me.menuAlign);\r
396 }\r
397 },\r
398\r
399 getRefItems: function(deep) {\r
400 var menu = this.menu,\r
401 items;\r
402\r
403 if (menu) {\r
404 items = menu.getRefItems(deep);\r
405 items.unshift(menu);\r
406 }\r
407 return items || [];\r
408 },\r
409\r
410 getValue: function () {\r
411 return this.value;\r
412 },\r
413\r
414 hideMenu: function(delay) {\r
415 var me = this;\r
416\r
417 if (me.menu) {\r
418 me.cancelDeferExpand();\r
419 me.hideMenuTimer = Ext.defer(me.doHideMenu, Ext.isNumber(delay) ? delay : me.menuHideDelay, me);\r
420 }\r
421 },\r
422\r
423 onClick: function (e) {\r
424 var me = this,\r
425 clickHideDelay = me.clickHideDelay,\r
426 browserEvent = e.browserEvent,\r
427 clickResult, preventDefault;\r
428\r
429 if (!me.href || me.disabled) {\r
430 e.stopEvent();\r
431 if (me.disabled) {\r
432 return false;\r
433 }\r
434 }\r
435\r
436 if (me.disabled || me.handlingClick) {\r
437 return;\r
438 }\r
439\r
440 if (me.hideOnClick) {\r
441 // on mobile webkit, when the menu item has an href, a longpress will \r
442 // trigger the touch call-out menu to show. If this is the case, the tap \r
443 // event object's browser event type will be 'touchcancel', and we do not \r
444 // want to hide the menu.\r
445 \r
446 // items with submenus are activated by touchstart on mobile browsers, so\r
447 // we cannot hide the menu on "tap"\r
448 if (!clickHideDelay) {\r
449 me.deferHideParentMenus();\r
450 } else {\r
451 me.deferHideParentMenusTimer = Ext.defer(me.deferHideParentMenus, clickHideDelay, me);\r
452 }\r
453 }\r
454\r
455 // Click event may have destroyed the menu, don't do anything further\r
456 clickResult = me.fireEvent('click', me, e);\r
457 if (me.destroyed) {\r
458 return;\r
459 }\r
460\r
461 if (clickResult !== false && me.handler) {\r
462 Ext.callback(me.handler, me.scope, [me, e], 0, me);\r
463 }\r
464\r
465 // If there's an href, invoke dom.click() after we've fired the click event in case a click\r
466 // listener wants to handle it.\r
467 //\r
468 // Note that we're having to do this because the key navigation code will blindly call stopEvent()\r
469 // on all key events that it handles!\r
470 //\r
471 // But, we need to check the browser event object that was passed to the listeners to determine if\r
472 // the default action has been prevented. If so, we don't want to honor the .href config.\r
473 if (Ext.isIE9m) {\r
474 // Here we need to invert the value since it's meaning is the opposite of defaultPrevented.\r
475 preventDefault = browserEvent.returnValue === false ? true : false;\r
476 } else {\r
477 preventDefault = !!browserEvent.defaultPrevented;\r
478 }\r
479\r
480 // We only manually need to trigger the click event if it's come from a key event.\r
481 if (me.href && e.type !== 'click' && !preventDefault) {\r
482 me.handlingClick = true;\r
483 me.itemEl.dom.click();\r
484 me.handlingClick = false;\r
485 }\r
486\r
487 if (!me.hideOnClick) {\r
488 me.focus();\r
489 }\r
490 return clickResult;\r
491 },\r
492\r
493 onRemoved: function() {\r
494 var me = this;\r
495\r
496 // Removing the active item, must deactivate it.\r
497 if (me.activated && me.parentMenu.activeItem === me) {\r
498 me.parentMenu.deactivateActiveItem();\r
499 }\r
500 me.callParent(arguments);\r
501 me.parentMenu = me.ownerCmp = null;\r
502 },\r
503\r
504 /**\r
505 * @private\r
506 */\r
507 beforeDestroy: function() {\r
508 var me = this;\r
509 if (me.rendered) {\r
510 me.clearTip();\r
511 }\r
512 me.callParent();\r
513 },\r
514\r
515 onDestroy: function() {\r
516 var me = this;\r
517\r
518 me.cancelDeferExpand();\r
519 me.cancelDeferHide();\r
520 clearTimeout(me.deferHideParentMenusTimer);\r
521\r
522 me.setMenu(null);\r
523 me.callParent(arguments);\r
524 },\r
525\r
526 beforeRender: function() {\r
527 var me = this,\r
528 glyph = me.glyph,\r
529 glyphFontFamily = Ext._glyphFontFamily,\r
530 hasIcon = !!(me.icon || me.iconCls || glyph),\r
531 hasMenu = !!me.menu,\r
532 rightIcon = ((me.iconAlign === 'right') && !hasMenu),\r
533 isCheckItem = me.isMenuCheckItem,\r
534 indentCls = [],\r
535 ownerCt = me.ownerCt,\r
536 isOwnerPlain = ownerCt.plain,\r
537 glyphParts;\r
538\r
539 if (me.plain) {\r
540 me.ariaEl = 'el';\r
541 }\r
542 \r
543 me.callParent();\r
544\r
545 if (hasIcon) {\r
546 if (hasMenu && me.showCheckbox) {\r
547 // nowhere to put the icon, menu arrow on one side, checkbox on the other.\r
548 // TODO: maybe put the icon or checkbox next to the arrow?\r
549 hasIcon = false;\r
550 }\r
551 }\r
552\r
553 if (typeof glyph === 'string') {\r
554 glyphParts = glyph.split('@');\r
555 glyph = glyphParts[0];\r
556 glyphFontFamily = glyphParts[1];\r
557 }\r
558\r
559 if (!isOwnerPlain || (hasIcon && !rightIcon) || isCheckItem) {\r
560 if (ownerCt.showSeparator && !isOwnerPlain) {\r
561 indentCls.push(me.indentCls);\r
562 } else {\r
563 indentCls.push(me.indentNoSeparatorCls);\r
564 }\r
565 }\r
566\r
567 if (hasMenu) {\r
568 indentCls.push(me.indentRightArrowCls);\r
569 } else if (hasIcon && (rightIcon || isCheckItem)) {\r
570 indentCls.push(me.indentRightIconCls);\r
571 }\r
572\r
573 Ext.applyIf(me.renderData, {\r
574 hasHref: !!me.href,\r
575 href: me.href || '#',\r
576 hrefTarget: me.hrefTarget,\r
577 icon: me.icon,\r
578 iconCls: me.iconCls,\r
579 glyph: glyph,\r
580 glyphCls: glyph ? Ext.baseCSSPrefix + 'menu-item-glyph' : undefined,\r
581 glyphFontFamily: glyphFontFamily,\r
582 hasIcon: hasIcon,\r
583 hasMenu: hasMenu,\r
584 indent: !isOwnerPlain || hasIcon || isCheckItem,\r
585 isCheckItem: isCheckItem,\r
586 rightIcon: rightIcon,\r
587 plain: me.plain,\r
588 text: me.text,\r
589 arrowCls: me.arrowCls,\r
590 baseIconCls: me.baseIconCls,\r
591 textCls: me.textCls,\r
592 indentCls: indentCls.join(' '),\r
593 linkCls: me.linkCls,\r
594 linkHrefCls: me.linkHrefCls,\r
595 groupCls: me.group ? me.groupCls : '',\r
596 tabIndex: me.tabIndex\r
597 });\r
598 },\r
599\r
600 onRender: function() {\r
601 var me = this;\r
602\r
603 me.callParent(arguments);\r
604\r
605 if (me.tooltip) {\r
606 me.setTooltip(me.tooltip, true);\r
607 }\r
608 },\r
609\r
610 /**\r
611 * Get the attached sub-menu for this item.\r
612 * @return {Ext.menu.Menu} The sub-menu. `null` if it doesn't exist.\r
613 */\r
614 getMenu: function() {\r
615 return this.menu || null;\r
616 },\r
617\r
618 /**\r
619 * Set a child menu for this item. See the {@link #cfg-menu} configuration.\r
620 * @param {Ext.menu.Menu/Object} menu A menu, or menu configuration. null may be\r
621 * passed to remove the menu.\r
622 * @param {Boolean} [destroyMenu] True to destroy any existing menu. False to\r
623 * prevent destruction. If not specified, the {@link #destroyMenu} configuration\r
624 * will be used.\r
625 */\r
626 setMenu: function(menu, destroyMenu) {\r
627 var me = this,\r
628 oldMenu = me.menu,\r
629 arrowEl = me.arrowEl,\r
630 ariaDom = me.ariaEl.dom,\r
631 ariaAttr, instanced;\r
632\r
633 if (oldMenu) {\r
634 oldMenu.ownerCmp = oldMenu.parentMenu = null;\r
635\r
636 if (destroyMenu === true || (destroyMenu !== false && me.destroyMenu)) {\r
637 Ext.destroy(oldMenu);\r
638 }\r
639 \r
640 if (ariaDom) {\r
641 ariaDom.removeAttribute('aria-haspopup');\r
642 ariaDom.removeAttribute('aria-owns');\r
643 }\r
644 else {\r
645 ariaAttr = (me.ariaRenderAttributes || (me.ariaRenderAttributes = {}));\r
646 \r
647 delete ariaAttr['aria-haspopup'];\r
648 delete ariaAttr['aria-owns'];\r
649 }\r
650 }\r
651 \r
652 if (menu) {\r
653 instanced = menu.isMenu;\r
654 menu = me.menu = Ext.menu.Manager.get(menu, {\r
655 ownerCmp: me,\r
656 focusOnToFront: false\r
657 });\r
658 // We need to forcibly set this here because we could be passed\r
659 // an existing menu, which means the config above won't get applied\r
660 // during creation.\r
661 menu.setOwnerCmp(me, instanced);\r
662 \r
663 if (ariaDom) {\r
664 ariaDom.setAttribute('aria-haspopup', true);\r
665 ariaDom.setAttribute('aria-owns', menu.id);\r
666 }\r
667 else {\r
668 ariaAttr = (me.ariaRenderAttributes || (me.ariaRenderAttributes = {}));\r
669 \r
670 ariaAttr['aria-haspopup'] = true;\r
671 ariaAttr['aria-owns'] = menu.id;\r
672 }\r
673 }\r
674 else {\r
675 menu = me.menu = null;\r
676 }\r
677\r
678 if (menu && me.rendered && !me.destroying && arrowEl) {\r
679 arrowEl[menu ? 'addCls' : 'removeCls'](me.arrowCls);\r
680 }\r
681 },\r
682\r
683 /**\r
684 * Sets the {@link #click} handler of this item\r
685 * @param {Function} fn The handler function\r
686 * @param {Object} [scope] The scope of the handler function\r
687 */\r
688 setHandler: function(fn, scope) {\r
689 this.handler = fn || null;\r
690 this.scope = scope;\r
691 },\r
692\r
693 /**\r
694 * Sets the {@link #icon} on this item.\r
695 * @param {String} icon The new icon\r
696 */\r
697 setIcon: function(icon){\r
698 var iconEl = this.iconEl,\r
699 oldIcon = this.icon;\r
700 if (iconEl) {\r
701 iconEl.src = icon || Ext.BLANK_IMAGE_URL;\r
702 }\r
703 this.icon = icon;\r
704 this.fireEvent('iconchange', this, oldIcon, icon);\r
705 },\r
706\r
707 /**\r
708 * Sets the {@link #iconCls} of this item\r
709 * @param {String} iconCls The CSS class to set to {@link #iconCls}\r
710 */\r
711 setIconCls: function(iconCls) {\r
712 var me = this,\r
713 iconEl = me.iconEl,\r
714 oldCls = me.iconCls;\r
715\r
716 if (iconEl) {\r
717 if (me.iconCls) {\r
718 iconEl.removeCls(me.iconCls);\r
719 }\r
720\r
721 if (iconCls) {\r
722 iconEl.addCls(iconCls);\r
723 }\r
724 }\r
725\r
726 me.iconCls = iconCls;\r
727 me.fireEvent('iconchange', me, oldCls, iconCls);\r
728 },\r
729\r
730 /**\r
731 * Sets the {@link #text} of this item\r
732 * @param {String} text The {@link #text}\r
733 */\r
734 setText: function(text) {\r
735 var me = this,\r
736 el = me.textEl || me.el,\r
737 oldText = me.text;\r
738\r
739 me.text = text;\r
740\r
741 if (me.rendered) {\r
742 el.setHtml(text || '');\r
743 me.updateLayout();\r
744 }\r
745 me.fireEvent('textchange', me, oldText, text);\r
746 },\r
747\r
748 getTipAttr: function(){\r
749 return this.tooltipType === 'qtip' ? 'data-qtip' : 'title';\r
750 },\r
751\r
752 /**\r
753 * @private\r
754 */\r
755 clearTip: function() {\r
756 if (Ext.quickTipsActive && Ext.isObject(this.tooltip)) {\r
757 Ext.tip.QuickTipManager.unregister(this.itemEl);\r
758 }\r
759 },\r
760\r
761 /**\r
762 * Sets the tooltip for this menu item.\r
763 *\r
764 * @param {String/Object} tooltip This may be:\r
765 *\r
766 * - **String** : A string to be used as innerHTML (html tags are accepted) to show in a tooltip\r
767 * - **Object** : A configuration object for {@link Ext.tip.QuickTipManager#register}.\r
768 *\r
769 * @return {Ext.menu.Item} this\r
770 */\r
771 setTooltip: function(tooltip, initial) {\r
772 var me = this;\r
773\r
774 if (me.rendered) {\r
775 if (!initial) {\r
776 me.clearTip();\r
777 }\r
778\r
779 if (Ext.quickTipsActive && Ext.isObject(tooltip)) {\r
780 Ext.tip.QuickTipManager.register(Ext.apply({\r
781 target: me.itemEl.id\r
782 },\r
783 tooltip));\r
784 me.tooltip = tooltip;\r
785 } else {\r
786 me.itemEl.dom.setAttribute(me.getTipAttr(), tooltip);\r
787 }\r
788 } else {\r
789 me.tooltip = tooltip;\r
790 }\r
791\r
792 return me;\r
793 },\r
794\r
795 privates: {\r
796 cancelDeferExpand: function() {\r
797 window.clearTimeout(this.expandMenuTimer);\r
798 },\r
799\r
800 cancelDeferHide: function(){\r
801 window.clearTimeout(this.hideMenuTimer);\r
802 },\r
803\r
804 getFocusEl: function() {\r
805 return this.plain ? this.el : this.itemEl;\r
806 }\r
807 }\r
808});\r