mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 05:21:52 +08:00
refactor(gestures): using new DomController
This commit is contained in:
@ -4,7 +4,7 @@ import { List } from '../list/list';
|
||||
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';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -17,12 +17,16 @@ export class ItemSlidingGesture extends PanGesture {
|
||||
private firstCoordX: number;
|
||||
private firstTimestamp: number;
|
||||
|
||||
constructor(public list: List, gestureCtrl: GestureController) {
|
||||
constructor(
|
||||
public list: List,
|
||||
gestureCtrl: GestureController,
|
||||
domCtrl: DomController
|
||||
) {
|
||||
super(list.getNativeElement(), {
|
||||
maxAngle: 20,
|
||||
threshold: 10,
|
||||
threshold: 5,
|
||||
zone: false,
|
||||
debouncer: new NativeRafDebouncer(),
|
||||
domController: domCtrl,
|
||||
gesture: gestureCtrl.createGesture({
|
||||
name: GESTURE_ITEM_SWIPE,
|
||||
priority: GesturePriority.SlidingItem,
|
||||
|
@ -5,6 +5,7 @@ import { Ion } from '../ion';
|
||||
import { isTrueProperty } from '../../util/util';
|
||||
import { ItemSlidingGesture } from '../item/item-sliding-gesture';
|
||||
import { GestureController } from '../../gestures/gesture-controller';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* The List is a widely used interface element in almost any mobile app,
|
||||
@ -53,7 +54,8 @@ export class List extends Ion {
|
||||
config: Config,
|
||||
elementRef: ElementRef,
|
||||
renderer: Renderer,
|
||||
public _gestureCtrl: GestureController
|
||||
private _gestureCtrl: GestureController,
|
||||
private _domCtrl: DomController,
|
||||
) {
|
||||
super(config, elementRef, renderer, 'list');
|
||||
}
|
||||
@ -95,7 +97,7 @@ export class List extends Ion {
|
||||
|
||||
} else if (!this._slidingGesture) {
|
||||
console.debug('enableSlidingItems');
|
||||
this._slidingGesture = new ItemSlidingGesture(this, this._gestureCtrl);
|
||||
this._slidingGesture = new ItemSlidingGesture(this, this._gestureCtrl, this._domCtrl);
|
||||
this._slidingGesture.listen();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
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, GESTURE_MENU_SWIPE } from '../../gestures/gesture-controller';
|
||||
import { NativeRafDebouncer } from '../../util/debouncer';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* Gesture attached to the content which the menu is assigned to
|
||||
@ -12,24 +11,23 @@ export class MenuContentGesture extends SlideEdgeGesture {
|
||||
|
||||
constructor(
|
||||
public menu: Menu,
|
||||
contentEle: HTMLElement,
|
||||
gestureCtrl: GestureController,
|
||||
options: any = {}
|
||||
domCtrl: DomController,
|
||||
) {
|
||||
super(contentEle, assign({
|
||||
super(document.body, {
|
||||
direction: 'x',
|
||||
edge: menu.side,
|
||||
threshold: 5,
|
||||
maxEdgeStart: menu.maxEdgeStart || 50,
|
||||
zone: false,
|
||||
passive: true,
|
||||
debouncer: new NativeRafDebouncer(),
|
||||
domController: domCtrl,
|
||||
gesture: gestureCtrl.createGesture({
|
||||
name: GESTURE_MENU_SWIPE,
|
||||
priority: GesturePriority.MenuSwipe,
|
||||
disableScroll: true
|
||||
})
|
||||
}, options));
|
||||
});
|
||||
}
|
||||
|
||||
canStart(ev: any): boolean {
|
||||
@ -48,19 +46,19 @@ export class MenuContentGesture extends SlideEdgeGesture {
|
||||
// Set CSS, then wait one frame for it to apply before sliding starts
|
||||
onSlideBeforeStart(ev: any) {
|
||||
console.debug('menu gesture, onSlideBeforeStart', this.menu.side);
|
||||
this.menu.swipeBeforeStart();
|
||||
this.menu._swipeBeforeStart();
|
||||
}
|
||||
|
||||
onSlideStart() {
|
||||
console.debug('menu gesture, onSlideStart', this.menu.side);
|
||||
this.menu.swipeStart();
|
||||
this.menu._swipeStart();
|
||||
}
|
||||
|
||||
onSlide(slide: SlideData, ev: any) {
|
||||
let z = (this.menu.side === 'right' ? slide.min : slide.max);
|
||||
let stepValue = (slide.distance / z);
|
||||
|
||||
this.menu.swipeProgress(stepValue);
|
||||
this.menu._swipeProgress(stepValue);
|
||||
}
|
||||
|
||||
onSlideEnd(slide: SlideData, ev: any) {
|
||||
@ -84,7 +82,7 @@ export class MenuContentGesture extends SlideEdgeGesture {
|
||||
'shouldCompleteRight', shouldCompleteRight,
|
||||
'currentStepValue', currentStepValue);
|
||||
|
||||
this.menu.swipeEnd(shouldCompleteLeft, shouldCompleteRight, currentStepValue, velocity);
|
||||
this.menu._swipeEnd(shouldCompleteLeft, shouldCompleteRight, currentStepValue, velocity);
|
||||
}
|
||||
|
||||
getElementStartPos(slide: SlideData, ev: any) {
|
||||
|
@ -12,6 +12,7 @@ import { Platform } from '../../platform/platform';
|
||||
import { BlockerDelegate, GestureController, GESTURE_GO_BACK_SWIPE } from '../../gestures/gesture-controller';
|
||||
import { UIEventManager } from '../../util/ui-event-manager';
|
||||
import { Content } from '../content/content';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @name Menu
|
||||
@ -190,13 +191,14 @@ import { Content } from '../content/content';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class Menu {
|
||||
|
||||
private _cntEle: HTMLElement;
|
||||
private _cntGesture: MenuContentGesture;
|
||||
private _gesture: MenuContentGesture;
|
||||
private _type: MenuType;
|
||||
private _isEnabled: boolean = true;
|
||||
private _isSwipeEnabled: boolean = true;
|
||||
private _isAnimating: boolean = false;
|
||||
private _isPers: boolean = false;
|
||||
private _isPersistent: boolean = false;
|
||||
private _init: boolean = false;
|
||||
private _events: UIEventManager = new UIEventManager();
|
||||
private _gestureBlocker: BlockerDelegate;
|
||||
@ -269,11 +271,11 @@ export class Menu {
|
||||
*/
|
||||
@Input()
|
||||
get persistent(): boolean {
|
||||
return this._isPers;
|
||||
return this._isPersistent;
|
||||
}
|
||||
|
||||
set persistent(val: boolean) {
|
||||
this._isPers = isTrueProperty(val);
|
||||
this._isPersistent = isTrueProperty(val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,7 +307,8 @@ export class Menu {
|
||||
private _keyboard: Keyboard,
|
||||
private _zone: NgZone,
|
||||
private _gestureCtrl: GestureController,
|
||||
private _app: App
|
||||
private _domCtrl: DomController,
|
||||
private _app: App,
|
||||
) {
|
||||
this._gestureBlocker = _gestureCtrl.createBlocker({
|
||||
disable: [GESTURE_GO_BACK_SWIPE]
|
||||
@ -339,7 +342,7 @@ export class Menu {
|
||||
this.setElementAttribute('type', this.type);
|
||||
|
||||
// add the gestures
|
||||
this._cntGesture = new MenuContentGesture(this, <any>document, this._gestureCtrl);
|
||||
this._gesture = new MenuContentGesture(this, this._gestureCtrl, this._domCtrl);
|
||||
|
||||
// register listeners if this menu is enabled
|
||||
// check if more than one menu is on the same side
|
||||
@ -362,11 +365,10 @@ export class Menu {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onBackdropClick(ev: UIEvent): boolean {
|
||||
onBackdropClick(ev: UIEvent) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this._menuCtrl.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -376,17 +378,17 @@ export class Menu {
|
||||
if (!this._init) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gesture = this._gesture;
|
||||
// only listen/unlisten if the menu has initialized
|
||||
if (this._isEnabled && this._isSwipeEnabled && !this._cntGesture.isListening) {
|
||||
if (this._isEnabled && this._isSwipeEnabled && !gesture.isListening) {
|
||||
// should listen, but is not currently listening
|
||||
console.debug('menu, gesture listen', this.side);
|
||||
this._cntGesture.listen();
|
||||
gesture.listen();
|
||||
|
||||
} else if (this._cntGesture.isListening && (!this._isEnabled || !this._isSwipeEnabled)) {
|
||||
} else if (gesture.isListening && (!this._isEnabled || !this._isSwipeEnabled)) {
|
||||
// should not listen, but is currently listening
|
||||
console.debug('menu, gesture unlisten', this.side);
|
||||
this._cntGesture.unlisten();
|
||||
gesture.unlisten();
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,7 +426,6 @@ export class Menu {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -435,10 +436,7 @@ export class Menu {
|
||||
this._app.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
swipeBeforeStart() {
|
||||
_swipeBeforeStart() {
|
||||
if (!this.canSwipe()) {
|
||||
assert(false, 'canSwipe() has to be true');
|
||||
return;
|
||||
@ -446,44 +444,36 @@ export class Menu {
|
||||
this._before();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
swipeStart() {
|
||||
// user actively dragging the menu
|
||||
_swipeStart() {
|
||||
if (!this._isAnimating) {
|
||||
assert(false, '_isAnimating has to be true');
|
||||
return;
|
||||
}
|
||||
|
||||
this._getType().setProgressStart(this.isOpen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
swipeProgress(stepValue: number) {
|
||||
// user actively dragging the menu
|
||||
_swipeProgress(stepValue: number) {
|
||||
if (!this._isAnimating) {
|
||||
assert(false, '_isAnimating has to be true');
|
||||
return;
|
||||
}
|
||||
this._getType().setProgessStep(stepValue);
|
||||
|
||||
let ionDrag = this.ionDrag;
|
||||
this._getType().setProgessStep(stepValue);
|
||||
const ionDrag = this.ionDrag;
|
||||
if (ionDrag.observers.length > 0) {
|
||||
ionDrag.emit(stepValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
swipeEnd(shouldCompleteLeft: boolean, shouldCompleteRight: boolean, stepValue: number, velocity: number) {
|
||||
_swipeEnd(shouldCompleteLeft: boolean, shouldCompleteRight: boolean, stepValue: number, velocity: number) {
|
||||
if (!this._isAnimating) {
|
||||
assert(false, '_isAnimating has to be true');
|
||||
return;
|
||||
}
|
||||
|
||||
// user has finished dragging the menu
|
||||
let opening = !this.isOpen;
|
||||
const opening = !this.isOpen;
|
||||
let shouldComplete = false;
|
||||
if (opening) {
|
||||
shouldComplete = (this.side === 'right') ? shouldCompleteLeft : shouldCompleteRight;
|
||||
@ -511,6 +501,7 @@ export class Menu {
|
||||
|
||||
private _after(isOpen: boolean) {
|
||||
assert(this._isAnimating, '_before() should be called while animating');
|
||||
|
||||
// keep opening/closing the menu disabled for a touch more yet
|
||||
// only add listeners/css if it's enabled and isOpen
|
||||
// and only remove listeners/css if it's not open
|
||||
@ -660,10 +651,10 @@ export class Menu {
|
||||
ngOnDestroy() {
|
||||
this._menuCtrl.unregister(this);
|
||||
this._events.unlistenAll();
|
||||
this._cntGesture && this._cntGesture.destroy();
|
||||
this._gesture && this._gesture.destroy();
|
||||
this._type && this._type.destroy();
|
||||
|
||||
this._cntGesture = null;
|
||||
this._gesture = null;
|
||||
this._type = null;
|
||||
this._cntEle = null;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import { NavControllerBase } from '../../navigation/nav-controller-base';
|
||||
import { NavOptions } from '../../navigation/nav-util';
|
||||
import { TransitionController } from '../../transitions/transition-controller';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @name Nav
|
||||
@ -66,9 +67,10 @@ export class Nav extends NavControllerBase implements AfterViewInit {
|
||||
cfr: ComponentFactoryResolver,
|
||||
gestureCtrl: GestureController,
|
||||
transCtrl: TransitionController,
|
||||
@Optional() linker: DeepLinker
|
||||
@Optional() linker: DeepLinker,
|
||||
domCtrl: DomController,
|
||||
) {
|
||||
super(parent, app, config, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker);
|
||||
super(parent, app, config, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl);
|
||||
|
||||
if (viewCtrl) {
|
||||
// an ion-nav can also act as an ion-page within a parent ion-nav
|
||||
@ -149,6 +151,7 @@ export class Nav extends NavControllerBase implements AfterViewInit {
|
||||
}
|
||||
set swipeBackEnabled(val: boolean) {
|
||||
this._sbEnabled = isTrueProperty(val);
|
||||
this._swipeBackCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@ import { GestureController } from '../../gestures/gesture-controller';
|
||||
import { Keyboard } from '../../util/keyboard';
|
||||
import { NavControllerBase } from '../../navigation/nav-controller-base';
|
||||
import { TransitionController } from '../../transitions/transition-controller';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -26,9 +27,10 @@ export class OverlayPortal extends NavControllerBase {
|
||||
gestureCtrl: GestureController,
|
||||
transCtrl: TransitionController,
|
||||
@Optional() linker: DeepLinker,
|
||||
viewPort: ViewContainerRef
|
||||
viewPort: ViewContainerRef,
|
||||
domCtrl: DomController,
|
||||
) {
|
||||
super(null, app, config, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker);
|
||||
super(null, app, config, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl);
|
||||
this._isPortal = true;
|
||||
this._init = true;
|
||||
this.setViewport(viewPort);
|
||||
|
@ -13,7 +13,7 @@ import { TabButton } from './tab-button';
|
||||
import { Tabs } from './tabs';
|
||||
import { TransitionController } from '../../transitions/transition-controller';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @name Tab
|
||||
@ -273,10 +273,11 @@ export class Tab extends NavControllerBase {
|
||||
private _cd: ChangeDetectorRef,
|
||||
gestureCtrl: GestureController,
|
||||
transCtrl: TransitionController,
|
||||
@Optional() private linker: DeepLinker
|
||||
@Optional() private linker: DeepLinker,
|
||||
domCtrl: DomController,
|
||||
) {
|
||||
// A Tab is a NavController for its child pages
|
||||
super(parent, app, config, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker);
|
||||
super(parent, app, config, keyboard, elementRef, zone, renderer, cfr, gestureCtrl, transCtrl, linker, domCtrl);
|
||||
|
||||
this.id = parent.add(this);
|
||||
this._tabsHideOnSubPages = config.getBoolean('tabsHideOnSubPages');
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { GestureController, GesturePriority, GESTURE_TOGGLE } from '../../gestures/gesture-controller';
|
||||
import { PanGesture } from '../../gestures/drag-gesture';
|
||||
import { pointerCoord } from '../../util/dom';
|
||||
import { NativeRafDebouncer } from '../../util/debouncer';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
import { Toggle } from './toggle';
|
||||
|
||||
/**
|
||||
@ -9,11 +9,14 @@ import { Toggle } from './toggle';
|
||||
*/
|
||||
export class ToggleGesture extends PanGesture {
|
||||
|
||||
constructor(public toogle: Toggle, gestureCtrl: GestureController) {
|
||||
constructor(
|
||||
public toogle: Toggle,
|
||||
gestureCtrl: GestureController,
|
||||
domCtrl: DomController
|
||||
) {
|
||||
super(toogle.getNativeElement(), {
|
||||
maxAngle: 20,
|
||||
threshold: 0,
|
||||
debouncer: new NativeRafDebouncer(),
|
||||
domController: domCtrl,
|
||||
gesture: gestureCtrl.createGesture({
|
||||
name: GESTURE_TOGGLE,
|
||||
priority: GesturePriority.Toggle,
|
||||
|
@ -2,14 +2,15 @@ import { AfterContentInit, Component, ElementRef, EventEmitter, forwardRef, Host
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
|
||||
import { Config } from '../../config/config';
|
||||
import { Form, IonicTapInput } from '../../util/form';
|
||||
import { isTrueProperty, assert } from '../../util/util';
|
||||
import { Ion } from '../ion';
|
||||
import { Item } from '../item/item';
|
||||
import { Key } from '../../util/key';
|
||||
import { Haptic } from '../../util/haptic';
|
||||
import { ToggleGesture } from './toggle-gesture';
|
||||
import { GestureController } from '../../gestures/gesture-controller';
|
||||
import { Key } from '../../util/key';
|
||||
import { Haptic } from '../../util/haptic';
|
||||
import { Form, IonicTapInput } from '../../util/form';
|
||||
import { isTrueProperty, assert } from '../../util/util';
|
||||
import { DomController } from '../../util/dom-controller';
|
||||
|
||||
export const TOGGLE_VALUE_ACCESSOR: any = {
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
@ -118,7 +119,8 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
|
||||
renderer: Renderer,
|
||||
private _haptic: Haptic,
|
||||
@Optional() public _item: Item,
|
||||
private _gestureCtrl: GestureController
|
||||
private _gestureCtrl: GestureController,
|
||||
private _domCtrl: DomController
|
||||
) {
|
||||
super(config, elementRef, renderer, 'toggle');
|
||||
_form.register(this);
|
||||
@ -135,7 +137,7 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
|
||||
*/
|
||||
ngAfterContentInit() {
|
||||
this._init = true;
|
||||
this._gesture = new ToggleGesture(this, this._gestureCtrl);
|
||||
this._gesture = new ToggleGesture(this, this._gestureCtrl, this._domCtrl);
|
||||
this._gesture.listen();
|
||||
}
|
||||
|
||||
@ -143,6 +145,9 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
|
||||
* @private
|
||||
*/
|
||||
_onDragStart(startX: number) {
|
||||
assert(startX, 'startX must be valid');
|
||||
console.debug('toggle, _onDragStart', startX);
|
||||
|
||||
this._startX = startX;
|
||||
this._activated = true;
|
||||
}
|
||||
@ -151,9 +156,12 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
|
||||
* @private
|
||||
*/
|
||||
_onDragMove(currentX: number) {
|
||||
assert(this._startX, '_startX must be valid');
|
||||
if (!this._startX) {
|
||||
assert(false, '_startX must be valid');
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('toggle, pointerMove', currentX);
|
||||
console.debug('toggle, _onDragMove', currentX);
|
||||
|
||||
if (this._checked) {
|
||||
if (currentX + 15 < this._startX) {
|
||||
@ -175,7 +183,11 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
|
||||
* @private
|
||||
*/
|
||||
_onDragEnd(endX: number) {
|
||||
assert(this._startX, '_startX must be valid');
|
||||
if (!this._startX) {
|
||||
assert(false, '_startX must be valid');
|
||||
return;
|
||||
}
|
||||
console.debug('toggle, _onDragEnd', endX);
|
||||
|
||||
if (this.checked) {
|
||||
if (this._startX + 4 > endX) {
|
||||
|
@ -3,7 +3,7 @@ import { GestureDelegate } from '../gestures/gesture-controller';
|
||||
import { PanRecognizer } from './recognizers';
|
||||
import { PointerEvents, PointerEventsConfig, UIEventManager } from '../util/ui-event-manager';
|
||||
import { pointerCoord } from '../util/dom';
|
||||
import { Debouncer, FakeDebouncer } from '../util/debouncer';
|
||||
import { DomDebouncer, DomController } from '../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -13,7 +13,7 @@ export interface PanGestureConfig {
|
||||
maxAngle?: number;
|
||||
direction?: 'x' | 'y';
|
||||
gesture?: GestureDelegate;
|
||||
debouncer?: Debouncer;
|
||||
domController?: DomController;
|
||||
zone?: boolean;
|
||||
capture?: boolean;
|
||||
passive?: boolean;
|
||||
@ -24,7 +24,7 @@ export interface PanGestureConfig {
|
||||
*/
|
||||
export class PanGesture {
|
||||
|
||||
private debouncer: Debouncer;
|
||||
private debouncer: DomDebouncer;
|
||||
private events: UIEventManager = new UIEventManager(false);
|
||||
private pointerEvents: PointerEvents;
|
||||
private detector: PanRecognizer;
|
||||
@ -44,10 +44,9 @@ export class PanGesture {
|
||||
capture: false,
|
||||
passive: false,
|
||||
});
|
||||
|
||||
this.debouncer = (opts.debouncer)
|
||||
? opts.debouncer
|
||||
: new FakeDebouncer();
|
||||
if (opts.domController) {
|
||||
this.debouncer = opts.domController.debouncer();
|
||||
}
|
||||
this.gestute = opts.gesture;
|
||||
this.direction = opts.direction;
|
||||
this.eventsConfig = {
|
||||
@ -124,7 +123,7 @@ export class PanGesture {
|
||||
pointerMove(ev: any) {
|
||||
assert(this.started === true, 'started must be true');
|
||||
if (this.captured) {
|
||||
this.debouncer.debounce(() => {
|
||||
this.debouncer.write(() => {
|
||||
this.onDragMove(ev);
|
||||
});
|
||||
return;
|
||||
|
@ -120,6 +120,7 @@ export class GestureController {
|
||||
if (maxPriority === priority) {
|
||||
this.capturedID = id;
|
||||
this.requestedStart = {};
|
||||
console.debug(`${gestureName} captured!`);
|
||||
return true;
|
||||
}
|
||||
delete requestedStart[id];
|
||||
@ -170,12 +171,13 @@ export class GestureController {
|
||||
|
||||
canStart(gestureName: string): boolean {
|
||||
if (this.capturedID) {
|
||||
console.debug(`${gestureName} can not start becuse gesture was already captured`);
|
||||
// a gesture already captured
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isDisabled(gestureName)) {
|
||||
console.debug('GestureController: Disabled', gestureName);
|
||||
console.debug(`${gestureName} is disabled`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -17,7 +17,7 @@ import { NavParams } from './nav-params';
|
||||
import { SwipeBackGesture } from './swipe-back';
|
||||
import { Transition } from '../transitions/transition';
|
||||
import { TransitionController } from '../transitions/transition-controller';
|
||||
|
||||
import { DomController } from '../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -32,7 +32,6 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
_queue: TransitionInstruction[] = [];
|
||||
_sbEnabled: boolean;
|
||||
_sbGesture: SwipeBackGesture;
|
||||
_sbThreshold: number;
|
||||
_sbTrns: Transition;
|
||||
_trnsId: number = null;
|
||||
_trnsTm: boolean = false;
|
||||
@ -60,12 +59,12 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
public _cfr: ComponentFactoryResolver,
|
||||
public _gestureCtrl: GestureController,
|
||||
public _trnsCtrl: TransitionController,
|
||||
public _linker: DeepLinker
|
||||
public _linker: DeepLinker,
|
||||
private _domCtrl: DomController
|
||||
) {
|
||||
super(config, elementRef, renderer);
|
||||
|
||||
this._sbEnabled = config.getBoolean('swipeBackEnabled');
|
||||
this._sbThreshold = config.getNumber('swipeBackThreshold', 0);
|
||||
|
||||
this.id = 'n' + (++ctrlIds);
|
||||
}
|
||||
@ -151,12 +150,12 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}
|
||||
|
||||
setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> {
|
||||
let viewControllers = [convertToView(this._linker, pageOrViewCtrl, params)];
|
||||
const viewControllers = [convertToView(this._linker, pageOrViewCtrl, params)];
|
||||
return this._setPages(viewControllers, opts, done);
|
||||
}
|
||||
|
||||
setPages(pages: any[], opts?: NavOptions, done?: Function): Promise<any> {
|
||||
let viewControllers = convertToViews(this._linker, pages);
|
||||
const viewControllers = convertToViews(this._linker, pages);
|
||||
return this._setPages(viewControllers, opts, done);
|
||||
}
|
||||
|
||||
@ -199,7 +198,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
|
||||
// let's see if there's another to kick off
|
||||
this.setTransitioning(false);
|
||||
this._sbCheck();
|
||||
this._swipeBackCheck();
|
||||
this._nextTrns();
|
||||
};
|
||||
|
||||
@ -226,7 +225,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
|
||||
// let's see if there's another to kick off
|
||||
this.setTransitioning(false);
|
||||
this._sbCheck();
|
||||
this._swipeBackCheck();
|
||||
this._nextTrns();
|
||||
};
|
||||
|
||||
@ -306,7 +305,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
assert(isPresent(ti.removeStart), 'removeView needs removeStart');
|
||||
assert(isPresent(ti.removeCount), 'removeView needs removeCount');
|
||||
|
||||
let index = this._views.indexOf(ti.removeView);
|
||||
var index = this._views.indexOf(ti.removeView);
|
||||
if (index >= 0) {
|
||||
ti.removeStart += index;
|
||||
}
|
||||
@ -342,10 +341,10 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
|
||||
const removeStart = ti.removeStart;
|
||||
if (isPresent(removeStart)) {
|
||||
const views = this._views;
|
||||
const removeEnd = removeStart + ti.removeCount;
|
||||
let i: number;
|
||||
let view: ViewController;
|
||||
var views = this._views;
|
||||
var removeEnd = removeStart + ti.removeCount;
|
||||
var i: number;
|
||||
var view: ViewController;
|
||||
for (i = views.length - 1; i >= 0; i--) {
|
||||
view = views[i];
|
||||
if ((i < removeStart || i >= removeEnd) && view !== leavingView) {
|
||||
@ -507,7 +506,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
if (leavingView) {
|
||||
const leavingTestResult = leavingView._lifecycleTest('Leave');
|
||||
var leavingTestResult = leavingView._lifecycleTest('Leave');
|
||||
|
||||
if (leavingTestResult === false) {
|
||||
// synchronous reject
|
||||
@ -520,7 +519,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}
|
||||
|
||||
if (enteringView) {
|
||||
const enteringTestResult = enteringView._lifecycleTest('Enter');
|
||||
var enteringTestResult = enteringView._lifecycleTest('Enter');
|
||||
|
||||
if (enteringTestResult === false) {
|
||||
// synchronous reject
|
||||
@ -564,7 +563,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
direction: opts.direction,
|
||||
duration: (opts.animate === false ? 0 : opts.duration),
|
||||
easing: opts.easing,
|
||||
isRTL: this.config.platform.isRTL(),
|
||||
isRTL: this._config.platform.isRTL(),
|
||||
ev: opts.ev,
|
||||
};
|
||||
|
||||
@ -627,9 +626,9 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
|
||||
// we should animate (duration > 0) if the pushed page is not the first one (startup)
|
||||
// or if it is a portal (modal, actionsheet, etc.)
|
||||
let isFirstPage = !this._init && this._views.length === 1;
|
||||
let shouldNotAnimate = isFirstPage && !this._isPortal;
|
||||
let canNotAnimate = this.config.get('animate') === false;
|
||||
const isFirstPage = !this._init && this._views.length === 1;
|
||||
const shouldNotAnimate = isFirstPage && !this._isPortal;
|
||||
const canNotAnimate = this._config.get('animate') === false;
|
||||
if (shouldNotAnimate || canNotAnimate) {
|
||||
opts.animate = false;
|
||||
}
|
||||
@ -743,7 +742,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}
|
||||
|
||||
_insertViewAt(view: ViewController, index: number) {
|
||||
var existingIndex = this._views.indexOf(view);
|
||||
const existingIndex = this._views.indexOf(view);
|
||||
if (existingIndex > -1) {
|
||||
// this view is already in the stack!!
|
||||
// move it to its new location
|
||||
@ -897,10 +896,14 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
for (var view of this._views) {
|
||||
const views = this._views;
|
||||
let view: ViewController;
|
||||
for (var i = 0; i < views.length; i++) {
|
||||
view = views[i];
|
||||
view._willUnload();
|
||||
view._destroy(this._renderer);
|
||||
}
|
||||
|
||||
// purge stack
|
||||
this._views.length = 0;
|
||||
|
||||
@ -947,35 +950,26 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
swipeBackEnd(shouldComplete: boolean, currentStepValue: number, velocity: number) {
|
||||
if (this._sbTrns && this._sbGesture) {
|
||||
// the swipe back gesture has ended
|
||||
const dur = this._sbTrns.getDuration() / (Math.abs(velocity) + 1);
|
||||
var dur = this._sbTrns.getDuration() / (Math.abs(velocity) + 1);
|
||||
this._sbTrns.progressEnd(shouldComplete, currentStepValue, dur);
|
||||
}
|
||||
}
|
||||
|
||||
_sbCheck() {
|
||||
if (!this._sbEnabled && this._isPortal) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this nav controller can have swipe to go back
|
||||
if (!this._sbGesture) {
|
||||
// create the swipe back gesture if we haven't already
|
||||
const opts = {
|
||||
edge: 'left',
|
||||
threshold: this._sbThreshold
|
||||
};
|
||||
this._sbGesture = new SwipeBackGesture(this, document.body, this._gestureCtrl, opts);
|
||||
}
|
||||
|
||||
_swipeBackCheck() {
|
||||
if (this.canSwipeBack()) {
|
||||
if (!this._sbGesture) {
|
||||
this._sbGesture = new SwipeBackGesture(this, this._gestureCtrl, this._domCtrl);
|
||||
}
|
||||
this._sbGesture.listen();
|
||||
} else {
|
||||
|
||||
} else if (this._sbGesture) {
|
||||
this._sbGesture.unlisten();
|
||||
}
|
||||
}
|
||||
|
||||
canSwipeBack(): boolean {
|
||||
return (this._sbEnabled &&
|
||||
!this._isPortal &&
|
||||
!this._children.length &&
|
||||
!this.isTransitioning() &&
|
||||
this._app.isEnabled() &&
|
||||
@ -984,7 +978,7 @@ export class NavControllerBase extends Ion implements NavController {
|
||||
|
||||
canGoBack(): boolean {
|
||||
const activeView = this.getActive();
|
||||
return !!(activeView && activeView.enableBack()) || false;
|
||||
return !!(activeView && activeView.enableBack());
|
||||
}
|
||||
|
||||
isTransitioning(): boolean {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { assign, swipeShouldReset } from '../util/util';
|
||||
import { swipeShouldReset } from '../util/util';
|
||||
import { GestureController, GesturePriority, GESTURE_GO_BACK_SWIPE } from '../gestures/gesture-controller';
|
||||
import { NavControllerBase } from './nav-controller-base';
|
||||
import { SlideData } from '../gestures/slide-gesture';
|
||||
import { SlideEdgeGesture } from '../gestures/slide-edge-gesture';
|
||||
import { NativeRafDebouncer } from '../util/debouncer';
|
||||
import { DomController } from '../util/dom-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@ -12,22 +12,22 @@ export class SwipeBackGesture extends SlideEdgeGesture {
|
||||
|
||||
constructor(
|
||||
private _nav: NavControllerBase,
|
||||
element: HTMLElement,
|
||||
gestureCtlr: GestureController,
|
||||
options: any,
|
||||
domCtrl: DomController,
|
||||
) {
|
||||
super(element, assign({
|
||||
super(document.body, {
|
||||
direction: 'x',
|
||||
edge: 'left',
|
||||
maxEdgeStart: 75,
|
||||
zone: false,
|
||||
threshold: 5,
|
||||
debouncer: new NativeRafDebouncer(),
|
||||
zone: false,
|
||||
domController: domCtrl,
|
||||
gesture: gestureCtlr.createGesture({
|
||||
name: GESTURE_GO_BACK_SWIPE,
|
||||
priority: GesturePriority.GoBackSwipe,
|
||||
disableScroll: true
|
||||
})
|
||||
}, options));
|
||||
});
|
||||
}
|
||||
|
||||
canStart(ev: any): boolean {
|
||||
|
@ -7,29 +7,83 @@ import { nativeRaf } from './dom';
|
||||
import { removeArrayItem } from './util';
|
||||
|
||||
|
||||
export type DomCallback = { (timeStamp: number) };
|
||||
|
||||
export class DomDebouncer {
|
||||
|
||||
private writeTask: Function = null;
|
||||
private readTask: Function = null;
|
||||
|
||||
constructor(private dom: DomController) { }
|
||||
|
||||
read(fn: DomCallback): Function {
|
||||
if (this.readTask) {
|
||||
return;
|
||||
}
|
||||
return this.readTask = this.dom.read((t) => {
|
||||
this.readTask = null;
|
||||
fn(t);
|
||||
});
|
||||
}
|
||||
|
||||
write(fn: DomCallback, ctx?: any): Function {
|
||||
if (this.writeTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.writeTask = this.dom.write((t) => {
|
||||
this.writeTask = null;
|
||||
fn(t);
|
||||
});
|
||||
}
|
||||
|
||||
cancel() {
|
||||
const writeTask = this.writeTask;
|
||||
writeTask && this.dom.cancelW(writeTask);
|
||||
this.writeTask = null;
|
||||
|
||||
const readTask = this.readTask;
|
||||
readTask && this.dom.cancelR(readTask);
|
||||
this.readTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
export class DomController {
|
||||
|
||||
private r: Function[] = [];
|
||||
private w: Function[] = [];
|
||||
private q: boolean;
|
||||
|
||||
read(fn: {(timeStamp: number)}, ctx?: any): Function {
|
||||
debouncer(): DomDebouncer {
|
||||
return new DomDebouncer(this);
|
||||
}
|
||||
|
||||
read(fn: DomCallback, ctx?: any): Function {
|
||||
const task = !ctx ? fn : fn.bind(ctx);
|
||||
this.r.push(task);
|
||||
this.queue();
|
||||
return task;
|
||||
}
|
||||
|
||||
write(fn: {(timeStamp: number)}, ctx?: any): Function {
|
||||
write(fn: DomCallback, ctx?: any): Function {
|
||||
const task = !ctx ? fn : fn.bind(ctx);
|
||||
this.w.push(task);
|
||||
this.queue();
|
||||
return task;
|
||||
}
|
||||
|
||||
cancel(task: any) {
|
||||
cancel(task: any): boolean {
|
||||
return removeArrayItem(this.r, task) || removeArrayItem(this.w, task);
|
||||
}
|
||||
|
||||
cancelW(task: any): boolean {
|
||||
return removeArrayItem(this.w, task);
|
||||
}
|
||||
|
||||
cancelR(task: any): boolean {
|
||||
return removeArrayItem(this.r, task);
|
||||
}
|
||||
|
||||
protected queue() {
|
||||
const self = this;
|
||||
if (!self.q) {
|
||||
@ -41,32 +95,32 @@ export class DomController {
|
||||
}
|
||||
|
||||
protected flush(timeStamp: number) {
|
||||
let err;
|
||||
let task;
|
||||
|
||||
try {
|
||||
this.dispatch(timeStamp);
|
||||
} finally {
|
||||
this.q = false;
|
||||
}
|
||||
}
|
||||
|
||||
private dispatch(timeStamp: number) {
|
||||
let i: number;
|
||||
const r = this.r;
|
||||
const rLen = r.length;
|
||||
const w = this.w;
|
||||
const wLen = w.length;
|
||||
|
||||
// ******** DOM READS ****************
|
||||
while (task = this.r.shift()) {
|
||||
task(timeStamp);
|
||||
for (i = 0; i < rLen; i++) {
|
||||
r[i](timeStamp);
|
||||
}
|
||||
|
||||
// ******** DOM WRITES ****************
|
||||
while (task = this.w.shift()) {
|
||||
task(timeStamp);
|
||||
}
|
||||
} catch (e) {
|
||||
err = e;
|
||||
for (i = 0; i < wLen; i++) {
|
||||
w[i](timeStamp);
|
||||
}
|
||||
|
||||
this.q = false;
|
||||
|
||||
if (this.r.length || this.w.length) {
|
||||
this.queue();
|
||||
}
|
||||
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
r.length = 0;
|
||||
w.length = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import { ViewController } from '../navigation/view-controller';
|
||||
|
||||
import { NavControllerBase } from '../navigation/nav-controller-base';
|
||||
import { Haptic } from './haptic';
|
||||
import { DomController } from './dom-controller';
|
||||
|
||||
export const mockConfig = function(config?: any, url: string = '/', platform?: Platform) {
|
||||
const c = new Config();
|
||||
@ -246,6 +247,8 @@ export const mockNavController = function(): NavControllerBase {
|
||||
|
||||
let trnsCtrl = mockTrasitionController(config);
|
||||
|
||||
let dom = new DomController();
|
||||
|
||||
let nav = new NavControllerBase(
|
||||
null,
|
||||
app,
|
||||
@ -257,7 +260,8 @@ export const mockNavController = function(): NavControllerBase {
|
||||
componentFactoryResolver,
|
||||
gestureCtrl,
|
||||
trnsCtrl,
|
||||
linker
|
||||
linker,
|
||||
dom,
|
||||
);
|
||||
|
||||
nav._viewInit = function(enteringView: ViewController) {
|
||||
@ -296,6 +300,8 @@ export const mockOverlayPortal = function(app: App, config: Config, platform: Pl
|
||||
|
||||
let deepLinker = new DeepLinker(app, serializer, location);
|
||||
|
||||
let dom = new DomController();
|
||||
|
||||
return new OverlayPortal(
|
||||
app,
|
||||
config,
|
||||
@ -307,7 +313,8 @@ export const mockOverlayPortal = function(app: App, config: Config, platform: Pl
|
||||
gestureCtrl,
|
||||
null,
|
||||
deepLinker,
|
||||
null
|
||||
null,
|
||||
dom
|
||||
);
|
||||
};
|
||||
|
||||
@ -334,6 +341,8 @@ export const mockTab = function(parentTabs: Tabs): Tab {
|
||||
|
||||
let linker = mockDeepLinker(null, app);
|
||||
|
||||
let dom = new DomController();
|
||||
|
||||
let tab = new Tab(
|
||||
parentTabs,
|
||||
app,
|
||||
@ -346,7 +355,8 @@ export const mockTab = function(parentTabs: Tabs): Tab {
|
||||
changeDetectorRef,
|
||||
gestureCtrl,
|
||||
null,
|
||||
linker
|
||||
linker,
|
||||
dom
|
||||
);
|
||||
|
||||
tab.load = (opts: any, cb: Function) => {
|
||||
@ -371,7 +381,8 @@ export const mockTabs = function(app?: App): Tabs {
|
||||
export const mockMenu = function (): Menu {
|
||||
let app = mockApp();
|
||||
let gestureCtrl = new GestureController(app);
|
||||
return new Menu(null, null, null, null, null, null, null, gestureCtrl, app);
|
||||
let dom = new DomController();
|
||||
return new Menu(null, null, null, null, null, null, null, gestureCtrl, dom, app);
|
||||
};
|
||||
|
||||
export const mockDeepLinkConfig = function(links?: any[]): DeepLinkConfig {
|
||||
|
Reference in New Issue
Block a user