mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 21:15:24 +08:00
Merge branch 'menu-improvements' into 2.0
This commit is contained in:
@ -207,8 +207,9 @@ export class MenuController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to enable or disable a menu. For example, there could be multiple
|
* 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
|
||||||
* @param {boolean} shouldEnable True if it should be enabled, false if not.
|
* 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.
|
* @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.
|
* @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
|
* Used to get a menu instance. If a `menuId` is not provided then it'll
|
||||||
* the first menu found. If a `menuId` is provided, then it'll first try to find
|
* return the first menu found. If a `menuId` is `left` or `right`, then
|
||||||
* the menu using the menu's `id` attribute. If a menu is not found using the `id`
|
* it'll return the enabled menu on that side. Otherwise, if a `menuId` is
|
||||||
* attribute, then it'll try to find the menu by its `side` name.
|
* 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.
|
* @param {string} [menuId] Optionally get the menu by its id, or side.
|
||||||
* @return {Menu} Returns the instance of the menu if found, otherwise `null`.
|
* @return {Menu} Returns the instance of the menu if found, otherwise `null`.
|
||||||
*/
|
*/
|
||||||
get(menuId?: string): Menu {
|
get(menuId?: string): Menu {
|
||||||
if (menuId) {
|
var menu: Menu;
|
||||||
// first try by "id"
|
|
||||||
let menu = this._menus.find(m => m.id === menuId);
|
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;
|
if (menu) return menu;
|
||||||
|
|
||||||
// not found by "id", next try by "side"
|
// didn't find a menu side that is enabled
|
||||||
menu = this._menus.find(m => m.side === menuId);
|
// so try to get the first menu side found
|
||||||
if (menu) return menu;
|
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
|
// get the first menu in the array, if one exists
|
||||||
return (this._menus.length ? this._menus[0] : null);
|
return (this._menus.length ? this._menus[0] : null);
|
||||||
}
|
}
|
||||||
|
@ -370,15 +370,29 @@ export class Menu extends Ion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to enable or disable a menu. For example, there could be multiple
|
* 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.
|
* @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.
|
* @return {Menu} Returns the instance of the menu, which is useful for chaining.
|
||||||
*/
|
*/
|
||||||
enable(shouldEnable: boolean): Menu {
|
enable(shouldEnable: boolean): Menu {
|
||||||
this.enabled = shouldEnable;
|
this.enabled = shouldEnable;
|
||||||
if (!shouldEnable && this.isOpen) {
|
if (!shouldEnable && this.isOpen) {
|
||||||
|
// close if this menu is open, and should not be enabled
|
||||||
this.close();
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class E2EApp {
|
|||||||
constructor(app: IonicApp, menu: MenuController) {
|
constructor(app: IonicApp, menu: MenuController) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.menu = menu;
|
this.menu = menu;
|
||||||
|
|
||||||
this.page1 = Page1;
|
this.page1 = Page1;
|
||||||
this.page2 = Page2;
|
this.page2 = Page2;
|
||||||
|
|
||||||
@ -39,13 +39,18 @@ class E2EApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
menu1Active() {
|
menu1Active() {
|
||||||
this.activeMenu = 'menu1';
|
|
||||||
this.menu.enable(true, 'menu1');
|
this.menu.enable(true, 'menu1');
|
||||||
this.menu.enable(false, 'menu2');
|
this.menu.enable(false, 'menu2');
|
||||||
|
this.menu.enable(false, 'menu3');
|
||||||
}
|
}
|
||||||
menu2Active() {
|
menu2Active() {
|
||||||
this.activeMenu = 'menu2';
|
|
||||||
this.menu.enable(false, 'menu1');
|
this.menu.enable(false, 'menu1');
|
||||||
this.menu.enable(true, 'menu2');
|
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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<ion-list>
|
<ion-list>
|
||||||
<button ion-item menuClose (click)="menu1Active()">Make Menu 1 Active</button>
|
<button ion-item menuClose (click)="menu1Active()">Make Menu 1 Active</button>
|
||||||
<button ion-item menuClose (click)="menu2Active()">Make Menu 2 Active</button>
|
<button ion-item menuClose (click)="menu2Active()">Make Menu 2 Active</button>
|
||||||
|
<button ion-item menuClose (click)="menu3Active()">Make Menu 3 Active</button>
|
||||||
<button ion-item menuClose (click)="openPage(page1)">
|
<button ion-item menuClose (click)="openPage(page1)">
|
||||||
Page 1
|
Page 1
|
||||||
</button>
|
</button>
|
||||||
@ -33,7 +34,8 @@
|
|||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<button ion-item menuClose (click)="menu1Active()">Make Menu 1 Active</button>
|
<button ion-item menuClose (click)="menu1Active()">Make Menu 1 Active</button>
|
||||||
<button ion-item menuClose (click)="menu2Active()">Make Menu 2 Active</button>
|
<button ion-item menuClose (click)="menu2Active()">Make Menu 2 Active</button>
|
||||||
|
<button ion-item menuClose (click)="menu3Active()">Make Menu 3 Active</button>
|
||||||
<button ion-item menuClose (click)="openPage(page1)">
|
<button ion-item menuClose (click)="openPage(page1)">
|
||||||
Page 1
|
Page 1
|
||||||
</button>
|
</button>
|
||||||
@ -48,5 +50,30 @@
|
|||||||
|
|
||||||
</ion-menu>
|
</ion-menu>
|
||||||
|
|
||||||
|
<ion-menu [content]="content" id="menu3">
|
||||||
|
|
||||||
|
<ion-toolbar primary>
|
||||||
|
<ion-title>Menu 3</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
|
||||||
|
<ion-content>
|
||||||
|
<ion-list>
|
||||||
|
<button ion-item menuClose (click)="menu1Active()">Make Menu 1 Active</button>
|
||||||
|
<button ion-item menuClose (click)="menu2Active()">Make Menu 2 Active</button>
|
||||||
|
<button ion-item menuClose (click)="menu3Active()">Make Menu 3 Active</button>
|
||||||
|
<button ion-item menuClose (click)="openPage(page1)">
|
||||||
|
Page 1
|
||||||
|
</button>
|
||||||
|
<button ion-item menuClose (click)="openPage(page2)">
|
||||||
|
Page 2
|
||||||
|
</button>
|
||||||
|
<button ion-item menuClose detail-none>
|
||||||
|
Close Menu 3
|
||||||
|
</button>
|
||||||
|
</ion-list>
|
||||||
|
</ion-content>
|
||||||
|
|
||||||
|
</ion-menu>
|
||||||
|
|
||||||
|
|
||||||
<ion-nav id="nav" [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>
|
<ion-nav id="nav" [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
<ion-navbar *navbar>
|
<ion-navbar *navbar>
|
||||||
<button [menuToggle]="activeMenu">
|
<button menuToggle="left">
|
||||||
<ion-icon name="menu"></ion-icon>
|
<ion-icon name="menu"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
<ion-title>
|
<ion-title>
|
||||||
@ -12,10 +12,8 @@
|
|||||||
<ion-content padding>
|
<ion-content padding>
|
||||||
<h3> Page 1 </h3>
|
<h3> Page 1 </h3>
|
||||||
|
|
||||||
<h4>Active Menu: {{ activeMenu }}</h4>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button [menuToggle]="activeMenu">Toggle Menu</button>
|
<button menuToggle="left">Toggle Menu</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>This page has two left menus, but only one is active at a time.</p>
|
<p>This page has two left menus, but only one is active at a time.</p>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
<ion-navbar *navbar>
|
<ion-navbar *navbar>
|
||||||
<button [menuToggle]="activeMenu">
|
<button menuToggle="left">
|
||||||
<ion-icon name="menu"></ion-icon>
|
<ion-icon name="menu"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
<ion-title>
|
<ion-title>
|
||||||
@ -12,10 +12,8 @@
|
|||||||
<ion-content padding>
|
<ion-content padding>
|
||||||
<h3> Page 2 </h3>
|
<h3> Page 2 </h3>
|
||||||
|
|
||||||
<h4>Active Menu: {{ activeMenu }}</h4>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button [menuToggle]="activeMenu">Toggle Menu</button>
|
<button menuToggle="left">Toggle Menu</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>This page has two left menus, but only one is active at a time.</p>
|
<p>This page has two left menus, but only one is active at a time.</p>
|
||||||
|
250
ionic/components/menu/test/menu.spec.ts
Normal file
250
ionic/components/menu/test/menu.spec.ts
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
Reference in New Issue
Block a user