fix(menu): only one menu can be opened at a time

fixes #6826
This commit is contained in:
Manu Mtz.-Almeida
2016-07-18 03:42:29 +02:00
committed by Adam Bradley
parent 6e9eb93717
commit cac378f35b
9 changed files with 90 additions and 62 deletions

View File

@ -289,11 +289,12 @@ export class Animation {
var self = this; var self = this;
var i: number; var i: number;
let dur = this._dur;
if (isDefined(opts.duration)) { if (isDefined(opts.duration)) {
self._dur = opts.duration; dur = opts.duration;
} }
console.debug('Animation, play, duration', self._dur, 'easing', self._easing); console.debug('Animation, play, duration', dur, 'easing', this._easing);
// always default that an animation does not tween // always default that an animation does not tween
// a tween requires that an Animation class has an element // a tween requires that an Animation class has an element
@ -313,7 +314,7 @@ export class Animation {
// ensure all past transition end events have been cleared // ensure all past transition end events have been cleared
self._clearAsync(); self._clearAsync();
if (self._dur > 30) { if (dur > 30) {
// this animation has a duration, so it should animate // this animation has a duration, so it should animate
// place all the elements with their FROM properties // place all the elements with their FROM properties
@ -328,7 +329,7 @@ export class Animation {
// set the async TRANSITION END event // set the async TRANSITION END event
// and run onFinishes when the transition ends // and run onFinishes when the transition ends
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
self._asyncEnd(self._dur, true); self._asyncEnd(dur, true);
// begin each animation when everything is rendered in their place // begin each animation when everything is rendered in their place
// and the transition duration/easing is ready to go // and the transition duration/easing is ready to go

View File

@ -6,8 +6,8 @@ import {ionicBootstrap, Config, Animation} from '../../../../../src';
templateUrl: 'main.html' templateUrl: 'main.html'
}) })
class E2EPage { class E2EPage {
duration; duration: string;
easing; easing: string;
constructor(config: Config) { constructor(config: Config) {
this.duration = '1000'; this.duration = '1000';

View File

@ -125,6 +125,10 @@ export class MenuController {
open(menuId?: string): Promise<boolean> { open(menuId?: string): Promise<boolean> {
let menu = this.get(menuId); let menu = this.get(menuId);
if (menu) { if (menu) {
let openedMenu = this.getOpen();
if (openedMenu && menu !== openedMenu) {
openedMenu.setOpen(false, false);
}
return menu.open(); return menu.open();
} }
@ -147,7 +151,7 @@ export class MenuController {
} else { } else {
// find the menu that is open // find the menu that is open
menu = this._menus.find(m => m.isOpen); menu = this.getOpen();
} }
if (menu) { if (menu) {
@ -158,11 +162,6 @@ export class MenuController {
return Promise.resolve(false); return Promise.resolve(false);
} }
tempDisable(temporarilyDisable: boolean) {
this._menus.forEach(menu => {
menu.tempDisable(temporarilyDisable);
});
}
/** /**
* Toggle the menu. If it's closed, it will open, and if opened, it * Toggle the menu. If it's closed, it will open, and if opened, it
@ -173,6 +172,10 @@ export class MenuController {
toggle(menuId?: string): Promise<boolean> { toggle(menuId?: string): Promise<boolean> {
let menu = this.get(menuId); let menu = this.get(menuId);
if (menu) { if (menu) {
let openedMenu = this.getOpen();
if (openedMenu && menu !== openedMenu) {
openedMenu.setOpen(false, false);
}
return menu.toggle(); return menu.toggle();
} }
return Promise.resolve(false); return Promise.resolve(false);
@ -229,7 +232,7 @@ export class MenuController {
* provided, then it'll try to find the menu using the menu's `id` * 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`. * 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 {
var menu: Menu; var menu: Menu;
@ -252,12 +255,21 @@ export class MenuController {
// return the first enabled menu // return the first enabled menu
menu = this._menus.find(m => m.enabled); menu = this._menus.find(m => m.enabled);
if (menu) return menu; 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);
} }
/**
* @return {Menu} Returns the instance of the menu already opened, otherwise `null`.
*/
getOpen(): Menu {
return this._menus.find(m => m.isOpen);
}
/** /**
* @return {Array<Menu>} Returns an array of all menu instances. * @return {Array<Menu>} Returns an array of all menu instances.

View File

@ -24,11 +24,15 @@ export class MenuContentGesture extends SlideEdgeGesture {
canStart(ev: any): boolean { canStart(ev: any): boolean {
let menu = this.menu; let menu = this.menu;
return ( if (!menu.enabled || !menu.swipeEnabled) {
menu.enabled && return false;
menu.swipeEnabled && }
(menu.isOpen || super.canStart(ev)) if (menu.isOpen) {
); return true;
} else if (menu.getMenuController().getOpen()) {
return false;
}
return super.canStart(ev);
} }
// Set CSS, then wait one frame for it to apply before sliding starts // Set CSS, then wait one frame for it to apply before sliding starts

View File

@ -15,11 +15,15 @@ export class MenuType {
ani: Animation = new Animation(); ani: Animation = new Animation();
isOpening: boolean; isOpening: boolean;
setOpen(shouldOpen: boolean, done: Function) { setOpen(shouldOpen: boolean, animated: boolean, done: Function) {
this.ani let ani = this.ani
.onFinish(done, true) .onFinish(done, true)
.reverse(!shouldOpen) .reverse(!shouldOpen);
.play(); if (animated) {
ani.play();
} else {
ani.play({ duration: 0 });
}
} }
setProgressStart(isOpen: boolean) { setProgressStart(isOpen: boolean) {

View File

@ -198,7 +198,6 @@ export class Menu extends Ion {
private _isSwipeEnabled: boolean = true; private _isSwipeEnabled: boolean = true;
private _isPers: boolean = false; private _isPers: boolean = false;
private _init: boolean = false; private _init: boolean = false;
private _prevEnabled: boolean;
/** /**
* @private * @private
@ -414,7 +413,7 @@ export class Menu extends Ion {
/** /**
* @private * @private
*/ */
setOpen(shouldOpen: boolean): Promise<boolean> { setOpen(shouldOpen: boolean, animated: boolean = true): Promise<boolean> {
// _isPrevented is used to prevent unwanted opening/closing after swiping open/close // _isPrevented is used to prevent unwanted opening/closing after swiping open/close
// or swiping open the menu while pressing down on the MenuToggle button // or swiping open the menu while pressing down on the MenuToggle button
if ((shouldOpen && this.isOpen) || this._isPrevented()) { if ((shouldOpen && this.isOpen) || this._isPrevented()) {
@ -424,7 +423,7 @@ export class Menu extends Ion {
this._before(); this._before();
return new Promise(resolve => { return new Promise(resolve => {
this._getType().setOpen(shouldOpen, () => { this._getType().setOpen(shouldOpen, animated, () => {
this._after(shouldOpen); this._after(shouldOpen);
resolve(this.isOpen); resolve(this.isOpen);
}); });
@ -515,21 +514,6 @@ export class Menu extends Ion {
} }
} }
/**
* @private
*/
tempDisable(temporarilyDisable: boolean) {
if (temporarilyDisable) {
this._prevEnabled = this._isEnabled;
this._getType().setProgessStep(0);
this.enable(false);
} else {
this.enable(this._prevEnabled);
this._after(false);
}
}
private _prevent() { private _prevent() {
// used to prevent unwanted opening/closing after swiping open/close // used to prevent unwanted opening/closing after swiping open/close
// or swiping open the menu while pressing down on the MenuToggle // or swiping open the menu while pressing down on the MenuToggle
@ -613,6 +597,13 @@ export class Menu extends Ion {
return this.backdrop.getNativeElement(); return this.backdrop.getNativeElement();
} }
/**
* @private
*/
getMenuController(): MenuController {
return this._menuCtrl;
}
/** /**
* @private * @private
*/ */

View File

@ -67,6 +67,14 @@ class E2EPage {
}); });
} }
openRightMenu() {
this.menu.open('right');
}
openLeftMenu() {
this.menu.open('left');
}
onDrag(ev: any) { onDrag(ev: any) {
console.log('Menu is being dragged', ev); console.log('Menu is being dragged', ev);
} }

View File

@ -14,6 +14,10 @@
{{p.title}} {{p.title}}
</button> </button>
<button ion-item (click)="openRightMenu()">
Open Right Menu
</button>
<button ion-item menuClose="left" class="e2eCloseLeftMenu" detail-none> <button ion-item menuClose="left" class="e2eCloseLeftMenu" detail-none>
Close Menu Close Menu
</button> </button>
@ -90,6 +94,10 @@
{{p.title}} {{p.title}}
</button> </button>
<button ion-item (click)="openLeftMenu()">
Open Left Menu
</button>
<button ion-item menuClose="right" class="e2eCloseRightMenu" detail-none> <button ion-item menuClose="right" class="e2eCloseRightMenu" detail-none>
Close Menu Close Menu
</button> </button>

View File

@ -6,7 +6,7 @@ import { ActionSheetController, App, Config, ionicBootstrap, ModalController, Na
@Injectable() @Injectable()
class SomeComponentProvider { class SomeComponentProvider {
constructor(private config: Config) { constructor(private config: Config) {
console.log('SomeComponentProvider constructor') console.log('SomeComponentProvider constructor');
} }
getName() { getName() {
@ -17,7 +17,7 @@ class SomeComponentProvider {
@Injectable() @Injectable()
class SomeAppProvider { class SomeAppProvider {
constructor(private config: Config) { constructor(private config: Config) {
console.log('SomeAppProvider constructor') console.log('SomeAppProvider constructor');
} }
getData() { getData() {
@ -84,7 +84,7 @@ class E2EPage {
} }
presentModalWithInputs() { presentModalWithInputs() {
let modal = this.modalCtrl.create(ModalWithInputs); let modal = this.modalCtrl.create(ModalWithInputs);
modal.onDidDismiss((data: any) => { modal.onDidDismiss((data: any) => {
console.log('Modal with inputs data:', data); console.log('Modal with inputs data:', data);
}); });
@ -98,7 +98,7 @@ class E2EPage {
}); });
} }
presentNavigableModal(){ presentNavigableModal() {
this.modalCtrl.create(NavigableModal).present(); this.modalCtrl.create(NavigableModal).present();
} }
} }
@ -139,10 +139,10 @@ class NavigableModal {
` `
}) })
class NavigableModal2 { class NavigableModal2 {
constructor(private navController:NavController) { constructor(private navController: NavController) {
} }
submit(){ submit() {
this.navController.pop(); this.navController.pop();
} }
} }
@ -188,23 +188,23 @@ class ModalPassData {
this.viewCtrl.dismiss(this.data); this.viewCtrl.dismiss(this.data);
} }
ionViewLoaded(){ ionViewLoaded() {
console.log('ModalPassData ionViewLoaded fired'); console.log('ModalPassData ionViewLoaded fired');
} }
ionViewWillEnter(){ ionViewWillEnter() {
console.log('ModalPassData ionViewWillEnter fired'); console.log('ModalPassData ionViewWillEnter fired');
} }
ionViewDidEnter(){ ionViewDidEnter() {
console.log('ModalPassData ionViewDidEnter fired'); console.log('ModalPassData ionViewDidEnter fired');
} }
ionViewWillLeave(){ ionViewWillLeave() {
console.log('ModalPassData ionViewWillLeave fired'); console.log('ModalPassData ionViewWillLeave fired');
} }
ionViewDidLeave(){ ionViewDidLeave() {
console.log('ModalPassData ionViewDidLeave fired'); console.log('ModalPassData ionViewDidLeave fired');
} }
} }
@ -375,10 +375,10 @@ class ContactUs {
}) })
class ModalFirstPage { class ModalFirstPage {
private items:any[]; private items: any[];
constructor(private nav: NavController, private app: App, private actionSheetCtrl: ActionSheetController) { constructor(private nav: NavController, private app: App, private actionSheetCtrl: ActionSheetController) {
this.items = []; this.items = [];
for ( let i = 0; i < 50; i++ ){ for ( let i = 0; i < 50; i++ ) {
this.items.push({ this.items.push({
value: (i + 1) value: (i + 1)
}); });
@ -387,7 +387,7 @@ class ModalFirstPage {
push() { push() {
let page = ModalSecondPage; let page = ModalSecondPage;
let params = { id: 8675309, myData: [1,2,3,4] }; let params = { id: 8675309, myData: [1, 2, 3, 4] };
this.nav.push(page, params); this.nav.push(page, params);
} }
@ -396,15 +396,15 @@ class ModalFirstPage {
this.app.getRootNav().pop(); this.app.getRootNav().pop();
} }
ionViewLoaded(){ ionViewLoaded() {
console.log('ModalFirstPage ionViewLoaded fired'); console.log('ModalFirstPage ionViewLoaded fired');
} }
ionViewWillEnter(){ ionViewWillEnter() {
console.log('ModalFirstPage ionViewWillEnter fired'); console.log('ModalFirstPage ionViewWillEnter fired');
} }
ionViewDidEnter(){ ionViewDidEnter() {
console.log('ModalFirstPage ionViewDidEnter fired'); console.log('ModalFirstPage ionViewDidEnter fired');
} }
@ -477,15 +477,15 @@ class ModalSecondPage {
console.log('Second page params:', params); console.log('Second page params:', params);
} }
ionViewLoaded(){ ionViewLoaded() {
console.log('ModalSecondPage ionViewLoaded'); console.log('ModalSecondPage ionViewLoaded');
} }
ionViewWillEnter(){ ionViewWillEnter() {
console.log('ModalSecondPage ionViewWillEnter'); console.log('ModalSecondPage ionViewWillEnter');
} }
ionViewDidEnter(){ ionViewDidEnter() {
console.log('ModalSecondPage ionViewDidEnter'); console.log('ModalSecondPage ionViewDidEnter');
} }
} }