From cac71647f3ce12b24c1c53bafa0bdfbb71c446ba Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Tue, 29 Nov 2016 10:27:07 -0600 Subject: [PATCH] feat(DomController): organize dom reads/writes --- src/module.ts | 15 ++++---- src/util/dom-controller.ts | 71 ++++++++++++++++++++++++++++++++++++++ src/util/events.ts | 9 ++--- 3 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 src/util/dom-controller.ts diff --git a/src/module.ts b/src/module.ts index 1d65f051f1c..e9d603ce264 100644 --- a/src/module.ts +++ b/src/module.ts @@ -10,8 +10,11 @@ import { HttpModule } from '@angular/http'; import { ActionSheetController } from './components/action-sheet/action-sheet'; import { AlertController } from './components/alert/alert'; import { App } from './components/app/app'; +import { AppRootToken } from './components/app/app-root'; +import { ClickBlock } from './util/click-block'; import { Config, ConfigToken, setupConfig } from './config/config'; import { DeepLinker, setupDeepLinker } from './navigation/deep-linker'; +import { DomController } from './util/dom-controller'; import { Events, setupProvideEvents } from './util/events'; import { Form } from './util/form'; import { GestureController } from './gestures/gesture-controller'; @@ -31,9 +34,7 @@ import { ToastController } from './components/toast/toast'; import { registerModeConfigs } from './config/mode-registry'; import { registerTransitions } from './transitions/transition-registry'; import { TransitionController } from './transitions/transition-controller'; -import { AppRootToken } from './components/app/app-root'; import { UrlSerializer, setupUrlSerializer, DeepLinkConfigToken } from './navigation/url-serializer'; -import { ClickBlock } from './util/click-block'; /** * Import Overlay Entry Components */ @@ -51,6 +52,7 @@ import { ToastCmp } from './components/toast/toast-component'; * Export Providers */ export { Config, setupConfig, ConfigToken } from './config/config'; +export { DomController } from './util/dom-controller'; export { Platform, setupPlatform, UserAgentToken, DocumentDirToken, DocLangToken, NavigatorPlatformToken } from './platform/platform'; export { Haptic } from './util/haptic'; export { QueryParams, setupQueryParams, UrlToken } from './platform/query-params'; @@ -102,13 +104,13 @@ export { ViewController } from './navigation/view-controller'; declarations: [ ActionSheetCmp, AlertCmp, + ClickBlock, IONIC_DIRECTIVES, LoadingCmp, ModalCmp, PickerCmp, PopoverCmp, - ToastCmp, - ClickBlock + ToastCmp ], entryComponents: [ ActionSheetCmp, @@ -154,7 +156,7 @@ export class IonicModule { // useFactory: ionic app initializers { provide: APP_INITIALIZER, useFactory: registerModeConfigs, deps: [ Config ], multi: true }, { provide: APP_INITIALIZER, useFactory: registerTransitions, deps: [ Config ], multi: true }, - { provide: APP_INITIALIZER, useFactory: setupProvideEvents, deps: [ Platform ], multi: true }, + { provide: APP_INITIALIZER, useFactory: setupProvideEvents, deps: [ Platform, DomController ], multi: true }, { provide: APP_INITIALIZER, useFactory: setupTapClick, deps: [ Config, App, NgZone, GestureController ], multi: true }, // useClass @@ -167,10 +169,11 @@ export class IonicModule { ActionSheetController, AlertController, App, + DomController, Events, Form, - Haptic, GestureController, + Haptic, Keyboard, LoadingController, Location, diff --git a/src/util/dom-controller.ts b/src/util/dom-controller.ts new file mode 100644 index 00000000000..fb06acae026 --- /dev/null +++ b/src/util/dom-controller.ts @@ -0,0 +1,71 @@ +/** + * Adopted from FastDom + * https://github.com/wilsonpage/fastdom + * MIT License + */ +import { nativeRaf } from './dom'; +import { removeArrayItem } from './util'; + + +export class DomController { + private r: Function[] = []; + private w: Function[] = []; + private q: boolean; + + read(fn: Function, ctx?: any): Function { + const task = !ctx ? fn : fn.bind(ctx); + this.r.push(task); + this.queue(); + return task; + } + + write(fn: Function, ctx?: any): Function { + const task = !ctx ? fn : fn.bind(ctx); + this.w.push(task); + this.queue(); + return task; + } + + cancel(task: any) { + return removeArrayItem(this.r, task) || removeArrayItem(this.w, task); + } + + private queue() { + if (!this.q) { + this.q = true; + nativeRaf(timestamp => { + this.flush(timestamp); + }); + } + } + + private flush(timestamp: number) { + let err; + let task; + + try { + // ******** DOM READS **************** + while (task = this.r.shift()) { + task(timestamp); + } + + // ******** DOM WRITES **************** + while (task = this.w.shift()) { + task(timestamp); + } + } catch (e) { + err = e; + } + + this.q = false; + + if (this.r.length || this.w.length) { + this.queue(); + } + + if (err) { + throw err; + } + } + +} diff --git a/src/util/events.ts b/src/util/events.ts index 432d2e6c7a5..113d24ea065 100644 --- a/src/util/events.ts +++ b/src/util/events.ts @@ -1,3 +1,4 @@ +import { DomController } from '../util/dom-controller'; import { nativeTimeout, nativeRaf } from '../util/dom'; import { Platform } from '../platform/platform'; import { ScrollView } from '../util/scroll-view'; @@ -109,7 +110,7 @@ export class Events { /** * @private */ -export function setupEvents(platform: Platform): Events { +export function setupEvents(platform: Platform, dom: DomController): Events { const events = new Events(); // start listening for resizes XXms after the app starts @@ -134,7 +135,7 @@ export function setupEvents(platform: Platform): Events { let content = el.closest('.scroll-content'); if (content) { - var scroll = new ScrollView(content); + var scroll = new ScrollView(content, dom); // We need to stop scrolling if it's happening and scroll up content.style['WebkitBackfaceVisibility'] = 'hidden'; @@ -173,8 +174,8 @@ export function setupEvents(platform: Platform): Events { /** * @private */ -export function setupProvideEvents(platform: Platform) { +export function setupProvideEvents(platform: Platform, dom: DomController) { return function() { - return setupEvents(platform); + return setupEvents(platform, dom); }; }