Skip to content

Commit

Permalink
fix(toggle): uses PanGesture abstraction
Browse files Browse the repository at this point in the history
fixes #9428
  • Loading branch information
manucorporat committed Dec 1, 2016
1 parent 0b642e7 commit 6ef6f0a
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 97 deletions.
20 changes: 20 additions & 0 deletions src/components/app/test/gesture-collision/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
</ion-item-options>
</ion-item-sliding>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle item-left></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle></ion-toggle>
</ion-item>

<button ion-item menuClose="left" class="e2eCloseLeftMenu" detail-none>
Close Menu
</button>
Expand Down Expand Up @@ -94,6 +104,16 @@

<ion-list>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle item-left></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle></ion-toggle>
</ion-item>

<button ion-item *ngFor="let p of pages" (click)="openPage(p)">
{{p.title}}
</button>
Expand Down
10 changes: 10 additions & 0 deletions src/components/app/test/gesture-collision/page1.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ <h3>Page 1</h3>
</ion-item-options>
</ion-item-sliding>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle item-left></ion-toggle>
</ion-item>

<ion-item>
<ion-label>Apple</ion-label>
<ion-toggle></ion-toggle>
</ion-item>

<button ion-item (click)="goToPage1()">Push same page</button>

<ion-item>
Expand Down
45 changes: 45 additions & 0 deletions src/components/toggle/toggle-gesture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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 { Toggle } from './toggle';

/**
* @private
*/
export class ToggleGesture extends PanGesture {

constructor(public toogle: Toggle, gestureCtrl: GestureController) {
super(toogle.getNativeElement(), {
maxAngle: 20,
threshold: 0,
debouncer: new NativeRafDebouncer(),
gesture: gestureCtrl.createGesture({
name: GESTURE_TOGGLE,
priority: GesturePriority.Toggle,
})
});
}

canStart(ev: any): boolean {
return true;
}

onDragStart(ev: any) {
ev.preventDefault();

this.toogle._onDragStart(pointerCoord(ev).x);
}

onDragMove(ev: any) {
ev.preventDefault();

this.toogle._onDragMove(pointerCoord(ev).x);
}

onDragEnd(ev: any) {
ev.preventDefault();

this.toogle._onDragEnd(pointerCoord(ev).x);
}
}
114 changes: 48 additions & 66 deletions src/components/toggle/toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import { Config } from '../../config/config';
import { Form, IonicTapInput } from '../../util/form';
import { isTrueProperty } from '../../util/util';
import { isTrueProperty, assert } from '../../util/util';
import { Ion } from '../ion';
import { Item } from '../item/item';
import { pointerCoord } from '../../util/dom';
import { Key } from '../../util/key';
import { Haptic } from '../../util/haptic';
import { UIEventManager } from '../../util/ui-event-manager';
import { ToggleGesture } from './toggle-gesture';
import { GestureController } from '../../gestures/gesture-controller';

export const TOGGLE_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -76,28 +76,18 @@ export const TOGGLE_VALUE_ACCESSOR: any = {
encapsulation: ViewEncapsulation.None,
})
export class Toggle extends Ion implements IonicTapInput, AfterContentInit, ControlValueAccessor, OnDestroy {
/** @private */

_checked: boolean = false;
/** @private */
_init: boolean = false;
/** @private */
_disabled: boolean = false;
/** @private */
_labelId: string;
/** @private */
_activated: boolean = false;
/** @private */
_startX: number;
/** @private */
_msPrv: number = 0;
/** @private */
_fn: Function = null;
/** @private */
_events: UIEventManager = new UIEventManager();
_gesture: ToggleGesture;

/**
* @private
*/
/** @private */
id: string;

/**
Expand Down Expand Up @@ -126,8 +116,9 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
config: Config,
elementRef: ElementRef,
renderer: Renderer,
public _haptic: Haptic,
@Optional() public _item: Item
private _haptic: Haptic,
@Optional() public _item: Item,
private _gestureCtrl: GestureController
) {
super(config, elementRef, renderer, 'toggle');
_form.register(this);
Expand All @@ -142,59 +133,63 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
/**
* @private
*/
pointerDown(ev: UIEvent): boolean {
this._startX = pointerCoord(ev).x;
ngAfterContentInit() {
this._init = true;
this._gesture = new ToggleGesture(this, this._gestureCtrl);
this._gesture.listen();
}

/**
* @private
*/
_onDragStart(startX: number) {
this._startX = startX;
this._activated = true;
return true;
}

/**
* @private
*/
pointerMove(ev: UIEvent) {
if (this._startX) {
let currentX = pointerCoord(ev).x;
console.debug('toggle, pointerMove', ev.type, currentX);

if (this._checked) {
if (currentX + 15 < this._startX) {
this.onChange(false);
this._haptic.selection();
this._startX = currentX;
this._activated = true;
}

} else if (currentX - 15 > this._startX) {
this.onChange(true);
// Create a haptic event
_onDragMove(currentX: number) {
assert(this._startX, '_startX must be valid');

console.debug('toggle, pointerMove', currentX);

if (this._checked) {
if (currentX + 15 < this._startX) {
this.onChange(false);
this._haptic.selection();
this._startX = currentX;
this._activated = (currentX < this._startX + 5);
this._activated = true;
}

} else if (currentX - 15 > this._startX) {
this.onChange(true);
this._haptic.selection();
this._startX = currentX;
this._activated = (currentX < this._startX + 5);
}
}

/**
* @private
*/
pointerUp(ev: UIEvent) {
if (this._startX) {
let endX = pointerCoord(ev).x;

if (this.checked) {
if (this._startX + 4 > endX) {
this.onChange(false);
this._haptic.selection();
}

} else if (this._startX - 4 < endX) {
this.onChange(true);
_onDragEnd(endX: number) {
assert(this._startX, '_startX must be valid');

if (this.checked) {
if (this._startX + 4 > endX) {
this.onChange(false);
this._haptic.selection();
}

this._activated = false;
this._startX = null;
} else if (this._startX - 4 < endX) {
this.onChange(true);
this._haptic.selection();
}

this._activated = false;
this._startX = null;
}

/**
Expand Down Expand Up @@ -273,19 +268,6 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
*/
onTouched() {}

/**
* @private
*/
ngAfterContentInit() {
this._init = true;
this._events.pointerEvents({
elementRef: this._elementRef,
pointerDown: this.pointerDown.bind(this),
pointerMove: this.pointerMove.bind(this),
pointerUp: this.pointerUp.bind(this)
});
}

/**
* @private
*/
Expand All @@ -310,7 +292,7 @@ export class Toggle extends Ion implements IonicTapInput, AfterContentInit, Cont
*/
ngOnDestroy() {
this._form.deregister(this);
this._events.unlistenAll();
this._gesture.destroy();
this._fn = null;
}

Expand Down
75 changes: 50 additions & 25 deletions src/gestures/drag-gesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface PanGestureConfig {
* @private
*/
export class PanGesture {

private debouncer: Debouncer;
private events: UIEventManager = new UIEventManager(false);
private pointerEvents: PointerEvents;
Expand Down Expand Up @@ -58,7 +59,9 @@ export class PanGesture {
capture: opts.capture,
passive: opts.passive
};
this.detector = new PanRecognizer(opts.direction, opts.threshold, opts.maxAngle);
if (opts.threshold > 0) {
this.detector = new PanRecognizer(opts.direction, opts.threshold, opts.maxAngle);
}
}

listen() {
Expand Down Expand Up @@ -100,40 +103,42 @@ export class PanGesture {
return false;
}
}

let coord = pointerCoord(ev);
this.detector.start(coord);
this.started = true;
this.captured = false;

const coord = pointerCoord(ev);
if (this.detector) {
this.detector.start(coord);

} else {
if (!this.tryToCapture(ev)) {
this.started = false;
this.captured = false;
this.gestute.release();
return false;
}
}
return true;
}

pointerMove(ev: any) {
if (!this.started) {
assert(this.started === true, 'started must be true');
if (this.captured) {
this.debouncer.debounce(() => {
this.onDragMove(ev);
});
return;
}
this.debouncer.debounce(() => {
if (this.captured) {
this.onDragMove(ev);
return;
}
let coord = pointerCoord(ev);
if (this.detector.detect(coord)) {

if (this.detector.pan() !== 0 &&
(!this.gestute || this.gestute.capture())) {
this.onDragStart(ev);
this.captured = true;
return;
}

// Detection/capturing was not successful, aborting!
this.started = false;
this.captured = false;
this.pointerEvents.stop();
this.notCaptured(ev);
assert(this.detector, 'detector has to be valid');
const coord = pointerCoord(ev);
if (this.detector.detect(coord)) {
if (this.detector.pan() !== 0) {
if (!this.tryToCapture(ev)) {
this.abort(ev);
}
}
});
}
}

pointerUp(ev: any) {
Expand All @@ -151,6 +156,26 @@ export class PanGesture {
this.started = false;
}

tryToCapture(ev: any): boolean {
assert(this.started === true, 'started has be true');
assert(this.captured === false, 'captured has be false');

if (this.gestute && !this.gestute.capture()) {
return false;
}
this.onDragStart(ev);
this.captured = true;
return true;
}

abort(ev: any) {
this.started = false;
this.captured = false;
this.gestute.release();
this.pointerEvents.stop();
this.notCaptured(ev);
}

getNativeElement(): HTMLElement {
return this.element;
}
Expand Down
Loading

0 comments on commit 6ef6f0a

Please sign in to comment.