mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 04:53:58 +08:00
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:

committed by
Adam Bradley

parent
339857af1e
commit
32ab817181
@ -5,7 +5,8 @@ import { Form } from '../../util/form';
|
|||||||
import { Key } from '../../util/key';
|
import { Key } from '../../util/key';
|
||||||
import { NavParams } from '../../navigation/nav-params';
|
import { NavParams } from '../../navigation/nav-params';
|
||||||
import { ViewController } from '../../navigation/view-controller';
|
import { ViewController } from '../../navigation/view-controller';
|
||||||
|
import { BlockerDelegate, GestureController, BLOCK_ALL } from '../../gestures/gesture-controller';
|
||||||
|
import { assert } from '../../util/util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -53,15 +54,18 @@ export class ActionSheetCmp {
|
|||||||
hdrId: string;
|
hdrId: string;
|
||||||
id: number;
|
id: number;
|
||||||
mode: string;
|
mode: string;
|
||||||
|
gestureBlocker: BlockerDelegate;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _viewCtrl: ViewController,
|
private _viewCtrl: ViewController,
|
||||||
private _config: Config,
|
private _config: Config,
|
||||||
private _elementRef: ElementRef,
|
private _elementRef: ElementRef,
|
||||||
private _form: Form,
|
private _form: Form,
|
||||||
|
gestureCtrl: GestureController,
|
||||||
params: NavParams,
|
params: NavParams,
|
||||||
renderer: Renderer
|
renderer: Renderer
|
||||||
) {
|
) {
|
||||||
|
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
|
||||||
this.d = params.data;
|
this.d = params.data;
|
||||||
this.mode = _config.get('mode');
|
this.mode = _config.get('mode');
|
||||||
renderer.setElementClass(_elementRef.nativeElement, `action-sheet-${this.mode}`, true);
|
renderer.setElementClass(_elementRef.nativeElement, `action-sheet-${this.mode}`, true);
|
||||||
@ -110,6 +114,14 @@ export class ActionSheetCmp {
|
|||||||
this.d.buttons = buttons;
|
this.d.buttons = buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ionViewWillEnter() {
|
||||||
|
this.gestureBlocker.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
ionViewDidLeave() {
|
||||||
|
this.gestureBlocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
ionViewDidEnter() {
|
ionViewDidEnter() {
|
||||||
this._form.focusOut();
|
this._form.focusOut();
|
||||||
|
|
||||||
@ -166,6 +178,11 @@ export class ActionSheetCmp {
|
|||||||
dismiss(role: any): Promise<any> {
|
dismiss(role: any): Promise<any> {
|
||||||
return this._viewCtrl.dismiss(null, role);
|
return this._viewCtrl.dismiss(null, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
|
||||||
|
this.gestureBlocker.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let actionSheetIds = -1;
|
let actionSheetIds = -1;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Component, ElementRef, HostListener, Renderer, ViewEncapsulation } from '@angular/core';
|
import { Component, ElementRef, HostListener, Renderer, ViewEncapsulation } from '@angular/core';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
import { Config } from '../../config/config';
|
||||||
import { isPresent } from '../../util/util';
|
import { isPresent, assert } from '../../util/util';
|
||||||
import { Key } from '../../util/key';
|
import { Key } from '../../util/key';
|
||||||
import { NavParams } from '../../navigation/nav-params';
|
import { NavParams } from '../../navigation/nav-params';
|
||||||
import { ViewController } from '../../navigation/view-controller';
|
import { ViewController } from '../../navigation/view-controller';
|
||||||
|
import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/gesture-controller';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -86,14 +86,18 @@ export class AlertCmp {
|
|||||||
msgId: string;
|
msgId: string;
|
||||||
subHdrId: string;
|
subHdrId: string;
|
||||||
mode: string;
|
mode: string;
|
||||||
|
gestureBlocker: BlockerDelegate;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public _viewCtrl: ViewController,
|
public _viewCtrl: ViewController,
|
||||||
public _elementRef: ElementRef,
|
public _elementRef: ElementRef,
|
||||||
public _config: Config,
|
public _config: Config,
|
||||||
|
gestureCtrl: GestureController,
|
||||||
params: NavParams,
|
params: NavParams,
|
||||||
renderer: Renderer
|
renderer: Renderer
|
||||||
) {
|
) {
|
||||||
|
// gesture blocker is used to disable gestures dynamically
|
||||||
|
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
|
||||||
this.d = params.data;
|
this.d = params.data;
|
||||||
this.mode = _config.get('mode');
|
this.mode = _config.get('mode');
|
||||||
renderer.setElementClass(_elementRef.nativeElement, `alert-${this.mode}`, true);
|
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'])
|
@HostListener('body:keyup', ['$event'])
|
||||||
keyUp(ev: KeyboardEvent) {
|
keyUp(ev: KeyboardEvent) {
|
||||||
if (this.enabled && this._viewCtrl.isLast()) {
|
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) {
|
btnClick(button: any, dismissDelay?: number) {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return;
|
return;
|
||||||
@ -293,6 +305,11 @@ export class AlertCmp {
|
|||||||
});
|
});
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
|
||||||
|
this.gestureBlocker.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let alertIds = -1;
|
let alertIds = -1;
|
||||||
|
@ -5,6 +5,7 @@ import { Config } from '../../config/config';
|
|||||||
import { Ion } from '../ion';
|
import { Ion } from '../ion';
|
||||||
import { OverlayPortal } from '../nav/overlay-portal';
|
import { OverlayPortal } from '../nav/overlay-portal';
|
||||||
import { Platform } from '../../platform/platform';
|
import { Platform } from '../../platform/platform';
|
||||||
|
import { nativeTimeout } from '../../util/dom';
|
||||||
|
|
||||||
export const AppRootToken = new OpaqueToken('USERROOT');
|
export const AppRootToken = new OpaqueToken('USERROOT');
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ export const AppRootToken = new OpaqueToken('USERROOT');
|
|||||||
})
|
})
|
||||||
export class IonicApp extends Ion implements OnInit {
|
export class IonicApp extends Ion implements OnInit {
|
||||||
|
|
||||||
|
private _stopScrollPlugin: any;
|
||||||
|
private _rafId: number;
|
||||||
@ViewChild('viewport', {read: ViewContainerRef}) _viewport: ViewContainerRef;
|
@ViewChild('viewport', {read: ViewContainerRef}) _viewport: ViewContainerRef;
|
||||||
|
|
||||||
@ViewChild('modalPortal', { read: OverlayPortal }) _modalPortal: OverlayPortal;
|
@ViewChild('modalPortal', { read: OverlayPortal }) _modalPortal: OverlayPortal;
|
||||||
@ -45,6 +48,7 @@ export class IonicApp extends Ion implements OnInit {
|
|||||||
super(config, elementRef, renderer);
|
super(config, elementRef, renderer);
|
||||||
// register with App that this is Ionic's appRoot component. tada!
|
// register with App that this is Ionic's appRoot component. tada!
|
||||||
app._appRoot = this;
|
app._appRoot = this;
|
||||||
|
this._stopScrollPlugin = window['IonicStopScroll'];
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -109,7 +113,26 @@ export class IonicApp extends Ion implements OnInit {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_disableScroll(shouldDisableScroll: boolean) {
|
_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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export class App {
|
|||||||
private _title: string = '';
|
private _title: string = '';
|
||||||
private _titleSrv: Title = new Title();
|
private _titleSrv: Title = new Title();
|
||||||
private _rootNav: NavController = null;
|
private _rootNav: NavController = null;
|
||||||
private _canDisableScroll: boolean;
|
private _disableScrollAssist: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -71,7 +71,7 @@ export class App {
|
|||||||
// listen for hardware back button events
|
// listen for hardware back button events
|
||||||
// register this back button action with a default priority
|
// register this back button action with a default priority
|
||||||
_platform.registerBackButtonAction(this.navPop.bind(this));
|
_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.
|
* scrolling is enabled. When set to `true`, scrolling is disabled.
|
||||||
*/
|
*/
|
||||||
setScrollDisabled(disableScroll: boolean) {
|
setScrollDisabled(disableScroll: boolean) {
|
||||||
if (this._canDisableScroll) {
|
if (this._disableScrollAssist) {
|
||||||
this._appRoot._disableScroll(disableScroll);
|
this._appRoot._disableScroll(disableScroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,3 @@ ion-backdrop {
|
|||||||
opacity: .01;
|
opacity: .01;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-backdrop.hide-backdrop {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
import { Directive, ElementRef, Input, Renderer } from '@angular/core';
|
import { Directive, ElementRef, Renderer } from '@angular/core';
|
||||||
|
|
||||||
import { GestureController } from '../../gestures/gesture-controller';
|
|
||||||
import { isTrueProperty } from '../../util/util';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -16,26 +12,11 @@ import { isTrueProperty } from '../../util/util';
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
export class Backdrop {
|
export class Backdrop {
|
||||||
private _gestureID: number = null;
|
|
||||||
@Input() disableScroll = true;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _gestureCtrl: GestureController,
|
|
||||||
private _elementRef: ElementRef,
|
private _elementRef: ElementRef,
|
||||||
private _renderer: Renderer) { }
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getNativeElement(): HTMLElement {
|
getNativeElement(): HTMLElement {
|
||||||
return this._elementRef.nativeElement;
|
return this._elementRef.nativeElement;
|
||||||
|
@ -51,7 +51,7 @@ ion-content.js-scroll > .scroll-content {
|
|||||||
will-change: initial;
|
will-change: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disable-scroll .ion-page .scroll-content {
|
.disable-scroll .ion-page {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { ItemSliding } from './item-sliding';
|
import { ItemSliding } from './item-sliding';
|
||||||
import { List } from '../list/list';
|
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 { PanGesture } from '../../gestures/drag-gesture';
|
||||||
import { pointerCoord } from '../../util/dom';
|
import { pointerCoord } from '../../util/dom';
|
||||||
import { NativeRafDebouncer } from '../../util/debouncer';
|
import { NativeRafDebouncer } from '../../util/debouncer';
|
||||||
|
|
||||||
const DRAG_THRESHOLD = 10;
|
/**
|
||||||
const MAX_ATTACK_ANGLE = 20;
|
* @private
|
||||||
|
*/
|
||||||
export class ItemSlidingGesture extends PanGesture {
|
export class ItemSlidingGesture extends PanGesture {
|
||||||
|
|
||||||
private preSelectedContainer: ItemSliding = null;
|
private preSelectedContainer: ItemSliding = null;
|
||||||
@ -17,14 +17,16 @@ export class ItemSlidingGesture extends PanGesture {
|
|||||||
private firstCoordX: number;
|
private firstCoordX: number;
|
||||||
private firstTimestamp: number;
|
private firstTimestamp: number;
|
||||||
|
|
||||||
constructor(public list: List) {
|
constructor(public list: List, gestureCtrl: GestureController) {
|
||||||
super(list.getNativeElement(), {
|
super(list.getNativeElement(), {
|
||||||
maxAngle: MAX_ATTACK_ANGLE,
|
maxAngle: 20,
|
||||||
threshold: DRAG_THRESHOLD,
|
threshold: 10,
|
||||||
zone: false,
|
zone: false,
|
||||||
debouncer: new NativeRafDebouncer(),
|
debouncer: new NativeRafDebouncer(),
|
||||||
gesture: list._gestureCtrl.create('item-sliding', {
|
gesture: gestureCtrl.createGesture({
|
||||||
|
name: GESTURE_ITEM_SWIPE,
|
||||||
priority: GesturePriority.SlidingItem,
|
priority: GesturePriority.SlidingItem,
|
||||||
|
disableScroll: false // TODO: set true
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ export class List extends Ion {
|
|||||||
|
|
||||||
} else if (!this._slidingGesture) {
|
} else if (!this._slidingGesture) {
|
||||||
console.debug('enableSlidingItems');
|
console.debug('enableSlidingItems');
|
||||||
this._slidingGesture = new ItemSlidingGesture(this);
|
this._slidingGesture = new ItemSlidingGesture(this, this._gestureCtrl);
|
||||||
this._slidingGesture.listen();
|
this._slidingGesture.listen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { Component, ElementRef, Renderer, ViewEncapsulation } from '@angular/core';
|
import { Component, ElementRef, Renderer, ViewEncapsulation } from '@angular/core';
|
||||||
|
|
||||||
import { Config } from '../../config/config';
|
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 { NavParams } from '../../navigation/nav-params';
|
||||||
import { ViewController } from '../../navigation/view-controller';
|
import { ViewController } from '../../navigation/view-controller';
|
||||||
import { LoadingOptions } from './loading-options';
|
import { LoadingOptions } from './loading-options';
|
||||||
|
import { BlockerDelegate, GestureController, BLOCK_ALL } from '../../gestures/gesture-controller';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -12,7 +13,7 @@ import { LoadingOptions } from './loading-options';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-loading',
|
selector: 'ion-loading',
|
||||||
template:
|
template:
|
||||||
'<ion-backdrop [class.hide-backdrop]="!d.showBackdrop"></ion-backdrop>' +
|
'<ion-backdrop [hidden]="!d.showBackdrop"></ion-backdrop>' +
|
||||||
'<div class="loading-wrapper">' +
|
'<div class="loading-wrapper">' +
|
||||||
'<div *ngIf="showSpinner" class="loading-spinner">' +
|
'<div *ngIf="showSpinner" class="loading-spinner">' +
|
||||||
'<ion-spinner [name]="d.spinner"></ion-spinner>' +
|
'<ion-spinner [name]="d.spinner"></ion-spinner>' +
|
||||||
@ -29,14 +30,17 @@ export class LoadingCmp {
|
|||||||
id: number;
|
id: number;
|
||||||
showSpinner: boolean;
|
showSpinner: boolean;
|
||||||
durationTimeout: number;
|
durationTimeout: number;
|
||||||
|
gestureBlocker: BlockerDelegate;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _viewCtrl: ViewController,
|
private _viewCtrl: ViewController,
|
||||||
private _config: Config,
|
private _config: Config,
|
||||||
private _elementRef: ElementRef,
|
private _elementRef: ElementRef,
|
||||||
|
gestureCtrl: GestureController,
|
||||||
params: NavParams,
|
params: NavParams,
|
||||||
renderer: Renderer
|
renderer: Renderer
|
||||||
) {
|
) {
|
||||||
|
this.gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
|
||||||
this.d = params.data;
|
this.d = params.data;
|
||||||
|
|
||||||
renderer.setElementClass(_elementRef.nativeElement, `loading-${_config.get('mode')}`, true);
|
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';
|
this.showSpinner = isDefined(this.d.spinner) && this.d.spinner !== 'hide';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ionViewWillEnter() {
|
||||||
|
this.gestureBlocker.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
ionViewDidLeave() {
|
||||||
|
this.gestureBlocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
ionViewDidEnter() {
|
ionViewDidEnter() {
|
||||||
let activeElement: any = document.activeElement;
|
let activeElement: any = document.activeElement;
|
||||||
if (document.activeElement) {
|
activeElement && activeElement.blur();
|
||||||
activeElement.blur();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is a duration, dismiss after that amount of time
|
// If there is a duration, dismiss after that amount of time
|
||||||
if ( this.d && this.d.duration ) {
|
if ( this.d && this.d.duration ) {
|
||||||
this.durationTimeout = (<any> setTimeout( () => {
|
this.durationTimeout = setTimeout(() => this.dismiss('backdrop'), this.d.duration);
|
||||||
this.dismiss('backdrop');
|
|
||||||
}, this.d.duration));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -83,6 +91,11 @@ export class LoadingCmp {
|
|||||||
}
|
}
|
||||||
return this._viewCtrl.dismiss(null, role);
|
return this._viewCtrl.dismiss(null, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
|
||||||
|
this.gestureBlocker.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadingIds = -1;
|
let loadingIds = -1;
|
||||||
|
@ -2,7 +2,7 @@ import { Menu } from './menu';
|
|||||||
import { SlideEdgeGesture } from '../../gestures/slide-edge-gesture';
|
import { SlideEdgeGesture } from '../../gestures/slide-edge-gesture';
|
||||||
import { SlideData } from '../../gestures/slide-gesture';
|
import { SlideData } from '../../gestures/slide-gesture';
|
||||||
import { assign } from '../../util/util';
|
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';
|
import { NativeRafDebouncer } from '../../util/debouncer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,17 +14,19 @@ export class MenuContentGesture extends SlideEdgeGesture {
|
|||||||
public menu: Menu,
|
public menu: Menu,
|
||||||
contentEle: HTMLElement,
|
contentEle: HTMLElement,
|
||||||
gestureCtrl: GestureController,
|
gestureCtrl: GestureController,
|
||||||
options: any = {}) {
|
options: any = {}
|
||||||
|
) {
|
||||||
super(contentEle, assign({
|
super(contentEle, assign({
|
||||||
direction: 'x',
|
direction: 'x',
|
||||||
edge: menu.side,
|
edge: menu.side,
|
||||||
threshold: 0,
|
threshold: 0,
|
||||||
maxEdgeStart: menu.maxEdgeStart || 50,
|
maxEdgeStart: menu.maxEdgeStart || 50,
|
||||||
maxAngle: 40,
|
|
||||||
zone: false,
|
zone: false,
|
||||||
debouncer: new NativeRafDebouncer(),
|
debouncer: new NativeRafDebouncer(),
|
||||||
gesture: gestureCtrl.create('menu-swipe', {
|
gesture: gestureCtrl.createGesture({
|
||||||
|
name: GESTURE_MENU_SWIPE,
|
||||||
priority: GesturePriority.MenuSwipe,
|
priority: GesturePriority.MenuSwipe,
|
||||||
|
disableScroll: true
|
||||||
})
|
})
|
||||||
}, options));
|
}, options));
|
||||||
}
|
}
|
||||||
@ -52,13 +54,6 @@ export class MenuContentGesture extends SlideEdgeGesture {
|
|||||||
let z = (this.menu.side === 'right' ? slide.min : slide.max);
|
let z = (this.menu.side === 'right' ? slide.min : slide.max);
|
||||||
let stepValue = (slide.distance / z);
|
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);
|
this.menu.swipeProgress(stepValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import { MenuContentGesture } from './menu-gestures';
|
|||||||
import { MenuController } from './menu-controller';
|
import { MenuController } from './menu-controller';
|
||||||
import { MenuType } from './menu-types';
|
import { MenuType } from './menu-types';
|
||||||
import { Platform } from '../../platform/platform';
|
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 { UIEventManager } from '../../util/ui-event-manager';
|
||||||
import { Content } from '../content/content';
|
import { Content } from '../content/content';
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ import { Content } from '../content/content';
|
|||||||
selector: 'ion-menu',
|
selector: 'ion-menu',
|
||||||
template:
|
template:
|
||||||
'<div class="menu-inner"><ng-content></ng-content></div>' +
|
'<div class="menu-inner"><ng-content></ng-content></div>' +
|
||||||
'<ion-backdrop disableScroll="false"></ion-backdrop>',
|
'<ion-backdrop></ion-backdrop>',
|
||||||
host: {
|
host: {
|
||||||
'role': 'navigation'
|
'role': 'navigation'
|
||||||
},
|
},
|
||||||
@ -198,7 +198,7 @@ export class Menu {
|
|||||||
private _isPers: boolean = false;
|
private _isPers: boolean = false;
|
||||||
private _init: boolean = false;
|
private _init: boolean = false;
|
||||||
private _events: UIEventManager = new UIEventManager();
|
private _events: UIEventManager = new UIEventManager();
|
||||||
private _gestureID: number = 0;
|
private _gestureBlocker: BlockerDelegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -305,9 +305,9 @@ export class Menu {
|
|||||||
private _zone: NgZone,
|
private _zone: NgZone,
|
||||||
private _gestureCtrl: GestureController
|
private _gestureCtrl: GestureController
|
||||||
) {
|
) {
|
||||||
if (_gestureCtrl) {
|
this._gestureBlocker = _gestureCtrl.createBlocker({
|
||||||
this._gestureID = _gestureCtrl.newID();
|
disable: [GESTURE_GO_BACK_SWIPE]
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -503,7 +503,7 @@ export class Menu {
|
|||||||
this._events.unlistenAll();
|
this._events.unlistenAll();
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
// Disable swipe to go back gesture
|
// Disable swipe to go back gesture
|
||||||
this._gestureCtrl.disableGesture('goback-swipe', this._gestureID);
|
this._gestureBlocker.block();
|
||||||
|
|
||||||
this._cntEle.classList.add('menu-content-open');
|
this._cntEle.classList.add('menu-content-open');
|
||||||
let callback = this.onBackdropClick.bind(this);
|
let callback = this.onBackdropClick.bind(this);
|
||||||
@ -519,7 +519,7 @@ export class Menu {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Enable swipe to go back gesture
|
// Enable swipe to go back gesture
|
||||||
this._gestureCtrl.enableGesture('goback-swipe', this._gestureID);
|
this._gestureBlocker.unblock();
|
||||||
|
|
||||||
this._cntEle.classList.remove('menu-content-open');
|
this._cntEle.classList.remove('menu-content-open');
|
||||||
this.setElementClass('show-menu', false);
|
this.setElementClass('show-menu', false);
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
import { Component, ViewChild, NgModule } from '@angular/core';
|
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({
|
@Component({
|
||||||
templateUrl: 'page1.html'
|
templateUrl: 'page1.html'
|
||||||
})
|
})
|
||||||
export class Page1 {
|
export class Page1 {
|
||||||
constructor(public navCtrl: NavController, public alertCtrl: AlertController) {}
|
constructor(
|
||||||
|
public navCtrl: NavController,
|
||||||
|
public alertCtrl: AlertController,
|
||||||
|
public modalCtrl: ModalController
|
||||||
|
) { }
|
||||||
|
|
||||||
presentAlert() {
|
presentAlert() {
|
||||||
let alert = this.alertCtrl.create({
|
let alert = this.alertCtrl.create({
|
||||||
@ -18,11 +22,24 @@ export class Page1 {
|
|||||||
alert.present();
|
alert.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
presentModal() {
|
||||||
|
let modal = this.modalCtrl.create(Modal);
|
||||||
|
modal.present();
|
||||||
|
}
|
||||||
|
|
||||||
goToPage2() {
|
goToPage2() {
|
||||||
this.navCtrl.push(Page2);
|
this.navCtrl.push(Page2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({templateUrl: 'modal.html'})
|
||||||
|
export class Modal {
|
||||||
|
constructor(public viewController: ViewController) {}
|
||||||
|
close() {
|
||||||
|
this.viewController.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Component({templateUrl: 'page3.html'})
|
@Component({templateUrl: 'page3.html'})
|
||||||
export class Page3 {}
|
export class Page3 {}
|
||||||
@ -106,7 +123,8 @@ export class E2EApp {
|
|||||||
E2EPage,
|
E2EPage,
|
||||||
Page1,
|
Page1,
|
||||||
Page2,
|
Page2,
|
||||||
Page3
|
Page3,
|
||||||
|
Modal
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
IonicModule.forRoot(E2EApp)
|
IonicModule.forRoot(E2EApp)
|
||||||
@ -117,7 +135,8 @@ export class E2EApp {
|
|||||||
E2EPage,
|
E2EPage,
|
||||||
Page1,
|
Page1,
|
||||||
Page2,
|
Page2,
|
||||||
Page3
|
Page3,
|
||||||
|
Modal
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
20
src/components/menu/test/basic/modal.html
Normal file
20
src/components/menu/test/basic/modal.html
Normal 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>
|
@ -64,6 +64,10 @@
|
|||||||
<button ion-button (click)="presentAlert()">Open alert</button>
|
<button ion-button (click)="presentAlert()">Open alert</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<button ion-button (click)="presentModal()">Open modal</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button ion-button (click)="goToPage2()">Go to Page 2</button>
|
<button ion-button (click)="goToPage2()">Go to Page 2</button>
|
||||||
</p>
|
</p>
|
||||||
|
@ -3,7 +3,8 @@ import { Component, ComponentFactoryResolver, HostListener, Renderer, ViewChild,
|
|||||||
import { Key } from '../../util/key';
|
import { Key } from '../../util/key';
|
||||||
import { NavParams } from '../../navigation/nav-params';
|
import { NavParams } from '../../navigation/nav-params';
|
||||||
import { ViewController } from '../../navigation/view-controller';
|
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
|
* @private
|
||||||
@ -11,7 +12,7 @@ import { ViewController } from '../../navigation/view-controller';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-modal',
|
selector: 'ion-modal',
|
||||||
template:
|
template:
|
||||||
'<ion-backdrop disableScroll="false" (click)="_bdClick()"></ion-backdrop>' +
|
'<ion-backdrop (click)="_bdClick()"></ion-backdrop>' +
|
||||||
'<div class="modal-wrapper">' +
|
'<div class="modal-wrapper">' +
|
||||||
'<div #viewport nav-viewport></div>' +
|
'<div #viewport nav-viewport></div>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
@ -20,13 +21,20 @@ export class ModalCmp {
|
|||||||
|
|
||||||
@ViewChild('viewport', { read: ViewContainerRef }) _viewport: ViewContainerRef;
|
@ViewChild('viewport', { read: ViewContainerRef }) _viewport: ViewContainerRef;
|
||||||
|
|
||||||
/** @private */
|
|
||||||
_bdDismiss: boolean;
|
_bdDismiss: boolean;
|
||||||
|
|
||||||
/** @private */
|
|
||||||
_enabled: boolean;
|
_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;
|
this._bdDismiss = _navParams.data.opts.enableBackdropDismiss;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,9 +54,20 @@ export class ModalCmp {
|
|||||||
this._setCssClass(componentRef, 'ion-page');
|
this._setCssClass(componentRef, 'ion-page');
|
||||||
this._setCssClass(componentRef, 'show-page');
|
this._setCssClass(componentRef, 'show-page');
|
||||||
this._enabled = true;
|
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 */
|
/** @private */
|
||||||
_setCssClass(componentRef: any, className: string) {
|
_setCssClass(componentRef: any, className: string) {
|
||||||
this._renderer.setElementClass(componentRef.location.nativeElement, className, true);
|
this._renderer.setElementClass(componentRef.location.nativeElement, className, true);
|
||||||
@ -66,4 +85,9 @@ export class ModalCmp {
|
|||||||
this._bdClick();
|
this._bdClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
|
||||||
|
this._gestureBlocker.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -834,7 +834,9 @@ export const deepLinkConfig: DeepLinkConfig = {
|
|||||||
TabItemPage
|
TabItemPage
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
IonicModule.forRoot(E2EApp, null, deepLinkConfig)
|
IonicModule.forRoot(E2EApp, {
|
||||||
|
swipeBackEnabled: true
|
||||||
|
}, deepLinkConfig)
|
||||||
],
|
],
|
||||||
bootstrap: [IonicApp],
|
bootstrap: [IonicApp],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
|
@ -2,7 +2,7 @@ import { Component, ElementRef, EventEmitter, Input, HostListener, NgZone, Outpu
|
|||||||
import { DomSanitizer } from '@angular/platform-browser';
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { CSS, cancelRaf, pointerCoord, nativeRaf } from '../../util/dom';
|
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 { Config } from '../../config/config';
|
||||||
import { Key } from '../../util/key';
|
import { Key } from '../../util/key';
|
||||||
import { NavParams } from '../../navigation/nav-params';
|
import { NavParams } from '../../navigation/nav-params';
|
||||||
@ -12,6 +12,7 @@ import { Haptic } from '../../util/haptic';
|
|||||||
import { UIEventManager } from '../../util/ui-event-manager';
|
import { UIEventManager } from '../../util/ui-event-manager';
|
||||||
import { ViewController } from '../../navigation/view-controller';
|
import { ViewController } from '../../navigation/view-controller';
|
||||||
import { Debouncer, NativeRafDebouncer } from '../../util/debouncer';
|
import { Debouncer, NativeRafDebouncer } from '../../util/debouncer';
|
||||||
|
import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/gesture-controller';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -454,14 +455,17 @@ export class PickerCmp {
|
|||||||
lastClick: number;
|
lastClick: number;
|
||||||
id: number;
|
id: number;
|
||||||
mode: string;
|
mode: string;
|
||||||
|
_gestureBlocker: BlockerDelegate;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _viewCtrl: ViewController,
|
private _viewCtrl: ViewController,
|
||||||
private _elementRef: ElementRef,
|
private _elementRef: ElementRef,
|
||||||
private _config: Config,
|
private _config: Config,
|
||||||
|
gestureCtrl: GestureController,
|
||||||
params: NavParams,
|
params: NavParams,
|
||||||
renderer: Renderer
|
renderer: Renderer
|
||||||
) {
|
) {
|
||||||
|
this._gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
|
||||||
this.d = params.data;
|
this.d = params.data;
|
||||||
this.mode = _config.get('mode');
|
this.mode = _config.get('mode');
|
||||||
renderer.setElementClass(_elementRef.nativeElement, `picker-${this.mode}`, true);
|
renderer.setElementClass(_elementRef.nativeElement, `picker-${this.mode}`, true);
|
||||||
@ -523,6 +527,14 @@ export class PickerCmp {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ionViewWillEnter() {
|
||||||
|
this._gestureBlocker.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
ionViewDidLeave() {
|
||||||
|
this._gestureBlocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
this._cols.forEach(column => {
|
this._cols.forEach(column => {
|
||||||
column.refresh();
|
column.refresh();
|
||||||
@ -617,6 +629,12 @@ export class PickerCmp {
|
|||||||
});
|
});
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
|
||||||
|
this._gestureBlocker.destroy();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pickerIds = -1;
|
let pickerIds = -1;
|
||||||
|
@ -4,7 +4,8 @@ import { Config } from '../../config/config';
|
|||||||
import { Key } from '../../util/key';
|
import { Key } from '../../util/key';
|
||||||
import { NavParams } from '../../navigation/nav-params';
|
import { NavParams } from '../../navigation/nav-params';
|
||||||
import { ViewController } from '../../navigation/view-controller';
|
import { ViewController } from '../../navigation/view-controller';
|
||||||
|
import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/gesture-controller';
|
||||||
|
import { assert } from '../../util/util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -12,7 +13,7 @@ import { ViewController } from '../../navigation/view-controller';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-popover',
|
selector: 'ion-popover',
|
||||||
template:
|
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-wrapper">' +
|
||||||
'<div class="popover-arrow"></div>' +
|
'<div class="popover-arrow"></div>' +
|
||||||
'<div class="popover-content">' +
|
'<div class="popover-content">' +
|
||||||
@ -32,10 +33,9 @@ export class PopoverCmp {
|
|||||||
enableBackdropDismiss?: boolean;
|
enableBackdropDismiss?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @private */
|
|
||||||
_enabled: boolean;
|
_enabled: boolean;
|
||||||
|
_gestureBlocker: BlockerDelegate;
|
||||||
|
|
||||||
/** @private */
|
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -44,8 +44,10 @@ export class PopoverCmp {
|
|||||||
public _renderer: Renderer,
|
public _renderer: Renderer,
|
||||||
public _config: Config,
|
public _config: Config,
|
||||||
public _navParams: NavParams,
|
public _navParams: NavParams,
|
||||||
public _viewCtrl: ViewController
|
public _viewCtrl: ViewController,
|
||||||
|
gestureCtrl: GestureController,
|
||||||
) {
|
) {
|
||||||
|
this._gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
|
||||||
this.d = _navParams.data.opts;
|
this.d = _navParams.data.opts;
|
||||||
|
|
||||||
_renderer.setElementClass(_elementRef.nativeElement, `popover-${_config.get('mode')}`, true);
|
_renderer.setElementClass(_elementRef.nativeElement, `popover-${_config.get('mode')}`, true);
|
||||||
@ -62,13 +64,11 @@ export class PopoverCmp {
|
|||||||
|
|
||||||
ionViewPreLoad() {
|
ionViewPreLoad() {
|
||||||
let activeElement: any = document.activeElement;
|
let activeElement: any = document.activeElement;
|
||||||
if (document.activeElement) {
|
activeElement && activeElement.blur();
|
||||||
activeElement.blur();
|
|
||||||
}
|
|
||||||
this._load(this._navParams.data.component);
|
this._load(this._navParams.data.component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @private */
|
|
||||||
_load(component: any) {
|
_load(component: any) {
|
||||||
if (component) {
|
if (component) {
|
||||||
const componentFactory = this._cfr.resolveComponentFactory(component);
|
const componentFactory = this._cfr.resolveComponentFactory(component);
|
||||||
@ -76,12 +76,23 @@ export class PopoverCmp {
|
|||||||
// ******** DOM WRITE ****************
|
// ******** DOM WRITE ****************
|
||||||
const componentRef = this._viewport.createComponent(componentFactory, this._viewport.length, this._viewport.parentInjector, []);
|
const componentRef = this._viewport.createComponent(componentFactory, this._viewport.length, this._viewport.parentInjector, []);
|
||||||
this._viewCtrl._setInstance(componentRef.instance);
|
this._viewCtrl._setInstance(componentRef.instance);
|
||||||
|
|
||||||
this._enabled = true;
|
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) {
|
_setCssClass(componentRef: any, className: string) {
|
||||||
this._renderer.setElementClass(componentRef.location.nativeElement, className, true);
|
this._renderer.setElementClass(componentRef.location.nativeElement, className, true);
|
||||||
}
|
}
|
||||||
@ -98,6 +109,11 @@ export class PopoverCmp {
|
|||||||
this._bdClick();
|
this._bdClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
|
||||||
|
this._gestureBlocker.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let popoverIds = -1;
|
let popoverIds = -1;
|
||||||
|
@ -2,7 +2,7 @@ import { Directive, EventEmitter, Host, Input, Output, NgZone } from '@angular/c
|
|||||||
|
|
||||||
import { Content } from '../content/content';
|
import { Content } from '../content/content';
|
||||||
import { CSS, pointerCoord } from '../../util/dom';
|
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 { isTrueProperty } from '../../util/util';
|
||||||
import { PointerEvents, UIEventManager } from '../../util/ui-event-manager';
|
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) {
|
constructor(@Host() private _content: Content, private _zone: NgZone, gestureCtrl: GestureController) {
|
||||||
_content.setElementClass('has-refresher', true);
|
_content.setElementClass('has-refresher', true);
|
||||||
this._gesture = gestureCtrl.create('refresher', {
|
this._gesture = gestureCtrl.createGesture({
|
||||||
|
name: GESTURE_REFRESHER,
|
||||||
priority: GesturePriority.Refresher,
|
priority: GesturePriority.Refresher,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -53,10 +53,10 @@
|
|||||||
|
|
||||||
.back-button {
|
.back-button {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
&.show-back-button {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.back-button.show-back-button {
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-button-text {
|
.back-button-text {
|
||||||
|
@ -1,6 +1,22 @@
|
|||||||
import { forwardRef, Inject, Injectable } from '@angular/core';
|
import { forwardRef, Inject, Injectable } from '@angular/core';
|
||||||
import { App } from '../components/app/app';
|
import { App } from '../components/app/app';
|
||||||
|
import { assert } from '../util/util';
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
export const GESTURE_GO_BACK_SWIPE = 'goback-swipe';
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
export const GESTURE_MENU_SWIPE = 'menu-swipe';
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
export const GESTURE_ITEM_SWIPE = 'item-swipe';
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
export const GESTURE_REFRESHER = 'refresher';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
export const enum GesturePriority {
|
export const enum GesturePriority {
|
||||||
Minimun = -10000,
|
Minimun = -10000,
|
||||||
VeryLow = -20,
|
VeryLow = -20,
|
||||||
@ -15,23 +31,37 @@ export const enum GesturePriority {
|
|||||||
Refresher = Normal,
|
Refresher = Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum DisableScroll {
|
/**
|
||||||
Never,
|
* @private
|
||||||
DuringCapture,
|
*/
|
||||||
Always,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GestureOptions {
|
export interface GestureOptions {
|
||||||
disable?: string[];
|
name: string;
|
||||||
disableScroll?: DisableScroll;
|
disableScroll?: boolean;
|
||||||
priority?: number;
|
priority?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export interface BlockerOptions {
|
||||||
|
disableScroll?: boolean;
|
||||||
|
disable?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export const BLOCK_ALL: BlockerOptions = {
|
||||||
|
disable: [GESTURE_MENU_SWIPE, GESTURE_GO_BACK_SWIPE],
|
||||||
|
disableScroll: true
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GestureController {
|
export class GestureController {
|
||||||
|
|
||||||
private id: number = 1;
|
private id: number = 1;
|
||||||
private requestedStart: { [eventId: number]: number } = {};
|
private requestedStart: { [eventId: number]: number } = {};
|
||||||
private disabledGestures: { [eventName: string]: Set<number> } = {};
|
private disabledGestures: { [eventName: string]: Set<number> } = {};
|
||||||
@ -40,8 +70,21 @@ export class GestureController {
|
|||||||
|
|
||||||
constructor(@Inject(forwardRef(() => App)) private _app: App) { }
|
constructor(@Inject(forwardRef(() => App)) private _app: App) { }
|
||||||
|
|
||||||
create(name: string, opts: GestureOptions = {}): GestureDelegate {
|
createGesture(opts: GestureOptions): GestureDelegate {
|
||||||
return new GestureDelegate(name, this.newID(), this, opts);
|
if (!opts.name) {
|
||||||
|
throw new Error('name is undefined');
|
||||||
|
}
|
||||||
|
return new GestureDelegate(opts.name, this.newID(), this,
|
||||||
|
opts.priority || 0,
|
||||||
|
!!opts.disableScroll
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
createBlocker(opts: BlockerOptions = {}): BlockerDelegate {
|
||||||
|
return new BlockerDelegate(this.newID(), this,
|
||||||
|
opts.disable,
|
||||||
|
!!opts.disableScroll
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
newID(): number {
|
newID(): number {
|
||||||
@ -127,6 +170,7 @@ export class GestureController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDisabled(gestureName)) {
|
if (this.isDisabled(gestureName)) {
|
||||||
|
console.debug('GestureController: Disabled', gestureName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -154,33 +198,18 @@ export class GestureController {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export class GestureDelegate {
|
export class GestureDelegate {
|
||||||
private disable: string[];
|
|
||||||
private disableScroll: DisableScroll;
|
|
||||||
public priority: number = 0;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private name: string,
|
private name: string,
|
||||||
private id: number,
|
private id: number,
|
||||||
private controller: GestureController,
|
private controller: GestureController,
|
||||||
opts: GestureOptions
|
private priority: number,
|
||||||
) {
|
private disableScroll: boolean
|
||||||
this.disable = opts.disable || [];
|
) { }
|
||||||
this.disableScroll = opts.disableScroll || DisableScroll.Never;
|
|
||||||
this.priority = opts.priority || 0;
|
|
||||||
|
|
||||||
// Disable gestures
|
|
||||||
for (let gestureName of this.disable) {
|
|
||||||
controller.disableGesture(gestureName, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable scrolling (always)
|
|
||||||
if (this.disableScroll === DisableScroll.Always) {
|
|
||||||
controller.disableScroll(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canStart(): boolean {
|
canStart(): boolean {
|
||||||
if (!this.controller) {
|
if (!this.controller) {
|
||||||
|
assert(false, 'delegate was destroyed');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.controller.canStart(this.name);
|
return this.controller.canStart(this.name);
|
||||||
@ -188,6 +217,7 @@ export class GestureDelegate {
|
|||||||
|
|
||||||
start(): boolean {
|
start(): boolean {
|
||||||
if (!this.controller) {
|
if (!this.controller) {
|
||||||
|
assert(false, 'delegate was destroyed');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.controller.start(this.name, this.id, this.priority);
|
return this.controller.start(this.name, this.id, this.priority);
|
||||||
@ -195,10 +225,11 @@ export class GestureDelegate {
|
|||||||
|
|
||||||
capture(): boolean {
|
capture(): boolean {
|
||||||
if (!this.controller) {
|
if (!this.controller) {
|
||||||
|
assert(false, 'delegate was destroyed');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let captured = this.controller.capture(this.name, this.id, this.priority);
|
let captured = this.controller.capture(this.name, this.id, this.priority);
|
||||||
if (captured && this.disableScroll === DisableScroll.DuringCapture) {
|
if (captured && this.disableScroll) {
|
||||||
this.controller.disableScroll(this.id);
|
this.controller.disableScroll(this.id);
|
||||||
}
|
}
|
||||||
return captured;
|
return captured;
|
||||||
@ -206,26 +237,70 @@ export class GestureDelegate {
|
|||||||
|
|
||||||
release() {
|
release() {
|
||||||
if (!this.controller) {
|
if (!this.controller) {
|
||||||
|
assert(false, 'delegate was destroyed');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.controller.release(this.id);
|
this.controller.release(this.id);
|
||||||
if (this.disableScroll === DisableScroll.DuringCapture) {
|
if (this.disableScroll) {
|
||||||
this.controller.enableScroll(this.id);
|
this.controller.enableScroll(this.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
if (!this.controller) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.release();
|
this.release();
|
||||||
|
this.controller = null;
|
||||||
for (let disabled of this.disable) {
|
}
|
||||||
this.controller.enableGesture(disabled, this.id);
|
}
|
||||||
}
|
|
||||||
if (this.disableScroll === DisableScroll.Always) {
|
/**
|
||||||
this.controller.enableScroll(this.id);
|
* @private
|
||||||
}
|
*/
|
||||||
|
export class BlockerDelegate {
|
||||||
|
|
||||||
|
blocked: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private id: number,
|
||||||
|
private controller: GestureController,
|
||||||
|
private disable: string[],
|
||||||
|
private disableScroll: boolean
|
||||||
|
) { }
|
||||||
|
|
||||||
|
block() {
|
||||||
|
if (!this.controller) {
|
||||||
|
assert(false, 'delegate was destroyed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.disable) {
|
||||||
|
this.disable.forEach(gesture => {
|
||||||
|
this.controller.disableGesture(gesture, this.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.disableScroll) {
|
||||||
|
this.controller.disableScroll(this.id);
|
||||||
|
}
|
||||||
|
this.blocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unblock() {
|
||||||
|
if (!this.controller) {
|
||||||
|
assert(false, 'delegate was destroyed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.disable) {
|
||||||
|
this.disable.forEach(gesture => {
|
||||||
|
this.controller.enableGesture(gesture, this.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.disableScroll) {
|
||||||
|
this.controller.enableScroll(this.id);
|
||||||
|
}
|
||||||
|
this.blocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.unblock();
|
||||||
this.controller = null;
|
this.controller = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { GestureController, DisableScroll } from '../gesture-controller';
|
import { GestureController, GestureOptions } from '../gesture-controller';
|
||||||
|
|
||||||
describe('gesture controller', () => {
|
describe('gesture controller', () => {
|
||||||
it('should create an instance of GestureController', () => {
|
it('should create an instance of GestureController', () => {
|
||||||
@ -80,41 +80,51 @@ describe('gesture controller', () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should initialize a delegate without options', () => {
|
it('should throw error if initializing without a name a gesture delegate without options', () => {
|
||||||
let c = new GestureController(null);
|
let c = new GestureController(null);
|
||||||
let g = c.create('event');
|
expect(() => {
|
||||||
|
let a = {};
|
||||||
|
c.createGesture(<GestureOptions>a);
|
||||||
|
}).toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should initialize without options', () => {
|
||||||
|
let c = new GestureController(null);
|
||||||
|
|
||||||
|
let g = c.createGesture({
|
||||||
|
name: 'event',
|
||||||
|
});
|
||||||
expect(g['name']).toEqual('event');
|
expect(g['name']).toEqual('event');
|
||||||
expect(g.priority).toEqual(0);
|
expect(g['priority']).toEqual(0);
|
||||||
expect(g['disable']).toEqual([]);
|
expect(g['disableScroll']).toEqual(false);
|
||||||
expect(g['disableScroll']).toEqual(DisableScroll.Never);
|
|
||||||
expect(g['controller']).toEqual(c);
|
expect(g['controller']).toEqual(c);
|
||||||
expect(g['id']).toEqual(1);
|
expect(g['id']).toEqual(1);
|
||||||
|
|
||||||
let g2 = c.create('event2');
|
let g2 = c.createGesture({ name: 'event2' });
|
||||||
expect(g2['id']).toEqual(2);
|
expect(g2['id']).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should initialize a delegate with options', () => {
|
it('should initialize a delegate with options', () => {
|
||||||
let c = new GestureController(null);
|
let c = new GestureController(null);
|
||||||
let g = c.create('swipe', {
|
let g = c.createGesture({
|
||||||
|
name: 'swipe',
|
||||||
priority: -123,
|
priority: -123,
|
||||||
disableScroll: DisableScroll.DuringCapture,
|
disableScroll: true,
|
||||||
disable: ['event2']
|
|
||||||
});
|
});
|
||||||
expect(g['name']).toEqual('swipe');
|
expect(g['name']).toEqual('swipe');
|
||||||
expect(g.priority).toEqual(-123);
|
expect(g['priority']).toEqual(-123);
|
||||||
expect(g['disable']).toEqual(['event2']);
|
expect(g['disableScroll']).toEqual(true);
|
||||||
expect(g['disableScroll']).toEqual(DisableScroll.DuringCapture);
|
|
||||||
expect(g['controller']).toEqual(c);
|
expect(g['controller']).toEqual(c);
|
||||||
expect(g['id']).toEqual(1);
|
expect(g['id']).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should test if several gestures can be started', () => {
|
it('should test if several gestures can be started', () => {
|
||||||
let c = new GestureController(null);
|
let c = new GestureController(null);
|
||||||
let g1 = c.create('swipe');
|
let g1 = c.createGesture({ name: 'swipe' });
|
||||||
let g2 = c.create('swipe1', {priority: 3});
|
let g2 = c.createGesture({name: 'swipe1', priority: 3});
|
||||||
let g3 = c.create('swipe2', {priority: 4});
|
let g3 = c.createGesture({name: 'swipe2', priority: 4});
|
||||||
|
|
||||||
for (var i = 0; i < 10; i++) {
|
for (var i = 0; i < 10; i++) {
|
||||||
expect(g1.start()).toEqual(true);
|
expect(g1.start()).toEqual(true);
|
||||||
@ -137,6 +147,7 @@ describe('gesture controller', () => {
|
|||||||
expect(g1.start()).toEqual(true);
|
expect(g1.start()).toEqual(true);
|
||||||
expect(g2.start()).toEqual(true);
|
expect(g2.start()).toEqual(true);
|
||||||
g3.destroy();
|
g3.destroy();
|
||||||
|
expect(g3['controller']).toBeNull();
|
||||||
|
|
||||||
expect(c['requestedStart']).toEqual({
|
expect(c['requestedStart']).toEqual({
|
||||||
1: 0,
|
1: 0,
|
||||||
@ -147,11 +158,11 @@ describe('gesture controller', () => {
|
|||||||
|
|
||||||
it('should test if several gestures try to capture at the same time', () => {
|
it('should test if several gestures try to capture at the same time', () => {
|
||||||
let c = new GestureController(null);
|
let c = new GestureController(null);
|
||||||
let g1 = c.create('swipe1');
|
let g1 = c.createGesture({name: 'swipe1'});
|
||||||
let g2 = c.create('swipe2', { priority: 2 });
|
let g2 = c.createGesture({name: 'swipe2', priority: 2 });
|
||||||
let g3 = c.create('swipe3', { priority: 3 });
|
let g3 = c.createGesture({name: 'swipe3', priority: 3 });
|
||||||
let g4 = c.create('swipe4', { priority: 4 });
|
let g4 = c.createGesture({name: 'swipe4', priority: 4 });
|
||||||
let g5 = c.create('swipe5', { priority: 5 });
|
let g5 = c.createGesture({name: 'swipe5', priority: 5 });
|
||||||
|
|
||||||
// Low priority capture() returns false
|
// Low priority capture() returns false
|
||||||
expect(g2.start()).toEqual(true);
|
expect(g2.start()).toEqual(true);
|
||||||
@ -196,90 +207,13 @@ describe('gesture controller', () => {
|
|||||||
expect(g1.capture()).toEqual(true);
|
expect(g1.capture()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should destroy correctly', () => {
|
|
||||||
let c = new GestureController(null);
|
|
||||||
let g = c.create('swipe', {
|
|
||||||
priority: 123,
|
|
||||||
disableScroll: DisableScroll.Always,
|
|
||||||
disable: ['event2']
|
|
||||||
});
|
|
||||||
expect(c.isScrollDisabled()).toEqual(true);
|
|
||||||
|
|
||||||
// Capturing
|
|
||||||
expect(g.capture()).toEqual(true);
|
|
||||||
expect(c.isCaptured()).toEqual(true);
|
|
||||||
expect(g.capture()).toEqual(false);
|
|
||||||
expect(c.isScrollDisabled()).toEqual(true);
|
|
||||||
|
|
||||||
// Releasing
|
|
||||||
g.release();
|
|
||||||
expect(c.isCaptured()).toEqual(false);
|
|
||||||
expect(c.isScrollDisabled()).toEqual(true);
|
|
||||||
expect(g.capture()).toEqual(true);
|
|
||||||
expect(c.isCaptured()).toEqual(true);
|
|
||||||
|
|
||||||
// Destroying
|
|
||||||
g.destroy();
|
|
||||||
expect(c.isCaptured()).toEqual(false);
|
|
||||||
expect(g['controller']).toBeNull();
|
|
||||||
|
|
||||||
// it should return false and not crash
|
|
||||||
expect(g.start()).toEqual(false);
|
|
||||||
expect(g.capture()).toEqual(false);
|
|
||||||
g.release();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should disable some events', () => {
|
|
||||||
let c = new GestureController(null);
|
|
||||||
|
|
||||||
let goback = c.create('goback');
|
|
||||||
expect(goback.canStart()).toEqual(true);
|
|
||||||
|
|
||||||
let g2 = c.create('goback2');
|
|
||||||
expect(g2.canStart()).toEqual(true);
|
|
||||||
|
|
||||||
let g3 = c.create('swipe', {
|
|
||||||
disable: ['range', 'goback', 'something']
|
|
||||||
});
|
|
||||||
|
|
||||||
let g4 = c.create('swipe2', {
|
|
||||||
disable: ['range']
|
|
||||||
});
|
|
||||||
|
|
||||||
// it should be noop
|
|
||||||
g3.release();
|
|
||||||
|
|
||||||
// goback is disabled
|
|
||||||
expect(c.isDisabled('range')).toEqual(true);
|
|
||||||
expect(c.isDisabled('goback')).toEqual(true);
|
|
||||||
expect(c.isDisabled('something')).toEqual(true);
|
|
||||||
expect(c.isDisabled('goback2')).toEqual(false);
|
|
||||||
expect(goback.canStart()).toEqual(false);
|
|
||||||
expect(goback.start()).toEqual(false);
|
|
||||||
expect(goback.capture()).toEqual(false);
|
|
||||||
expect(g3.canStart()).toEqual(true);
|
|
||||||
|
|
||||||
// Once g3 is destroyed, goback and something should be enabled
|
|
||||||
g3.destroy();
|
|
||||||
expect(c.isDisabled('range')).toEqual(true);
|
|
||||||
expect(c.isDisabled('goback')).toEqual(false);
|
|
||||||
expect(c.isDisabled('something')).toEqual(false);
|
|
||||||
expect(g3.canStart()).toEqual(false);
|
|
||||||
|
|
||||||
// Once g4 is destroyed, range is also enabled
|
|
||||||
g4.destroy();
|
|
||||||
expect(c.isDisabled('range')).toEqual(false);
|
|
||||||
expect(g4.canStart()).toEqual(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should disable scrolling on capture', () => {
|
it('should disable scrolling on capture', () => {
|
||||||
let c = new GestureController(null);
|
let c = new GestureController(null);
|
||||||
let g = c.create('goback', {
|
let g = c.createGesture({
|
||||||
disableScroll: DisableScroll.DuringCapture,
|
name: 'goback',
|
||||||
|
disableScroll: true,
|
||||||
});
|
});
|
||||||
let g1 = c.create('swipe');
|
let g1 = c.createGesture({ name: 'swipe' });
|
||||||
|
|
||||||
g.start();
|
g.start();
|
||||||
expect(c.isScrollDisabled()).toEqual(false);
|
expect(c.isScrollDisabled()).toEqual(false);
|
||||||
@ -294,19 +228,116 @@ describe('gesture controller', () => {
|
|||||||
g.capture();
|
g.capture();
|
||||||
expect(c.isScrollDisabled()).toEqual(true);
|
expect(c.isScrollDisabled()).toEqual(true);
|
||||||
|
|
||||||
let g2 = c.create('swipe2', {
|
|
||||||
disableScroll: DisableScroll.Always,
|
|
||||||
});
|
|
||||||
g.release();
|
|
||||||
expect(c.isScrollDisabled()).toEqual(true);
|
|
||||||
|
|
||||||
g2.destroy();
|
|
||||||
expect(c.isScrollDisabled()).toEqual(false);
|
|
||||||
|
|
||||||
g.capture();
|
|
||||||
expect(c.isScrollDisabled()).toEqual(true);
|
|
||||||
|
|
||||||
g.destroy();
|
g.destroy();
|
||||||
expect(c.isScrollDisabled()).toEqual(false);
|
expect(c.isScrollDisabled()).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('BlockerDelegate', () => {
|
||||||
|
it('create one', () => {
|
||||||
|
let c = new GestureController(null);
|
||||||
|
let b = c.createBlocker({
|
||||||
|
disableScroll: true,
|
||||||
|
disable: ['event1', 'event2', 'event3', 'event4']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(b['disable']).toEqual(['event1', 'event2', 'event3', 'event4']);
|
||||||
|
expect(b['disableScroll']).toEqual(true);
|
||||||
|
expect(b['controller']).toEqual(c);
|
||||||
|
expect(b['id']).toEqual(1);
|
||||||
|
|
||||||
|
let b2 = c.createBlocker({
|
||||||
|
disable: ['event2', 'event3', 'event4', 'event5']
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(b2['disable']).toEqual(['event2', 'event3', 'event4', 'event5']);
|
||||||
|
expect(b2['disableScroll']).toEqual(false);
|
||||||
|
expect(b2['controller']).toEqual(c);
|
||||||
|
expect(b2['id']).toEqual(2);
|
||||||
|
|
||||||
|
|
||||||
|
expect(c.isDisabled('event1')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event2')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event3')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event4')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event5')).toBeFalsy();
|
||||||
|
|
||||||
|
b.block();
|
||||||
|
b.block();
|
||||||
|
|
||||||
|
expect(c.isDisabled('event1')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event2')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event3')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event4')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event5')).toBeFalsy();
|
||||||
|
|
||||||
|
b2.block();
|
||||||
|
b2.block();
|
||||||
|
b2.block();
|
||||||
|
|
||||||
|
expect(c.isDisabled('event1')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event2')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event3')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event4')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event5')).toBeTruthy();
|
||||||
|
|
||||||
|
b.unblock();
|
||||||
|
|
||||||
|
expect(c.isDisabled('event1')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event2')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event3')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event4')).toBeTruthy();
|
||||||
|
expect(c.isDisabled('event5')).toBeTruthy();
|
||||||
|
|
||||||
|
b2.destroy();
|
||||||
|
expect(b2['controller']).toBeNull();
|
||||||
|
|
||||||
|
expect(c.isDisabled('event1')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event2')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event3')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event4')).toBeFalsy();
|
||||||
|
expect(c.isDisabled('event5')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should disable some events', () => {
|
||||||
|
let c = new GestureController(null);
|
||||||
|
|
||||||
|
let goback = c.createGesture({ name: 'goback' });
|
||||||
|
expect(goback.canStart()).toEqual(true);
|
||||||
|
|
||||||
|
let g2 = c.createGesture({ name: 'goback2' });
|
||||||
|
expect(g2.canStart()).toEqual(true);
|
||||||
|
|
||||||
|
let g3 = c.createBlocker({
|
||||||
|
disable: ['range', 'goback', 'something']
|
||||||
|
});
|
||||||
|
|
||||||
|
let g4 = c.createBlocker({
|
||||||
|
disable: ['range']
|
||||||
|
});
|
||||||
|
|
||||||
|
g3.block();
|
||||||
|
g4.block();
|
||||||
|
|
||||||
|
// goback is disabled
|
||||||
|
expect(c.isDisabled('range')).toEqual(true);
|
||||||
|
expect(c.isDisabled('goback')).toEqual(true);
|
||||||
|
expect(c.isDisabled('something')).toEqual(true);
|
||||||
|
expect(c.isDisabled('goback2')).toEqual(false);
|
||||||
|
expect(goback.canStart()).toEqual(false);
|
||||||
|
expect(goback.start()).toEqual(false);
|
||||||
|
expect(goback.capture()).toEqual(false);
|
||||||
|
|
||||||
|
// Once g3 is destroyed, goback and something should be enabled
|
||||||
|
g3.destroy();
|
||||||
|
expect(c.isDisabled('range')).toEqual(true);
|
||||||
|
expect(c.isDisabled('goback')).toEqual(false);
|
||||||
|
expect(c.isDisabled('something')).toEqual(false);
|
||||||
|
|
||||||
|
// Once g4 is destroyed, range is also enabled
|
||||||
|
g4.unblock();
|
||||||
|
expect(c.isDisabled('range')).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { assign, swipeShouldReset } from '../util/util';
|
import { assign, swipeShouldReset } from '../util/util';
|
||||||
import { GestureController, GesturePriority, DisableScroll } from '../gestures/gesture-controller';
|
import { GestureController, GesturePriority, GESTURE_GO_BACK_SWIPE } from '../gestures/gesture-controller';
|
||||||
import { NavControllerBase } from './nav-controller-base';
|
import { NavControllerBase } from './nav-controller-base';
|
||||||
import { SlideData } from '../gestures/slide-gesture';
|
import { SlideData } from '../gestures/slide-gesture';
|
||||||
import { SlideEdgeGesture } from '../gestures/slide-edge-gesture';
|
import { SlideEdgeGesture } from '../gestures/slide-edge-gesture';
|
||||||
import { NativeRafDebouncer } from '../util/debouncer';
|
import { NativeRafDebouncer } from '../util/debouncer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
export class SwipeBackGesture extends SlideEdgeGesture {
|
export class SwipeBackGesture extends SlideEdgeGesture {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _nav: NavControllerBase,
|
private _nav: NavControllerBase,
|
||||||
element: HTMLElement,
|
element: HTMLElement,
|
||||||
@ -17,11 +21,11 @@ export class SwipeBackGesture extends SlideEdgeGesture {
|
|||||||
maxEdgeStart: 75,
|
maxEdgeStart: 75,
|
||||||
zone: false,
|
zone: false,
|
||||||
threshold: 0,
|
threshold: 0,
|
||||||
maxAngle: 40,
|
|
||||||
debouncer: new NativeRafDebouncer(),
|
debouncer: new NativeRafDebouncer(),
|
||||||
gesture: gestureCtlr.create('goback-swipe', {
|
gesture: gestureCtlr.createGesture({
|
||||||
|
name: GESTURE_GO_BACK_SWIPE,
|
||||||
priority: GesturePriority.GoBackSwipe,
|
priority: GesturePriority.GoBackSwipe,
|
||||||
disableScroll: DisableScroll.DuringCapture
|
disableScroll: true
|
||||||
})
|
})
|
||||||
}, options));
|
}, options));
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,7 @@ export const PLATFORM_CONFIGS: {[key: string]: PlatformConfig} = {
|
|||||||
swipeBackThreshold: 40,
|
swipeBackThreshold: 40,
|
||||||
tapPolyfill: isIOSDevice,
|
tapPolyfill: isIOSDevice,
|
||||||
virtualScrollEventAssist: !(window.indexedDB),
|
virtualScrollEventAssist: !(window.indexedDB),
|
||||||
|
disableScrollAssist: isIOSDevice,
|
||||||
},
|
},
|
||||||
isMatch(p: Platform) {
|
isMatch(p: Platform) {
|
||||||
return p.isPlatformMatch('ios', ['iphone', 'ipad', 'ipod'], ['windows phone']);
|
return p.isPlatformMatch('ios', ['iphone', 'ipad', 'ipod'], ['windows phone']);
|
||||||
|
@ -374,8 +374,11 @@ export const mockTabs = function(app?: App): Tabs {
|
|||||||
return new Tabs(null, null, app, config, elementRef, platform, renderer, linker);
|
return new Tabs(null, null, app, config, elementRef, platform, renderer, linker);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const mockMenu = function (): Menu {
|
export const mockMenu = function (): Menu {
|
||||||
return new Menu(null, null, null, null, null, null, null, null);
|
let app = mockApp();
|
||||||
|
let gestureCtrl = new GestureController(app);
|
||||||
|
return new Menu(null, null, null, null, null, null, null, gestureCtrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockDeepLinkConfig = function(links?: any[]): DeepLinkConfig {
|
export const mockDeepLinkConfig = function(links?: any[]): DeepLinkConfig {
|
||||||
|
Reference in New Issue
Block a user