Compare commits
	
		
			1 Commits
		
	
	
		
			mobile-abo
			...
			refactor-c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d16c60aa7a | 
| @@ -20,6 +20,7 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import EventEmitter from 'EventEmitter'; | ||||
| /** | ||||
|  * @typedef {import('../objects/ObjectAPI').DomainObject} DomainObject | ||||
|  */ | ||||
| @@ -60,6 +61,10 @@ export default class CompositionCollection { | ||||
|     #publicAPI; | ||||
|     #listeners; | ||||
|     #mutables; | ||||
|     #onGlobalAdd; | ||||
|     #onGlobalRemove; | ||||
|     static #globalEvents = new EventEmitter(); | ||||
|  | ||||
|     /** | ||||
|      * @constructor | ||||
|      * @param {DomainObject} domainObject the domain object | ||||
| @@ -95,6 +100,21 @@ export default class CompositionCollection { | ||||
|                 unobserve(); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         const keyString = publicAPI.objects.makeKeyString(domainObject.identifier); | ||||
|         this.#onGlobalAdd = this._onGlobalAdd.bind(this); | ||||
|         this.#onGlobalRemove = this._onGlobalRemove.bind(this); | ||||
|  | ||||
|         CompositionCollection.#globalEvents.on(`add:${keyString}`, this.#onGlobalAdd); | ||||
|         CompositionCollection.#globalEvents.on(`remove:${keyString}`, this.#onGlobalRemove); | ||||
|     } | ||||
|  | ||||
|     _onGlobalAdd(object) { | ||||
|         this.#emit('add', object); | ||||
|     } | ||||
|  | ||||
|     _onGlobalRemove(identifier) { | ||||
|         this.#emit('remove', identifier); | ||||
|     } | ||||
|     /** | ||||
|      * Listen for changes to this composition.  Supports 'add', 'remove', and | ||||
| @@ -209,23 +229,21 @@ export default class CompositionCollection { | ||||
|      * **Intended for internal use ONLY.** | ||||
|      * true if the underlying provider should not be updated. | ||||
|      */ | ||||
|     add(child, skipMutate) { | ||||
|         if (!skipMutate) { | ||||
|             if (!this.#publicAPI.composition.checkPolicy(this.domainObject, child)) { | ||||
|                 throw `Object of type ${child.type} cannot be added to object of type ${this.domainObject.type}`; | ||||
|             } | ||||
|  | ||||
|             this.#provider.add(this.domainObject, child.identifier); | ||||
|         } else { | ||||
|             if (this.returnMutables && this.#publicAPI.objects.supportsMutation(child.identifier)) { | ||||
|                 let keyString = this.#publicAPI.objects.makeKeyString(child.identifier); | ||||
|  | ||||
|                 child = this.#publicAPI.objects.toMutable(child); | ||||
|                 this.#mutables[keyString] = child; | ||||
|             } | ||||
|  | ||||
|             this.#emit('add', child); | ||||
|     add(child) { | ||||
|         if (!this.#publicAPI.composition.checkPolicy(this.domainObject, child)) { | ||||
|             throw `Object of type ${child.type} cannot be added to object of type ${this.domainObject.type}`; | ||||
|         } | ||||
|  | ||||
|         this.#provider.add(this.domainObject, child.identifier); | ||||
|         if (this.returnMutables && this.#publicAPI.objects.supportsMutation(child.identifier)) { | ||||
|             let keyString = this.#publicAPI.objects.makeKeyString(child.identifier); | ||||
|  | ||||
|             child = this.#publicAPI.objects.toMutable(child); | ||||
|             this.#mutables[keyString] = child; | ||||
|         } | ||||
|  | ||||
|         // const keyString = this.#publicAPI.objects.makeKeyString(this.domainObject.identifier); | ||||
|         // CompositionCollection.#globalEvents.emit(`add:${keyString}`, child); | ||||
|     } | ||||
|     /** | ||||
|      * Load the domain objects in this composition. | ||||
| @@ -240,7 +258,12 @@ export default class CompositionCollection { | ||||
|         this.#cleanUpMutables(); | ||||
|         const children = await this.#provider.load(this.domainObject); | ||||
|         const childObjects = await Promise.all(children.map((c) => this.#publicAPI.objects.get(c, abortSignal))); | ||||
|         childObjects.forEach(c => this.add(c, true)); | ||||
|         childObjects.forEach(c => { | ||||
|             this.add(c); | ||||
|  | ||||
|             const keyString = this.#publicAPI.objects.makeKeyString(this.domainObject.identifier); | ||||
|             CompositionCollection.#globalEvents.emit(`add:${keyString}`, c); | ||||
|         }); | ||||
|         this.#emit('load'); | ||||
|  | ||||
|         return childObjects; | ||||
| @@ -259,20 +282,18 @@ export default class CompositionCollection { | ||||
|      * true if the underlying provider should not be updated. | ||||
|      * @name remove | ||||
|      */ | ||||
|     remove(child, skipMutate) { | ||||
|         if (!skipMutate) { | ||||
|             this.#provider.remove(this.domainObject, child.identifier); | ||||
|         } else { | ||||
|             if (this.returnMutables) { | ||||
|                 let keyString = this.#publicAPI.objects.makeKeyString(child); | ||||
|                 if (this.#mutables[keyString] !== undefined && this.#mutables[keyString].isMutable) { | ||||
|                     this.#publicAPI.objects.destroyMutable(this.#mutables[keyString]); | ||||
|                     delete this.#mutables[keyString]; | ||||
|                 } | ||||
|     remove(child) { | ||||
|         this.#provider.remove(this.domainObject, child.identifier); | ||||
|         if (this.returnMutables) { | ||||
|             let keyString = this.#publicAPI.objects.makeKeyString(child); | ||||
|             if (this.#mutables[keyString] !== undefined && this.#mutables[keyString].isMutable) { | ||||
|                 this.#publicAPI.objects.destroyMutable(this.#mutables[keyString]); | ||||
|                 delete this.#mutables[keyString]; | ||||
|             } | ||||
|  | ||||
|             this.#emit('remove', child); | ||||
|         } | ||||
|  | ||||
|         // const keyString = this.#publicAPI.objects.makeKeyString(this.domainObject.identifier); | ||||
|         // CompositionCollection.#globalEvents.emit(`remove:${keyString}`, child.identifier); | ||||
|     } | ||||
|     /** | ||||
|      * Reorder the domain objects in this composition. | ||||
| @@ -295,6 +316,10 @@ export default class CompositionCollection { | ||||
|             this.mutationListener(); | ||||
|             delete this.mutationListener; | ||||
|         } | ||||
|  | ||||
|         const keyString = this.#publicAPI.objects.makeKeyString(this.domainObject.identifier); | ||||
|         CompositionCollection.#globalEvents.off(`add:${keyString}`, this.#onGlobalAdd); | ||||
|         CompositionCollection.#globalEvents.off(`remove:${keyString}`, this.#onGlobalRemove); | ||||
|     } | ||||
|     /** | ||||
|      * Handle reorder from provider. | ||||
|   | ||||
| @@ -71,10 +71,6 @@ export default class CompositionProvider { | ||||
|         return this.#listeningTo; | ||||
|     } | ||||
|  | ||||
|     get establishTopicListener() { | ||||
|         return this.#establishTopicListener.bind(this); | ||||
|     } | ||||
|  | ||||
|     get publicAPI() { | ||||
|         return this.#publicAPI; | ||||
|     } | ||||
| @@ -181,22 +177,6 @@ export default class CompositionProvider { | ||||
|         throw new Error("This method must be implemented by a subclass."); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|       * Listens on general mutation topic, using injector to fetch to avoid | ||||
|       * circular dependencies. | ||||
|       * @private | ||||
|       */ | ||||
|     #establishTopicListener() { | ||||
|         if (this.topicListener) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.#publicAPI.objects.eventEmitter.on('mutation', this.#onMutation.bind(this)); | ||||
|         this.topicListener = () => { | ||||
|             this.#publicAPI.objects.eventEmitter.off('mutation', this.#onMutation.bind(this)); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|       * @private | ||||
|       * @param {DomainObject} parent | ||||
| @@ -216,47 +196,5 @@ export default class CompositionProvider { | ||||
|     #supportsComposition(parent, _child) { | ||||
|         return this.#publicAPI.composition.supportsComposition(parent); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|       * Handles mutation events.  If there are active listeners for the mutated | ||||
|       * object, detects changes to composition and triggers necessary events. | ||||
|       * | ||||
|       * @private | ||||
|       * @param {DomainObject} oldDomainObject | ||||
|       */ | ||||
|     #onMutation(oldDomainObject) { | ||||
|         const id = objectUtils.makeKeyString(oldDomainObject.identifier); | ||||
|         const listeners = this.#listeningTo[id]; | ||||
|  | ||||
|         if (!listeners) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const oldComposition = listeners.composition.map(objectUtils.makeKeyString); | ||||
|         const newComposition = oldDomainObject.composition.map(objectUtils.makeKeyString); | ||||
|  | ||||
|         const added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString); | ||||
|         const removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString); | ||||
|  | ||||
|         function notify(value) { | ||||
|             return function (listener) { | ||||
|                 if (listener.context) { | ||||
|                     listener.callback.call(listener.context, value); | ||||
|                 } else { | ||||
|                     listener.callback(value); | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         listeners.composition = newComposition.map(objectUtils.parseKeyString); | ||||
|  | ||||
|         added.forEach(function (addedChild) { | ||||
|             listeners.add.forEach(notify(addedChild)); | ||||
|         }); | ||||
|  | ||||
|         removed.forEach(function (removedChild) { | ||||
|             listeners.remove.forEach(notify(removedChild)); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -89,7 +89,7 @@ export default class DefaultCompositionProvider extends CompositionProvider { | ||||
|         event, | ||||
|         callback, | ||||
|         context) { | ||||
|         this.establishTopicListener(); | ||||
|         //this.establishTopicListener(); | ||||
|  | ||||
|         /** @type {string} */ | ||||
|         const keyString = objectUtils.makeKeyString(domainObject.identifier); | ||||
| @@ -157,6 +157,8 @@ export default class DefaultCompositionProvider extends CompositionProvider { | ||||
|         }); | ||||
|  | ||||
|         this.publicAPI.objects.mutate(domainObject, 'composition', composition); | ||||
|  | ||||
|         this.objectListeners.remove?.forEach(listener => listener.callback.apply(listener.context, childId)); | ||||
|     } | ||||
|     /** | ||||
|      * Add a domain object to another domain object's composition. | ||||
| @@ -174,6 +176,8 @@ export default class DefaultCompositionProvider extends CompositionProvider { | ||||
|         if (!this.includes(parent, childId)) { | ||||
|             parent.composition.push(childId); | ||||
|             this.publicAPI.objects.mutate(parent, 'composition', parent.composition); | ||||
|  | ||||
|             this.objectListeners.add?.forEach(listener => listener.callback.apply(listener.context, childId)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user