/**
Class for menu layouts in LudoJS
An instance of this class is created dynamically when
layout.type for a View is set to "menu".
@namespace layout
@class Menu
@constructor
@example
layout:{
type:'Menu',
rightOf:'leftMenu'
},
children:[
{
html:'Games',
children:[
{ html:'Console games',
children:['XBox 360',
{
html:'Wii U',
children:['NintendoLand', 'Batman Arkham City', 'SuperMario Wii U']
}, 'PlayStation']},
'PC Games',
'Mac Games',
'Mobile games'
]
},
'Apps',
'Utilities'
],
listeners:{
'click' : function(item){
console.log('You clicked ' + item.html);
}
}
*/
ludo.layout.Menu = new Class({
Extends:ludo.layout.Base,
active:false,
alwaysActive:false,
onCreate:function () {
this.menuContainer = new ludo.layout.MenuContainer(this);
if (this.view.layout.active) {
this.alwaysActive = true;
}
if (this.view.id === this.getTopMenuComponent().id) {
document.id(document.documentElement).addEvent('click', this.autoHideMenus.bind(this));
ludo.EffectObject.addEvent('start', this.hideAllMenus.bind(this));
}
},
getMenuContainer:function () {
return this.menuContainer;
},
getValidChild:function (child) {
if (ludo.util.isString(child))child = { html:child };
child.layout = child.layout || {};
if (child.children && !child.layout.type) {
child.layout.type = 'menu';
child.layout.orientation = 'vertical';
}
child.type = child.type || 'menu.Item';
if (child.type === 'menu.Item') {
child.orientation = this.view.layout.orientation;
} else {
child.layout.height = child.layout.height || child.height;
}
return child;
},
parentForNewChild:undefined,
getParentForNewChild:function () {
if (this.parentForNewChild === undefined) {
var isTop = !this.hasMenuLayout(this.view.parentComponent);
var p = isTop ? this.parent() : this.getMenuContainer().getBody();
ludo.dom.addClass(p.parentNode, 'ludo-menu');
ludo.dom.addClass(p.parentNode, 'ludo-menu-' + this.view.layout.orientation);
if (isTop && !this.view.layout.isContext)ludo.dom.addClass(p.parentNode, 'ludo-menu-top');
this.parentForNewChild = p;
if (isTop) {
this.view.addEvent('show', this.resize.bind(this));
}
}
return this.parentForNewChild;
},
onNewChild:function (child) {
this.assignMenuItemFns(child);
if (this.hasMenuLayout(child)) {
child.addEvent('addChild', this.assignMenuItemFns.bind(this));
}
},
hasMenuLayout:function (item) {
return item && item.layout && item.layout.type && item.layout.type.toLowerCase() === 'menu';
},
parentContainers:undefined,
getTopMenuComponent:function () {
var v = this.view;
while (v.parentComponent && this.hasMenuLayout(v.parentComponent)) {
v = v.getParent();
}
return v;
},
assignMenuItemFns:function (child) {
var lm = this;
var p = lm.view.getParent();
var topMenu = this.getTopMenuComponent();
var topLm = topMenu.getLayout();
if (child.mouseOver === undefined) {
child.getEl().addEvent('mouseenter', function () {
this.mouseOver();
}.bind(child));
child.mouseOver = function () {
this.fireEvent('enterMenuItem', this);
}.bind(child);
}
child.getMenuLayoutManager = function () {
return this.parentComponent && this.parentComponent.getMenuLayoutManager ? this.parentComponent.getMenuLayoutManager() : lm;
}.bind(child);
child.getParentMenuItem = function () {
return lm.hasMenuLayout(p) ? lm.view : undefined;
}.bind(child);
child.isTopMenuItem = function () {
return !lm.hasMenuLayout(p);
}.bind(child);
child.getMenuContainer = function () {
return lm.getMenuContainer();
}.bind(child);
child.getMenuContainerToShow = function () {
if (this.containerToShow === undefined) {
if (lm.hasMenuLayout(this) && this.children.length > 0) {
if (!this.children[0].lifeCycleComplete)this.children[0].remainingLifeCycle();
this.containerToShow = this.children[0].getMenuContainer();
} else {
this.containerToShow = undefined;
}
}
return this.containerToShow;
}.bind(child);
child.getMenuContainersToShow = function () {
if (!this.menuContainersToShow) {
var cnt = [];
var v = this.getParent();
while (v && v.layout.orientation === 'vertical') {
if (v.getMenuContainerToShow)cnt.unshift(v.getMenuContainerToShow());
v = v.getParent();
}
var cmp = this.getMenuContainerToShow();
if (cmp)cnt.push(cmp);
this.menuContainersToShow = cnt;
}
return this.menuContainersToShow;
}.bind(child);
child.getMenuComponent = function () {
return topMenu;
}.bind(child);
child.getParentMenuItems = function () {
if (!this.parentMenuItems) {
this.parentMenuItems = [];
var v = this.getParent();
while (v && v.getMenuContainer) {
this.parentMenuItems.push(v);
v = v.getParent();
}
}
return this.parentMenuItems;
}.bind(child);
child.addEvent('click', function () {
topMenu.fireEvent('click', this);
}.bind(child));
if (this.view.layout.orientation === 'horizontal' && child.children.length > 0) {
child.addEvent('click', function () {
topLm.activate(child);
}.bind(this));
} else {
child.addEvent('click', topLm.hideAllMenus.bind(topLm));
}
child.addEvent('enterMenuItem', function () {
topLm.showMenusFor(child);
topLm.highlightItemPath(child);
}.bind(this));
},
shownMenus:[],
activate:function (child) {
this.active = !this.active;
if (this.shownMenus.length === 0) {
ludo.EffectObject.fireEvents();
}
this.showMenusFor(child);
},
showMenusFor:function (child) {
if (!this.active && !this.alwaysActive) {
this.hideMenus();
} else {
var menusToShow = child.getMenuContainersToShow();
this.hideMenus(menusToShow);
this.shownMenus = menusToShow;
for (var i = 0; i < this.shownMenus.length; i++) {
this.shownMenus[i].show();
}
}
},
hideAllMenus:function () {
this.hideMenus();
this.clearHighlightedPath();
if (this.view.layout.isContext) {
this.view.getEl().style.display = 'none';
}
this.shownMenus = [];
},
hideMenus:function (except) {
except = except || [];
for (var i = 0; i < this.shownMenus.length; i++) {
if (except.indexOf(this.shownMenus[i]) === -1) this.shownMenus[i].hide();
}
},
highlightedItems:[],
highlightItemPath:function (child) {
var items = child.getParentMenuItems();
this.clearHighlightedPath(items);
for (var i = 0; i < items.length; i++) {
ludo.dom.addClass(items[i].getEl(), 'ludo-menu-item-active');
}
this.highlightedItems = items;
},
clearHighlightedPath:function (except) {
except = except || [];
var items = this.highlightedItems;
for (var i = 0; i < items.length; i++) {
if (except.indexOf(items[i]) === -1) {
ludo.dom.removeClass(items[i].getEl(), 'ludo-menu-item-active');
}
}
},
autoHideMenus:function (e) {
if (this.active || this.alwaysActive) {
if (e.target.className && e.target.className.indexOf && e.target.className.indexOf('ludo-menu-item') === -1 && !e.target.getParent('.ludo-menu')) {
this.hideAllMenus();
if (this.view.layout.orientation === 'horizontal') {
this.active = false;
}
}
}
}
});