diff --git a/src/robotlegs/bender/bundles/openfl/OpenFLBundle.ts b/src/robotlegs/bender/bundles/openfl/OpenFLBundle.ts index ca6a929..27420be 100644 --- a/src/robotlegs/bender/bundles/openfl/OpenFLBundle.ts +++ b/src/robotlegs/bender/bundles/openfl/OpenFLBundle.ts @@ -5,7 +5,11 @@ // in accordance with the terms of the license agreement accompanying it. // ------------------------------------------------------------------------------ -import { IBundle, IContext, ILogger, instanceOfType } from "@robotlegsjs/core"; +import { interfaces, IBundle, IContext, ILogger, instanceOfType } from "@robotlegsjs/core"; + +import { IDisplayObject } from "../../displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../displayList/api/IDisplayObjectObserverFactory"; import { IContextView } from "../../extensions/contextView/api/IContextView"; import { ContextView } from "../../extensions/contextView/impl/ContextView"; @@ -17,6 +21,8 @@ import { StageCrawlerExtension } from "../../extensions/viewManager/StageCrawler import { StageObserverExtension } from "../../extensions/viewManager/StageObserverExtension"; import { ViewManagerExtension } from "../../extensions/viewManager/ViewManagerExtension"; +import { DisplayObjectObserver } from "./observer/DisplayObjectObserver"; + /** * For that Classic Robotlegs flavour * @@ -42,6 +48,14 @@ export class OpenFLBundle implements IBundle { this._context = context; this._logger = context.getLogger(this); + this._context.injector + .bind>(IDisplayObjectObserverFactory) + .toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); + this._context.install( ContextViewExtension, ViewManagerExtension, @@ -59,7 +73,7 @@ export class OpenFLBundle implements IBundle { /* Private Functions */ /*============================================================================*/ - private handleContextView(): void { + private handleContextView(contextView: ContextView): void { this._context.configure(ContextViewListenerConfig); } diff --git a/src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver.ts b/src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver.ts new file mode 100644 index 0000000..3b03d23 --- /dev/null +++ b/src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver.ts @@ -0,0 +1,129 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../displayList/api/IDisplayObjectObserver"; + +import { ConfigureViewEvent } from "../../../extensions/viewManager/impl/ConfigureViewEvent"; + +import DisplayObject from "openfl/display/DisplayObject"; + +import Event from "openfl/events/Event"; + +/** + * + */ +export class DisplayObjectObserver implements IDisplayObjectObserver { + private _displayObject: DisplayObject; + private _useCapture: boolean; + + private _addedToStageHandler: Function; + private _removedFromStageHandler: Function; + private _configureViewHandler: Function; + + /*============================================================================*/ + /* Constructor */ + /*============================================================================*/ + + /** + * + * @param displayObject + * @param useCapture + */ + constructor(displayObject: IDisplayObject, useCapture: boolean) { + if (displayObject !== null && displayObject !== undefined) { + this._displayObject = displayObject; + this._useCapture = useCapture; + } else { + throw new Error("DisplayObject can't be null or undefined"); + } + } + + /*============================================================================*/ + /* Public Functions */ + /*============================================================================*/ + + /** + * + * @param handler + */ + public addAddedToStageHandler(handler: Function): void { + if (handler !== null && handler !== undefined && this._displayObject.addEventListener !== undefined) { + this._addedToStageHandler = handler; + this._displayObject.addEventListener("addedToStage", this.onAddedToStage, this._useCapture); + } + } + + /** + * + * @param handler + */ + public addRemovedFromStageHandler(handler: Function): void { + if (handler !== null && handler !== undefined && this._displayObject.addEventListener !== undefined) { + this._removedFromStageHandler = handler; + this._displayObject.addEventListener("removedFromStage", this.onRemovedFromStage, this._useCapture); + } + } + + /** + * + * @param handler + */ + public addConfigureViewHandler(handler: Function): void { + if (handler !== null && handler !== undefined && this._displayObject.addEventListener !== undefined) { + this._configureViewHandler = handler; + this._displayObject.addEventListener(ConfigureViewEvent.CONFIGURE_VIEW, this.onConfigureView, this._useCapture); + } + } + + /** + * + */ + public destroy(): void { + if (this._displayObject.removeEventListener !== undefined) { + this._displayObject.removeEventListener("addedToStage", this.onAddedToStage, this._useCapture); + this._displayObject.removeEventListener("removedFromStage", this.onRemovedFromStage, this._useCapture); + this._displayObject.removeEventListener(ConfigureViewEvent.CONFIGURE_VIEW, this.onConfigureView, this._useCapture); + } + + this._displayObject = null; + + this._addedToStageHandler = null; + this._removedFromStageHandler = null; + this._configureViewHandler = null; + } + + /*============================================================================*/ + /* Private Functions */ + /*============================================================================*/ + + private onAddedToStage = (event: Event): void => { + this._addedToStageHandler(event.target); + }; + + private onRemovedFromStage = (event: Event): void => { + this._removedFromStageHandler(event.target); + }; + + private onConfigureView = (event: ConfigureViewEvent): void => { + // Stop that event! + event.stopPropagation(); + + this._configureViewHandler(event.currentTarget, event.target); + }; + + /*============================================================================*/ + /* Public Properties */ + /*============================================================================*/ + + /** + * The display object + */ + public get displayObject(): IDisplayObject { + return this._displayObject; + } +} diff --git a/src/robotlegs/bender/displayList/api/IDisplayObject.ts b/src/robotlegs/bender/displayList/api/IDisplayObject.ts new file mode 100644 index 0000000..0f75a43 --- /dev/null +++ b/src/robotlegs/bender/displayList/api/IDisplayObject.ts @@ -0,0 +1,13 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObjectContainer } from "./IDisplayObjectContainer"; + +export let IDisplayObject = Symbol("IDisplayObject"); +export interface IDisplayObject { + parent: IDisplayObjectContainer; +} diff --git a/src/robotlegs/bender/displayList/api/IDisplayObjectContainer.ts b/src/robotlegs/bender/displayList/api/IDisplayObjectContainer.ts new file mode 100644 index 0000000..6feb0e7 --- /dev/null +++ b/src/robotlegs/bender/displayList/api/IDisplayObjectContainer.ts @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "./IDisplayObject"; + +export let IDisplayObjectContainer = Symbol("IDisplayObjectContainer"); +export interface IDisplayObjectContainer extends IDisplayObject { + children?: IDisplayObject[]; + + numChildren?: number; + getChildAt?(index: number): IDisplayObject; + + contains(child: IDisplayObject): boolean; +} diff --git a/src/robotlegs/bender/displayList/api/IDisplayObjectObserver.ts b/src/robotlegs/bender/displayList/api/IDisplayObjectObserver.ts new file mode 100644 index 0000000..cefae61 --- /dev/null +++ b/src/robotlegs/bender/displayList/api/IDisplayObjectObserver.ts @@ -0,0 +1,23 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "./IDisplayObject"; + +/** + * + */ +export interface IDisplayObjectObserver { + displayObject: IDisplayObject; + + addAddedToStageHandler(handler: Function): void; + + addRemovedFromStageHandler(handler: Function): void; + + addConfigureViewHandler(handler: Function): void; + + destroy(): void; +} diff --git a/src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory.ts b/src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory.ts new file mode 100644 index 0000000..79fc2e2 --- /dev/null +++ b/src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory.ts @@ -0,0 +1,15 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "./IDisplayObject"; +import { IDisplayObjectObserver } from "./IDisplayObjectObserver"; + +/** + * + */ +export let IDisplayObjectObserverFactory = Symbol("IDisplayObjectObserverFactory"); +export type IDisplayObjectObserverFactory = (view: IDisplayObject, useCapture: boolean) => IDisplayObjectObserver; diff --git a/src/robotlegs/bender/extensions/contextView/api/IContextView.ts b/src/robotlegs/bender/extensions/contextView/api/IContextView.ts index 3c6ba8c..eae0124 100644 --- a/src/robotlegs/bender/extensions/contextView/api/IContextView.ts +++ b/src/robotlegs/bender/extensions/contextView/api/IContextView.ts @@ -5,9 +5,9 @@ // in accordance with the terms of the license agreement accompanying it. // ------------------------------------------------------------------------------ -import Stage from "openfl/display/Stage"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; -export let IContextView = Symbol("IContextView"); +export const IContextView = Symbol("IContextView"); export interface IContextView { - view: Stage; + view: IDisplayObjectContainer; } diff --git a/src/robotlegs/bender/extensions/contextView/impl/ContextView.ts b/src/robotlegs/bender/extensions/contextView/impl/ContextView.ts index c58b16b..a480476 100644 --- a/src/robotlegs/bender/extensions/contextView/impl/ContextView.ts +++ b/src/robotlegs/bender/extensions/contextView/impl/ContextView.ts @@ -7,15 +7,15 @@ import { IConfig } from "@robotlegsjs/core"; -import { IContextView } from "../api/IContextView"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; -import Stage from "openfl/display/Stage"; +import { IContextView } from "../api/IContextView"; /** * The Context View represents the root Container for a Context */ export class ContextView implements IContextView, IConfig { - private _view: Stage; + private _view: IDisplayObjectContainer; /*============================================================================*/ /* Constructor */ @@ -25,7 +25,7 @@ export class ContextView implements IContextView, IConfig { * The Context View represents the root Container for a Context * @param view The root Container for this Context */ - constructor(view: Stage) { + constructor(view: IDisplayObjectContainer) { if (view !== null && view !== undefined) { this._view = view; } else { @@ -45,7 +45,7 @@ export class ContextView implements IContextView, IConfig { /** * The root Container for this Context */ - public get view(): Stage { + public get view(): IDisplayObjectContainer { return this._view; } } diff --git a/src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMap.ts b/src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMap.ts index 0eda753..0fa38c9 100644 --- a/src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMap.ts +++ b/src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMap.ts @@ -13,7 +13,7 @@ import { IMediatorUnmapper } from "../dsl/IMediatorUnmapper"; /** * The Mediator Map allows you to bind Mediators to objects */ -export let IMediatorMap = Symbol("IMediatorMap"); +export const IMediatorMap = Symbol("IMediatorMap"); export interface IMediatorMap { /** * Maps a matcher that will be tested against incoming items to be handled. diff --git a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory.ts b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory.ts index 50e878e..e201d53 100755 --- a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory.ts +++ b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory.ts @@ -7,6 +7,8 @@ import { IClass, IType, IInjector, applyHooks, guardsApprove, instantiateUnmapped, ITypeFilter } from "@robotlegsjs/core"; +import { IDisplayObjectObserverFactory } from "../../../displayList/api/IDisplayObjectObserverFactory"; + import { IMediatorMapping } from "../api/IMediatorMapping"; import { MediatorManager } from "./MediatorManager"; @@ -34,7 +36,7 @@ export class MediatorFactory { */ constructor(injector: IInjector, manager?: MediatorManager) { this._injector = injector; - this._manager = manager || new MediatorManager(this); + this._manager = manager || new MediatorManager(this, this._injector.get(IDisplayObjectObserverFactory)); } /*============================================================================*/ diff --git a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorManager.ts b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorManager.ts index 3946072..70f0394 100644 --- a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorManager.ts +++ b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorManager.ts @@ -5,12 +5,13 @@ // in accordance with the terms of the license agreement accompanying it. // ------------------------------------------------------------------------------ +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../displayList/api/IDisplayObjectObserverFactory"; + import { IMediatorMapping } from "../api/IMediatorMapping"; import { MediatorFactory } from "./MediatorFactory"; -import DisplayObject from "openfl/display/DisplayObject"; -import Event from "openfl/events/Event"; - /** * @private */ @@ -19,7 +20,10 @@ export class MediatorManager { /* Private Properties */ /*============================================================================*/ - private _factory: MediatorFactory; + private _mediatorFactory: MediatorFactory; + private _displayObjectObserverFactory: IDisplayObjectObserverFactory; + + private _observers: Map = new Map(); /*============================================================================*/ /* Constructor */ @@ -28,8 +32,9 @@ export class MediatorManager { /** * @private */ - constructor(factory: MediatorFactory) { - this._factory = factory; + constructor(factory: MediatorFactory, displayObjectObserverFactory: IDisplayObjectObserverFactory) { + this._mediatorFactory = factory; + this._displayObjectObserverFactory = displayObjectObserverFactory; } /*============================================================================*/ @@ -40,9 +45,15 @@ export class MediatorManager { * @private */ public addMediator(mediator: any, item: any, mapping: IMediatorMapping): void { + const displayObject: IDisplayObject = item; + // Watch Display Object for removal - if (item instanceof DisplayObject && mapping.autoRemoveEnabled) { - item.addEventListener(Event.REMOVED_FROM_STAGE, this.onRemovedFromStage); + if (displayObject !== undefined && mapping.autoRemoveEnabled) { + if (!this._observers.has(displayObject)) { + let observer: IDisplayObjectObserver = this._displayObjectObserverFactory(displayObject, false); + observer.addRemovedFromStageHandler(this.onRemovedFromStage); + this._observers.set(displayObject, observer); + } } // Synchronize with item life-cycle @@ -53,8 +64,15 @@ export class MediatorManager { * @private */ public removeMediator(mediator: any, item: any, mapping: IMediatorMapping): void { - if (item instanceof DisplayObject) { - item.removeEventListener(Event.REMOVED_FROM_STAGE, this.onRemovedFromStage); + const displayObject: IDisplayObject = item; + + // Watch Display Object for removal + if (displayObject !== undefined && mapping.autoRemoveEnabled) { + if (this._observers.has(displayObject)) { + let observer = this._observers.get(displayObject); + observer.destroy(); + this._observers.delete(displayObject); + } } this.destroyMediator(mediator); @@ -64,8 +82,8 @@ export class MediatorManager { /* Private Functions */ /*============================================================================*/ - private onRemovedFromStage = (event: Event): void => { - this._factory.removeMediators(event.target); + private onRemovedFromStage = (view: IDisplayObject): void => { + this._mediatorFactory.removeMediators(view); }; private initializeMediator(mediator: any, mediatedItem: any): void { diff --git a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap.ts b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap.ts index 76a1ba1..6a76913 100755 --- a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap.ts +++ b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap.ts @@ -7,19 +7,19 @@ import { injectable, inject, IClass, IContext, ILogger, ITypeMatcher, TypeMatcher } from "@robotlegsjs/core"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; + +import { IViewHandler } from "../../viewManager/api/IViewHandler"; + import { IMediatorMap } from "../api/IMediatorMap"; import { IMediatorMapper } from "../dsl/IMediatorMapper"; import { IMediatorUnmapper } from "../dsl/IMediatorUnmapper"; -import { IViewHandler } from "../../viewManager/api/IViewHandler"; - import { MediatorFactory } from "./MediatorFactory"; import { MediatorViewHandler } from "./MediatorViewHandler"; import { NullMediatorUnmapper } from "./NullMediatorUnmapper"; import { MediatorMapper } from "./MediatorMapper"; -import DisplayObject from "openfl/display/DisplayObject"; - /** * @private */ @@ -96,7 +96,7 @@ export class MediatorMap implements IMediatorMap, IViewHandler { /** * @inheritDoc */ - public handleView(view: DisplayObject, type: IClass): void { + public handleView(view: IDisplayObject, type: IClass): void { this._viewHandler.handleView(view, type); } diff --git a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorViewHandler.ts b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorViewHandler.ts index c25ee50..b603759 100755 --- a/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorViewHandler.ts +++ b/src/robotlegs/bender/extensions/mediatorMap/impl/MediatorViewHandler.ts @@ -7,13 +7,13 @@ import { IClass } from "@robotlegsjs/core"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; + import { IMediatorMapping } from "../api/IMediatorMapping"; import { IViewHandler } from "../../viewManager/api/IViewHandler"; import { MediatorFactory } from "./MediatorFactory"; -import DisplayObject from "openfl/display/DisplayObject"; - /** * @private */ @@ -70,7 +70,7 @@ export class MediatorViewHandler implements IViewHandler { /** * @private */ - public handleView(view: DisplayObject, type: IClass): void { + public handleView(view: IDisplayObject, type: IClass): void { let interestedMappings = this.getInterestedMappingsFor(view, type); if (interestedMappings) { this._factory.createMediators(view, type, interestedMappings); diff --git a/src/robotlegs/bender/extensions/viewManager/ManualStageObserverExtension.ts b/src/robotlegs/bender/extensions/viewManager/ManualStageObserverExtension.ts index 603b784..1a9d24b 100644 --- a/src/robotlegs/bender/extensions/viewManager/ManualStageObserverExtension.ts +++ b/src/robotlegs/bender/extensions/viewManager/ManualStageObserverExtension.ts @@ -9,6 +9,7 @@ import { IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; import { ContainerRegistry } from "./impl/ContainerRegistry"; import { ManualStageObserver } from "./impl/ManualStageObserver"; +import { IDisplayObjectObserverFactory } from "../../displayList/api/IDisplayObjectObserverFactory"; let installCount: number = 0; @@ -54,8 +55,9 @@ export class ManualStageObserverExtension implements IExtension { // Hark, an actual Singleton! if (!ManualStageObserverExtension._manualStageObserver) { let containerRegistry: ContainerRegistry = this._injector.get(ContainerRegistry); + let factory: IDisplayObjectObserverFactory = this._injector.get(IDisplayObjectObserverFactory); this._logger.debug("Creating genuine ManualStageObserver Singleton"); - ManualStageObserverExtension._manualStageObserver = new ManualStageObserver(containerRegistry); + ManualStageObserverExtension._manualStageObserver = new ManualStageObserver(containerRegistry, factory); } } diff --git a/src/robotlegs/bender/extensions/viewManager/StageCrawlerExtension.ts b/src/robotlegs/bender/extensions/viewManager/StageCrawlerExtension.ts index 1b64177..423afd7 100644 --- a/src/robotlegs/bender/extensions/viewManager/StageCrawlerExtension.ts +++ b/src/robotlegs/bender/extensions/viewManager/StageCrawlerExtension.ts @@ -7,6 +7,8 @@ import { IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; +import { IDisplayObjectContainer } from "../../displayList/api/IDisplayObjectContainer"; + import { IContextView } from "../contextView/api/IContextView"; import { IViewManager } from "./api/IViewManager"; @@ -14,8 +16,6 @@ import { ContainerBinding } from "./impl/ContainerBinding"; import { ContainerRegistry } from "./impl/ContainerRegistry"; import { StageCrawler } from "./impl/StageCrawler"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; - /** * View Handlers (like the MediatorMap) handle views as they land on stage. * @@ -58,7 +58,7 @@ export class StageCrawlerExtension implements IExtension { private scanViewManagedContainers(): void { this._logger.debug("ViewManager is installed. Checking for managed containers..."); let viewManager: IViewManager = this._injector.get(IViewManager); - viewManager.containers.forEach((container: DisplayObjectContainer) => { + viewManager.containers.forEach((container: IDisplayObjectContainer) => { this.scanContainer(container); }); } @@ -73,7 +73,7 @@ export class StageCrawlerExtension implements IExtension { } } - private scanContainer(container: DisplayObjectContainer): void { + private scanContainer(container: IDisplayObjectContainer): void { let binding: ContainerBinding = this._containerRegistry.getBinding(container); this._logger.debug("StageCrawler scanning container {0} ...", [container]); new StageCrawler(binding).scan(container); diff --git a/src/robotlegs/bender/extensions/viewManager/StageObserverExtension.ts b/src/robotlegs/bender/extensions/viewManager/StageObserverExtension.ts index 68197f3..59f2cc6 100644 --- a/src/robotlegs/bender/extensions/viewManager/StageObserverExtension.ts +++ b/src/robotlegs/bender/extensions/viewManager/StageObserverExtension.ts @@ -7,6 +7,8 @@ import { IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; +import { IDisplayObjectObserverFactory } from "../../displayList/api/IDisplayObjectObserverFactory"; + import { ContainerRegistry } from "./impl/ContainerRegistry"; import { StageObserver } from "./impl/StageObserver"; @@ -54,8 +56,9 @@ export class StageObserverExtension implements IExtension { // Hark, an actual Singleton! if (!StageObserverExtension._stageObserver) { let containerRegistry: ContainerRegistry = this._injector.get(ContainerRegistry); + let factory: IDisplayObjectObserverFactory = this._injector.get(IDisplayObjectObserverFactory); this._logger.debug("Creating genuine StageObserver Singleton"); - StageObserverExtension._stageObserver = new StageObserver(containerRegistry); + StageObserverExtension._stageObserver = new StageObserver(containerRegistry, factory); } } diff --git a/src/robotlegs/bender/extensions/viewManager/ViewManagerExtension.ts b/src/robotlegs/bender/extensions/viewManager/ViewManagerExtension.ts index cd3f75f..0ecf840 100644 --- a/src/robotlegs/bender/extensions/viewManager/ViewManagerExtension.ts +++ b/src/robotlegs/bender/extensions/viewManager/ViewManagerExtension.ts @@ -7,8 +7,8 @@ import { IContext, IExtension, IInjector } from "@robotlegsjs/core"; -import { IViewManager } from "./api/IViewManager"; -import { ViewManager } from "./impl/ViewManager"; +import { IViewManager } from "../viewManager/api/IViewManager"; +import { ViewManager } from "../viewManager/impl/ViewManager"; import { ContainerRegistry } from "./impl/ContainerRegistry"; diff --git a/src/robotlegs/bender/extensions/viewManager/api/IViewHandler.ts b/src/robotlegs/bender/extensions/viewManager/api/IViewHandler.ts index 0c6d96e..6d78a13 100644 --- a/src/robotlegs/bender/extensions/viewManager/api/IViewHandler.ts +++ b/src/robotlegs/bender/extensions/viewManager/api/IViewHandler.ts @@ -7,7 +7,7 @@ import { IClass } from "@robotlegsjs/core"; -import DisplayObject from "openfl/display/DisplayObject"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; /** * View handler contract @@ -18,5 +18,5 @@ export interface IViewHandler { * @param view The view instance to handle * @param type The class of the view instance */ - handleView(view: DisplayObject, type: IClass): void; + handleView(view: IDisplayObject, type: IClass): void; } diff --git a/src/robotlegs/bender/extensions/viewManager/api/IViewManager.ts b/src/robotlegs/bender/extensions/viewManager/api/IViewManager.ts index f282b27..59d85e4 100644 --- a/src/robotlegs/bender/extensions/viewManager/api/IViewManager.ts +++ b/src/robotlegs/bender/extensions/viewManager/api/IViewManager.ts @@ -6,9 +6,10 @@ // ------------------------------------------------------------------------------ import { IEventDispatcher } from "@robotlegsjs/core"; -import { IViewHandler } from "./IViewHandler"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; + +import { IViewHandler } from "./IViewHandler"; /*[Event(name="containerAdd", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ /*[Event(name="containerRemove", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ @@ -18,24 +19,24 @@ import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; /** * The View Manager allows you to add multiple "view root" containers to a context */ -export let IViewManager = Symbol("IViewManager"); +export const IViewManager = Symbol("IViewManager"); export interface IViewManager extends IEventDispatcher { /** * A list of currently registered containers */ - containers: DisplayObjectContainer[]; + containers: IDisplayObjectContainer[]; /** * Adds a container as a "view root" into the context * @param container */ - addContainer(container: DisplayObjectContainer): void; + addContainer(container: IDisplayObjectContainer): void; /** * Removes a container from this context * @param container */ - removeContainer(container: DisplayObjectContainer): void; + removeContainer(container: IDisplayObjectContainer): void; /** * Registers a view handler diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ConfigureViewEvent.ts b/src/robotlegs/bender/extensions/viewManager/impl/ConfigureViewEvent.ts index d48cba9..d8e75b8 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/ConfigureViewEvent.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ConfigureViewEvent.ts @@ -7,7 +7,7 @@ import { Event } from "@robotlegsjs/core"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; /** * View Configuration Event @@ -24,12 +24,12 @@ export class ConfigureViewEvent extends Event { /* Public Properties */ /*============================================================================*/ - private _view: DisplayObjectContainer; + private _view: IDisplayObjectContainer; /** * The view instance associated with this event */ - public get view(): DisplayObjectContainer { + public get view(): IDisplayObjectContainer { return this._view; } @@ -42,7 +42,7 @@ export class ConfigureViewEvent extends Event { * @param type The event type * @param view The associated view instance */ - constructor(type: string, view: DisplayObjectContainer) { + constructor(type: string, view: IDisplayObjectContainer) { super(type, true); this._view = view; } diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ContainerBinding.ts b/src/robotlegs/bender/extensions/viewManager/impl/ContainerBinding.ts index c5c64d5..ad3b9b4 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/ContainerBinding.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ContainerBinding.ts @@ -7,13 +7,13 @@ import { IClass, EventDispatcher } from "@robotlegsjs/core"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; + import { IViewHandler } from "../api/IViewHandler"; import { ContainerBindingEvent } from "./ContainerBindingEvent"; -import DisplayObject from "openfl/display/DisplayObject"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; - /*[Event(name="bindingEmpty", type="robotlegs.bender.extensions.viewManager.impl.ContainerBindingEvent")]*/ /** * @private @@ -39,12 +39,12 @@ export class ContainerBinding extends EventDispatcher { this._parent = value; } - private _container: DisplayObjectContainer; + private _container: IDisplayObjectContainer; /** * @private */ - public get container(): DisplayObjectContainer { + public get container(): IDisplayObjectContainer { return this._container; } @@ -61,7 +61,7 @@ export class ContainerBinding extends EventDispatcher { /** * @private */ - constructor(container: DisplayObjectContainer) { + constructor(container: IDisplayObjectContainer) { super(); this._container = container; } @@ -96,7 +96,7 @@ export class ContainerBinding extends EventDispatcher { /** * @private */ - public handleView(view: DisplayObject, type: IClass): void { + public handleView(view: IDisplayObject, type: IClass): void { let length: number = this._handlers.length; for (let i: number = 0; i < length; i++) { let handler: IViewHandler = this._handlers[i]; diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry.ts b/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry.ts index a54720f..bc110ef 100755 --- a/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry.ts @@ -7,12 +7,12 @@ import { EventDispatcher } from "@robotlegsjs/core"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; + import { ContainerBinding } from "./ContainerBinding"; import { ContainerBindingEvent } from "./ContainerBindingEvent"; import { ContainerRegistryEvent } from "./ContainerRegistryEvent"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; - /*[Event(name="containerAdd", type="robotlegs.bender.extensions.viewManager.impl.ContainerRegistryEvent")]*/ /*[Event(name="containerRemove", type="robotlegs.bender.extensions.viewManager.impl.ContainerRegistryEvent")]*/ /*[Event(name="rootContainerAdd", type="robotlegs.bender.extensions.viewManager.impl.ContainerRegistryEvent")]*/ @@ -48,7 +48,7 @@ export class ContainerRegistry extends EventDispatcher { /* Private Properties */ /*============================================================================*/ - private _bindingByContainer: Map = new Map(); + private _bindingByContainer: Map = new Map(); /*============================================================================*/ /* Public Functions */ @@ -57,7 +57,7 @@ export class ContainerRegistry extends EventDispatcher { /** * @private */ - public addContainer(container: DisplayObjectContainer): ContainerBinding { + public addContainer(container: IDisplayObjectContainer): ContainerBinding { let binding = this._bindingByContainer.get(container); if (!binding) { binding = this.createBinding(container); @@ -69,7 +69,7 @@ export class ContainerRegistry extends EventDispatcher { /** * @private */ - public removeContainer(container: DisplayObjectContainer): ContainerBinding { + public removeContainer(container: IDisplayObjectContainer): ContainerBinding { let binding: ContainerBinding = this._bindingByContainer.get(container); if (binding) { @@ -84,8 +84,8 @@ export class ContainerRegistry extends EventDispatcher { * * @private */ - public findParentBinding(target: DisplayObjectContainer): ContainerBinding { - let parent: DisplayObjectContainer = target.parent; + public findParentBinding(target: IDisplayObjectContainer): ContainerBinding { + let parent: IDisplayObjectContainer = target.parent; while (parent) { let binding: ContainerBinding = this._bindingByContainer.get(parent); if (binding) { @@ -99,7 +99,7 @@ export class ContainerRegistry extends EventDispatcher { /** * @private */ - public getBinding(container: DisplayObjectContainer): ContainerBinding { + public getBinding(container: IDisplayObjectContainer): ContainerBinding { return this._bindingByContainer.get(container); } @@ -107,16 +107,16 @@ export class ContainerRegistry extends EventDispatcher { /* Private Functions */ /*============================================================================*/ - private createBinding(container: DisplayObjectContainer): ContainerBinding { + private createBinding(container: IDisplayObjectContainer): ContainerBinding { let binding: ContainerBinding = new ContainerBinding(container); this._bindings.push(binding); // Add a listener so that we can remove this binding when it has no handlers - binding.addEventListener(ContainerBindingEvent.BINDING_EMPTY, this.onBindingEmpty.bind(this)); + binding.addEventListener(ContainerBindingEvent.BINDING_EMPTY, this.onBindingEmpty); // If the new binding doesn't have a parent it is a Root binding.parent = this.findParentBinding(container); - if (binding.parent == null) { + if (!binding.parent) { this.addRootBinding(binding); } @@ -178,7 +178,7 @@ export class ContainerRegistry extends EventDispatcher { this.dispatchEvent(new ContainerRegistryEvent(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, binding.container)); } - private onBindingEmpty(event: ContainerBindingEvent): void { + private onBindingEmpty = (event: ContainerBindingEvent): void => { this.removeBinding(event.target); - } + }; } diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistryEvent.ts b/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistryEvent.ts index f1002ae..00efbf3 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistryEvent.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistryEvent.ts @@ -7,7 +7,7 @@ import { Event } from "@robotlegsjs/core"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; /** * Container existence event @@ -30,12 +30,12 @@ export class ContainerRegistryEvent extends Event { /* Public Properties */ /*============================================================================*/ - private _container: DisplayObjectContainer; + private _container: IDisplayObjectContainer; /** * The container associated with this event */ - public get container(): DisplayObjectContainer { + public get container(): IDisplayObjectContainer { return this._container; } @@ -48,7 +48,7 @@ export class ContainerRegistryEvent extends Event { * @param type The event type * @param container The container associated with this event */ - constructor(type: string, container: DisplayObjectContainer) { + constructor(type: string, container: IDisplayObjectContainer) { super(type); this._container = container; } diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ManualStageObserver.ts b/src/robotlegs/bender/extensions/viewManager/impl/ManualStageObserver.ts index be729bc..95b4b1f 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/ManualStageObserver.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ManualStageObserver.ts @@ -7,16 +7,16 @@ import { IClass } from "@robotlegsjs/core"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; +import { IDisplayObjectObserver } from "../../../displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../displayList/api/IDisplayObjectObserverFactory"; + import { ContainerRegistryEvent } from "./ContainerRegistryEvent"; import { ContainerRegistry } from "./ContainerRegistry"; import { ContainerBinding } from "./ContainerBinding"; -import { ConfigureViewEvent } from "./ConfigureViewEvent"; - -import DisplayObject from "openfl/display/DisplayObject"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; - /** * @private */ @@ -26,7 +26,10 @@ export class ManualStageObserver { /*============================================================================*/ private _registry: ContainerRegistry; - private _eventListener: (event: ConfigureViewEvent) => void; + + private _displayObjectObserverFactory: IDisplayObjectObserverFactory; + + private _observers: Map = new Map(); /*============================================================================*/ /* Constructor */ @@ -35,12 +38,13 @@ export class ManualStageObserver { /** * @private */ - constructor(containerRegistry: ContainerRegistry) { + constructor(containerRegistry: ContainerRegistry, displayObjectObserverFactory: IDisplayObjectObserverFactory) { this._registry = containerRegistry; + this._displayObjectObserverFactory = displayObjectObserverFactory; // We care about all containers (not just roots) - this._registry.addEventListener(ContainerRegistryEvent.CONTAINER_ADD, this.onContainerAdd, this); - this._registry.addEventListener(ContainerRegistryEvent.CONTAINER_REMOVE, this.onContainerRemove, this); + this._registry.addEventListener(ContainerRegistryEvent.CONTAINER_ADD, this.onContainerAdd); + this._registry.addEventListener(ContainerRegistryEvent.CONTAINER_REMOVE, this.onContainerRemove); // We might have arrived late on the scene this._registry.bindings.forEach((binding: ContainerBinding) => { @@ -56,44 +60,58 @@ export class ManualStageObserver { * @private */ public destroy(): void { - this._registry.removeEventListener(ContainerRegistryEvent.CONTAINER_ADD, this.onContainerAdd, this); - this._registry.removeEventListener(ContainerRegistryEvent.CONTAINER_REMOVE, this.onContainerRemove, this); - - this._registry.rootBindings.forEach((binding: ContainerBinding) => { - this.removeContainerListener(binding.container); - }); + if (this._registry) { + this._registry.removeEventListener(ContainerRegistryEvent.CONTAINER_ADD, this.onContainerAdd); + this._registry.removeEventListener(ContainerRegistryEvent.CONTAINER_REMOVE, this.onContainerRemove); + + this._registry.rootBindings.forEach((binding: ContainerBinding) => { + this.removeContainerListener(binding.container); + }); + } + + if (this._observers) { + this._observers.forEach((observer: IDisplayObjectObserver) => { + observer.destroy(); + }); + } + + this._registry = null; + this._displayObjectObserverFactory = null; + this._observers = null; } /*============================================================================*/ /* Private Functions */ /*============================================================================*/ - private onContainerAdd(event: ContainerRegistryEvent): void { + private onContainerAdd = (event: ContainerRegistryEvent): void => { this.addContainerListener(event.container); - } + }; - private onContainerRemove(event: ContainerRegistryEvent): void { + private onContainerRemove = (event: ContainerRegistryEvent): void => { this.removeContainerListener(event.container); + }; + + private addContainerListener(container: IDisplayObjectContainer): void { + if (!this._observers.has(container)) { + // We're interested in ALL container bindings + // but just for normal, bubbling events + let observer: IDisplayObjectObserver = this._displayObjectObserverFactory(container, false); + observer.addConfigureViewHandler(this.onConfigureView); + this._observers.set(container, observer); + } } - private addContainerListener(container: DisplayObjectContainer): void { - // We're interested in ALL container bindings - // but just for normal, bubbling events - this._eventListener = this.onConfigureView.bind(this); - container.addEventListener(ConfigureViewEvent.CONFIGURE_VIEW, this._eventListener); - } - - private removeContainerListener(container: DisplayObjectContainer): void { - container.removeEventListener(ConfigureViewEvent.CONFIGURE_VIEW, this._eventListener); + private removeContainerListener(container: IDisplayObjectContainer): void { + if (this._observers.has(container)) { + let observer: IDisplayObjectObserver = this._observers.get(container); + observer.destroy(); + this._observers.delete(container); + } } - private onConfigureView(event: ConfigureViewEvent): void { - // Stop that event! - event.stopPropagation(); - - let container: DisplayObjectContainer = event.currentTarget; - let view: DisplayObject = event.target; + private onConfigureView = (container: IDisplayObjectContainer, view: IDisplayObject): void => { let type: IClass = >view.constructor; this._registry.getBinding(container).handleView(view, type); - } + }; } diff --git a/src/robotlegs/bender/extensions/viewManager/impl/StageCrawler.ts b/src/robotlegs/bender/extensions/viewManager/impl/StageCrawler.ts index 5e76cb6..d53dd28 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/StageCrawler.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/StageCrawler.ts @@ -7,10 +7,10 @@ import { IClass } from "@robotlegsjs/core"; -import { ContainerBinding } from "./ContainerBinding"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; -import DisplayObject from "openfl/display/DisplayObject"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { ContainerBinding } from "./ContainerBinding"; /** * @private @@ -40,7 +40,7 @@ export class StageCrawler { /** * @private */ - public scan(container: DisplayObjectContainer): void { + public scan(container: IDisplayObjectContainer): void { this.scanContainer(container); } @@ -48,21 +48,31 @@ export class StageCrawler { /* Private Functions */ /*============================================================================*/ - private scanContainer(container: DisplayObjectContainer): void { + private scanContainer(container: IDisplayObjectContainer): void { this.processView(container); - for (let i: number = 0; i < container.numChildren; i++) { - let child: DisplayObject = container.getChildAt(i); + if (container.children !== undefined) { + container.children.forEach((child: IDisplayObject) => { + if ((child).children !== undefined) { + this.scanContainer(child); + } else { + this.processView(child); + } + }); + } else if (container.numChildren !== undefined && container.getChildAt !== undefined) { + for (let i: number = 0; i < container.numChildren; i++) { + let child: any = container.getChildAt(i); - if (child instanceof DisplayObjectContainer) { - this.scanContainer(child); - } else { - this.processView(child); + if (child.numChildren !== undefined && child.getChildAt !== undefined) { + this.scanContainer(child); + } else { + this.processView(child); + } } } } - private processView(view: DisplayObject): void { + private processView(view: IDisplayObject): void { this._binding.handleView(view, >view.constructor); } } diff --git a/src/robotlegs/bender/extensions/viewManager/impl/StageObserver.ts b/src/robotlegs/bender/extensions/viewManager/impl/StageObserver.ts index 48d33b2..fa97abf 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/StageObserver.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/StageObserver.ts @@ -7,13 +7,15 @@ import { IClass } from "@robotlegsjs/core"; +import { IDisplayObject } from "../../../displayList/api/IDisplayObject"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; +import { IDisplayObjectObserver } from "../../../displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../displayList/api/IDisplayObjectObserverFactory"; + import { ContainerBinding } from "./ContainerBinding"; import { ContainerRegistry } from "./ContainerRegistry"; import { ContainerRegistryEvent } from "./ContainerRegistryEvent"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import Event from "openfl/events/Event"; - /** * @private */ @@ -24,6 +26,10 @@ export class StageObserver { private _registry: ContainerRegistry; + private _displayObjectObserverFactory: IDisplayObjectObserverFactory; + + private _observers: Map = new Map(); + /*============================================================================*/ /* Constructor */ /*============================================================================*/ @@ -31,12 +37,13 @@ export class StageObserver { /** * @private */ - constructor(containerRegistry: ContainerRegistry) { + constructor(containerRegistry: ContainerRegistry, displayObjectObserverFactory: IDisplayObjectObserverFactory) { this._registry = containerRegistry; + this._displayObjectObserverFactory = displayObjectObserverFactory; // We only care about roots - this._registry.addEventListener(ContainerRegistryEvent.ROOT_CONTAINER_ADD, this.onRootContainerAdd, this); - this._registry.addEventListener(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, this.onRootContainerRemove, this); + this._registry.addEventListener(ContainerRegistryEvent.ROOT_CONTAINER_ADD, this.onRootContainerAdd); + this._registry.addEventListener(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, this.onRootContainerRemove); // We might have arrived late on the scene this._registry.rootBindings.forEach((binding: ContainerBinding) => { @@ -52,36 +59,55 @@ export class StageObserver { * @private */ public destroy(): void { - this._registry.removeEventListener(ContainerRegistryEvent.ROOT_CONTAINER_ADD, this.onRootContainerAdd, this); - this._registry.removeEventListener(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, this.onRootContainerRemove, this); + if (this._registry) { + this._registry.removeEventListener(ContainerRegistryEvent.ROOT_CONTAINER_ADD, this.onRootContainerAdd); + this._registry.removeEventListener(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, this.onRootContainerRemove); - this._registry.rootBindings.forEach((binding: ContainerBinding) => { - this.removeRootListener(binding.container); - }); + this._registry.rootBindings.forEach((binding: ContainerBinding) => { + this.removeRootListener(binding.container); + }); + } + + if (this._observers) { + this._observers.forEach((observer: IDisplayObjectObserver) => { + observer.destroy(); + }); + } + + this._registry = null; + this._displayObjectObserverFactory = null; + this._observers = null; } /*============================================================================*/ /* Private Functions */ /*============================================================================*/ - private onRootContainerAdd(event: ContainerRegistryEvent): void { + private onRootContainerAdd = (event: ContainerRegistryEvent): void => { this.addRootListener(event.container); - } + }; - private onRootContainerRemove(event: ContainerRegistryEvent): void { + private onRootContainerRemove = (event: ContainerRegistryEvent): void => { this.removeRootListener(event.container); - } + }; - private addRootListener(container: DisplayObjectContainer): void { - container.addEventListener(Event.ADDED_TO_STAGE, this.onViewAddedToStage, true); + private addRootListener(container: IDisplayObjectContainer): void { + if (!this._observers.has(container)) { + let observer: IDisplayObjectObserver = this._displayObjectObserverFactory(container, true); + observer.addAddedToStageHandler(this.onViewAddedToStage); + this._observers.set(container, observer); + } } - private removeRootListener(container: DisplayObjectContainer): void { - container.removeEventListener(Event.ADDED_TO_STAGE, this.onViewAddedToStage, true); + private removeRootListener(container: IDisplayObjectContainer): void { + if (this._observers.has(container)) { + let observer: IDisplayObjectObserver = this._observers.get(container); + observer.destroy(); + this._observers.delete(container); + } } - private onViewAddedToStage = (event: Event): void => { - let view: DisplayObjectContainer = event.target; + private onViewAddedToStage = (view: IDisplayObjectContainer): void => { let type: IClass = >view.constructor; // Walk upwards from the nearest binding diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ViewManager.ts b/src/robotlegs/bender/extensions/viewManager/impl/ViewManager.ts index 079a227..77d309e 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/ViewManager.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ViewManager.ts @@ -7,15 +7,15 @@ import { injectable, inject, EventDispatcher } from "@robotlegsjs/core"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; + import { IViewHandler } from "../api/IViewHandler"; import { IViewManager } from "../api/IViewManager"; import { ViewManagerEvent } from "./ViewManagerEvent"; -import { ContainerRegistry } from "./ContainerRegistry"; -import { ContainerBinding } from "./ContainerBinding"; - -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { ContainerRegistry } from "../impl/ContainerRegistry"; +import { ContainerBinding } from "../impl/ContainerBinding"; /*[Event(name="containerAdd", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ /*[Event(name="containerRemove", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ @@ -31,12 +31,12 @@ export class ViewManager extends EventDispatcher implements IViewManager { /* Public Properties */ /*============================================================================*/ - private _containers: DisplayObjectContainer[] = []; + private _containers: IDisplayObjectContainer[] = []; /** * @inheritDoc */ - public get containers(): DisplayObjectContainer[] { + public get containers(): IDisplayObjectContainer[] { return this._containers; } @@ -67,7 +67,7 @@ export class ViewManager extends EventDispatcher implements IViewManager { /** * @inheritDoc */ - public addContainer(container: DisplayObjectContainer): void { + public addContainer(container: IDisplayObjectContainer): void { if (!this.validContainer(container)) { return; } @@ -83,7 +83,7 @@ export class ViewManager extends EventDispatcher implements IViewManager { /** * @inheritDoc */ - public removeContainer(container: DisplayObjectContainer): void { + public removeContainer(container: IDisplayObjectContainer): void { let index: number = this._containers.indexOf(container); if (index === -1) { @@ -153,7 +153,7 @@ export class ViewManager extends EventDispatcher implements IViewManager { /* Private Functions */ /*============================================================================*/ - private validContainer(container: DisplayObjectContainer): boolean { + private validContainer(container: IDisplayObjectContainer): boolean { let isValid: boolean = this._containers.indexOf(container) < 0; if (isValid) { diff --git a/src/robotlegs/bender/extensions/viewManager/impl/ViewManagerEvent.ts b/src/robotlegs/bender/extensions/viewManager/impl/ViewManagerEvent.ts index 64d01ac..d5c66e6 100644 --- a/src/robotlegs/bender/extensions/viewManager/impl/ViewManagerEvent.ts +++ b/src/robotlegs/bender/extensions/viewManager/impl/ViewManagerEvent.ts @@ -7,9 +7,9 @@ import { Event } from "@robotlegsjs/core"; -import { IViewHandler } from "../api/IViewHandler"; +import { IDisplayObjectContainer } from "../../../displayList/api/IDisplayObjectContainer"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { IViewHandler } from "../api/IViewHandler"; /** * Container existence event @@ -32,12 +32,12 @@ export class ViewManagerEvent extends Event { /* Public Properties */ /*============================================================================*/ - private _container: DisplayObjectContainer; + private _container: IDisplayObjectContainer; /** * The container associated with this event */ - public get container(): DisplayObjectContainer { + public get container(): IDisplayObjectContainer { return this._container; } @@ -60,7 +60,7 @@ export class ViewManagerEvent extends Event { * @param container The container associated with this event * @param handler The view handler associated with this event */ - constructor(type: string, container?: DisplayObjectContainer, handler?: IViewHandler) { + constructor(type: string, container?: IDisplayObjectContainer, handler?: IViewHandler) { super(type); this._container = container; this._handler = handler; diff --git a/test/robotlegs/bender/extensions/displayList/support/MockDisplayObject.ts b/test/robotlegs/bender/extensions/displayList/support/MockDisplayObject.ts new file mode 100644 index 0000000..28a6cfe --- /dev/null +++ b/test/robotlegs/bender/extensions/displayList/support/MockDisplayObject.ts @@ -0,0 +1,19 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectContainer } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectContainer"; + +export class MockDisplayObject implements IDisplayObject { + private _parent: IDisplayObjectContainer; + public set parent(value: IDisplayObjectContainer) { + this._parent = value; + } + public get parent(): IDisplayObjectContainer { + return this._parent; + } +} diff --git a/test/robotlegs/bender/extensions/displayList/support/MockDisplayObjectContainer.ts b/test/robotlegs/bender/extensions/displayList/support/MockDisplayObjectContainer.ts new file mode 100644 index 0000000..09dd7e7 --- /dev/null +++ b/test/robotlegs/bender/extensions/displayList/support/MockDisplayObjectContainer.ts @@ -0,0 +1,17 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectContainer } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectContainer"; + +import { MockDisplayObject } from "./MockDisplayObject"; + +export class MockDisplayObjectContainer extends MockDisplayObject implements IDisplayObjectContainer { + public contains(child: IDisplayObject): boolean { + return false; + } +} diff --git a/test/robotlegs/bender/extensions/displayList/support/MockDisplayObjectObserver.ts b/test/robotlegs/bender/extensions/displayList/support/MockDisplayObjectObserver.ts new file mode 100644 index 0000000..5722151 --- /dev/null +++ b/test/robotlegs/bender/extensions/displayList/support/MockDisplayObjectObserver.ts @@ -0,0 +1,79 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; + +import { MockDisplayObject } from "./MockDisplayObject"; + +/** + * + */ +export class MockDisplayObjectObserver implements IDisplayObjectObserver { + private _displayObject: MockDisplayObject; + + /*============================================================================*/ + /* Constructor */ + /*============================================================================*/ + + /** + * + * @param displayObject + * @param useCapture + */ + constructor(displayObject: IDisplayObject, useCapture: boolean) { + if (displayObject !== null && displayObject !== undefined) { + this._displayObject = displayObject; + } else { + throw new Error("DisplayObject can't be null or undefined"); + } + } + + /*============================================================================*/ + /* Public Functions */ + /*============================================================================*/ + + /** + * + * @param handler + */ + public addAddedToStageHandler(handler: Function): void {} + + /** + * + * @param handler + */ + public addRemovedFromStageHandler(handler: Function): void {} + + /** + * + * @param handler + */ + public addConfigureViewHandler(handler: Function): void {} + + /** + * + */ + public destroy(): void { + this._displayObject = null; + } + + /*============================================================================*/ + /* Private Functions */ + /*============================================================================*/ + + /*============================================================================*/ + /* Public Properties */ + /*============================================================================*/ + + /** + * The display object + */ + public get displayObject(): IDisplayObject { + return this._displayObject; + } +} diff --git a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorFactory.test.ts b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorFactory.test.ts index 338e1f0..25a512a 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorFactory.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorFactory.test.ts @@ -14,7 +14,13 @@ import { assert } from "chai"; import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; import DisplayObject from "openfl/display/DisplayObject"; -import { IInjector, ITypeFilter, RobotlegsInjector, TypeMatcher } from "@robotlegsjs/core"; +import { interfaces, IInjector, ITypeFilter, RobotlegsInjector, TypeMatcher } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { IMediator } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/api/IMediator"; import { IMediatorMapping } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMapping"; @@ -38,6 +44,12 @@ describe("MediatorFactory", () => { beforeEach(() => { injector = new RobotlegsInjector(); + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); + factory = new MediatorFactory(injector); }); @@ -189,7 +201,7 @@ describe("MediatorFactory", () => { it("creating_mediator_gives_mediator_to_mediator_manager", () => { const mediatedItem: DisplayObjectContainer = new DisplayObjectContainer(); const mapping: IMediatorMapping = new MediatorMapping(createTypeFilter([DisplayObjectContainer]), CallbackMediator); - manager = new MediatorManager(factory); + manager = new MediatorManager(factory, injector.get(IDisplayObjectObserverFactory)); let managerMock = sinon.mock(manager); managerMock.expects("addMediator").once(); factory = new MediatorFactory(injector, manager); @@ -202,7 +214,7 @@ describe("MediatorFactory", () => { it("removeMediator_removes_mediator_from_manager", () => { const mediatedItem: DisplayObjectContainer = new DisplayObjectContainer(); const mapping: IMediatorMapping = new MediatorMapping(createTypeFilter([DisplayObjectContainer]), CallbackMediator); - manager = new MediatorManager(factory); + manager = new MediatorManager(factory, injector.get(IDisplayObjectObserverFactory)); let managerMock = sinon.mock(manager); managerMock.expects("removeMediator").once(); factory = new MediatorFactory(injector, manager); @@ -218,7 +230,7 @@ describe("MediatorFactory", () => { const mediatedItem2: DisplayObjectContainer = new DisplayObjectContainer(); const mapping1: IMediatorMapping = new MediatorMapping(createTypeFilter([DisplayObjectContainer]), CallbackMediator); const mapping2: IMediatorMapping = new MediatorMapping(createTypeFilter([DisplayObject]), ViewInjectedAsRequestedMediator); - manager = new MediatorManager(factory); + manager = new MediatorManager(factory, injector.get(IDisplayObjectObserverFactory)); let managerMock = sinon.mock(manager); managerMock.expects("removeMediator").exactly(4); factory = new MediatorFactory(injector, manager); diff --git a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorManager.test.ts b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorManager.test.ts index 52addb6..147e3fe 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorManager.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorManager.test.ts @@ -14,7 +14,13 @@ import { assert } from "chai"; import Stage from "openfl/display/Stage"; import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import { instantiateUnmapped, IInjector, ITypeFilter, RobotlegsInjector, TypeMatcher } from "@robotlegsjs/core"; +import { interfaces, instantiateUnmapped, IInjector, ITypeFilter, RobotlegsInjector, TypeMatcher } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { IMediator } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/api/IMediator"; import { IMediatorMapping } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMapping"; @@ -34,6 +40,12 @@ describe("MediatorManager", () => { beforeEach(() => { injector = new RobotlegsInjector(); + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); + factory = new MediatorFactory(injector); manager = (factory)._manager; stage = new Stage(); diff --git a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMap.test.ts b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMap.test.ts index 818508f..25aae91 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMap.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMap.test.ts @@ -9,21 +9,33 @@ import "../../../../../entry"; import { assert } from "chai"; -import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import DisplayObject from "openfl/display/DisplayObject"; +import { interfaces, IContext, Context, TypeMatcher } from "@robotlegsjs/core"; -import { IContext, Context, TypeMatcher } from "@robotlegsjs/core"; +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { IMediatorMapper } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/dsl/IMediatorMapper"; import { MediatorMap } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap"; import { MediatorMapper } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMapper"; +import { MockDisplayObject } from "../../displayList/support/MockDisplayObject"; +import { MockDisplayObjectContainer } from "../../displayList/support/MockDisplayObjectContainer"; +import { MockDisplayObjectObserver } from "../../displayList/support/MockDisplayObjectObserver"; + describe("MediatorMap", () => { let context: IContext = null; let mediatorMap: MediatorMap = null; beforeEach(() => { context = new Context(); + context.injector + .bind>(IDisplayObjectObserverFactory) + .toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new MockDisplayObjectObserver(view, useCapture); + }; + }); mediatorMap = new MediatorMap(context); }); @@ -36,56 +48,58 @@ describe("MediatorMap", () => { mediatorMap = null; }); - xit("mapMatcher_creates_mapper", () => { - const matcher: TypeMatcher = new TypeMatcher().allOf(DisplayObjectContainer); + it("mapMatcher_creates_mapper", () => { + const matcher: TypeMatcher = new TypeMatcher().allOf(MockDisplayObjectContainer); assert.instanceOf(mediatorMap.mapMatcher(matcher), MediatorMapper); }); - xit("mapMatcher_to_matching_TypeMatcher_returns_same_mapper", () => { - const matcher1: TypeMatcher = new TypeMatcher().allOf(DisplayObjectContainer); - const matcher2: TypeMatcher = new TypeMatcher().allOf(DisplayObjectContainer); + it("mapMatcher_to_matching_TypeMatcher_returns_same_mapper", () => { + const matcher1: TypeMatcher = new TypeMatcher().allOf(MockDisplayObjectContainer); + const matcher2: TypeMatcher = new TypeMatcher().allOf(MockDisplayObjectContainer); const mapper1: IMediatorMapper = mediatorMap.mapMatcher(matcher1); const mapper2: IMediatorMapper = mediatorMap.mapMatcher(matcher2); assert.equal(mapper1, mapper2); }); - xit("mapMatcher_to_differing_TypeMatcher_returns_different_mapper", () => { - const matcher1: TypeMatcher = new TypeMatcher().allOf(DisplayObjectContainer); - const matcher2: TypeMatcher = new TypeMatcher().allOf(DisplayObject); + it("mapMatcher_to_differing_TypeMatcher_returns_different_mapper", () => { + const matcher1: TypeMatcher = new TypeMatcher().allOf(MockDisplayObjectContainer); + const matcher2: TypeMatcher = new TypeMatcher().allOf(MockDisplayObject); const mapper1: IMediatorMapper = mediatorMap.mapMatcher(matcher1); const mapper2: IMediatorMapper = mediatorMap.mapMatcher(matcher2); assert.notEqual(mapper1, mapper2); }); - xit("map_creates_mapper", () => { - assert.instanceOf(mediatorMap.map(DisplayObjectContainer), MediatorMapper); + it("map_creates_mapper", () => { + assert.instanceOf(mediatorMap.map(MockDisplayObjectContainer), MediatorMapper); }); - xit("map_to_matching_TypeMatcher_returns_same_mapper", () => { - const mapper1: IMediatorMapper = mediatorMap.map(DisplayObjectContainer); - const mapper2: IMediatorMapper = mediatorMap.map(DisplayObjectContainer); + it("map_to_matching_TypeMatcher_returns_same_mapper", () => { + const mapper1: IMediatorMapper = mediatorMap.map(MockDisplayObjectContainer); + const mapper2: IMediatorMapper = mediatorMap.map(MockDisplayObjectContainer); assert.equal(mapper1, mapper2); }); - xit("map_to_differing_TypeMatcher_returns_different_mapper", () => { - const mapper1: IMediatorMapper = mediatorMap.map(DisplayObjectContainer); - const mapper2: IMediatorMapper = mediatorMap.map(DisplayObject); + it("map_to_differing_TypeMatcher_returns_different_mapper", () => { + const mapper1: IMediatorMapper = mediatorMap.map(MockDisplayObjectContainer); + const mapper2: IMediatorMapper = mediatorMap.map(MockDisplayObject); assert.notEqual(mapper1, mapper2); }); - xit("unmapMatcher_returns_mapper", () => { - const mapper: MediatorMapper = mediatorMap.mapMatcher(new TypeMatcher().allOf(DisplayObjectContainer)); - const unmappedMapper: MediatorMapper = mediatorMap.unmapMatcher(new TypeMatcher().allOf(DisplayObjectContainer)); + it("unmapMatcher_returns_mapper", () => { + const mapper: MediatorMapper = mediatorMap.mapMatcher(new TypeMatcher().allOf(MockDisplayObjectContainer)); + const unmappedMapper: MediatorMapper = ( + mediatorMap.unmapMatcher(new TypeMatcher().allOf(MockDisplayObjectContainer)) + ); assert.equal(unmappedMapper, mapper); }); - xit("unmap_returns_mapper", () => { - const mapper: MediatorMapper = mediatorMap.map(DisplayObjectContainer); - const unmappedMapper: MediatorMapper = mediatorMap.unmap(DisplayObjectContainer); + it("unmap_returns_mapper", () => { + const mapper: MediatorMapper = mediatorMap.map(MockDisplayObjectContainer); + const unmappedMapper: MediatorMapper = mediatorMap.unmap(MockDisplayObjectContainer); assert.equal(unmappedMapper, mapper); }); - xit("robust_to_unmapping_non_existent_mappings", () => { - mediatorMap.unmapMatcher(new TypeMatcher().allOf(DisplayObjectContainer)).fromAll(); + it("robust_to_unmapping_non_existent_mappings", () => { + mediatorMap.unmapMatcher(new TypeMatcher().allOf(MockDisplayObjectContainer)).fromAll(); }); }); diff --git a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapPreload.test.ts b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapPreload.test.ts index 663a3fd..8bc03e0 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapPreload.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapPreload.test.ts @@ -10,9 +10,14 @@ import "../../../../../entry"; import { assert } from "chai"; import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import DisplayObject from "openfl/display/DisplayObject"; -import { IInjector, IContext, Context, TypeMatcher } from "@robotlegsjs/core"; +import { interfaces, IInjector, IContext, Context, TypeMatcher } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { MediatorMap } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap"; @@ -20,8 +25,8 @@ import { Alpha50PercentHook } from "../support/Alpha50PercentHook"; import { ExampleMediator } from "../support/ExampleMediator"; import { ExampleMediator2 } from "../support/ExampleMediator2"; import { ExampleView } from "../support/ExampleView"; +import { ExampleView2 } from "../support/ExampleView2"; import { HappyGuard } from "../support/HappyGuard"; -import { ExampleDisplayObjectMediator } from "../support/ExampleDisplayObjectMediator"; import { HookWithMediatorAndViewInjectionReportFunction } from "../support/HookWithMediatorAndViewInjectionReportFunction"; import { MediatorWatcher } from "../support/MediatorWatcher"; import { NotAView } from "../support/NotAView"; @@ -38,6 +43,11 @@ describe("MediatorMap", () => { beforeEach(() => { context = new Context(); injector = context.injector; + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); mediatorMap = new MediatorMap(context); mediatorWatcher = new MediatorWatcher(); injector.bind(MediatorWatcher).toConstantValue(mediatorWatcher); @@ -116,20 +126,20 @@ describe("MediatorMap", () => { assert.isFalse(injector.isBound(ExampleMediator)); }); - xit("handler_creates_mediator_for_view_mapped_by_matcher", () => { - mediatorMap.mapMatcher(new TypeMatcher().allOf(DisplayObject)).toMediator(ExampleDisplayObjectMediator); + it("handler_creates_mediator_for_view_mapped_by_matcher", () => { + mediatorMap.mapMatcher(new TypeMatcher().allOf(ExampleView)).toMediator(ExampleMediator); mediatorMap.handleView(new ExampleView(), ExampleView); - const expectedNotifications: string[] = ["ExampleDisplayObjectMediator"]; + const expectedNotifications: string[] = ["ExampleMediator"]; assert.deepEqual(expectedNotifications, mediatorWatcher.notifications); }); - xit("handler_doesnt_create_mediator_for_wrong_view_mapped_by_matcher", () => { - mediatorMap.mapMatcher(new TypeMatcher().allOf(DisplayObjectContainer)).toMediator(ExampleDisplayObjectMediator); + it("handler_doesnt_create_mediator_for_wrong_view_mapped_by_matcher", () => { + mediatorMap.mapMatcher(new TypeMatcher().allOf(ExampleView)).toMediator(ExampleMediator); - mediatorMap.handleView(new DisplayObject(), null); + mediatorMap.handleView(new ExampleView2(), ExampleView2); const expectedNotifications: string[] = []; diff --git a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapper.test.ts b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapper.test.ts index 0e754d7..a4fc608 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapper.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMapper.test.ts @@ -11,7 +11,13 @@ import sinon = require("sinon"); import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import { IContext, IInjector, ILogger, Context, TypeMatcher } from "@robotlegsjs/core"; +import { interfaces, IContext, IInjector, ILogger, Context, TypeMatcher } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { MediatorFactory } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory"; import { MediatorMapper } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMapper"; @@ -33,6 +39,11 @@ describe("MediatorMapper", () => { context = new Context(); injector = context.injector; + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); factory = new MediatorFactory(injector); handler = new MediatorViewHandler(factory); matcher.createTypeFilter(); diff --git a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorViewHandler.test.ts b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorViewHandler.test.ts index 25b9be7..7ec9ed4 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorViewHandler.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/impl/mediatorViewHandler.test.ts @@ -13,7 +13,13 @@ import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; import DisplayObject from "openfl/display/DisplayObject"; import Sprite from "openfl/display/Sprite"; -import { IContext, IInjector, ITypeFilter, Context, TypeMatcher } from "@robotlegsjs/core"; +import { interfaces, IContext, IInjector, ITypeFilter, Context, TypeMatcher } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { MediatorFactory } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorFactory"; import { MediatorMapping } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMapping"; @@ -31,6 +37,11 @@ describe("MediatorViewHandler", () => { beforeEach(() => { context = new Context(); injector = context.injector; + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); factory = new MediatorFactory(injector); handler = new MediatorViewHandler(factory); context.initialize(); diff --git a/test/robotlegs/bender/extensions/mediatorMap/mediatorMapExtension.test.ts b/test/robotlegs/bender/extensions/mediatorMap/mediatorMapExtension.test.ts index 5c9a089..b0a09b8 100644 --- a/test/robotlegs/bender/extensions/mediatorMap/mediatorMapExtension.test.ts +++ b/test/robotlegs/bender/extensions/mediatorMap/mediatorMapExtension.test.ts @@ -9,7 +9,13 @@ import "../../../../entry"; import { assert } from "chai"; -import { IContext, Context } from "@robotlegsjs/core"; +import { interfaces, IContext, Context } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { ViewManagerExtension, MediatorMapExtension, IMediatorMap } from "../../../../../src"; @@ -20,6 +26,13 @@ describe("MediatorMapExtension", () => { beforeEach(() => { context = new Context(); + context.injector + .bind>(IDisplayObjectObserverFactory) + .toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); }); afterEach(() => { diff --git a/test/robotlegs/bender/extensions/mediatorMap/support/ExampleView2.ts b/test/robotlegs/bender/extensions/mediatorMap/support/ExampleView2.ts new file mode 100644 index 0000000..4b0ed27 --- /dev/null +++ b/test/robotlegs/bender/extensions/mediatorMap/support/ExampleView2.ts @@ -0,0 +1,10 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. +// +// NOTICE: You are permitted to use, modify, and distribute this file +// in accordance with the terms of the license agreement accompanying it. +// ------------------------------------------------------------------------------ + +import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; + +export class ExampleView2 extends DisplayObjectContainer {} diff --git a/test/robotlegs/bender/extensions/viewManager/impl/containerRegistry.test.ts b/test/robotlegs/bender/extensions/viewManager/impl/containerRegistry.test.ts index b5e5bc4..4bb619f 100644 --- a/test/robotlegs/bender/extensions/viewManager/impl/containerRegistry.test.ts +++ b/test/robotlegs/bender/extensions/viewManager/impl/containerRegistry.test.ts @@ -11,6 +11,8 @@ import { assert } from "chai"; import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; +import { IDisplayObjectContainer } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectContainer"; + import { IViewHandler } from "../../../../../../src/robotlegs/bender/extensions/viewManager/api/IViewHandler"; import { ContainerBinding } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerBinding"; import { ContainerRegistry } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry"; @@ -97,8 +99,16 @@ describe("ContainerRegistry", () => { let searchItem: DisplayObjectContainer = searchTrees[1].treeChildren[3].treeChildren[3].treeChildren[3].treeChildren[3]; let result: ContainerBinding = registry.findParentBinding(searchItem); - assert.equal(searchTrees[1].treeChildren[3], result.container, "Binding returns with correct container view"); - assert.equal(searchTrees[1], result.parent.container, "Binding returns with correct container parent view"); + assert.equal( + searchTrees[1].treeChildren[3], + result.container, + "Binding returns with correct container view" + ); + assert.equal( + searchTrees[1], + result.parent.container, + "Binding returns with correct container parent view" + ); assert.equal(null, result.parent.parent, "Further parents are null"); }); @@ -112,9 +122,17 @@ describe("ContainerRegistry", () => { let searchItem: DisplayObjectContainer = searchTrees[1].treeChildren[3].treeChildren[3].treeChildren[3].treeChildren[3]; let result: ContainerBinding = registry.findParentBinding(searchItem); - assert.equal(searchTrees[1].treeChildren[3], result.container, "Binding returns with correct container view"); + assert.equal( + searchTrees[1].treeChildren[3], + result.container, + "Binding returns with correct container view" + ); - assert.equal(searchTrees[1], result.parent.container, "Binding returns with correct container parent view"); + assert.equal( + searchTrees[1], + result.parent.container, + "Binding returns with correct container parent view" + ); assert.equal(null, result.parent.parent, "Further parents are null"); }); @@ -128,9 +146,17 @@ describe("ContainerRegistry", () => { let searchItem: DisplayObjectContainer = searchTrees[1].treeChildren[3].treeChildren[2].treeChildren[3].treeChildren[3]; let result: ContainerBinding = registry.findParentBinding(searchItem); - assert.equal(searchTrees[1].treeChildren[3].treeChildren[2], result.container, "Binding returns with correct container view"); + assert.equal( + searchTrees[1].treeChildren[3].treeChildren[2], + result.container, + "Binding returns with correct container view" + ); - assert.equal(searchTrees[1], result.parent.container, "Binding returns with correct container parent view"); + assert.equal( + searchTrees[1], + result.parent.container, + "Binding returns with correct container parent view" + ); assert.equal(null, result.parent.parent, "Further parents are null"); }); @@ -149,12 +175,20 @@ describe("ContainerRegistry", () => { let result: ContainerBinding = registry.findParentBinding(searchItem); assert.equal( - searchTrees[1].treeChildren[3].treeChildren[2].treeChildren[3], + searchTrees[1].treeChildren[3].treeChildren[2].treeChildren[3], result.container, "Binding returns with correct container view" ); - assert.equal(searchTrees[1].treeChildren[3], result.parent.container, "Binding returns with correct container parent view"); - assert.equal(searchTrees[1], result.parent.parent.container, "Binding returns with correct container parent parent view"); + assert.equal( + searchTrees[1].treeChildren[3], + result.parent.container, + "Binding returns with correct container parent view" + ); + assert.equal( + searchTrees[1], + result.parent.parent.container, + "Binding returns with correct container parent parent view" + ); assert.equal(null, result.parent.parent.parent, "Further parents are null"); }); diff --git a/test/robotlegs/bender/extensions/viewManager/impl/stageObserver.test.ts b/test/robotlegs/bender/extensions/viewManager/impl/stageObserver.test.ts index e90e95c..c5dd32b 100644 --- a/test/robotlegs/bender/extensions/viewManager/impl/stageObserver.test.ts +++ b/test/robotlegs/bender/extensions/viewManager/impl/stageObserver.test.ts @@ -12,7 +12,13 @@ import { assert } from "chai"; import Stage from "openfl/display/Stage"; import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import { IClass } from "@robotlegsjs/core"; +import { interfaces, IInjector, IClass, IContext, Context } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { ContainerRegistry } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry"; import { StageObserver } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/StageObserver"; @@ -20,17 +26,33 @@ import { StageObserver } from "../../../../../../src/robotlegs/bender/extensions import { CallbackViewHandler } from "../support/CallbackViewHandler"; describe("StageObserver", () => { + let context: IContext = null; + let injector: IInjector = null; let stage: Stage = null; let registry: ContainerRegistry = null; let observer: StageObserver = null; beforeEach(() => { + context = new Context(); + injector = context.injector; + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); stage = new Stage(); registry = new ContainerRegistry(); - observer = new StageObserver(registry); + observer = new StageObserver(registry, injector.get(IDisplayObjectObserverFactory)); }); afterEach(() => { + if (context.initialized) { + context.destroy(); + } + + context = null; + injector = null; + observer.destroy(); observer = null; registry = null; diff --git a/test/robotlegs/bender/extensions/viewManager/impl/viewManager.test.ts b/test/robotlegs/bender/extensions/viewManager/impl/viewManager.test.ts index 29f1dba..e49f449 100644 --- a/test/robotlegs/bender/extensions/viewManager/impl/viewManager.test.ts +++ b/test/robotlegs/bender/extensions/viewManager/impl/viewManager.test.ts @@ -12,7 +12,13 @@ import { assert } from "chai"; import Stage from "openfl/display/Stage"; import DisplayObjectContainer from "openfl/display/DisplayObjectContainer"; -import { IClass } from "@robotlegsjs/core"; +import { interfaces, IInjector, IClass, IContext, Context } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { ContainerRegistry } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry"; import { StageObserver } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/StageObserver"; @@ -21,16 +27,25 @@ import { ViewManager } from "../../../../../../src/robotlegs/bender/extensions/v import { CallbackViewHandler } from "../support/CallbackViewHandler"; describe("ViewManager", () => { + let context: IContext = null; + let injector: IInjector = null; let stage: Stage = null; let registry: ContainerRegistry = null; let viewManager: ViewManager = null; let stageObserver: StageObserver = null; beforeEach(() => { + context = new Context(); + injector = context.injector; + injector.bind>(IDisplayObjectObserverFactory).toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); stage = new Stage(); registry = new ContainerRegistry(); viewManager = new ViewManager(registry); - stageObserver = new StageObserver(registry); + stageObserver = new StageObserver(registry, injector.get(IDisplayObjectObserverFactory)); }); afterEach(() => { diff --git a/test/robotlegs/bender/extensions/viewManager/manualStageObserverExtension.test.ts b/test/robotlegs/bender/extensions/viewManager/manualStageObserverExtension.test.ts index 7404b32..461ab3c 100644 --- a/test/robotlegs/bender/extensions/viewManager/manualStageObserverExtension.test.ts +++ b/test/robotlegs/bender/extensions/viewManager/manualStageObserverExtension.test.ts @@ -9,7 +9,13 @@ import "../../../../entry"; import { assert } from "chai"; -import { IContext, Context, LogLevel } from "@robotlegsjs/core"; +import { interfaces, IContext, Context, LogLevel } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { ManualStageObserverExtension, ViewManagerExtension } from "../../../../../src"; @@ -21,6 +27,13 @@ describe("ManualStageObserverExtension", () => { beforeEach(() => { context = new Context(); + context.injector + .bind>(IDisplayObjectObserverFactory) + .toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); }); afterEach(() => { diff --git a/test/robotlegs/bender/extensions/viewManager/stageCrawlerExtension.test.ts b/test/robotlegs/bender/extensions/viewManager/stageCrawlerExtension.test.ts index cf45f3d..0ab9e3c 100644 --- a/test/robotlegs/bender/extensions/viewManager/stageCrawlerExtension.test.ts +++ b/test/robotlegs/bender/extensions/viewManager/stageCrawlerExtension.test.ts @@ -11,7 +11,13 @@ import { assert } from "chai"; import Stage from "openfl/display/Stage"; -import { IContext, Context, LogLevel } from "@robotlegsjs/core"; +import { interfaces, IContext, Context, LogLevel } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { ContextView, @@ -37,6 +43,13 @@ describe("StageCrawlerExtension", () => { beforeEach(() => { stage = new Stage(); context = new Context(); + context.injector + .bind>(IDisplayObjectObserverFactory) + .toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); }); afterEach(() => { diff --git a/test/robotlegs/bender/extensions/viewManager/stageObserverExtension.test.ts b/test/robotlegs/bender/extensions/viewManager/stageObserverExtension.test.ts index 75b44f4..dcd21de 100644 --- a/test/robotlegs/bender/extensions/viewManager/stageObserverExtension.test.ts +++ b/test/robotlegs/bender/extensions/viewManager/stageObserverExtension.test.ts @@ -9,7 +9,13 @@ import "../../../../entry"; import { assert } from "chai"; -import { IContext, Context, LogLevel } from "@robotlegsjs/core"; +import { interfaces, IContext, Context, LogLevel } from "@robotlegsjs/core"; + +import { DisplayObjectObserver } from "../../../../../src/robotlegs/bender/bundles/openfl/observer/DisplayObjectObserver"; + +import { IDisplayObject } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObject"; +import { IDisplayObjectObserver } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserver"; +import { IDisplayObjectObserverFactory } from "../../../../../src/robotlegs/bender/displayList/api/IDisplayObjectObserverFactory"; import { StageObserverExtension, ViewManagerExtension } from "../../../../../src"; @@ -21,6 +27,13 @@ describe("StageObserverExtension", () => { beforeEach(() => { context = new Context(); + context.injector + .bind>(IDisplayObjectObserverFactory) + .toFactory(() => { + return (view: IDisplayObject, useCapture: boolean): IDisplayObjectObserver => { + return new DisplayObjectObserver(view, useCapture); + }; + }); }); afterEach(() => { diff --git a/webpack.example.config.js b/webpack.example.config.js index d599884..18e3111 100644 --- a/webpack.example.config.js +++ b/webpack.example.config.js @@ -33,7 +33,7 @@ module.exports = options => { module: { rules: [ - { test: /\.ts$/, loader: "ts-loader" } + { test: /\.ts$/, loader: "ts-loader?configFile=tsconfig.example.json" } ] },