Skip to content

Commit

Permalink
fix(content): scroll listener is auto enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Mar 29, 2017
1 parent 54acc74 commit bfe533f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 46 deletions.
64 changes: 52 additions & 12 deletions src/components/content/content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';

import { App } from '../app/app';
import { Config } from '../../config/config';
Expand Down Expand Up @@ -125,7 +125,7 @@ export { ScrollEvent } from '../../util/scroll-view';
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class Content extends Ion implements OnDestroy {
export class Content extends Ion implements OnDestroy, AfterViewInit {
/** @internal */
_cTop: number;
/** @internal */
Expand Down Expand Up @@ -311,18 +311,37 @@ export class Content extends Ion implements OnDestroy {

/**
* @output {ScrollEvent} Emitted when the scrolling first starts.
* If it is used programatically, scroll events must be enabled explicitally with `enableScrollListener()`:
*
* ```ts
* content.ionScrollStart((ev) => onEvent(ev));
* content.enableScrollListener();
* ```
*
*/
@Output() ionScrollStart: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();

/**
* @output {ScrollEvent} Emitted on every scroll event.
*/
@Output() ionScroll: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();
* If it is used programatically, scroll events must be enabled explicitally with `enableScrollListener()`:
*
* ```ts
* content.ionScroll((ev) => onEvent(ev));
* content.enableScrollListener();
* ```
*
*/ @Output() ionScroll: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();

/**
* @output {ScrollEvent} Emitted when scrolling ends.
*/
@Output() ionScrollEnd: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();
* If it is used programatically, scroll events must be enabled explicitally with `enableScrollListener()`:
*
* ```ts
* content.ionScrollEnd((ev) => onEvent(ev));
* content.enableScrollListener();
* ```
*
*/ @Output() ionScrollEnd: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();


constructor(
Expand All @@ -348,7 +367,8 @@ export class Content extends Ion implements OnDestroy {
// goal is to completely remove this when iOS
// fully supports scroll events
// listen to JS scroll events
this._scroll = new ScrollView(_plt, _dom, config.getBoolean('virtualScrollEventAssist'));
const jsScroll = config.getBoolean('virtualScrollEventAssist');
this._scroll = new ScrollView(_app, _plt, _dom, jsScroll);

while (navCtrl) {
if (isTabs(<any>navCtrl)) {
Expand Down Expand Up @@ -383,7 +403,7 @@ export class Content extends Ion implements OnDestroy {
/**
* @hidden
*/
enableScrollListener() {
ngAfterViewInit() {
assert(this.getFixedElement(), 'fixed element was not found');
assert(this.getScrollElement(), 'scroll element was not found');

Expand All @@ -398,9 +418,6 @@ export class Content extends Ion implements OnDestroy {

// subscribe to every scroll move
scroll.onScroll = (ev) => {
// remind the app that it's currently scrolling
this._app.setScrolling();

// emit to all of our other friends things be scrolling
this.ionScroll.emit(ev);

Expand All @@ -414,7 +431,30 @@ export class Content extends Ion implements OnDestroy {
this.imgsUpdate();
};

scroll.setEnabled();
if (this.hasScrollObservers()) {
console.debug('Auto enabling scroll listener');
this.enableScrollListener();
}
}

/**
* @hidden
*/
hasScrollObservers(): boolean {
return this.ionScroll.observers.length > 0 ||
this.ionScrollStart.observers.length > 0 ||
this.ionScrollEnd.observers.length > 0;
}

/**
* Enables scroll events listening. By default, scroll events are disabled, so
* subscribing to `(ionScroll)`, `(ionScrollStart)` and `(ionScrollEnd)` will not fire any event.
*
* Listening for scroll events is an expensive operation, that runs at 60FPS.
* So it is a good idea to keep it disabled as long you are not using them.
*/
enableScrollListener() {
this._scroll.eventsEnabled = true;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/util/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ export function setupEvents(plt: Platform, dom: DomController): Events {
let contentEle = <any>el.closest('.scroll-content');
if (contentEle) {
var style = contentEle.style;
var scroll = new ScrollView(plt, dom, false);
scroll.init(contentEle, 0, 0);
var scroll = new ScrollView(null, plt, dom, false);
scroll._el = contentEle;
// We need to stop scrolling if it's happening and scroll up

style['WebkitBackfaceVisibility'] = 'hidden';
Expand Down
56 changes: 24 additions & 32 deletions src/util/scroll-view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import { assert } from './util';
import { App } from '../components/app/app';
import { DomController, DomCallback } from '../platform/dom-controller';
import { Platform, EventListenerOptions } from '../platform/platform';
import { pointerCoord } from './dom';
Expand All @@ -12,11 +13,11 @@ export class ScrollView {
onScroll: (ev: ScrollEvent) => void;
onScrollEnd: (ev: ScrollEvent) => void;
initialized: boolean = false;
enabled: boolean = false;
eventsEnabled: boolean = false;
contentTop: number;
contentBottom: number;

private _el: HTMLElement;
_el: HTMLElement;
private _js: boolean;
private _t: number = 0;
private _l: number = 0;
Expand All @@ -25,6 +26,7 @@ export class ScrollView {


constructor(
private _app: App,
private _plt: Platform,
private _dom: DomController,
virtualScrollEventAssist: boolean
Expand Down Expand Up @@ -60,35 +62,19 @@ export class ScrollView {

if (!this.initialized) {
this.initialized = true;

if (this.enabled) {
this.enable();
}
}
}

setEnabled() {
if (!this.enabled) {
this.enabled = true;
if (this.initialized) {
this.enable();
if (this._js) {
this.enableJsScroll();
} else {
this.enableNativeScrolling();
}
}
}

enable() {
assert(this.initialized, 'scroll must be initialized');
assert(this.enabled, 'scroll-view must be enabled');
assert(this._el, 'scroll-view, element can not be null');

if (this._js) {
this.enableJsScroll();
} else {
this.enableNativeScrolling();
}
}

private enableNativeScrolling() {
assert(this.onScrollStart, 'onScrollStart is not defined');
assert(this.onScroll, 'onScroll is not defined');
assert(this.onScrollEnd, 'onScrollEnd is not defined');

this._js = false;
if (!this._el) {
return;
Expand All @@ -101,6 +87,14 @@ export class ScrollView {
const positions: number[] = [];

function scrollCallback(scrollEvent: UIEvent) {
// remind the app that it's currently scrolling
self._app.setScrolling();

// if events are disabled, we do nothing
if (!self.eventsEnabled) {
return;
}

ev.timeStamp = scrollEvent.timeStamp;
// Event.timeStamp is 0 in firefox
if (!ev.timeStamp) {
Expand Down Expand Up @@ -151,13 +145,12 @@ export class ScrollView {

if (startPos !== endPos) {
// compute relative movement between these two points
var timeOffset = (positions[endPos] - positions[startPos]);
var movedTop = (positions[startPos - 2] - positions[endPos - 2]);
var movedLeft = (positions[startPos - 1] - positions[endPos - 1]);

var factor = FRAME_MS / (positions[endPos] - positions[startPos]);
// based on XXms compute the movement to apply for each render step
ev.velocityY = ((movedTop / timeOffset) * FRAME_MS);
ev.velocityX = ((movedLeft / timeOffset) * FRAME_MS);
ev.velocityY = movedTop * factor;
ev.velocityX = movedLeft * factor;

// figure out which direction we're scrolling
ev.directionY = (movedTop > 0 ? 'up' : 'down');
Expand Down Expand Up @@ -546,11 +539,10 @@ export class ScrollView {
this._endTmr && this._dom.cancel(this._endTmr);
this._lsn && this._lsn();

this.onScrollStart = this.onScroll = this.onScrollEnd = null;

let ev = this.ev;
ev.domWrite = ev.contentElement = ev.fixedElement = ev.scrollElement = ev.headerElement = null;
this._lsn = this._el = this._dom = this.ev = ev = null;
this.onScrollStart = this.onScroll = this.onScrollEnd = null;
}

}
Expand Down

0 comments on commit bfe533f

Please sign in to comment.