fix(gestures): gesture controller handled by components

* fix(gestures): gesture controller is handled by components

fixes #9046

* fix(gestures): adds hybrid disable scroll assistance

fixes #9130
fixes #9052
fixes #7444
This commit is contained in:
Manu Mtz.-Almeida
2016-11-16 17:03:51 +01:00
committed by Adam Bradley
parent 339857af1e
commit 32ab817181
26 changed files with 534 additions and 272 deletions

View File

@ -5,7 +5,8 @@ import { Form } from '../../util/form';
import { Key } from '../../util/key';
import { NavParams } from '../../navigation/nav-params';
import { ViewController } from '../../navigation/view-controller';
import { BlockerDelegate, GestureController, BLOCK_ALL } from '../../gestures/gesture-controller';
import { assert } from '../../util/util';
/**
* @private
@ -53,15 +54,18 @@ export class ActionSheetCmp {
hdrId: string;
id: number;
mode: string;
gestureBlocker: BlockerDelegate;
constructor(
private _viewCtrl: ViewController,
private _config: Config,
private _elementRef: ElementRef,
private _form: Form,
gestureCtrl: GestureController,
params: NavParams,
renderer: Renderer
) {
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
this.d = params.data;
this.mode = _config.get('mode');
renderer.setElementClass(_elementRef.nativeElement, `action-sheet-${this.mode}`, true);
@ -110,6 +114,14 @@ export class ActionSheetCmp {
this.d.buttons = buttons;
}
ionViewWillEnter() {
this.gestureBlocker.block();
}
ionViewDidLeave() {
this.gestureBlocker.unblock();
}
ionViewDidEnter() {
this._form.focusOut();
@ -166,6 +178,11 @@ export class ActionSheetCmp {
dismiss(role: any): Promise<any> {
return this._viewCtrl.dismiss(null, role);
}
ngOnDestroy() {
assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
this.gestureBlocker.destroy();
}
}
let actionSheetIds = -1;

View File

@ -1,11 +1,11 @@
import { Component, ElementRef, HostListener, Renderer, ViewEncapsulation } from '@angular/core';
import { Config } from '../../config/config';
import { isPresent } from '../../util/util';
import { isPresent, assert } from '../../util/util';
import { Key } from '../../util/key';
import { NavParams } from '../../navigation/nav-params';
import { ViewController } from '../../navigation/view-controller';
import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/gesture-controller';
/**
* @private
@ -86,14 +86,18 @@ export class AlertCmp {
msgId: string;
subHdrId: string;
mode: string;
gestureBlocker: BlockerDelegate;
constructor(
public _viewCtrl: ViewController,
public _elementRef: ElementRef,
public _config: Config,
gestureCtrl: GestureController,
params: NavParams,
renderer: Renderer
) {
// gesture blocker is used to disable gestures dynamically
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
this.d = params.data;
this.mode = _config.get('mode');
renderer.setElementClass(_elementRef.nativeElement, `alert-${this.mode}`, true);
@ -172,6 +176,27 @@ export class AlertCmp {
}
}
ionViewWillEnter() {
this.gestureBlocker.block();
}
ionViewDidLeave() {
this.gestureBlocker.unblock();
}
ionViewDidEnter() {
let activeElement: any = document.activeElement;
if (document.activeElement) {
activeElement.blur();
}
let focusableEle = this._elementRef.nativeElement.querySelector('input,button');
if (focusableEle) {
focusableEle.focus();
}
this.enabled = true;
}
@HostListener('body:keyup', ['$event'])
keyUp(ev: KeyboardEvent) {
if (this.enabled && this._viewCtrl.isLast()) {
@ -193,19 +218,6 @@ export class AlertCmp {
}
}
ionViewDidEnter() {
let activeElement: any = document.activeElement;
if (document.activeElement) {
activeElement.blur();
}
let focusableEle = this._elementRef.nativeElement.querySelector('input,button');
if (focusableEle) {
focusableEle.focus();
}
this.enabled = true;
}
btnClick(button: any, dismissDelay?: number) {
if (!this.enabled) {
return;
@ -293,6 +305,11 @@ export class AlertCmp {
});
return values;
}
ngOnDestroy() {
assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
this.gestureBlocker.destroy();
}
}
let alertIds = -1;

View File

@ -5,6 +5,7 @@ import { Config } from '../../config/config';
import { Ion } from '../ion';
import { OverlayPortal } from '../nav/overlay-portal';
import { Platform } from '../../platform/platform';
import { nativeTimeout } from '../../util/dom';
export const AppRootToken = new OpaqueToken('USERROOT');
@ -23,6 +24,8 @@ export const AppRootToken = new OpaqueToken('USERROOT');
})
export class IonicApp extends Ion implements OnInit {
private _stopScrollPlugin: any;
private _rafId: number;
@ViewChild('viewport', {read: ViewContainerRef}) _viewport: ViewContainerRef;
@ViewChild('modalPortal', { read: OverlayPortal }) _modalPortal: OverlayPortal;
@ -45,6 +48,7 @@ export class IonicApp extends Ion implements OnInit {
super(config, elementRef, renderer);
// register with App that this is Ionic's appRoot component. tada!
app._appRoot = this;
this._stopScrollPlugin = window['IonicStopScroll'];
}
ngOnInit() {
@ -109,7 +113,26 @@ export class IonicApp extends Ion implements OnInit {
* @private
*/
_disableScroll(shouldDisableScroll: boolean) {
this.setElementClass('disable-scroll', shouldDisableScroll);
console.log('App Root: Scroll Disable Assist', shouldDisableScroll);
if (shouldDisableScroll) {
this.stopScroll().then(() => {
this._rafId = nativeTimeout(() => this.setElementClass('disable-scroll', true), 16 * 2);
});
} else {
cancelAnimationFrame(this._rafId);
this.setElementClass('disable-scroll', false);
}
}
stopScroll(): Promise<boolean> {
if (this._stopScrollPlugin) {
return new Promise((resolve, reject) => {
this._stopScrollPlugin.stop(() => resolve(true));
});
} else {
return Promise.resolve(false);
}
}
}

View File

@ -22,7 +22,7 @@ export class App {
private _title: string = '';
private _titleSrv: Title = new Title();
private _rootNav: NavController = null;
private _canDisableScroll: boolean;
private _disableScrollAssist: boolean;
/**
* @private
@ -71,7 +71,7 @@ export class App {
// listen for hardware back button events
// register this back button action with a default priority
_platform.registerBackButtonAction(this.navPop.bind(this));
this._canDisableScroll = _config.get('canDisableScroll', false);
this._disableScrollAssist = _config.getBoolean('disableScrollAssist', false);
}
/**
@ -124,7 +124,7 @@ export class App {
* scrolling is enabled. When set to `true`, scrolling is disabled.
*/
setScrollDisabled(disableScroll: boolean) {
if (this._canDisableScroll) {
if (this._disableScrollAssist) {
this._appRoot._disableScroll(disableScroll);
}
}

View File

@ -19,7 +19,3 @@ ion-backdrop {
opacity: .01;
transform: translateZ(0);
}
ion-backdrop.hide-backdrop {
display: none;
}

View File

@ -1,8 +1,4 @@
import { Directive, ElementRef, Input, Renderer } from '@angular/core';
import { GestureController } from '../../gestures/gesture-controller';
import { isTrueProperty } from '../../util/util';
import { Directive, ElementRef, Renderer } from '@angular/core';
/**
* @private
@ -16,26 +12,11 @@ import { isTrueProperty } from '../../util/util';
},
})
export class Backdrop {
private _gestureID: number = null;
@Input() disableScroll = true;
constructor(
private _gestureCtrl: GestureController,
private _elementRef: ElementRef,
private _renderer: Renderer) { }
ngOnInit() {
if (isTrueProperty(this.disableScroll)) {
this._gestureID = this._gestureCtrl.newID();
this._gestureCtrl.disableScroll(this._gestureID);
}
}
ngOnDestroy() {
if (this._gestureID) {
this._gestureCtrl.enableScroll(this._gestureID);
}
}
private _renderer: Renderer
) { }
getNativeElement(): HTMLElement {
return this._elementRef.nativeElement;

View File

@ -51,7 +51,7 @@ ion-content.js-scroll > .scroll-content {
will-change: initial;
}
.disable-scroll .ion-page .scroll-content {
.disable-scroll .ion-page {
pointer-events: none;
}

View File

@ -1,14 +1,14 @@
import { ItemSliding } from './item-sliding';
import { List } from '../list/list';
import { GesturePriority } from '../../gestures/gesture-controller';
import { GestureController, GesturePriority, GESTURE_ITEM_SWIPE } from '../../gestures/gesture-controller';
import { PanGesture } from '../../gestures/drag-gesture';
import { pointerCoord } from '../../util/dom';
import { NativeRafDebouncer } from '../../util/debouncer';
const DRAG_THRESHOLD = 10;
const MAX_ATTACK_ANGLE = 20;
/**
* @private
*/
export class ItemSlidingGesture extends PanGesture {
private preSelectedContainer: ItemSliding = null;
@ -17,14 +17,16 @@ export class ItemSlidingGesture extends PanGesture {
private firstCoordX: number;
private firstTimestamp: number;
constructor(public list: List) {
constructor(public list: List, gestureCtrl: GestureController) {
super(list.getNativeElement(), {
maxAngle: MAX_ATTACK_ANGLE,
threshold: DRAG_THRESHOLD,
maxAngle: 20,
threshold: 10,
zone: false,
debouncer: new NativeRafDebouncer(),
gesture: list._gestureCtrl.create('item-sliding', {
gesture: gestureCtrl.createGesture({
name: GESTURE_ITEM_SWIPE,
priority: GesturePriority.SlidingItem,
disableScroll: false // TODO: set true
})
});
}

View File

@ -95,7 +95,7 @@ export class List extends Ion {
} else if (!this._slidingGesture) {
console.debug('enableSlidingItems');
this._slidingGesture = new ItemSlidingGesture(this);
this._slidingGesture = new ItemSlidingGesture(this, this._gestureCtrl);
this._slidingGesture.listen();
}
}

View File

@ -1,10 +1,11 @@
import { Component, ElementRef, Renderer, ViewEncapsulation } from '@angular/core';
import { Config } from '../../config/config';
import { isDefined, isUndefined } from '../../util/util';
import { isDefined, isUndefined, assert } from '../../util/util';
import { NavParams } from '../../navigation/nav-params';
import { ViewController } from '../../navigation/view-controller';
import { LoadingOptions } from './loading-options';
import { BlockerDelegate, GestureController, BLOCK_ALL } from '../../gestures/gesture-controller';
/**
* @private
@ -12,7 +13,7 @@ import { LoadingOptions } from './loading-options';
@Component({
selector: 'ion-loading',
template:
'<ion-backdrop [class.hide-backdrop]="!d.showBackdrop"></ion-backdrop>' +
'<ion-backdrop [hidden]="!d.showBackdrop"></ion-backdrop>' +
'<div class="loading-wrapper">' +
'<div *ngIf="showSpinner" class="loading-spinner">' +
'<ion-spinner [name]="d.spinner"></ion-spinner>' +
@ -29,14 +30,17 @@ export class LoadingCmp {
id: number;
showSpinner: boolean;
durationTimeout: number;
gestureBlocker: BlockerDelegate;
constructor(
private _viewCtrl: ViewController,
private _config: Config,
private _elementRef: ElementRef,
gestureCtrl: GestureController,
params: NavParams,
renderer: Renderer
) {
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
this.d = params.data;
renderer.setElementClass(_elementRef.nativeElement, `loading-${_config.get('mode')}`, true);
@ -62,17 +66,21 @@ export class LoadingCmp {
this.showSpinner = isDefined(this.d.spinner) && this.d.spinner !== 'hide';
}
ionViewWillEnter() {
this.gestureBlocker.block();
}
ionViewDidLeave() {
this.gestureBlocker.unblock();
}
ionViewDidEnter() {
let activeElement: any = document.activeElement;
if (document.activeElement) {
activeElement.blur();
}
activeElement && activeElement.blur();
// If there is a duration, dismiss after that amount of time
if ( this.d && this.d.duration ) {
this.durationTimeout = (<any> setTimeout( () => {
this.dismiss('backdrop');
}, this.d.duration));
this.durationTimeout = setTimeout(() => this.dismiss('backdrop'), this.d.duration);
}
}
@ -83,6 +91,11 @@ export class LoadingCmp {
}
return this._viewCtrl.dismiss(null, role);
}
ngOnDestroy() {
assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
this.gestureBlocker.destroy();
}
}
let loadingIds = -1;

View File

@ -2,7 +2,7 @@ import { Menu } from './menu';
import { SlideEdgeGesture } from '../../gestures/slide-edge-gesture';
import { SlideData } from '../../gestures/slide-gesture';
import { assign } from '../../util/util';
import { GestureController, GesturePriority } from '../../gestures/gesture-controller';
import { GestureController, GesturePriority, GESTURE_MENU_SWIPE } from '../../gestures/gesture-controller';
import { NativeRafDebouncer } from '../../util/debouncer';
/**
@ -14,17 +14,19 @@ export class MenuContentGesture extends SlideEdgeGesture {
public menu: Menu,
contentEle: HTMLElement,
gestureCtrl: GestureController,
options: any = {}) {
options: any = {}
) {
super(contentEle, assign({
direction: 'x',
edge: menu.side,
threshold: 0,
maxEdgeStart: menu.maxEdgeStart || 50,
maxAngle: 40,
zone: false,
debouncer: new NativeRafDebouncer(),
gesture: gestureCtrl.create('menu-swipe', {
gesture: gestureCtrl.createGesture({
name: GESTURE_MENU_SWIPE,
priority: GesturePriority.MenuSwipe,
disableScroll: true
})
}, options));
}
@ -52,13 +54,6 @@ export class MenuContentGesture extends SlideEdgeGesture {
let z = (this.menu.side === 'right' ? slide.min : slide.max);
let stepValue = (slide.distance / z);
console.debug('menu gesture, onSlide', this.menu.side,
'distance', slide.distance,
'min', slide.min,
'max', slide.max,
'z', z,
'stepValue', stepValue);
this.menu.swipeProgress(stepValue);
}

View File

@ -8,7 +8,7 @@ import { MenuContentGesture } from './menu-gestures';
import { MenuController } from './menu-controller';
import { MenuType } from './menu-types';
import { Platform } from '../../platform/platform';
import { GestureController } from '../../gestures/gesture-controller';
import { BlockerDelegate, GestureController, GESTURE_GO_BACK_SWIPE } from '../../gestures/gesture-controller';
import { UIEventManager } from '../../util/ui-event-manager';
import { Content } from '../content/content';
@ -181,7 +181,7 @@ import { Content } from '../content/content';
selector: 'ion-menu',
template:
'<div class="menu-inner"><ng-content></ng-content></div>' +
'<ion-backdrop disableScroll="false"></ion-backdrop>',
'<ion-backdrop></ion-backdrop>',
host: {
'role': 'navigation'
},
@ -198,7 +198,7 @@ export class Menu {
private _isPers: boolean = false;
private _init: boolean = false;
private _events: UIEventManager = new UIEventManager();
private _gestureID: number = 0;
private _gestureBlocker: BlockerDelegate;
/**
* @private
@ -305,9 +305,9 @@ export class Menu {
private _zone: NgZone,
private _gestureCtrl: GestureController
) {
if (_gestureCtrl) {
this._gestureID = _gestureCtrl.newID();
}
this._gestureBlocker = _gestureCtrl.createBlocker({
disable: [GESTURE_GO_BACK_SWIPE]
});
}
/**
@ -503,7 +503,7 @@ export class Menu {
this._events.unlistenAll();
if (isOpen) {
// Disable swipe to go back gesture
this._gestureCtrl.disableGesture('goback-swipe', this._gestureID);
this._gestureBlocker.block();
this._cntEle.classList.add('menu-content-open');
let callback = this.onBackdropClick.bind(this);
@ -519,7 +519,7 @@ export class Menu {
} else {
// Enable swipe to go back gesture
this._gestureCtrl.enableGesture('goback-swipe', this._gestureID);
this._gestureBlocker.unblock();
this._cntEle.classList.remove('menu-content-open');
this.setElementClass('show-menu', false);

View File

@ -1,12 +1,16 @@
import { Component, ViewChild, NgModule } from '@angular/core';
import { IonicApp, IonicModule, MenuController, NavController, AlertController, Nav } from '../../../..';
import { AlertController, IonicApp, IonicModule, MenuController, ModalController, NavController, Nav, ViewController } from '../../../..';
@Component({
templateUrl: 'page1.html'
})
export class Page1 {
constructor(public navCtrl: NavController, public alertCtrl: AlertController) {}
constructor(
public navCtrl: NavController,
public alertCtrl: AlertController,
public modalCtrl: ModalController
) { }
presentAlert() {
let alert = this.alertCtrl.create({
@ -18,11 +22,24 @@ export class Page1 {
alert.present();
}
presentModal() {
let modal = this.modalCtrl.create(Modal);
modal.present();
}
goToPage2() {
this.navCtrl.push(Page2);
}
}
@Component({templateUrl: 'modal.html'})
export class Modal {
constructor(public viewController: ViewController) {}
close() {
this.viewController.dismiss();
}
}
@Component({templateUrl: 'page3.html'})
export class Page3 {}
@ -106,7 +123,8 @@ export class E2EApp {
E2EPage,
Page1,
Page2,
Page3
Page3,
Modal
],
imports: [
IonicModule.forRoot(E2EApp)
@ -117,7 +135,8 @@ export class E2EApp {
E2EPage,
Page1,
Page2,
Page3
Page3,
Modal
]
})
export class AppModule {}

View File

@ -0,0 +1,20 @@
<ion-header>
<ion-navbar>
<ion-title>
MODAL
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>
<button ion-button (click)="close()">Close</button>
</p>
<div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div><div f></div>
</ion-content>

View File

@ -64,6 +64,10 @@
<button ion-button (click)="presentAlert()">Open alert</button>
</p>
<p>
<button ion-button (click)="presentModal()">Open modal</button>
</p>
<p>
<button ion-button (click)="goToPage2()">Go to Page 2</button>
</p>

View File

@ -3,7 +3,8 @@ import { Component, ComponentFactoryResolver, HostListener, Renderer, ViewChild,
import { Key } from '../../util/key';
import { NavParams } from '../../navigation/nav-params';
import { ViewController } from '../../navigation/view-controller';
import { GestureController, BlockerDelegate, GESTURE_MENU_SWIPE, GESTURE_GO_BACK_SWIPE } from '../../gestures/gesture-controller';
import { assert } from '../../util/util';
/**
* @private
@ -11,7 +12,7 @@ import { ViewController } from '../../navigation/view-controller';
@Component({
selector: 'ion-modal',
template:
'<ion-backdrop disableScroll="false" (click)="_bdClick()"></ion-backdrop>' +
'<ion-backdrop (click)="_bdClick()"></ion-backdrop>' +
'<div class="modal-wrapper">' +
'<div #viewport nav-viewport></div>' +
'</div>'
@ -20,13 +21,20 @@ export class ModalCmp {
@ViewChild('viewport', { read: ViewContainerRef }) _viewport: ViewContainerRef;
/** @private */
_bdDismiss: boolean;
/** @private */
_enabled: boolean;
_gestureBlocker: BlockerDelegate;
constructor(public _cfr: ComponentFactoryResolver, public _renderer: Renderer, public _navParams: NavParams, public _viewCtrl: ViewController) {
constructor(
public _cfr: ComponentFactoryResolver,
public _renderer: Renderer,
public _navParams: NavParams,
public _viewCtrl: ViewController,
gestureCtrl: GestureController
) {
this._gestureBlocker = gestureCtrl.createBlocker({
disable: [GESTURE_MENU_SWIPE, GESTURE_GO_BACK_SWIPE]
});
this._bdDismiss = _navParams.data.opts.enableBackdropDismiss;
}
@ -46,9 +54,20 @@ export class ModalCmp {
this._setCssClass(componentRef, 'ion-page');
this._setCssClass(componentRef, 'show-page');
this._enabled = true;
this._viewCtrl.willEnter.subscribe(this._viewWillEnter.bind(this));
this._viewCtrl.didLeave.subscribe(this._viewDidLeave.bind(this));
}
}
_viewWillEnter() {
this._gestureBlocker.block();
}
_viewDidLeave() {
this._gestureBlocker.unblock();
}
/** @private */
_setCssClass(componentRef: any, className: string) {
this._renderer.setElementClass(componentRef.location.nativeElement, className, true);
@ -66,4 +85,9 @@ export class ModalCmp {
this._bdClick();
}
}
ngOnDestroy() {
assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
this._gestureBlocker.destroy();
}
}

View File

@ -834,7 +834,9 @@ export const deepLinkConfig: DeepLinkConfig = {
TabItemPage
],
imports: [
IonicModule.forRoot(E2EApp, null, deepLinkConfig)
IonicModule.forRoot(E2EApp, {
swipeBackEnabled: true
}, deepLinkConfig)
],
bootstrap: [IonicApp],
entryComponents: [

View File

@ -2,7 +2,7 @@ import { Component, ElementRef, EventEmitter, Input, HostListener, NgZone, Outpu
import { DomSanitizer } from '@angular/platform-browser';
import { CSS, cancelRaf, pointerCoord, nativeRaf } from '../../util/dom';
import { clamp, isNumber, isPresent, isString } from '../../util/util';
import { clamp, isNumber, isPresent, isString, assert } from '../../util/util';
import { Config } from '../../config/config';
import { Key } from '../../util/key';
import { NavParams } from '../../navigation/nav-params';
@ -12,6 +12,7 @@ import { Haptic } from '../../util/haptic';
import { UIEventManager } from '../../util/ui-event-manager';
import { ViewController } from '../../navigation/view-controller';
import { Debouncer, NativeRafDebouncer } from '../../util/debouncer';
import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/gesture-controller';
/**
* @private
@ -454,14 +455,17 @@ export class PickerCmp {
lastClick: number;
id: number;
mode: string;
_gestureBlocker: BlockerDelegate;
constructor(
private _viewCtrl: ViewController,
private _elementRef: ElementRef,
private _config: Config,
gestureCtrl: GestureController,
params: NavParams,
renderer: Renderer
) {
this._gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
this.d = params.data;
this.mode = _config.get('mode');
renderer.setElementClass(_elementRef.nativeElement, `picker-${this.mode}`, true);
@ -523,6 +527,14 @@ export class PickerCmp {
});
}
ionViewWillEnter() {
this._gestureBlocker.block();
}
ionViewDidLeave() {
this._gestureBlocker.unblock();
}
refresh() {
this._cols.forEach(column => {
column.refresh();
@ -617,6 +629,12 @@ export class PickerCmp {
});
return selected;
}
ngOnDestroy() {
assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
this._gestureBlocker.destroy();
}
}
let pickerIds = -1;

View File

@ -4,7 +4,8 @@ import { Config } from '../../config/config';
import { Key } from '../../util/key';
import { NavParams } from '../../navigation/nav-params';
import { ViewController } from '../../navigation/view-controller';
import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/gesture-controller';
import { assert } from '../../util/util';
/**
* @private
@ -12,7 +13,7 @@ import { ViewController } from '../../navigation/view-controller';
@Component({
selector: 'ion-popover',
template:
'<ion-backdrop (click)="_bdClick()" [class.hide-backdrop]="!d.showBackdrop"></ion-backdrop>' +
'<ion-backdrop (click)="_bdClick()" [hidden]="!d.showBackdrop"></ion-backdrop>' +
'<div class="popover-wrapper">' +
'<div class="popover-arrow"></div>' +
'<div class="popover-content">' +
@ -32,10 +33,9 @@ export class PopoverCmp {
enableBackdropDismiss?: boolean;
};
/** @private */
_enabled: boolean;
_gestureBlocker: BlockerDelegate;
/** @private */
id: number;
constructor(
@ -44,8 +44,10 @@ export class PopoverCmp {
public _renderer: Renderer,
public _config: Config,
public _navParams: NavParams,
public _viewCtrl: ViewController
public _viewCtrl: ViewController,
gestureCtrl: GestureController,
) {
this._gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
this.d = _navParams.data.opts;
_renderer.setElementClass(_elementRef.nativeElement, `popover-${_config.get('mode')}`, true);
@ -62,13 +64,11 @@ export class PopoverCmp {
ionViewPreLoad() {
let activeElement: any = document.activeElement;
if (document.activeElement) {
activeElement.blur();
}
activeElement && activeElement.blur();
this._load(this._navParams.data.component);
}
/** @private */
_load(component: any) {
if (component) {
const componentFactory = this._cfr.resolveComponentFactory(component);
@ -76,12 +76,23 @@ export class PopoverCmp {
// ******** DOM WRITE ****************
const componentRef = this._viewport.createComponent(componentFactory, this._viewport.length, this._viewport.parentInjector, []);
this._viewCtrl._setInstance(componentRef.instance);
this._enabled = true;
// Subscribe to events in order to block gestures
// TODO, should we unsubscribe? memory leak?
this._viewCtrl.willEnter.subscribe(this._viewWillEnter.bind(this));
this._viewCtrl.didLeave.subscribe(this._viewDidLeave.bind(this));
}
}
/** @private */
_viewWillEnter() {
this._gestureBlocker.block();
}
_viewDidLeave() {
this._gestureBlocker.unblock();
}
_setCssClass(componentRef: any, className: string) {
this._renderer.setElementClass(componentRef.location.nativeElement, className, true);
}
@ -98,6 +109,11 @@ export class PopoverCmp {
this._bdClick();
}
}
ngOnDestroy() {
assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
this._gestureBlocker.destroy();
}
}
let popoverIds = -1;

View File

@ -2,7 +2,7 @@ import { Directive, EventEmitter, Host, Input, Output, NgZone } from '@angular/c
import { Content } from '../content/content';
import { CSS, pointerCoord } from '../../util/dom';
import { GestureController, GestureDelegate, GesturePriority } from '../../gestures/gesture-controller';
import { GestureController, GestureDelegate, GesturePriority, GESTURE_REFRESHER } from '../../gestures/gesture-controller';
import { isTrueProperty } from '../../util/util';
import { PointerEvents, UIEventManager } from '../../util/ui-event-manager';
@ -200,7 +200,8 @@ export class Refresher {
constructor(@Host() private _content: Content, private _zone: NgZone, gestureCtrl: GestureController) {
_content.setElementClass('has-refresher', true);
this._gesture = gestureCtrl.create('refresher', {
this._gesture = gestureCtrl.createGesture({
name: GESTURE_REFRESHER,
priority: GesturePriority.Refresher,
});
}

View File

@ -53,10 +53,10 @@
.back-button {
display: none;
}
&.show-back-button {
display: inline-block;
}
.back-button.show-back-button {
display: inline-block;
}
.back-button-text {