X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/menu/Manager.js?ds=sidebyside diff --git a/src/menu/Manager.js b/src/menu/Manager.js new file mode 100644 index 00000000..3265c885 --- /dev/null +++ b/src/menu/Manager.js @@ -0,0 +1,211 @@ +/** + * @class Ext.menu.Manager + * Provides a common registry of all menus on a page. + * @singleton + */ +Ext.define('Ext.menu.Manager', { + singleton: true, + requires: [ + 'Ext.util.MixedCollection', + 'Ext.util.KeyMap' + ], + alternateClassName: 'Ext.menu.MenuMgr', + + uses: ['Ext.menu.Menu'], + + menus: {}, + groups: {}, + attached: false, + lastShow: new Date(), + + init: function() { + var me = this; + + me.active = Ext.create('Ext.util.MixedCollection'); + Ext.getDoc().addKeyListener(27, function() { + if (me.active.length > 0) { + me.hideAll(); + } + }, me); + }, + + /** + * Hides all menus that are currently visible + * @return {Boolean} success True if any active menus were hidden. + */ + hideAll: function() { + var active = this.active, + c; + if (active && active.length > 0) { + c = active.clone(); + c.each(function(m) { + m.hide(); + }); + return true; + } + return false; + }, + + onHide: function(m) { + var me = this, + active = me.active; + active.remove(m); + if (active.length < 1) { + Ext.getDoc().un('mousedown', me.onMouseDown, me); + me.attached = false; + } + }, + + onShow: function(m) { + var me = this, + active = me.active, + last = active.last(), + attached = me.attached, + menuEl = m.getEl(), + zIndex; + + me.lastShow = new Date(); + active.add(m); + if (!attached) { + Ext.getDoc().on('mousedown', me.onMouseDown, me); + me.attached = true; + } + m.toFront(); + }, + + onBeforeHide: function(m) { + if (m.activeChild) { + m.activeChild.hide(); + } + if (m.autoHideTimer) { + clearTimeout(m.autoHideTimer); + delete m.autoHideTimer; + } + }, + + onBeforeShow: function(m) { + var active = this.active, + parentMenu = m.parentMenu; + + active.remove(m); + if (!parentMenu && !m.allowOtherMenus) { + this.hideAll(); + } + else if (parentMenu && parentMenu.activeChild && m != parentMenu.activeChild) { + parentMenu.activeChild.hide(); + } + }, + + // private + onMouseDown: function(e) { + var me = this, + active = me.active, + lastShow = me.lastShow; + + if (Ext.Date.getElapsed(lastShow) > 50 && active.length > 0 && !e.getTarget('.' + Ext.baseCSSPrefix + 'menu')) { + me.hideAll(); + } + }, + + // private + register: function(menu) { + var me = this; + + if (!me.active) { + me.init(); + } + + if (menu.floating) { + me.menus[menu.id] = menu; + menu.on({ + beforehide: me.onBeforeHide, + hide: me.onHide, + beforeshow: me.onBeforeShow, + show: me.onShow, + scope: me + }); + } + }, + + /** + * Returns a {@link Ext.menu.Menu} object + * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will + * be used to generate and return a new Menu this. + * @return {Ext.menu.Menu} The specified menu, or null if none are found + */ + get: function(menu) { + var menus = this.menus; + + if (typeof menu == 'string') { // menu id + if (!menus) { // not initialized, no menus to return + return null; + } + return menus[menu]; + } else if (menu.isMenu) { // menu instance + return menu; + } else if (Ext.isArray(menu)) { // array of menu items + return Ext.create('Ext.menu.Menu', {items:menu}); + } else { // otherwise, must be a config + return Ext.ComponentManager.create(menu, 'menu'); + } + }, + + // private + unregister: function(menu) { + var me = this, + menus = me.menus, + active = me.active; + + delete menus[menu.id]; + active.remove(menu); + menu.un({ + beforehide: me.onBeforeHide, + hide: me.onHide, + beforeshow: me.onBeforeShow, + show: me.onShow, + scope: me + }); + }, + + // private + registerCheckable: function(menuItem) { + var groups = this.groups, + groupId = menuItem.group; + + if (groupId) { + if (!groups[groupId]) { + groups[groupId] = []; + } + + groups[groupId].push(menuItem); + } + }, + + // private + unregisterCheckable: function(menuItem) { + var groups = this.groups, + groupId = menuItem.group; + + if (groupId) { + Ext.Array.remove(groups[groupId], menuItem); + } + }, + + onCheckChange: function(menuItem, state) { + var groups = this.groups, + groupId = menuItem.group, + i = 0, + group, ln, curr; + + if (groupId && state) { + group = groups[groupId]; + ln = group.length; + for (; i < ln; i++) { + curr = group[i]; + if (curr != menuItem) { + curr.setChecked(false); + } + } + } + } +}); \ No newline at end of file