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