feat(scroll): add domWrite and content elements to scroll events

This commit is contained in:
Adam Bradley
2016-12-07 22:12:38 -06:00
parent 22d6bc520b
commit bfd3314fff
6 changed files with 80 additions and 54 deletions

View File

@ -7,12 +7,12 @@ import { Img } from '../img/img';
import { Ion } from '../ion'; import { Ion } from '../ion';
import { isTrueProperty, assert, removeArrayItem } from '../../util/util'; import { isTrueProperty, assert, removeArrayItem } from '../../util/util';
import { Keyboard } from '../../util/keyboard'; import { Keyboard } from '../../util/keyboard';
import { ScrollView, ScrollDirection, ScrollEvent } from '../../util/scroll-view'; import { ScrollView, ScrollEvent } from '../../util/scroll-view';
import { Tabs } from '../tabs/tabs'; import { Tabs } from '../tabs/tabs';
import { transitionEnd } from '../../util/dom'; import { transitionEnd } from '../../util/dom';
import { ViewController } from '../../navigation/view-controller'; import { ViewController } from '../../navigation/view-controller';
export { ScrollEvent, ScrollDirection } from '../../util/scroll-view'; export { ScrollEvent } from '../../util/scroll-view';
/** /**
@ -242,7 +242,7 @@ export class Content extends Ion implements OnDestroy, OnInit {
* @return {number} * @return {number}
*/ */
get velocityY(): number { get velocityY(): number {
return this._scroll.ev.velocityY || 0; return this._scroll.ev.velocityY;
} }
/** /**
@ -251,24 +251,24 @@ export class Content extends Ion implements OnDestroy, OnInit {
* @return {number} * @return {number}
*/ */
get velocityX(): number { get velocityX(): number {
return this._scroll.ev.velocityX || 0; return this._scroll.ev.velocityX;
} }
/** /**
* The current, or last known, vertical scroll direction. * The current, or last known, vertical scroll direction.
* *
* @return {ScrollDirection} * @return {string}
*/ */
get directionY(): ScrollDirection { get directionY(): string {
return this._scroll.ev.directionY; return this._scroll.ev.directionY;
} }
/** /**
* The current, or last known, horizontal scroll direction. * The current, or last known, horizontal scroll direction.
* *
* @return {ScrollDirection} * @return {string}
*/ */
get directionX(): ScrollDirection { get directionX(): string {
return this._scroll.ev.directionX; return this._scroll.ev.directionX;
} }
@ -330,16 +330,18 @@ export class Content extends Ion implements OnDestroy, OnInit {
const children = this._elementRef.nativeElement.children; const children = this._elementRef.nativeElement.children;
assert(children && children.length >= 2, 'content needs at least two children'); assert(children && children.length >= 2, 'content needs at least two children');
this._fixedEle = children[0]; const scroll = this._scroll;
this._scrollEle = children[1];
scroll.ev.fixedElement = this._fixedEle = children[0];
scroll.ev.scrollElement = this._scrollEle = children[1];
// subscribe to the scroll start // subscribe to the scroll start
this._scroll.scrollStart.subscribe(ev => { scroll.scrollStart.subscribe(ev => {
this.ionScrollStart.emit(ev); this.ionScrollStart.emit(ev);
}); });
// subscribe to every scroll move // subscribe to every scroll move
this._scroll.scroll.subscribe(ev => { scroll.scroll.subscribe(ev => {
// remind the app that it's currently scrolling // remind the app that it's currently scrolling
this._app.setScrolling(); this._app.setScrolling();
@ -350,7 +352,7 @@ export class Content extends Ion implements OnDestroy, OnInit {
}); });
// subscribe to the scroll end // subscribe to the scroll end
this._scroll.scrollEnd.subscribe(ev => { scroll.scrollEnd.subscribe(ev => {
this.ionScrollEnd.emit(ev); this.ionScrollEnd.emit(ev);
this.imgsUpdate(); this.imgsUpdate();
@ -576,6 +578,8 @@ export class Content extends Ion implements OnDestroy, OnInit {
this._fTop = 0; this._fTop = 0;
this._fBottom = 0; this._fBottom = 0;
const scrollEvent = this._scroll.ev;
let ele: HTMLElement = this._elementRef.nativeElement; let ele: HTMLElement = this._elementRef.nativeElement;
if (!ele) { if (!ele) {
assert(false, 'ele should be valid'); assert(false, 'ele should be valid');
@ -590,6 +594,8 @@ export class Content extends Ion implements OnDestroy, OnInit {
ele = <HTMLElement>children[i]; ele = <HTMLElement>children[i];
tagName = ele.tagName; tagName = ele.tagName;
if (tagName === 'ION-CONTENT') { if (tagName === 'ION-CONTENT') {
scrollEvent.contentElement = ele;
// ******** DOM READ **************** // ******** DOM READ ****************
this.scrollWidth = ele.scrollWidth; this.scrollWidth = ele.scrollWidth;
// ******** DOM READ **************** // ******** DOM READ ****************
@ -605,10 +611,14 @@ export class Content extends Ion implements OnDestroy, OnInit {
} }
} else if (tagName === 'ION-HEADER') { } else if (tagName === 'ION-HEADER') {
scrollEvent.headerElement = ele;
// ******** DOM READ **************** // ******** DOM READ ****************
this._hdrHeight = ele.clientHeight; this._hdrHeight = ele.clientHeight;
} else if (tagName === 'ION-FOOTER') { } else if (tagName === 'ION-FOOTER') {
scrollEvent.footerElement = ele;
// ******** DOM READ **************** // ******** DOM READ ****************
this._ftrHeight = ele.clientHeight; this._ftrHeight = ele.clientHeight;
this._footerEle = ele; this._footerEle = ele;
@ -793,7 +803,7 @@ export class Content extends Ion implements OnDestroy, OnInit {
} }
export function updateImgs(imgs: Img[], scrollTop: number, scrollHeight: number, scrollDirectionY: ScrollDirection, requestableBuffer: number, renderableBuffer: number) { export function updateImgs(imgs: Img[], scrollTop: number, scrollHeight: number, scrollDirectionY: string, requestableBuffer: number, renderableBuffer: number) {
// ok, so it's time to see which images, if any, should be requested and rendered // ok, so it's time to see which images, if any, should be requested and rendered
// ultimately, if we're scrolling fast then don't bother requesting or rendering // ultimately, if we're scrolling fast then don't bother requesting or rendering
// when scrolling is done, then it needs to do a check to see which images are // when scrolling is done, then it needs to do a check to see which images are
@ -809,7 +819,7 @@ export function updateImgs(imgs: Img[], scrollTop: number, scrollHeight: number,
for (var i = 0, ilen = imgs.length; i < ilen; i++) { for (var i = 0, ilen = imgs.length; i < ilen; i++) {
img = imgs[i]; img = imgs[i];
if (scrollDirectionY === ScrollDirection.Up) { if (scrollDirectionY === 'up') {
// scrolling up // scrolling up
if (img.top < scrollBottom && img.bottom > scrollTop - renderableBuffer) { if (img.top < scrollBottom && img.bottom > scrollTop - renderableBuffer) {
// scrolling up, img is within viewable area // scrolling up, img is within viewable area
@ -870,7 +880,7 @@ export function updateImgs(imgs: Img[], scrollTop: number, scrollHeight: number,
// update all imgs which are viewable // update all imgs which are viewable
priority1.sort(sortTopToBottom).forEach(i => i.update()); priority1.sort(sortTopToBottom).forEach(i => i.update());
if (scrollDirectionY === ScrollDirection.Up) { if (scrollDirectionY === 'up') {
// scrolling up // scrolling up
priority2.sort(sortTopToBottom).reverse().forEach(i => i.update()); priority2.sort(sortTopToBottom).reverse().forEach(i => i.update());

View File

@ -96,7 +96,7 @@ describe('Infinite Scroll', () => {
let content: Content; let content: Content;
let contentElementRef; let contentElementRef;
let infiniteElementRef; let infiniteElementRef;
let ev: ScrollEvent = {}; let ev: ScrollEvent = (<any>{});
let dom: MockDomController; let dom: MockDomController;
beforeEach(() => { beforeEach(() => {

View File

@ -84,7 +84,7 @@ export { Card, CardContent, CardHeader, CardTitle } from './components/card/card
export { Checkbox } from './components/checkbox/checkbox'; export { Checkbox } from './components/checkbox/checkbox';
export { Chip } from './components/chip/chip'; export { Chip } from './components/chip/chip';
export { ClickBlock } from './util/click-block'; export { ClickBlock } from './util/click-block';
export { Content, ScrollEvent, ScrollDirection } from './components/content/content'; export { Content, ScrollEvent } from './components/content/content';
export { DateTime } from './components/datetime/datetime'; export { DateTime } from './components/datetime/datetime';
export { FabContainer, FabButton, FabList } from './components/fab/fab'; export { FabContainer, FabButton, FabList } from './components/fab/fab';
export { Grid, Row, Col } from './components/grid/grid'; export { Grid, Row, Col } from './components/grid/grid';

View File

@ -53,7 +53,7 @@ import { ToastCmp } from './components/toast/toast-component';
* Export Providers * Export Providers
*/ */
export { Config, setupConfig, ConfigToken } from './config/config'; export { Config, setupConfig, ConfigToken } from './config/config';
export { DomController } from './util/dom-controller'; export { DomController, DomCallback } from './util/dom-controller';
export { Platform, setupPlatform, UserAgentToken, DocumentDirToken, DocLangToken, NavigatorPlatformToken } from './platform/platform'; export { Platform, setupPlatform, UserAgentToken, DocumentDirToken, DocLangToken, NavigatorPlatformToken } from './platform/platform';
export { Haptic } from './util/haptic'; export { Haptic } from './util/haptic';
export { ImgLoader } from './components/img/img-loader'; export { ImgLoader } from './components/img/img-loader';

View File

@ -7,7 +7,7 @@ import { nativeRaf } from './dom';
import { removeArrayItem } from './util'; import { removeArrayItem } from './util';
export type DomCallback = { (timeStamp: number): void }; export type DomCallback = { (timeStamp?: number): void };
export class DomDebouncer { export class DomDebouncer {

View File

@ -2,11 +2,12 @@ import { Subject } from 'rxjs/Subject';
import { assert } from './util'; import { assert } from './util';
import { CSS, nativeRaf, pointerCoord, rafFrames } from './dom'; import { CSS, nativeRaf, pointerCoord, rafFrames } from './dom';
import { DomController } from './dom-controller'; import { DomController, DomCallback } from './dom-controller';
import { eventOptions, listenEvent } from './ui-event-manager'; import { eventOptions, listenEvent } from './ui-event-manager';
export class ScrollView { export class ScrollView {
ev: ScrollEvent;
isScrolling = false; isScrolling = false;
scrollStart = new Subject<ScrollEvent>(); scrollStart = new Subject<ScrollEvent>();
scroll = new Subject<ScrollEvent>(); scroll = new Subject<ScrollEvent>();
@ -20,13 +21,30 @@ export class ScrollView {
private _lsn: Function; private _lsn: Function;
private _endTmr: Function; private _endTmr: Function;
ev: ScrollEvent = {
directionY: ScrollDirection.Down,
directionX: null
};
constructor(private _dom: DomController) {
constructor(private _dom: DomController) {} this.ev = {
timeStamp: 0,
scrollTop: 0,
scrollLeft: 0,
startY: 0,
startX: 0,
deltaY: 0,
deltaX: 0,
velocityY: 0,
velocityX: 0,
directionY: 'down',
directionX: null,
domWrite: function(fn: DomCallback, ctx?: any) {
_dom.write(fn, ctx);
},
contentElement: null,
fixedElement: null,
scrollElement: null,
headerElement: null,
footerElement: null
};
}
init(ele: HTMLElement, contentTop: number, contentBottom: number) { init(ele: HTMLElement, contentTop: number, contentBottom: number) {
if (!this.initialized) { if (!this.initialized) {
@ -111,8 +129,8 @@ export class ScrollView {
ev.velocityX = ((movedLeft / timeOffset) * FRAME_MS); ev.velocityX = ((movedLeft / timeOffset) * FRAME_MS);
// figure out which direction we're scrolling // figure out which direction we're scrolling
ev.directionY = (movedTop > 0 ? ScrollDirection.Up : ScrollDirection.Down); ev.directionY = (movedTop > 0 ? 'up' : 'down');
ev.directionX = (movedLeft > 0 ? ScrollDirection.Left : ScrollDirection.Right); ev.directionX = (movedLeft > 0 ? 'left' : 'right');
} }
} }
@ -121,7 +139,7 @@ export class ScrollView {
// debounce for a moment after the last scroll event // debounce for a moment after the last scroll event
self._endTmr && self._endTmr(); self._endTmr && self._endTmr();
self._endTmr = rafFrames(5, function scrollEnd() { self._endTmr = rafFrames(6, function scrollEnd() {
// haven't scrolled in a while, so it's a scrollend // haven't scrolled in a while, so it's a scrollend
self.isScrolling = false; self.isScrolling = false;
@ -345,7 +363,7 @@ export class ScrollView {
if (this._js) { if (this._js) {
return this._t; return this._t;
} }
return this._t = this._el.scrollTop || 0; return this._t = this._el.scrollTop;
} }
/** /**
@ -355,7 +373,7 @@ export class ScrollView {
if (this._js) { if (this._js) {
return 0; return 0;
} }
return this._l = this._el.scrollLeft || 0; return this._l = this._el.scrollLeft;
} }
/** /**
@ -492,34 +510,32 @@ export class ScrollView {
this.stop(); this.stop();
this._endTmr && this._endTmr(); this._endTmr && this._endTmr();
this._lsn && this._lsn(); this._lsn && this._lsn();
this._el = this._dom = 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;
} }
} }
export interface ScrollEvent { export interface ScrollEvent {
scrollTop?: number; timeStamp: number;
scrollLeft?: number; scrollTop: number;
startY?: number; scrollLeft: number;
startX?: number; startY: number;
deltaY?: number; startX: number;
deltaX?: number; deltaY: number;
timeStamp?: number; deltaX: number;
velocityY?: number; velocityY: number;
velocityX?: number; velocityX: number;
directionY?: ScrollDirection; directionY: string;
directionX?: ScrollDirection; directionX: string;
} domWrite: {(fn: DomCallback, ctx?: any)};
contentElement: HTMLElement;
fixedElement: HTMLElement;
export enum ScrollDirection { scrollElement: HTMLElement;
Up, Down, Left, Right headerElement: HTMLElement;
} footerElement: HTMLElement;
export interface DomFn {
(callback: Function): void;
} }