3 * Copyright(c) 2006-2010 Ext JS, Inc.
5 * http://www.extjs.com/license
8 * Ext Core Library Examples 3.0 Beta
10 * Copyright(c) 2006-2009, Ext JS, LLC.
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36 Ext.ux.Menu = Ext.extend(Ext.util.Observable, {
37 direction: 'horizontal',
40 transitionType: 'fade',
41 transitionDuration: 0.3,
43 currentClass: 'current',
45 constructor: function(elId, config) {
46 config = config || {};
47 Ext.apply(this, config);
49 Ext.ux.Menu.superclass.constructor.call(this, config);
57 this.el = Ext.get(elId);
65 initMarkup: function(){
66 this.container = this.el.wrap({cls: 'ux-menu-container', style: 'z-index: ' + --Ext.ux.Menu.zSeed});
67 this.items = this.el.select('li');
69 this.el.addClass('ux-menu ux-menu-' + this.direction);
70 this.el.select('>li').addClass('ux-menu-item-main');
72 this.el.select('li:has(>ul)').addClass('ux-menu-item-parent').each(function(item) {
74 .addClass('ux-menu-link-parent')
75 .createChild({tag: 'span', cls: 'ux-menu-arrow'});
78 this.el.select('li:first-child>a').addClass('ux-menu-link-first');
79 this.el.select('li:last-child>a').addClass('ux-menu-link-last');
81 // create clear fixes for the floating stuff
82 this.container.addClass('ux-menu-clearfix');
84 // if autoWidth make every submenu as wide as its biggest child;
89 var subs = this.el.select('ul');
90 subs.addClass('ux-menu-sub');
92 //ie6 and ie7/ie8 quirksmode need iframes behind the submenus
93 if(Ext.isBorderBox || Ext.isIE7) {
94 subs.each(function(item) {
95 item.parent().createChild({tag: 'iframe', cls: 'ux-menu-ie-iframe'})
96 .setWidth(item.getWidth())
97 .setHeight(item.getHeight());
101 subs.addClass('ux-menu-hidden');
104 initEvents: function() {
105 this.showTask = new Ext.util.DelayedTask(this.showMenu, this);
106 this.hideTask = new Ext.util.DelayedTask(function() {
107 this.showTask.cancel();
109 this.fireEvent('hide');
112 this.el.hover(function() {
113 this.hideTask.cancel();
115 this.hideTask.delay(this.delay*1000);
118 // for each item that has a submenu, create a mouseenter function that shows its submenu
119 // delay 5 to make sure enter is fired after mouseover
120 this.el.select('li.ux-menu-item-parent').on('mouseenter', this.onParentEnter, false, {me: this, delay: 5});
122 // listen for mouseover events on items to hide other items submenus and remove hovers
123 this.el.on('mouseover', function(ev, t) {
124 this.manageSiblings(t);
125 // if this item does not have a submenu, the showMenu task for a sibling could potentially still be fired, so cancel it
126 if(!Ext.fly(t).hasClass('ux-menu-item-parent')) {
127 this.showTask.cancel();
129 }, this, {delegate: 'li'});
131 this.el.on('click', function(ev, t) {
132 return this.fireEvent('click', ev, t, this);
133 }, this, {delegate: 'a'})
136 onParentEnter: function(ev, link, o) {
137 var item = Ext.get(this),
140 // if this item is in a submenu and contains a submenu, check if the submenu is not still animating
141 if(!item.hasClass('ux-menu-item-main') && item.parent('ul').hasActiveFx()) {
142 item.parent('ul').stopFx(true);
145 // if submenu is already shown dont do anything
146 if(!item.child('ul').hasClass('ux-menu-hidden')) {
150 me.showTask.delay(me.delay*1000, false, false, [item]);
153 showMenu : function(item) {
154 var menu = item.child('ul'),
157 item.select('>a').addClass('ux-menu-link-hover');
159 // some different configurations require different positioning
160 if(this.direction == 'horizontal' && item.hasClass('ux-menu-item-main')) {
161 y = item.getHeight()+1;
164 x = item.getWidth()+1;
167 // if its ie, force a repaint of the submenu
169 menu.select('ul').addClass('ux-menu-hidden');
171 if(Ext.isBorderBox || Ext.isIE7) {
172 item.down('iframe').setStyle({left: x + 'px', top: y + 'px', display: 'block'});
176 menu.setStyle({left: x + 'px', top: y + 'px'}).removeClass('ux-menu-hidden');
179 switch(this.transitionType) {
181 if(this.direction == 'horizontal' && item.hasClass('ux-menu-item-main')) {
183 duration: this.transitionDuration
188 duration: this.transitionDuration
194 menu.setOpacity(0.001).fadeIn({
195 duration: this.transitionDuration
201 this.fireEvent('show', item, menu, this);
204 manageSiblings: function(item) {
205 var item = Ext.get(item);
206 item.parent().select('li.ux-menu-item-parent').each(function(child) {
207 if(child.dom.id !== item.dom.id) {
208 child.select('>a').removeClass('ux-menu-link-hover');
209 child.select('ul').stopFx(false).addClass('ux-menu-hidden');
210 if (Ext.isBorderBox || Ext.isIE7) {
211 child.select('iframe').setStyle('display', 'none');
217 hideAll: function() {
218 this.manageSiblings(this.el);
221 setCurrent: function() {
222 var els = this.el.query('.' + this.currentClass);
226 var item = Ext.get(els[els.length-1]).removeClass(this.currentClass).findParent('li', null, true);
227 while(item && item.parent('.ux-menu')) {
228 item.down('a').addClass(this.currentClass);
229 item = item.parent('li');
233 doAutoWidth: function() {
234 var fixWidth = function(sub) {
236 var items = sub.select('>li');
238 sub.setStyle({width: 3000 + 'px'});
239 items.each(function(item) {
240 widest = Math.max(widest, item.getWidth());
243 widest = Ext.isIE ? widest + 1 : widest;
244 items.setWidth(widest + 'px');
245 sub.setWidth(widest + 'px');
248 if(this.direction == 'vertical') {
249 this.container.select('ul').each(fixWidth);
252 this.el.select('ul').each(fixWidth);
258 Ext.ux.Menu.zSeed = 10000;