diff options
Diffstat (limited to 'src/api/composition/DefaultCompositionProvider.js')
-rw-r--r-- | src/api/composition/DefaultCompositionProvider.js | 248 |
1 files changed, 86 insertions, 162 deletions
diff --git a/src/api/composition/DefaultCompositionProvider.js b/src/api/composition/DefaultCompositionProvider.js index 3a46b127f..6c242a25c 100644 --- a/src/api/composition/DefaultCompositionProvider.js +++ b/src/api/composition/DefaultCompositionProvider.js @@ -19,102 +19,79 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ +import objectUtils from "../objects/object-utils"; +import CompositionProvider from './CompositionProvider'; -define([ - 'lodash', - 'objectUtils' -], function ( - _, - objectUtils -) { - /** - * A CompositionProvider provides the underlying implementation of - * composition-related behavior for certain types of domain object. - * - * By default, a composition provider will not support composition - * modification. You can add support for mutation of composition by - * defining `add` and/or `remove` methods. - * - * If the composition of an object can change over time-- perhaps via - * server updates or mutation via the add/remove methods, then one must - * trigger events as necessary. - * - * @interface CompositionProvider - * @memberof module:openmct - */ +/** + * @typedef {import('../objects/ObjectAPI').DomainObject} DomainObject + */ - function DefaultCompositionProvider(publicAPI, compositionAPI) { - this.publicAPI = publicAPI; - this.listeningTo = {}; - this.onMutation = this.onMutation.bind(this); +/** + * @typedef {import('../objects/ObjectAPI').Identifier} Identifier + */ - this.cannotContainItself = this.cannotContainItself.bind(this); - this.supportsComposition = this.supportsComposition.bind(this); +/** + * @typedef {import('./CompositionAPI').default} CompositionAPI + */ - compositionAPI.addPolicy(this.cannotContainItself); - compositionAPI.addPolicy(this.supportsComposition); - } - - /** - * @private - */ - DefaultCompositionProvider.prototype.cannotContainItself = function (parent, child) { - return !(parent.identifier.namespace === child.identifier.namespace - && parent.identifier.key === child.identifier.key); - }; - - /** - * @private - */ - DefaultCompositionProvider.prototype.supportsComposition = function (parent, child) { - return this.publicAPI.composition.supportsComposition(parent); - }; +/** + * @typedef {import('../../../openmct').OpenMCT} OpenMCT + */ +/** + * A CompositionProvider provides the underlying implementation of + * composition-related behavior for certain types of domain object. + * + * By default, a composition provider will not support composition + * modification. You can add support for mutation of composition by + * defining `add` and/or `remove` methods. + * + * If the composition of an object can change over time-- perhaps via + * server updates or mutation via the add/remove methods, then one must + * trigger events as necessary. + * @extends CompositionProvider + */ +export default class DefaultCompositionProvider extends CompositionProvider { /** * Check if this provider should be used to load composition for a * particular domain object. - * @param {module:openmct.DomainObject} domainObject the domain object + * @override + * @param {DomainObject} domainObject the domain object * to check - * @returns {boolean} true if this provider can provide - * composition for a given domain object - * @memberof module:openmct.CompositionProvider# - * @method appliesTo + * @returns {boolean} true if this provider can provide composition for a given domain object */ - DefaultCompositionProvider.prototype.appliesTo = function (domainObject) { + appliesTo(domainObject) { return Boolean(domainObject.composition); - }; - + } /** * Load any domain objects contained in the composition of this domain * object. - * @param {module:openmct.DomainObject} domainObject the domain object + * @override + * @param {DomainObject} domainObject the domain object * for which to load composition - * @returns {Promise.<Array.<module:openmct.Identifier>>} a promise for + * @returns {Promise<Identifier[]>} a promise for * the Identifiers in this composition - * @memberof module:openmct.CompositionProvider# - * @method load */ - DefaultCompositionProvider.prototype.load = function (domainObject) { + load(domainObject) { return Promise.all(domainObject.composition); - }; - + } /** * Attach listeners for changes to the composition of a given domain object. * Supports `add` and `remove` events. * - * @param {module:openmct.DomainObject} domainObject to listen to - * @param String event the event to bind to, either `add` or `remove`. - * @param Function callback callback to invoke when event is triggered. - * @param [context] context to use when invoking callback. + * @override + * @param {DomainObject} domainObject to listen to + * @param {string} event the event to bind to, either `add` or `remove`. + * @param {Function} callback callback to invoke when event is triggered. + * @param {any} [context] to use when invoking callback. */ - DefaultCompositionProvider.prototype.on = function ( - domainObject, + on(domainObject, event, callback, - context - ) { + context) { this.establishTopicListener(); + /** @type {string} */ const keyString = objectUtils.makeKeyString(domainObject.identifier); let objectListeners = this.listeningTo[keyString]; @@ -131,24 +108,24 @@ define([ callback: callback, context: context }); - }; - + } /** * Remove a listener that was previously added for a given domain object. * event name, callback, and context must be the same as when the listener * was originally attached. * - * @param {module:openmct.DomainObject} domainObject to remove listener for - * @param String event event to stop listening to: `add` or `remove`. - * @param Function callback callback to remove. - * @param [context] context of callback to remove. + * @override + * @param {DomainObject} domainObject to remove listener for + * @param {string} event event to stop listening to: `add` or `remove`. + * @param {Function} callback callback to remove. + * @param {any} context of callback to remove. */ - DefaultCompositionProvider.prototype.off = function ( - domainObject, + off(domainObject, event, callback, - context - ) { + context) { + + /** @type {string} */ const keyString = objectUtils.makeKeyString(domainObject.identifier); const objectListeners = this.listeningTo[keyString]; @@ -160,57 +137,64 @@ define([ if (!objectListeners.add.length && !objectListeners.remove.length && !objectListeners.reorder.length) { delete this.listeningTo[keyString]; } - }; - + } /** * Remove a domain object from another domain object's composition. * * This method is optional; if not present, adding to a domain object's * composition using this provider will be disallowed. * - * @param {module:openmct.DomainObject} domainObject the domain object + * @override + * @param {DomainObject} domainObject the domain object * which should have its composition modified - * @param {module:openmct.DomainObject} child the domain object to remove - * @memberof module:openmct.CompositionProvider# + * @param {Identifier} childId the domain object to remove * @method remove */ - DefaultCompositionProvider.prototype.remove = function (domainObject, childId) { + remove(domainObject, childId) { let composition = domainObject.composition.filter(function (child) { return !(childId.namespace === child.namespace - && childId.key === child.key); + && childId.key === child.key); }); this.publicAPI.objects.mutate(domainObject, 'composition', composition); - }; - + } /** * Add a domain object to another domain object's composition. * * This method is optional; if not present, adding to a domain object's * composition using this provider will be disallowed. * - * @param {module:openmct.DomainObject} domainObject the domain object + * @override + * @param {DomainObject} parent the domain object * which should have its composition modified - * @param {module:openmct.DomainObject} child the domain object to add - * @memberof module:openmct.CompositionProvider# + * @param {Identifier} childId the domain object to add * @method add */ - DefaultCompositionProvider.prototype.add = function (parent, childId) { + add(parent, childId) { if (!this.includes(parent, childId)) { parent.composition.push(childId); this.publicAPI.objects.mutate(parent, 'composition', parent.composition); } - }; + } /** - * @private + * @override + * @param {DomainObject} parent + * @param {Identifier} childId + * @returns {boolean} */ - DefaultCompositionProvider.prototype.includes = function (parent, childId) { - return parent.composition.some(composee => - this.publicAPI.objects.areIdsEqual(composee, childId)); - }; + includes(parent, childId) { + return parent.composition.some(composee => this.publicAPI.objects.areIdsEqual(composee, childId)); + } - DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) { + /** + * @override + * @param {DomainObject} domainObject + * @param {number} oldIndex + * @param {number} newIndex + * @returns + */ + reorder(domainObject, oldIndex, newIndex) { let newComposition = domainObject.composition.slice(); let removeId = oldIndex > newIndex ? oldIndex + 1 : oldIndex; let insertPosition = oldIndex < newIndex ? newIndex + 1 : newIndex; @@ -241,6 +225,7 @@ define([ this.publicAPI.objects.mutate(domainObject, 'composition', newComposition); + /** @type {string} */ let id = objectUtils.makeKeyString(domainObject.identifier); const listeners = this.listeningTo[id]; @@ -257,66 +242,5 @@ define([ listener.callback(reorderPlan); } } - }; - - /** - * Listens on general mutation topic, using injector to fetch to avoid - * circular dependencies. - * - * @private - */ - DefaultCompositionProvider.prototype.establishTopicListener = function () { - if (this.topicListener) { - return; - } - - this.publicAPI.objects.eventEmitter.on('mutation', this.onMutation); - this.topicListener = () => { - this.publicAPI.objects.eventEmitter.off('mutation', this.onMutation); - }; - }; - - /** - * Handles mutation events. If there are active listeners for the mutated - * object, detects changes to composition and triggers necessary events. - * - * @private - */ - DefaultCompositionProvider.prototype.onMutation = function (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)); - }); - - }; - - return DefaultCompositionProvider; -}); + } +} |