From ee27549c84d55d05ee571ab86546b314edb664ec Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Wed, 21 Mar 2018 16:22:59 +0100 Subject: [PATCH] refactor(dom): attachComponent() --- core/src/components/modal/modal.tsx | 13 ++++---- core/src/components/nav/view-controller.ts | 24 ++------------ core/src/components/popover/popover.tsx | 13 ++++---- .../components/router-outlet/route-outlet.tsx | 8 ++--- core/src/index.d.ts | 2 +- core/src/utils/dom-framework-delegate.ts | 5 --- core/src/utils/framework-delegate.ts | 32 +++++++++++++++++++ core/src/utils/overlays.ts | 27 +--------------- core/src/utils/theme.ts | 15 +++++---- 9 files changed, 63 insertions(+), 76 deletions(-) delete mode 100644 core/src/utils/dom-framework-delegate.ts create mode 100644 core/src/utils/framework-delegate.ts diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index f3af9a1026..1863bf92a2 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -1,8 +1,9 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; import { Animation, AnimationBuilder, Config, FrameworkDelegate } from '../../index'; -import { createThemedClasses, getClassMap } from '../../utils/theme'; -import { BACKDROP, OverlayEventDetail, OverlayInterface, attachComponent, detachComponent, dismiss, eventMethod, present } from '../../utils/overlays'; +import { createThemedClasses, getClassList } from '../../utils/theme'; +import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, present } from '../../utils/overlays'; +import { attachComponent, detachComponent } from '../../utils/framework-delegate'; import iosEnterAnimation from './animations/ios.enter'; import iosLeaveAnimation from './animations/ios.leave'; @@ -172,10 +173,10 @@ export class Modal implements OverlayInterface { ...this.data, modal: this.el }; - const classes = { - ...getClassMap(this.cssClass), - 'ion-page': true - }; + const classes = [ + ...getClassList(this.cssClass), + 'ion-page' + ]; return attachComponent(this.delegate, container, this.component, classes, data) .then(el => this.usersElement = el) .then(() => present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation)); diff --git a/core/src/components/nav/view-controller.ts b/core/src/components/nav/view-controller.ts index 3ec786961e..807e76f893 100644 --- a/core/src/components/nav/view-controller.ts +++ b/core/src/components/nav/view-controller.ts @@ -3,6 +3,7 @@ import { NavOptions, ViewState } from './nav-util'; import { NavControllerBase } from './nav'; import { assert } from '../../utils/helpers'; import { FrameworkDelegate } from '../..'; +import { attachComponent } from '../../utils/framework-delegate'; /** * @name ViewController @@ -42,30 +43,11 @@ export class ViewController { /** * @hidden */ - init(container: HTMLElement) { + async init(container: HTMLElement) { this._state = ViewState.Attached; const component = this.component; - if (this.delegate) { - return this.delegate.attachViewToDom(container, component, this.data, ['ion-page', 'hide-page']).then(el => { - this.element = el; - }); - } - const element = (this.element) - ? this.element - : typeof component === 'string' - ? document.createElement(component) - : component; - - element.classList.add('ion-page'); - element.classList.add('hide-page'); - - if (this.data) { - Object.assign(element, this.data); - } - container.appendChild(element); - this.element = element; - return Promise.resolve(); + this.element = await attachComponent(this.delegate, container, component, ['ion-page', 'hide-page'], this.data); } _setNav(navCtrl: NavControllerBase) { diff --git a/core/src/components/popover/popover.tsx b/core/src/components/popover/popover.tsx index 9858df6388..55100c13ab 100644 --- a/core/src/components/popover/popover.tsx +++ b/core/src/components/popover/popover.tsx @@ -1,8 +1,9 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; import { Animation, AnimationBuilder, Config, FrameworkDelegate } from '../../index'; -import { createThemedClasses, getClassMap } from '../../utils/theme'; -import { BACKDROP, OverlayEventDetail, OverlayInterface, attachComponent, detachComponent, dismiss, eventMethod, present } from '../../utils/overlays'; +import { createThemedClasses, getClassList } from '../../utils/theme'; +import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, present } from '../../utils/overlays'; +import { attachComponent, detachComponent } from '../../utils/framework-delegate'; import iosEnterAnimation from './animations/ios.enter'; import iosLeaveAnimation from './animations/ios.leave'; @@ -182,10 +183,10 @@ export class Popover implements OverlayInterface { ...this.data, popover: this.el }; - const classes = { - ...getClassMap(this.cssClass), - 'popover-viewport': true - }; + const classes = [ + ...getClassList(this.cssClass), + 'popover-viewport' + ]; return attachComponent(this.delegate, container, this.component, classes, data) .then(el => this.usersElement = el) .then(() => present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, this.ev)); diff --git a/core/src/components/router-outlet/route-outlet.tsx b/core/src/components/router-outlet/route-outlet.tsx index 99885e763d..f28d1597bb 100644 --- a/core/src/components/router-outlet/route-outlet.tsx +++ b/core/src/components/router-outlet/route-outlet.tsx @@ -2,11 +2,11 @@ import { Component, Element, Method, Prop } from '@stencil/core'; import { transition } from '../../utils'; import { NavDirection } from '../nav/nav-util'; import { AnimationBuilder, Config, FrameworkDelegate, NavOutlet } from '../..'; -import { attachComponent, detachComponent } from '../../utils/overlays'; +import { attachComponent, detachComponent } from '../../utils/framework-delegate'; +import { RouteID, RouteWrite } from '../router/utils/interfaces'; import iosTransitionAnimation from '../nav/animations/ios.transition'; import mdTransitionAnimation from '../nav/animations/md.transition'; -import { RouteID, RouteWrite } from '../router/utils/interfaces'; @Component({ tag: 'ion-router-outlet' @@ -37,7 +37,7 @@ export class RouterOutlet implements NavOutlet { return false; } // attach entering view to DOM - const enteringEl = await attachComponent(this.delegate, this.el, component, NAV_CLASSES, params); + const enteringEl = await attachComponent(this.delegate, this.el, component, ['ion-page', 'hide-page'], params); const leavingEl = this.activeEl; // commit animation @@ -121,5 +121,3 @@ export interface RouterOutletOptions { direction?: NavDirection; mode?: 'md' | 'ios'; } - -const NAV_CLASSES = {'ion-page': true, 'hide-page': true}; diff --git a/core/src/index.d.ts b/core/src/index.d.ts index 83d74d5985..7d6ef92281 100644 --- a/core/src/index.d.ts +++ b/core/src/index.d.ts @@ -107,7 +107,7 @@ export { PlatformConfig } from './global/platform-configs'; export * from './components'; export { DomController, RafCallback } from './global/dom-controller'; -export { FrameworkDelegate } from './utils/dom-framework-delegate'; +export { FrameworkDelegate } from './utils/framework-delegate'; export { OverlayEventDetail } from './utils/overlays'; export interface Config { diff --git a/core/src/utils/dom-framework-delegate.ts b/core/src/utils/dom-framework-delegate.ts deleted file mode 100644 index 77b1e70dc6..0000000000 --- a/core/src/utils/dom-framework-delegate.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export interface FrameworkDelegate { - attachViewToDom(container: any, component: any, propsOrDataObj?: any, cssClasses?: string[]): Promise; - removeViewFromDom(container: any, component: any): Promise; -} diff --git a/core/src/utils/framework-delegate.ts b/core/src/utils/framework-delegate.ts new file mode 100644 index 0000000000..214c50bde5 --- /dev/null +++ b/core/src/utils/framework-delegate.ts @@ -0,0 +1,32 @@ + +export interface FrameworkDelegate { + attachViewToDom(container: any, component: any, propsOrDataObj?: any, cssClasses?: string[]): Promise; + removeViewFromDom(container: any, component: any): Promise; +} + +export function attachComponent(delegate: FrameworkDelegate, container: Element, component: string|HTMLElement, cssClasses?: string[], params?: {[key: string]: any}): Promise { + if (delegate) { + return delegate.attachViewToDom(container, component, params, cssClasses); + } + const el = (typeof component === 'string') ? document.createElement(component) : component; + + cssClasses && cssClasses.forEach(c => el.classList.add(c)); + params && Object.assign(el, params); + + container.appendChild(el); + if ((el as any).componentOnReady) { + return (el as any).componentOnReady(); + } + return Promise.resolve(el); +} + +export function detachComponent(delegate: FrameworkDelegate, element: HTMLElement) { + if (element) { + if (delegate) { + const container = element.parentElement; + return delegate.removeViewFromDom(container, element); + } + element.remove(); + } + return Promise.resolve(); +} diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 90eda5bb86..062d77a053 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -1,5 +1,5 @@ import { EventEmitter } from '@stencil/core'; -import { Animation, AnimationBuilder, Config, CssClassMap, FrameworkDelegate } from '..'; +import { Animation, AnimationBuilder, Config } from '..'; let lastId = 1; @@ -138,31 +138,6 @@ export function autoFocus(containerEl: HTMLElement): HTMLElement|null { return null; } -export function attachComponent(delegate: FrameworkDelegate, container: Element, component: string|HTMLElement, cssClasses: CssClassMap, data: any): Promise { - if (delegate) { - return delegate.attachViewToDom(container, component, data, Object.keys(cssClasses)); - } - const el = (typeof component === 'string') ? document.createElement(component) : component; - Object.assign(el, data); - Object.keys(cssClasses).forEach(c => el.classList.add(c)); - container.appendChild(el); - if ((el as any).componentOnReady) { - return (el as any).componentOnReady(); - } - return Promise.resolve(el); -} - -export function detachComponent(delegate: FrameworkDelegate, element: HTMLElement) { - if (element) { - if (delegate) { - const container = element.parentElement; - return delegate.removeViewFromDom(container, element); - } - element.remove(); - } - return Promise.resolve(); -} - export function eventMethod(element: HTMLElement, eventName: string, callback?: (detail: T) => void): Promise { let resolve: Function; const promise = new Promise(r => resolve = r); diff --git a/core/src/utils/theme.ts b/core/src/utils/theme.ts index 20b8d87925..412c699fdc 100644 --- a/core/src/utils/theme.ts +++ b/core/src/utils/theme.ts @@ -50,15 +50,18 @@ export function getButtonClassMap(buttonType: string, mode: string): CssClassMap }; } +export function getClassList(classes: string | undefined): string[] { + if (classes) { + return classes + .split(' ') + .filter(c => c.trim() !== ''); + } + return []; +} export function getClassMap(classes: string | undefined): CssClassMap { const map: CssClassMap = {}; - if (classes) { - classes - .split(' ') - .filter(c => c.trim() !== '') - .forEach(c => map[c] = true); - } + getClassList(classes).forEach(c => map[c] = true); return map; }