From bfd3314fff345877f426dd8c6fc4fa1ccb7fd22d Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Wed, 7 Dec 2016 22:12:38 -0600 Subject: [PATCH] feat(scroll): add domWrite and content elements to scroll events --- src/components/content/content.ts | 42 ++++++---- .../test/infinite-scroll.spec.ts | 2 +- src/directives.ts | 2 +- src/module.ts | 2 +- src/util/dom-controller.ts | 2 +- src/util/scroll-view.ts | 84 +++++++++++-------- 6 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/components/content/content.ts b/src/components/content/content.ts index 437ae7604b..1a53842dfb 100644 --- a/src/components/content/content.ts +++ b/src/components/content/content.ts @@ -7,12 +7,12 @@ import { Img } from '../img/img'; import { Ion } from '../ion'; import { isTrueProperty, assert, removeArrayItem } from '../../util/util'; 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 { transitionEnd } from '../../util/dom'; 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} */ 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} */ get velocityX(): number { - return this._scroll.ev.velocityX || 0; + return this._scroll.ev.velocityX; } /** * The current, or last known, vertical scroll direction. * - * @return {ScrollDirection} + * @return {string} */ - get directionY(): ScrollDirection { + get directionY(): string { return this._scroll.ev.directionY; } /** * The current, or last known, horizontal scroll direction. * - * @return {ScrollDirection} + * @return {string} */ - get directionX(): ScrollDirection { + get directionX(): string { return this._scroll.ev.directionX; } @@ -330,16 +330,18 @@ export class Content extends Ion implements OnDestroy, OnInit { const children = this._elementRef.nativeElement.children; assert(children && children.length >= 2, 'content needs at least two children'); - this._fixedEle = children[0]; - this._scrollEle = children[1]; + const scroll = this._scroll; + + scroll.ev.fixedElement = this._fixedEle = children[0]; + scroll.ev.scrollElement = this._scrollEle = children[1]; // subscribe to the scroll start - this._scroll.scrollStart.subscribe(ev => { + scroll.scrollStart.subscribe(ev => { this.ionScrollStart.emit(ev); }); // subscribe to every scroll move - this._scroll.scroll.subscribe(ev => { + scroll.scroll.subscribe(ev => { // remind the app that it's currently scrolling this._app.setScrolling(); @@ -350,7 +352,7 @@ export class Content extends Ion implements OnDestroy, OnInit { }); // subscribe to the scroll end - this._scroll.scrollEnd.subscribe(ev => { + scroll.scrollEnd.subscribe(ev => { this.ionScrollEnd.emit(ev); this.imgsUpdate(); @@ -576,6 +578,8 @@ export class Content extends Ion implements OnDestroy, OnInit { this._fTop = 0; this._fBottom = 0; + const scrollEvent = this._scroll.ev; + let ele: HTMLElement = this._elementRef.nativeElement; if (!ele) { assert(false, 'ele should be valid'); @@ -590,6 +594,8 @@ export class Content extends Ion implements OnDestroy, OnInit { ele = children[i]; tagName = ele.tagName; if (tagName === 'ION-CONTENT') { + scrollEvent.contentElement = ele; + // ******** DOM READ **************** this.scrollWidth = ele.scrollWidth; // ******** DOM READ **************** @@ -605,10 +611,14 @@ export class Content extends Ion implements OnDestroy, OnInit { } } else if (tagName === 'ION-HEADER') { + scrollEvent.headerElement = ele; + // ******** DOM READ **************** this._hdrHeight = ele.clientHeight; } else if (tagName === 'ION-FOOTER') { + scrollEvent.footerElement = ele; + // ******** DOM READ **************** this._ftrHeight = ele.clientHeight; 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 // 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 @@ -809,7 +819,7 @@ export function updateImgs(imgs: Img[], scrollTop: number, scrollHeight: number, for (var i = 0, ilen = imgs.length; i < ilen; i++) { img = imgs[i]; - if (scrollDirectionY === ScrollDirection.Up) { + if (scrollDirectionY === 'up') { // scrolling up if (img.top < scrollBottom && img.bottom > scrollTop - renderableBuffer) { // 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 priority1.sort(sortTopToBottom).forEach(i => i.update()); - if (scrollDirectionY === ScrollDirection.Up) { + if (scrollDirectionY === 'up') { // scrolling up priority2.sort(sortTopToBottom).reverse().forEach(i => i.update()); diff --git a/src/components/infinite-scroll/test/infinite-scroll.spec.ts b/src/components/infinite-scroll/test/infinite-scroll.spec.ts index 3ec2f3c76d..2c24e83d8f 100644 --- a/src/components/infinite-scroll/test/infinite-scroll.spec.ts +++ b/src/components/infinite-scroll/test/infinite-scroll.spec.ts @@ -96,7 +96,7 @@ describe('Infinite Scroll', () => { let content: Content; let contentElementRef; let infiniteElementRef; - let ev: ScrollEvent = {}; + let ev: ScrollEvent = ({}); let dom: MockDomController; beforeEach(() => { diff --git a/src/directives.ts b/src/directives.ts index 492289a8a3..a2a1f8f3cb 100644 --- a/src/directives.ts +++ b/src/directives.ts @@ -84,7 +84,7 @@ export { Card, CardContent, CardHeader, CardTitle } from './components/card/card export { Checkbox } from './components/checkbox/checkbox'; export { Chip } from './components/chip/chip'; 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 { FabContainer, FabButton, FabList } from './components/fab/fab'; export { Grid, Row, Col } from './components/grid/grid'; diff --git a/src/module.ts b/src/module.ts index b1702b9319..8f61845a38 100644 --- a/src/module.ts +++ b/src/module.ts @@ -53,7 +53,7 @@ import { ToastCmp } from './components/toast/toast-component'; * Export Providers */ 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 { Haptic } from './util/haptic'; export { ImgLoader } from './components/img/img-loader'; diff --git a/src/util/dom-controller.ts b/src/util/dom-controller.ts index 77db22ffdb..ca0edb7316 100644 --- a/src/util/dom-controller.ts +++ b/src/util/dom-controller.ts @@ -7,7 +7,7 @@ import { nativeRaf } from './dom'; import { removeArrayItem } from './util'; -export type DomCallback = { (timeStamp: number): void }; +export type DomCallback = { (timeStamp?: number): void }; export class DomDebouncer { diff --git a/src/util/scroll-view.ts b/src/util/scroll-view.ts index 75489dec4a..3f717ab2ae 100644 --- a/src/util/scroll-view.ts +++ b/src/util/scroll-view.ts @@ -2,11 +2,12 @@ import { Subject } from 'rxjs/Subject'; import { assert } from './util'; 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'; export class ScrollView { + ev: ScrollEvent; isScrolling = false; scrollStart = new Subject(); scroll = new Subject(); @@ -20,13 +21,30 @@ export class ScrollView { private _lsn: 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) { if (!this.initialized) { @@ -111,8 +129,8 @@ export class ScrollView { ev.velocityX = ((movedLeft / timeOffset) * FRAME_MS); // figure out which direction we're scrolling - ev.directionY = (movedTop > 0 ? ScrollDirection.Up : ScrollDirection.Down); - ev.directionX = (movedLeft > 0 ? ScrollDirection.Left : ScrollDirection.Right); + ev.directionY = (movedTop > 0 ? 'up' : 'down'); + ev.directionX = (movedLeft > 0 ? 'left' : 'right'); } } @@ -121,7 +139,7 @@ export class ScrollView { // debounce for a moment after the last scroll event 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 self.isScrolling = false; @@ -345,7 +363,7 @@ export class ScrollView { if (this._js) { 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) { 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._endTmr && this._endTmr(); 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 { - scrollTop?: number; - scrollLeft?: number; - startY?: number; - startX?: number; - deltaY?: number; - deltaX?: number; - timeStamp?: number; - velocityY?: number; - velocityX?: number; - directionY?: ScrollDirection; - directionX?: ScrollDirection; -} - - -export enum ScrollDirection { - Up, Down, Left, Right -} - - -export interface DomFn { - (callback: Function): void; + timeStamp: number; + scrollTop: number; + scrollLeft: number; + startY: number; + startX: number; + deltaY: number; + deltaX: number; + velocityY: number; + velocityX: number; + directionY: string; + directionX: string; + domWrite: {(fn: DomCallback, ctx?: any)}; + contentElement: HTMLElement; + fixedElement: HTMLElement; + scrollElement: HTMLElement; + headerElement: HTMLElement; + footerElement: HTMLElement; }