Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / src / widgets / menu / Item.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**\r
8  * @class Ext.menu.Item\r
9  * @extends Ext.menu.BaseItem\r
10  * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static\r
11  * display items.  Item extends the base functionality of {@link Ext.menu.BaseItem} by adding menu-specific\r
12  * activation and click handling.\r
13  * @constructor\r
14  * Creates a new Item\r
15  * @param {Object} config Configuration options\r
16  * @xtype menuitem\r
17  */\r
18 Ext.menu.Item = function(config){\r
19     Ext.menu.Item.superclass.constructor.call(this, config);\r
20     if(this.menu){\r
21         this.menu = Ext.menu.MenuMgr.get(this.menu);\r
22     }\r
23 };\r
24 Ext.extend(Ext.menu.Item, Ext.menu.BaseItem, {\r
25     /**\r
26      * @property menu\r
27      * @type Ext.menu.Menu\r
28      * The submenu associated with this Item if one was configured.\r
29      */\r
30     /**\r
31      * @cfg {Mixed} menu (optional) Either an instance of {@link Ext.menu.Menu} or the config object for an\r
32      * {@link Ext.menu.Menu} which acts as the submenu when this item is activated.\r
33      */\r
34     /**\r
35      * @cfg {String} icon The path to an icon to display in this item (defaults to Ext.BLANK_IMAGE_URL).  If\r
36      * icon is specified {@link #iconCls} should not be.\r
37      */\r
38     /**\r
39      * @cfg {String} iconCls A CSS class that specifies a background image that will be used as the icon for\r
40      * this item (defaults to '').  If iconCls is specified {@link #icon} should not be.\r
41      */\r
42     /**\r
43      * @cfg {String} text The text to display in this item (defaults to '').\r
44      */\r
45     /**\r
46      * @cfg {String} href The href attribute to use for the underlying anchor link (defaults to '#').\r
47      */\r
48     /**\r
49      * @cfg {String} hrefTarget The target attribute to use for the underlying anchor link (defaults to '').\r
50      */\r
51     /**\r
52      * @cfg {String} itemCls The default CSS class to use for menu items (defaults to 'x-menu-item')\r
53      */\r
54     itemCls : 'x-menu-item',\r
55     /**\r
56      * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)\r
57      */\r
58     canActivate : true,\r
59     /**\r
60      * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)\r
61      */\r
62     showDelay: 200,\r
63     // doc'd in BaseItem\r
64     hideDelay: 200,\r
65 \r
66     // private\r
67     ctype: 'Ext.menu.Item',\r
68 \r
69     // private\r
70     onRender : function(container, position){\r
71         if (!this.itemTpl) {\r
72             this.itemTpl = Ext.menu.Item.prototype.itemTpl = new Ext.XTemplate(\r
73                 '<a id="{id}" class="{cls}" hidefocus="true" unselectable="on" href="{href}"',\r
74                     '<tpl if="hrefTarget">',\r
75                         ' target="{hrefTarget}"',\r
76                     '</tpl>',\r
77                  '>',\r
78                      '<img src="{icon}" class="x-menu-item-icon {iconCls}"/>',\r
79                      '<span class="x-menu-item-text">{text}</span>',\r
80                  '</a>'\r
81              );\r
82         }\r
83         var a = this.getTemplateArgs();\r
84         this.el = position ? this.itemTpl.insertBefore(position, a, true) : this.itemTpl.append(container, a, true);\r
85         this.iconEl = this.el.child('img.x-menu-item-icon');\r
86         this.textEl = this.el.child('.x-menu-item-text');\r
87         Ext.menu.Item.superclass.onRender.call(this, container, position);\r
88     },\r
89 \r
90     getTemplateArgs: function() {\r
91         return {\r
92             id: this.id,\r
93             cls: this.itemCls + (this.menu ?  ' x-menu-item-arrow' : '') + (this.cls ?  ' ' + this.cls : ''),\r
94             href: this.href || '#',\r
95             hrefTarget: this.hrefTarget,\r
96             icon: this.icon || Ext.BLANK_IMAGE_URL,\r
97             iconCls: this.iconCls || '',\r
98             text: this.itemText||this.text||'&#160;'\r
99         };\r
100     },\r
101 \r
102     /**\r
103      * Sets the text to display in this menu item\r
104      * @param {String} text The text to display\r
105      */\r
106     setText : function(text){\r
107         this.text = text||'&#160;';\r
108         if(this.rendered){\r
109             this.textEl.update(this.text);\r
110             this.parentMenu.layout.doAutoSize();\r
111         }\r
112     },\r
113 \r
114     /**\r
115      * Sets the CSS class to apply to the item's icon element\r
116      * @param {String} cls The CSS class to apply\r
117      */\r
118     setIconClass : function(cls){\r
119         var oldCls = this.iconCls;\r
120         this.iconCls = cls;\r
121         if(this.rendered){\r
122             this.iconEl.replaceClass(oldCls, this.iconCls);\r
123         }\r
124     },\r
125     \r
126     //private\r
127     beforeDestroy: function(){\r
128         if (this.menu){\r
129             this.menu.destroy();\r
130         }\r
131         Ext.menu.Item.superclass.beforeDestroy.call(this);\r
132     },\r
133 \r
134     // private\r
135     handleClick : function(e){\r
136         if(!this.href){ // if no link defined, stop the event automatically\r
137             e.stopEvent();\r
138         }\r
139         Ext.menu.Item.superclass.handleClick.apply(this, arguments);\r
140     },\r
141 \r
142     // private\r
143     activate : function(autoExpand){\r
144         if(Ext.menu.Item.superclass.activate.apply(this, arguments)){\r
145             this.focus();\r
146             if(autoExpand){\r
147                 this.expandMenu();\r
148             }\r
149         }\r
150         return true;\r
151     },\r
152 \r
153     // private\r
154     shouldDeactivate : function(e){\r
155         if(Ext.menu.Item.superclass.shouldDeactivate.call(this, e)){\r
156             if(this.menu && this.menu.isVisible()){\r
157                 return !this.menu.getEl().getRegion().contains(e.getPoint());\r
158             }\r
159             return true;\r
160         }\r
161         return false;\r
162     },\r
163 \r
164     // private\r
165     deactivate : function(){\r
166         Ext.menu.Item.superclass.deactivate.apply(this, arguments);\r
167         this.hideMenu();\r
168     },\r
169 \r
170     // private\r
171     expandMenu : function(autoActivate){\r
172         if(!this.disabled && this.menu){\r
173             clearTimeout(this.hideTimer);\r
174             delete this.hideTimer;\r
175             if(!this.menu.isVisible() && !this.showTimer){\r
176                 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);\r
177             }else if (this.menu.isVisible() && autoActivate){\r
178                 this.menu.tryActivate(0, 1);\r
179             }\r
180         }\r
181     },\r
182 \r
183     // private\r
184     deferExpand : function(autoActivate){\r
185         delete this.showTimer;\r
186         this.menu.show(this.container, this.parentMenu.subMenuAlign || 'tl-tr?', this.parentMenu);\r
187         if(autoActivate){\r
188             this.menu.tryActivate(0, 1);\r
189         }\r
190     },\r
191 \r
192     // private\r
193     hideMenu : function(){\r
194         clearTimeout(this.showTimer);\r
195         delete this.showTimer;\r
196         if(!this.hideTimer && this.menu && this.menu.isVisible()){\r
197             this.hideTimer = this.deferHide.defer(this.hideDelay, this);\r
198         }\r
199     },\r
200 \r
201     // private\r
202     deferHide : function(){\r
203         delete this.hideTimer;\r
204         if(this.menu.over){\r
205             this.parentMenu.setActiveItem(this, false);\r
206         }else{\r
207             this.menu.hide();\r
208         }\r
209     }\r
210 });\r
211 Ext.reg('menuitem', Ext.menu.Item);