diff --git a/ionic/components/menu/menu-controller.ts b/ionic/components/menu/menu-controller.ts index 1c1fd69ac3..a51359e2e3 100644 --- a/ionic/components/menu/menu-controller.ts +++ b/ionic/components/menu/menu-controller.ts @@ -207,8 +207,9 @@ export class MenuController { /** * Used to enable or disable a menu. For example, there could be multiple - * left menus, but only one of them should be able to be dragged open. - * @param {boolean} shouldEnable True if it should be enabled, false if not. + * left menus, but only one of them should be able to be opened at the same + * time. If there are multiple menus on the same side, then enabling one menu + * will also automatically disable all the others that are on the same side. * @param {string} [menuId] Optionally get the menu by its id, or side. * @return {Menu} Returns the instance of the menu, which is useful for chaining. */ @@ -249,24 +250,37 @@ export class MenuController { } /** - * Used to get a menu instance. If a `menuId` is not provided then it'll return - * the first menu found. If a `menuId` is provided, then it'll first try to find - * the menu using the menu's `id` attribute. If a menu is not found using the `id` - * attribute, then it'll try to find the menu by its `side` name. + * Used to get a menu instance. If a `menuId` is not provided then it'll + * return the first menu found. If a `menuId` is `left` or `right`, then + * it'll return the enabled menu on that side. Otherwise, if a `menuId` is + * provided, then it'll try to find the menu using the menu's `id` + * property. If a menu is not found then it'll return `null`. * @param {string} [menuId] Optionally get the menu by its id, or side. * @return {Menu} Returns the instance of the menu if found, otherwise `null`. */ get(menuId?: string): Menu { - if (menuId) { - // first try by "id" - let menu = this._menus.find(m => m.id === menuId); + var menu: Menu; + + if (menuId === 'left' || menuId === 'right') { + // there could be more than one menu on the same side + // so first try to get the enabled one + menu = this._menus.find(m => m.side === menuId && m.enabled); if (menu) return menu; - // not found by "id", next try by "side" - menu = this._menus.find(m => m.side === menuId); - if (menu) return menu; + // didn't find a menu side that is enabled + // so try to get the first menu side found + return this._menus.find(m => m.side === menuId) || null; + + } else if (menuId) { + // the menuId was not left or right + // so try to get the menu by its "id" + return this._menus.find(m => m.id === menuId) || null; } + // return the first enabled menu + menu = this._menus.find(m => m.enabled); + if (menu) return menu; + // get the first menu in the array, if one exists return (this._menus.length ? this._menus[0] : null); } diff --git a/ionic/components/menu/menu.ts b/ionic/components/menu/menu.ts index 87104a2cf3..af5bddb6bc 100644 --- a/ionic/components/menu/menu.ts +++ b/ionic/components/menu/menu.ts @@ -370,15 +370,29 @@ export class Menu extends Ion { /** * Used to enable or disable a menu. For example, there could be multiple - * left menus, but only one of them should be able to be dragged open. + * left menus, but only one of them should be able to be opened at the same + * time. If there are multiple menus on the same side, then enabling one menu + * will also automatically disable all the others that are on the same side. * @param {boolean} shouldEnable True if it should be enabled, false if not. * @return {Menu} Returns the instance of the menu, which is useful for chaining. */ enable(shouldEnable: boolean): Menu { this.enabled = shouldEnable; if (!shouldEnable && this.isOpen) { + // close if this menu is open, and should not be enabled this.close(); } + + if (shouldEnable) { + // if this menu should be enabled + // then find all the other menus on this same side + // and automatically disable other same side menus + let sameSideMenus = this._menuCtrl + .getMenus() + .filter(m => m.side === this.side && m !== this) + .map(m => m.enabled = false); + } + return this; } diff --git a/ionic/components/menu/test/enable-disable/index.ts b/ionic/components/menu/test/enable-disable/index.ts index 947ec1c699..24255c5f2a 100644 --- a/ionic/components/menu/test/enable-disable/index.ts +++ b/ionic/components/menu/test/enable-disable/index.ts @@ -24,7 +24,7 @@ class E2EApp { constructor(app: IonicApp, menu: MenuController) { this.app = app; this.menu = menu; - + this.page1 = Page1; this.page2 = Page2; @@ -39,13 +39,18 @@ class E2EApp { } menu1Active() { - this.activeMenu = 'menu1'; this.menu.enable(true, 'menu1'); this.menu.enable(false, 'menu2'); + this.menu.enable(false, 'menu3'); } menu2Active() { - this.activeMenu = 'menu2'; this.menu.enable(false, 'menu1'); this.menu.enable(true, 'menu2'); + this.menu.enable(false, 'menu3'); + } + menu3Active() { + this.menu.enable(false, 'menu1'); + this.menu.enable(false, 'menu2'); + this.menu.enable(true, 'menu3'); } } diff --git a/ionic/components/menu/test/enable-disable/main.html b/ionic/components/menu/test/enable-disable/main.html index 031d8a8998..c3a4f5e835 100644 --- a/ionic/components/menu/test/enable-disable/main.html +++ b/ionic/components/menu/test/enable-disable/main.html @@ -9,6 +9,7 @@ + @@ -33,7 +34,8 @@ - + + @@ -48,5 +50,30 @@ + + + + Menu 3 + + + + + + + + + + + + + + + diff --git a/ionic/components/menu/test/enable-disable/page1.html b/ionic/components/menu/test/enable-disable/page1.html index 842e288465..2192d0834d 100644 --- a/ionic/components/menu/test/enable-disable/page1.html +++ b/ionic/components/menu/test/enable-disable/page1.html @@ -1,6 +1,6 @@ - @@ -12,10 +12,8 @@

Page 1

-

Active Menu: {{ activeMenu }}

-

- +

This page has two left menus, but only one is active at a time.

diff --git a/ionic/components/menu/test/enable-disable/page2.html b/ionic/components/menu/test/enable-disable/page2.html index fa3317b687..a5841a3b32 100644 --- a/ionic/components/menu/test/enable-disable/page2.html +++ b/ionic/components/menu/test/enable-disable/page2.html @@ -1,6 +1,6 @@ - @@ -12,10 +12,8 @@

Page 2

-

Active Menu: {{ activeMenu }}

-

- +

This page has two left menus, but only one is active at a time.

diff --git a/ionic/components/menu/test/menu.spec.ts b/ionic/components/menu/test/menu.spec.ts new file mode 100644 index 0000000000..5d79fc94cc --- /dev/null +++ b/ionic/components/menu/test/menu.spec.ts @@ -0,0 +1,250 @@ +import {MenuController, Menu} from '../../../../ionic/ionic'; + +export function run() { + describe('MenuController', () => { + + describe('get() without menuId', () => { + + it('should not get a menu if no menus', () => { + let menu = menuCtrl.get(); + expect(menu).toEqual(null); + }); + + it('should get the only menu', () => { + let someMenu = mockMenu(); + menuCtrl.register(someMenu); + + let menu = menuCtrl.get(); + expect(menu).toEqual(someMenu); + }); + + it('should get the only menu if menuId === ""', () => { + let someMenu = mockMenu(); + menuCtrl.register(someMenu); + + let menu = menuCtrl.get(''); + expect(menu).toEqual(someMenu); + }); + + it('should get the enabled menu when multiple menus', () => { + let someMenu1 = mockMenu(); + someMenu1.enabled = false; + menuCtrl.register(someMenu1); + + let someMenu2 = mockMenu(); + someMenu2.enabled = true; + menuCtrl.register(someMenu2); + + let menu = menuCtrl.get(); + expect(menu).toEqual(someMenu2); + }); + + }); + + describe('get() by id', () => { + + it('should be null if no menus', () => { + let menu = menuCtrl.get('myid'); + expect(menu).toEqual(null); + }); + + it('should be null if no matching menus with id', () => { + let someMenu = mockMenu(); + someMenu.id = 'whatever'; + menuCtrl.register(someMenu); + + let menu = menuCtrl.get('myMenu'); + expect(menu).toEqual(null); + }); + + it('should get the menu by id with matching id', () => { + let someMenu = mockMenu(); + someMenu.id = 'myMenu'; + menuCtrl.register(someMenu); + + let menu = menuCtrl.get('myMenu'); + expect(menu).toEqual(someMenu); + }); + + it('should get the menu by id with left', () => { + let someMenu = mockMenu(); + someMenu.id = 'myMenu'; + someMenu.side = 'left'; + menuCtrl.register(someMenu); + + let menu = menuCtrl.get('myMenu'); + expect(menu).toEqual(someMenu); + }); + + it('should get the menu by id with matching id when multiple menus', () => { + let someMenu1 = mockMenu(); + someMenu1.id = 'myMenu1'; + menuCtrl.register(someMenu1); + + let someMenu2 = mockMenu(); + someMenu2.id = 'myMenu2'; + menuCtrl.register(someMenu2); + + let menu = menuCtrl.get('myMenu1'); + expect(menu).toEqual(someMenu1); + + menu = menuCtrl.get('myMenu2'); + expect(menu).toEqual(someMenu2); + }); + + }); + + describe('get() by side', () => { + + it('should not get a menu with a left side if no menus', () => { + let menu = menuCtrl.get('left'); + expect(menu).toEqual(null); + }); + + it('should not get a menu with a right side if no menus', () => { + let menu = menuCtrl.get('right'); + expect(menu).toEqual(null); + }); + + it('should get the only left menu', () => { + let someMenu = mockMenu(); + someMenu.side = 'left'; + menuCtrl.register(someMenu); + + let menu = menuCtrl.get('left'); + expect(menu).toEqual(someMenu); + }); + + it('should get the enabled left menu', () => { + let someMenu1 = mockMenu(); + someMenu1.side = 'left'; + someMenu1.enabled = false; + menuCtrl.register(someMenu1); + + let someMenu2 = mockMenu(); + someMenu2.side = 'left'; + someMenu2.enabled = true; + menuCtrl.register(someMenu2); + + let menu = menuCtrl.get('left'); + expect(menu).toEqual(someMenu2); + }); + + it('should get the first left menu when all are disabled', () => { + let someMenu1 = mockMenu(); + someMenu1.side = 'left'; + someMenu1.enabled = false; + menuCtrl.register(someMenu1); + + let someMenu2 = mockMenu(); + someMenu2.side = 'left'; + someMenu2.enabled = false; + menuCtrl.register(someMenu2); + + let menu = menuCtrl.get('left'); + expect(menu).toEqual(someMenu1); + }); + + it('should get the only right menu', () => { + let someMenu = mockMenu(); + someMenu.side = 'right'; + menuCtrl.register(someMenu); + + let menu = menuCtrl.get('right'); + expect(menu).toEqual(someMenu); + }); + + it('should get the menu by left with id', () => { + let someMenu = mockMenu(); + someMenu.id = 'myMenu'; + someMenu.side = 'left'; + menuCtrl.register(someMenu); + + let menu = menuCtrl.get('left'); + expect(menu).toEqual(someMenu); + }); + + }); + + describe('enable()', () => { + + it('should enable a menu', () => { + let someMenu = mockMenu(); + someMenu.enabled = true; + menuCtrl.register(someMenu); + someMenu._menuCtrl = menuCtrl; + + let menu = menuCtrl.enable(true); + expect(menu.enabled).toEqual(true); + + menu = menuCtrl.enable(false); + expect(menu.enabled).toEqual(false); + }); + + it('should be only one enabled menu on the same side', () => { + let someMenu1 = mockMenu(); + someMenu1.enabled = true; + someMenu1.side = 'left'; + someMenu1.id = 'menu1'; + someMenu1._menuCtrl = menuCtrl; + menuCtrl.register(someMenu1); + + let someMenu2 = mockMenu(); + someMenu2.enabled = false; + someMenu2.side = 'left'; + someMenu2.id = 'menu2'; + someMenu2._menuCtrl = menuCtrl; + menuCtrl.register(someMenu2); + + let someMenu3 = mockMenu(); + someMenu3.enabled = true; + someMenu3.side = 'right'; + someMenu3.id = 'menu2'; + someMenu3._menuCtrl = menuCtrl; + menuCtrl.register(someMenu3); + + menuCtrl.enable(true, 'menu1'); + expect(someMenu1.enabled).toEqual(true); + expect(someMenu2.enabled).toEqual(false); + expect(someMenu3.enabled).toEqual(true); + + menuCtrl.enable(true, 'menu2'); + expect(someMenu1.enabled).toEqual(false); + expect(someMenu2.enabled).toEqual(true); + expect(someMenu3.enabled).toEqual(true); + + menuCtrl.enable(true, 'menu1'); + expect(someMenu1.enabled).toEqual(true); + expect(someMenu2.enabled).toEqual(false); + expect(someMenu3.enabled).toEqual(true); + }); + + }); + + it('should register a menu', () => { + let menu = mockMenu(); + menuCtrl.register(menu); + expect(menuCtrl.getMenus().length).toEqual(1); + + let menu2 = mockMenu(); + menuCtrl.register(menu2); + expect(menuCtrl.getMenus().length).toEqual(2); + + menuCtrl.unregister(menu2); + menuCtrl.unregister(menu); + + expect(menuCtrl.getMenus().length).toEqual(0); + }); + + let menuCtrl: MenuController; + + beforeEach(() => { + menuCtrl = new MenuController(); + }); + + function mockMenu(): Menu { + return new Menu(null, null, null, null, null, null, null); + } + + }); +}