/**
* @class Ext.menu.MenuMgr
* Provides a common registry of all menus on a page so that they can be easily accessed by id.
* @singleton
*/
Ext.define('Ext.menu.MenuMgr', {
singleton: true,
requires: [
'Ext.util.MixedCollection',
'Ext.util.KeyMap'
],
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) {
if (typeof menu == 'string') { // menu id
if (!menus) { // not initialized, no menus to return
return null;
}
return menus[menu];
} else if (menu.events) { // menu instance
return menu;
} else if (typeof menu.length == 'number') { // array of menu items?
return Ext.create('Ext.menu.Menu', {items:menu});
} else { // otherwise, must be a config
return Ext.ComponentMgr.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, me);
menu.un('hide', me.onHide, me);
menu.un('beforeshow', this.onBeforeShow, me);
menu.un('show', me.onShow, 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) {
groups[groupId].remove(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);
}
}
}
}
});