From cac378f35b8462b6653ab56f94fa035fc7fcb122 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Mon, 18 Jul 2016 03:42:29 +0200 Subject: [PATCH] fix(menu): only one menu can be opened at a time fixes #6826 --- src/animations/animation.ts | 9 ++--- src/components/app/test/animations/index.ts | 4 +-- src/components/menu/menu-controller.ts | 28 ++++++++++----- src/components/menu/menu-gestures.ts | 14 +++++--- src/components/menu/menu-types.ts | 14 +++++--- src/components/menu/menu.ts | 27 +++++--------- src/components/menu/test/basic/index.ts | 8 +++++ src/components/menu/test/basic/main.html | 8 +++++ src/components/modal/test/basic/index.ts | 40 ++++++++++----------- 9 files changed, 90 insertions(+), 62 deletions(-) diff --git a/src/animations/animation.ts b/src/animations/animation.ts index 85d8faa42b1..c4cb6a0ea6d 100644 --- a/src/animations/animation.ts +++ b/src/animations/animation.ts @@ -289,11 +289,12 @@ export class Animation { var self = this; var i: number; + let dur = this._dur; 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 // 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 self._clearAsync(); - if (self._dur > 30) { + if (dur > 30) { // this animation has a duration, so it should animate // place all the elements with their FROM properties @@ -328,7 +329,7 @@ export class Animation { // set the async TRANSITION END event // and run onFinishes when the transition ends // ******** DOM WRITE **************** - self._asyncEnd(self._dur, true); + self._asyncEnd(dur, true); // begin each animation when everything is rendered in their place // and the transition duration/easing is ready to go diff --git a/src/components/app/test/animations/index.ts b/src/components/app/test/animations/index.ts index 49f43d27165..abaacd6699b 100644 --- a/src/components/app/test/animations/index.ts +++ b/src/components/app/test/animations/index.ts @@ -6,8 +6,8 @@ import {ionicBootstrap, Config, Animation} from '../../../../../src'; templateUrl: 'main.html' }) class E2EPage { - duration; - easing; + duration: string; + easing: string; constructor(config: Config) { this.duration = '1000'; diff --git a/src/components/menu/menu-controller.ts b/src/components/menu/menu-controller.ts index bf0178fdcf3..6c796973efd 100644 --- a/src/components/menu/menu-controller.ts +++ b/src/components/menu/menu-controller.ts @@ -125,6 +125,10 @@ export class MenuController { open(menuId?: string): Promise { let menu = this.get(menuId); if (menu) { + let openedMenu = this.getOpen(); + if (openedMenu && menu !== openedMenu) { + openedMenu.setOpen(false, false); + } return menu.open(); } @@ -147,7 +151,7 @@ export class MenuController { } else { // find the menu that is open - menu = this._menus.find(m => m.isOpen); + menu = this.getOpen(); } if (menu) { @@ -158,11 +162,6 @@ export class MenuController { 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 @@ -173,6 +172,10 @@ export class MenuController { toggle(menuId?: string): Promise { let menu = this.get(menuId); if (menu) { + let openedMenu = this.getOpen(); + if (openedMenu && menu !== openedMenu) { + openedMenu.setOpen(false, false); + } return menu.toggle(); } 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` * 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`. + * @return {Menu} Returns the instance of the menu if found, otherwise `null`. */ get(menuId?: string): Menu { var menu: Menu; @@ -252,12 +255,21 @@ export class MenuController { // return the first enabled menu 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 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} Returns an array of all menu instances. diff --git a/src/components/menu/menu-gestures.ts b/src/components/menu/menu-gestures.ts index dc55a4f8ee7..b9b277c32a2 100644 --- a/src/components/menu/menu-gestures.ts +++ b/src/components/menu/menu-gestures.ts @@ -24,11 +24,15 @@ export class MenuContentGesture extends SlideEdgeGesture { canStart(ev: any): boolean { let menu = this.menu; - return ( - menu.enabled && - menu.swipeEnabled && - (menu.isOpen || super.canStart(ev)) - ); + if (!menu.enabled || !menu.swipeEnabled) { + return false; + } + 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 diff --git a/src/components/menu/menu-types.ts b/src/components/menu/menu-types.ts index 032d8f233be..f4ddb538916 100644 --- a/src/components/menu/menu-types.ts +++ b/src/components/menu/menu-types.ts @@ -15,11 +15,15 @@ export class MenuType { ani: Animation = new Animation(); isOpening: boolean; - setOpen(shouldOpen: boolean, done: Function) { - this.ani - .onFinish(done, true) - .reverse(!shouldOpen) - .play(); + setOpen(shouldOpen: boolean, animated: boolean, done: Function) { + let ani = this.ani + .onFinish(done, true) + .reverse(!shouldOpen); + if (animated) { + ani.play(); + } else { + ani.play({ duration: 0 }); + } } setProgressStart(isOpen: boolean) { diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts index 0f12205dfba..69214542d94 100644 --- a/src/components/menu/menu.ts +++ b/src/components/menu/menu.ts @@ -198,7 +198,6 @@ export class Menu extends Ion { private _isSwipeEnabled: boolean = true; private _isPers: boolean = false; private _init: boolean = false; - private _prevEnabled: boolean; /** * @private @@ -414,7 +413,7 @@ export class Menu extends Ion { /** * @private */ - setOpen(shouldOpen: boolean): Promise { + setOpen(shouldOpen: boolean, animated: boolean = true): Promise { // _isPrevented is used to prevent unwanted opening/closing after swiping open/close // or swiping open the menu while pressing down on the MenuToggle button if ((shouldOpen && this.isOpen) || this._isPrevented()) { @@ -424,7 +423,7 @@ export class Menu extends Ion { this._before(); return new Promise(resolve => { - this._getType().setOpen(shouldOpen, () => { + this._getType().setOpen(shouldOpen, animated, () => { this._after(shouldOpen); 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() { // used to prevent unwanted opening/closing after swiping open/close // or swiping open the menu while pressing down on the MenuToggle @@ -613,6 +597,13 @@ export class Menu extends Ion { return this.backdrop.getNativeElement(); } + /** + * @private + */ + getMenuController(): MenuController { + return this._menuCtrl; + } + /** * @private */ diff --git a/src/components/menu/test/basic/index.ts b/src/components/menu/test/basic/index.ts index f54f20fb581..43e823f4df2 100644 --- a/src/components/menu/test/basic/index.ts +++ b/src/components/menu/test/basic/index.ts @@ -67,6 +67,14 @@ class E2EPage { }); } + openRightMenu() { + this.menu.open('right'); + } + + openLeftMenu() { + this.menu.open('left'); + } + onDrag(ev: any) { console.log('Menu is being dragged', ev); } diff --git a/src/components/menu/test/basic/main.html b/src/components/menu/test/basic/main.html index e56fb8c3d07..aa07376973f 100644 --- a/src/components/menu/test/basic/main.html +++ b/src/components/menu/test/basic/main.html @@ -14,6 +14,10 @@ {{p.title}} + + @@ -90,6 +94,10 @@ {{p.title}} + + diff --git a/src/components/modal/test/basic/index.ts b/src/components/modal/test/basic/index.ts index 33752896da6..d14b32d0290 100644 --- a/src/components/modal/test/basic/index.ts +++ b/src/components/modal/test/basic/index.ts @@ -6,7 +6,7 @@ import { ActionSheetController, App, Config, ionicBootstrap, ModalController, Na @Injectable() class SomeComponentProvider { constructor(private config: Config) { - console.log('SomeComponentProvider constructor') + console.log('SomeComponentProvider constructor'); } getName() { @@ -17,7 +17,7 @@ class SomeComponentProvider { @Injectable() class SomeAppProvider { constructor(private config: Config) { - console.log('SomeAppProvider constructor') + console.log('SomeAppProvider constructor'); } getData() { @@ -84,7 +84,7 @@ class E2EPage { } presentModalWithInputs() { - let modal = this.modalCtrl.create(ModalWithInputs); + let modal = this.modalCtrl.create(ModalWithInputs); modal.onDidDismiss((data: any) => { console.log('Modal with inputs data:', data); }); @@ -98,7 +98,7 @@ class E2EPage { }); } - presentNavigableModal(){ + presentNavigableModal() { this.modalCtrl.create(NavigableModal).present(); } } @@ -139,10 +139,10 @@ class NavigableModal { ` }) class NavigableModal2 { - constructor(private navController:NavController) { + constructor(private navController: NavController) { } - submit(){ + submit() { this.navController.pop(); } } @@ -188,23 +188,23 @@ class ModalPassData { this.viewCtrl.dismiss(this.data); } - ionViewLoaded(){ + ionViewLoaded() { console.log('ModalPassData ionViewLoaded fired'); } - ionViewWillEnter(){ + ionViewWillEnter() { console.log('ModalPassData ionViewWillEnter fired'); } - ionViewDidEnter(){ + ionViewDidEnter() { console.log('ModalPassData ionViewDidEnter fired'); } - ionViewWillLeave(){ + ionViewWillLeave() { console.log('ModalPassData ionViewWillLeave fired'); } - ionViewDidLeave(){ + ionViewDidLeave() { console.log('ModalPassData ionViewDidLeave fired'); } } @@ -375,10 +375,10 @@ class ContactUs { }) class ModalFirstPage { - private items:any[]; + private items: any[]; constructor(private nav: NavController, private app: App, private actionSheetCtrl: ActionSheetController) { this.items = []; - for ( let i = 0; i < 50; i++ ){ + for ( let i = 0; i < 50; i++ ) { this.items.push({ value: (i + 1) }); @@ -387,7 +387,7 @@ class ModalFirstPage { push() { 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); } @@ -396,15 +396,15 @@ class ModalFirstPage { this.app.getRootNav().pop(); } - ionViewLoaded(){ + ionViewLoaded() { console.log('ModalFirstPage ionViewLoaded fired'); } - ionViewWillEnter(){ + ionViewWillEnter() { console.log('ModalFirstPage ionViewWillEnter fired'); } - ionViewDidEnter(){ + ionViewDidEnter() { console.log('ModalFirstPage ionViewDidEnter fired'); } @@ -477,15 +477,15 @@ class ModalSecondPage { console.log('Second page params:', params); } - ionViewLoaded(){ + ionViewLoaded() { console.log('ModalSecondPage ionViewLoaded'); } - ionViewWillEnter(){ + ionViewWillEnter() { console.log('ModalSecondPage ionViewWillEnter'); } - ionViewDidEnter(){ + ionViewDidEnter() { console.log('ModalSecondPage ionViewDidEnter'); } }