From cca67e9add46df6c0ccaf6e4b308625c0d86759f Mon Sep 17 00:00:00 2001 From: LastLeaf Date: Fri, 21 Jul 2023 16:19:58 +0800 Subject: [PATCH] feat: add `groupRegister` for component space (#67) --- glass-easel/src/component_space.ts | 53 ++++++++++++++++++++-- glass-easel/tests/core/placeholder.test.ts | 38 +++++++++++++++- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/glass-easel/src/component_space.ts b/glass-easel/src/component_space.ts index 6dc9643..833796a 100644 --- a/glass-easel/src/component_space.ts +++ b/glass-easel/src/component_space.ts @@ -19,7 +19,7 @@ import { NormalizedComponentOptions, } from './global_options' import { StyleScopeManager } from './class_list' -import { GeneralBackendContext } from '.' +import { GeneralBackendContext, safeCallback } from '.' import { TraitBehavior } from './trait_behaviors' const normalizePath = (path: string, basePath: string): string => { @@ -146,6 +146,10 @@ export class ComponentSpace { [path: string]: ComponentWaitingList } /** @internal */ + private _$groupingListWaiting: + | { waiting: ComponentWaitingList; comp: GeneralComponentDefinition }[] + | null = null + /** @internal */ _$componentWaitingListener: | ((isPub: boolean, alias: string, owner: GeneralComponent) => void) | null = null @@ -373,10 +377,14 @@ export class ComponentSpace { _$registerComponent(is: string, comp: GeneralComponentDefinition) { this._$list[is] = comp this._$behaviorList[is] = comp.behavior as unknown as GeneralBehavior - const arr = this._$listWaiting[is] - if (arr) { + const waiting = this._$listWaiting[is] + if (waiting) { delete this._$listWaiting[is] - arr.call(comp) + if (this._$groupingListWaiting) { + this._$groupingListWaiting.push({ waiting, comp }) + } else { + waiting.call(comp) + } } } @@ -385,6 +393,43 @@ export class ComponentSpace { this._$behaviorList[is] = beh } + /** + * Start a series of components and behaviors registration + * + * In most cases, `groupRegister` is prefered. + */ + startGroupRegister() { + this._$groupingListWaiting = [] + } + + /** + * End a series of components and behaviors registration + * + * In most cases, `groupRegister` is prefered. + */ + endGroupRegister() { + const arr = this._$groupingListWaiting + if (!arr) return + this._$groupingListWaiting = null + for (let i = 0; i < arr.length; i += 1) { + const { waiting, comp } = arr[i]! + waiting.call(comp) + } + } + + /** + * Group a series of components and behaviors registration + * + * If any placeholder should be replaced, + * the replacement will happen after the whole series of registration. + */ + groupRegister(cb: () => R): R | undefined { + this.startGroupRegister() + const ret = safeCallback('group register', cb, this, []) + this.endGroupRegister() + return ret + } + /** * Assign a public alias to a component * diff --git a/glass-easel/tests/core/placeholder.test.ts b/glass-easel/tests/core/placeholder.test.ts index e9044e1..0f3a417 100644 --- a/glass-easel/tests/core/placeholder.test.ts +++ b/glass-easel/tests/core/placeholder.test.ts @@ -79,7 +79,7 @@ describe('placeholder', () => { matchElementWithDom(elem) }) - test('using other component as placeholder', () => { + test('using another component as placeholder', () => { const componentSpace = new glassEasel.ComponentSpace() const viewDef = componentSpace.define('view').registerComponent() componentSpace.setGlobalUsingComponent('view', viewDef) @@ -101,6 +101,42 @@ describe('placeholder', () => { matchElementWithDom(elem) }) + test('group register other components as placeholders', () => { + const componentSpace = new glassEasel.ComponentSpace() + componentSpace.define('').registerComponent() + + const def = componentSpace + .define() + .placeholders({ + parent: '', + }) + .definition({ + using: { + parent: 'parent', + }, + template: tmpl(''), + }) + .registerComponent() + const elem = glassEasel.Component.createWithContext('root', def.general(), domBackend) + expect(domHtml(elem)).toBe('') + matchElementWithDom(elem) + + componentSpace.groupRegister(() => { + const parentDef = componentSpace + .define('parent') + .usingComponents({ + child: 'child', + }) + .template(tmpl('')) + .registerComponent() + componentSpace.setGlobalUsingComponent('parent', parentDef) + const childDef = componentSpace.define('child').template(tmpl('CHILD')).registerComponent() + componentSpace.setGlobalUsingComponent('child', childDef) + }) + expect(domHtml(elem)).toBe('CHILD') + matchElementWithDom(elem) + }) + test('using placeholder across component spaces and waiting', () => { const mainCs = new glassEasel.ComponentSpace() mainCs.defineComponent({ is: '' })