mirror of
https://github.com/nasa/openmct.git
synced 2025-06-18 07:08:12 +00:00
[Code Style] Use prototypes in platform
WTD-1482
This commit is contained in:
@ -39,68 +39,59 @@ define(
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function CompositionCapability($injector, domainObject) {
|
||||
var objectService,
|
||||
lastPromise,
|
||||
lastModified;
|
||||
|
||||
// Get a reference to the object service from $injector
|
||||
function injectObjectService() {
|
||||
objectService = $injector.get("objectService");
|
||||
return objectService;
|
||||
}
|
||||
|
||||
// Get a reference to the object service (either cached or
|
||||
// from the injector)
|
||||
function getObjectService() {
|
||||
return objectService || injectObjectService();
|
||||
}
|
||||
|
||||
// Promise this domain object's composition (an array of domain
|
||||
// object instances corresponding to ids in its model.)
|
||||
function promiseComposition() {
|
||||
var model = domainObject.getModel(),
|
||||
ids;
|
||||
|
||||
// Then filter out non-existent objects,
|
||||
// and wrap others (such that they expose a
|
||||
// "context" capability)
|
||||
function contextualize(objects) {
|
||||
return ids.filter(function (id) {
|
||||
return objects[id];
|
||||
}).map(function (id) {
|
||||
return new ContextualDomainObject(
|
||||
objects[id],
|
||||
domainObject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Make a new request if we haven't made one, or if the
|
||||
// object has been modified.
|
||||
if (!lastPromise || lastModified !== model.modified) {
|
||||
ids = model.composition || [];
|
||||
lastModified = model.modified;
|
||||
// Load from the underlying object service
|
||||
lastPromise = getObjectService().getObjects(ids)
|
||||
.then(contextualize);
|
||||
}
|
||||
|
||||
return lastPromise;
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Request the composition of this object.
|
||||
* @returns {Promise.<DomainObject[]>} a list of all domain
|
||||
* objects which compose this domain object.
|
||||
* @memberof platform/core.CompositionCapability#
|
||||
*/
|
||||
invoke: promiseComposition
|
||||
this.injectObjectService = function () {
|
||||
this.objectService = $injector.get("objectService");
|
||||
};
|
||||
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the composition of this object.
|
||||
* @returns {Promise.<DomainObject[]>} a list of all domain
|
||||
* objects which compose this domain object.
|
||||
*/
|
||||
CompositionCapability.prototype.invoke = function () {
|
||||
var domainObject = this.domainObject,
|
||||
model = domainObject.getModel(),
|
||||
ids;
|
||||
|
||||
// Then filter out non-existent objects,
|
||||
// and wrap others (such that they expose a
|
||||
// "context" capability)
|
||||
function contextualize(objects) {
|
||||
return ids.filter(function (id) {
|
||||
return objects[id];
|
||||
}).map(function (id) {
|
||||
return new ContextualDomainObject(
|
||||
objects[id],
|
||||
domainObject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Lazily acquire object service (avoids cyclical dependency)
|
||||
if (!this.objectService) {
|
||||
this.injectObjectService();
|
||||
}
|
||||
|
||||
// Make a new request if we haven't made one, or if the
|
||||
// object has been modified.
|
||||
if (!this.lastPromise || this.lastModified !== model.modified) {
|
||||
ids = model.composition || [];
|
||||
this.lastModified = model.modified;
|
||||
// Load from the underlying object service
|
||||
this.lastPromise = this.objectService.getObjects(ids)
|
||||
.then(contextualize);
|
||||
}
|
||||
|
||||
return this.lastPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test to determine whether or not this capability should be exposed
|
||||
* by a domain object based on its model. Checks for the presence of
|
||||
|
@ -38,79 +38,76 @@ define(
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function ContextCapability(parentObject, domainObject) {
|
||||
return {
|
||||
/**
|
||||
* Get the immediate parent of a domain object.
|
||||
*
|
||||
* A domain object may be contained in multiple places; its
|
||||
* parent (as exposed by this capability) is the domain
|
||||
* object from which this object was accessed, usually
|
||||
* by way of a `composition` capability.
|
||||
*
|
||||
* @returns {DomainObject} the immediate parent of this
|
||||
* domain object.
|
||||
* @memberof platform/core.ContextCapability#
|
||||
*/
|
||||
getParent: function () {
|
||||
return parentObject;
|
||||
},
|
||||
/**
|
||||
* Get an array containing the complete direct ancestry
|
||||
* of this domain object, including the domain object
|
||||
* itself.
|
||||
*
|
||||
* A domain object may be contained in multiple places; its
|
||||
* parent and all ancestors (as exposed by this capability)
|
||||
* serve as a record of how this specific domain object
|
||||
* instance was reached.
|
||||
*
|
||||
* The first element in the returned array is the deepest
|
||||
* ancestor; subsequent elements are progressively more
|
||||
* recent ancestors, with the domain object which exposed
|
||||
* the capability occupying the last element of the array.
|
||||
*
|
||||
* @returns {DomainObject[]} the full composition ancestry
|
||||
* of the domain object which exposed this
|
||||
* capability.
|
||||
* @memberof platform/core.ContextCapability#
|
||||
*/
|
||||
getPath: function () {
|
||||
var parentPath = [],
|
||||
parentContext;
|
||||
|
||||
if (parentObject) {
|
||||
parentContext = parentObject.getCapability("context");
|
||||
parentPath = parentContext ?
|
||||
parentContext.getPath() :
|
||||
[parentObject];
|
||||
}
|
||||
|
||||
return parentPath.concat([domainObject]);
|
||||
},
|
||||
/**
|
||||
* Get the deepest ancestor available for this domain object;
|
||||
* equivalent to `getPath()[0]`.
|
||||
*
|
||||
* See notes on `getPath()` for how ancestry is defined in
|
||||
* the context of this capability.
|
||||
*
|
||||
* @returns {DomainObject} the deepest ancestor of the domain
|
||||
* object which exposed this capability.
|
||||
* @memberof platform/core.ContextCapability#
|
||||
*/
|
||||
getRoot: function () {
|
||||
var parentContext = parentObject &&
|
||||
parentObject.getCapability('context');
|
||||
|
||||
return parentContext ?
|
||||
parentContext.getRoot() :
|
||||
(parentObject || domainObject);
|
||||
}
|
||||
};
|
||||
this.parentObject = parentObject;
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the immediate parent of a domain object.
|
||||
*
|
||||
* A domain object may be contained in multiple places; its
|
||||
* parent (as exposed by this capability) is the domain
|
||||
* object from which this object was accessed, usually
|
||||
* by way of a `composition` capability.
|
||||
*
|
||||
* @returns {DomainObject} the immediate parent of this
|
||||
* domain object.
|
||||
*/
|
||||
ContextCapability.prototype.getParent = function () {
|
||||
return this.parentObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an array containing the complete direct ancestry
|
||||
* of this domain object, including the domain object
|
||||
* itself.
|
||||
*
|
||||
* A domain object may be contained in multiple places; its
|
||||
* parent and all ancestors (as exposed by this capability)
|
||||
* serve as a record of how this specific domain object
|
||||
* instance was reached.
|
||||
*
|
||||
* The first element in the returned array is the deepest
|
||||
* ancestor; subsequent elements are progressively more
|
||||
* recent ancestors, with the domain object which exposed
|
||||
* the capability occupying the last element of the array.
|
||||
*
|
||||
* @returns {DomainObject[]} the full composition ancestry
|
||||
* of the domain object which exposed this
|
||||
* capability.
|
||||
*/
|
||||
ContextCapability.prototype.getPath = function () {
|
||||
var parentObject = this.parentObject,
|
||||
parentContext =
|
||||
parentObject && parentObject.getCapability('context'),
|
||||
parentPath = parentContext ?
|
||||
parentContext.getPath() : [ this.parentObject ];
|
||||
|
||||
return parentPath.concat([this.domainObject]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the deepest ancestor available for this domain object;
|
||||
* equivalent to `getPath()[0]`.
|
||||
*
|
||||
* See notes on `getPath()` for how ancestry is defined in
|
||||
* the context of this capability.
|
||||
*
|
||||
* @returns {DomainObject} the deepest ancestor of the domain
|
||||
* object which exposed this capability.
|
||||
*/
|
||||
ContextCapability.prototype.getRoot = function () {
|
||||
var parentContext = this.parentObject &&
|
||||
this.parentObject.getCapability('context');
|
||||
|
||||
return parentContext ?
|
||||
parentContext.getRoot() :
|
||||
(this.parentObject || this.domainObject);
|
||||
};
|
||||
|
||||
return ContextCapability;
|
||||
}
|
||||
);
|
||||
|
@ -44,6 +44,7 @@ define(
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {DomainObject}
|
||||
*/
|
||||
function ContextualDomainObject(domainObject, parentObject) {
|
||||
// Prototypally inherit from the domain object, and
|
||||
|
@ -29,6 +29,19 @@ define(
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A capability provides an interface with dealing with some
|
||||
* dynamic behavior associated with a domain object.
|
||||
* @interface Capability
|
||||
*/
|
||||
|
||||
/**
|
||||
* Optional; if present, will be used by `DomainObject#useCapability`
|
||||
* to simplify interaction with a specific capability. Parameters
|
||||
* and return values vary depending on capability type.
|
||||
* @method Capability#invoke
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides capabilities based on extension definitions,
|
||||
* matched to domain object models.
|
||||
|
@ -45,13 +45,40 @@ define(
|
||||
* in the type's definition, which contains an array of names of
|
||||
* capabilities to be delegated.
|
||||
*
|
||||
* @param domainObject
|
||||
* @param $q Angular's $q, for promises
|
||||
* @param {DomainObject} domainObject the delegating domain object
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function DelegationCapability($q, domainObject) {
|
||||
var delegateCapabilities = {},
|
||||
type = domainObject.getCapability("type");
|
||||
var type = domainObject.getCapability("type"),
|
||||
self = this;
|
||||
|
||||
this.$q = $q;
|
||||
this.delegateCapabilities = {};
|
||||
this.domainObject = domainObject;
|
||||
|
||||
// Generate set for easy lookup of capability delegation
|
||||
if (type && type.getDefinition) {
|
||||
(type.getDefinition().delegates || []).forEach(function (key) {
|
||||
self.delegateCapabilities[key] = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the domain objects which are intended to be delegated
|
||||
* responsibility for some specific capability.
|
||||
*
|
||||
* @param {string} key the name of the delegated capability
|
||||
* @returns {DomainObject[]} the domain objects to which
|
||||
* responsibility for this capability is delegated.
|
||||
* @memberof platform/core.DelegationCapability#
|
||||
*/
|
||||
DelegationCapability.prototype.getDelegates = function (key) {
|
||||
var domainObject = this.domainObject;
|
||||
|
||||
function filterObjectsWithCapability(capability) {
|
||||
return function (objects) {
|
||||
@ -65,55 +92,40 @@ define(
|
||||
return domainObject.useCapability('composition');
|
||||
}
|
||||
|
||||
function doesDelegate(key) {
|
||||
return delegateCapabilities[key] || false;
|
||||
}
|
||||
return this.doesDelegateCapability(key) ?
|
||||
promiseChildren().then(
|
||||
filterObjectsWithCapability(key)
|
||||
) :
|
||||
this.$q.when([]);
|
||||
};
|
||||
|
||||
function getDelegates(capability) {
|
||||
return doesDelegate(capability) ?
|
||||
promiseChildren().then(
|
||||
filterObjectsWithCapability(capability)
|
||||
) :
|
||||
$q.when([]);
|
||||
}
|
||||
|
||||
// Generate set for easy lookup of capability delegation
|
||||
if (type && type.getDefinition) {
|
||||
(type.getDefinition().delegates || []).forEach(function (key) {
|
||||
delegateCapabilities[key] = true;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Invoke this capability; alias of `getDelegates`, used to
|
||||
* simplify usage, e.g.:
|
||||
*
|
||||
* `domainObject.useCapability("delegation", "telemetry")`
|
||||
*
|
||||
* ...will retrieve all members of a domain object's
|
||||
* composition which have a "telemetry" capability.
|
||||
*
|
||||
* @param {string} the name of the delegated capability
|
||||
* @returns {DomainObject[]} the domain objects to which
|
||||
* responsibility for this capability is delegated.
|
||||
* @memberof platform/core.DelegationCapability#
|
||||
*/
|
||||
invoke: getDelegates,
|
||||
/**
|
||||
* Get the domain objects which are intended to be delegated
|
||||
* responsibility for some specific capability.
|
||||
*
|
||||
* @param {string} the name of the delegated capability
|
||||
* @returns {DomainObject[]} the domain objects to which
|
||||
* responsibility for this capability is delegated.
|
||||
* @memberof platform/core.DelegationCapability#
|
||||
*/
|
||||
getDelegates: getDelegates,
|
||||
doesDelegateCapability: doesDelegate
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Check if the domain object which exposed this capability
|
||||
* wishes to delegate another capability.
|
||||
*
|
||||
* @param {string} key the capability to check for
|
||||
* @returns {boolean} true if the capability is delegated
|
||||
*/
|
||||
DelegationCapability.prototype.doesDelegateCapability = function (key) {
|
||||
return !!(this.delegateCapabilities[key]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Invoke this capability; alias of `getDelegates`, used to
|
||||
* simplify usage, e.g.:
|
||||
*
|
||||
* `domainObject.useCapability("delegation", "telemetry")`
|
||||
*
|
||||
* ...will retrieve all members of a domain object's
|
||||
* composition which have a "telemetry" capability.
|
||||
*
|
||||
* @param {string} the name of the delegated capability
|
||||
* @returns {DomainObject[]} the domain objects to which
|
||||
* responsibility for this capability is delegated.
|
||||
* @memberof platform/core.DelegationCapability#
|
||||
*/
|
||||
DelegationCapability.prototype.invoke =
|
||||
DelegationCapability.prototype.getDelegates;
|
||||
|
||||
return DelegationCapability;
|
||||
|
||||
|
@ -11,8 +11,6 @@ define(
|
||||
* @property {string} name the human-readable name of this property
|
||||
* @property {string} value the human-readable value of this property,
|
||||
* for this specific domain object
|
||||
* @constructor
|
||||
* @memberof platform/core
|
||||
*/
|
||||
|
||||
var TIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
|
||||
@ -27,10 +25,23 @@ define(
|
||||
* `value` properties describing that domain object (suitable for
|
||||
* display.)
|
||||
*
|
||||
* @param {DomainObject} domainObject the domain object whose
|
||||
* metadata is to be exposed
|
||||
* @implements {Capability}
|
||||
* @constructor
|
||||
* @memberof platform/core
|
||||
*/
|
||||
function MetadataCapability(domainObject) {
|
||||
var model = domainObject.getModel();
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata about this object.
|
||||
* @returns {MetadataProperty[]} metadata about this object
|
||||
*/
|
||||
MetadataCapability.prototype.invoke = function () {
|
||||
var domainObject = this.domainObject,
|
||||
model = domainObject.getModel();
|
||||
|
||||
function hasDisplayableValue(metadataProperty) {
|
||||
var t = typeof metadataProperty.value;
|
||||
@ -39,8 +50,8 @@ define(
|
||||
|
||||
function formatTimestamp(timestamp) {
|
||||
return typeof timestamp === 'number' ?
|
||||
(moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
|
||||
undefined;
|
||||
(moment.utc(timestamp).format(TIME_FORMAT) + " UTC") :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function getProperties() {
|
||||
@ -75,20 +86,9 @@ define(
|
||||
];
|
||||
}
|
||||
|
||||
function getMetadata() {
|
||||
return getProperties().concat(getCommonMetadata())
|
||||
.filter(hasDisplayableValue);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get metadata about this object.
|
||||
* @returns {MetadataProperty[]} metadata about this object
|
||||
* @memberof platform/core.MetadataCapability#
|
||||
*/
|
||||
invoke: getMetadata
|
||||
};
|
||||
}
|
||||
return getProperties().concat(getCommonMetadata())
|
||||
.filter(hasDisplayableValue);
|
||||
};
|
||||
|
||||
return MetadataCapability;
|
||||
}
|
||||
|
@ -69,100 +69,103 @@ define(
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param {Function} topic a service for creating listeners
|
||||
* @param {Function} now a service to get the current time
|
||||
* @param {DomainObject} domainObject the domain object
|
||||
* which will expose this capability
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function MutationCapability(topic, now, domainObject) {
|
||||
var t = topic(TOPIC_PREFIX + domainObject.getId());
|
||||
this.mutationTopic = topic(TOPIC_PREFIX + domainObject.getId());
|
||||
this.now = now;
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
function mutate(mutator, timestamp) {
|
||||
// Get the object's model and clone it, so the
|
||||
// mutator function has a temporary copy to work with.
|
||||
var model = domainObject.getModel(),
|
||||
clone = JSON.parse(JSON.stringify(model)),
|
||||
useTimestamp = arguments.length > 1;
|
||||
/**
|
||||
* Modify the domain object's model, using a provided
|
||||
* function. This function will receive a copy of the
|
||||
* domain object's model as an argument; behavior
|
||||
* varies depending on that function's return value:
|
||||
*
|
||||
* * If no value (or undefined) is returned by the mutator,
|
||||
* the state of the model object delivered as the mutator's
|
||||
* argument will become the domain object's new model.
|
||||
* This is useful for writing code that modifies the model
|
||||
* directly.
|
||||
* * If a plain object is returned, that object will be used
|
||||
* as the domain object's new model.
|
||||
* * If boolean `false` is returned, the mutation will be
|
||||
* cancelled.
|
||||
* * If a promise is returned, its resolved value will be
|
||||
* handled as one of the above.
|
||||
*
|
||||
*
|
||||
* @param {Function} mutator the function which will make
|
||||
* changes to the domain object's model.
|
||||
* @param {number} [timestamp] timestamp to record for
|
||||
* this mutation (otherwise, system time will be
|
||||
* used)
|
||||
* @returns {Promise.<boolean>} a promise for the result
|
||||
* of the mutation; true if changes were made.
|
||||
*/
|
||||
MutationCapability.prototype.mutate = function (mutator, timestamp) {
|
||||
// Get the object's model and clone it, so the
|
||||
// mutator function has a temporary copy to work with.
|
||||
var domainObject = this.domainObject,
|
||||
now = this.now,
|
||||
t = this.mutationTopic,
|
||||
model = domainObject.getModel(),
|
||||
clone = JSON.parse(JSON.stringify(model)),
|
||||
useTimestamp = arguments.length > 1;
|
||||
|
||||
// Function to handle copying values to the actual
|
||||
function handleMutation(mutationResult) {
|
||||
// If mutation result was undefined, just use
|
||||
// the clone; this allows the mutator to omit return
|
||||
// values and just change the model directly.
|
||||
var result = mutationResult || clone;
|
||||
// Function to handle copying values to the actual
|
||||
function handleMutation(mutationResult) {
|
||||
// If mutation result was undefined, just use
|
||||
// the clone; this allows the mutator to omit return
|
||||
// values and just change the model directly.
|
||||
var result = mutationResult || clone;
|
||||
|
||||
// Allow mutators to change their mind by
|
||||
// returning false.
|
||||
if (mutationResult !== false) {
|
||||
// Copy values if result was a different object
|
||||
// (either our clone or some other new thing)
|
||||
if (model !== result) {
|
||||
copyValues(model, result);
|
||||
}
|
||||
model.modified = useTimestamp ? timestamp : now();
|
||||
t.notify(model);
|
||||
// Allow mutators to change their mind by
|
||||
// returning false.
|
||||
if (mutationResult !== false) {
|
||||
// Copy values if result was a different object
|
||||
// (either our clone or some other new thing)
|
||||
if (model !== result) {
|
||||
copyValues(model, result);
|
||||
}
|
||||
|
||||
// Report the result of the mutation
|
||||
return mutationResult !== false;
|
||||
model.modified = useTimestamp ? timestamp : now();
|
||||
t.notify(model);
|
||||
}
|
||||
|
||||
// Invoke the provided mutator, then make changes to
|
||||
// the underlying model (if applicable.)
|
||||
return fastPromise(mutator(clone)).then(handleMutation);
|
||||
// Report the result of the mutation
|
||||
return mutationResult !== false;
|
||||
}
|
||||
|
||||
function listen(listener) {
|
||||
return t.listen(listener);
|
||||
}
|
||||
// Invoke the provided mutator, then make changes to
|
||||
// the underlying model (if applicable.)
|
||||
return fastPromise(mutator(clone)).then(handleMutation);
|
||||
};
|
||||
|
||||
return {
|
||||
/**
|
||||
* Alias of `mutate`, used to support useCapability.
|
||||
* @memberof platform/core.MutationCapability#
|
||||
*/
|
||||
invoke: mutate,
|
||||
/**
|
||||
* Modify the domain object's model, using a provided
|
||||
* function. This function will receive a copy of the
|
||||
* domain object's model as an argument; behavior
|
||||
* varies depending on that function's return value:
|
||||
*
|
||||
* * If no value (or undefined) is returned by the mutator,
|
||||
* the state of the model object delivered as the mutator's
|
||||
* argument will become the domain object's new model.
|
||||
* This is useful for writing code that modifies the model
|
||||
* directly.
|
||||
* * If a plain object is returned, that object will be used
|
||||
* as the domain object's new model.
|
||||
* * If boolean `false` is returned, the mutation will be
|
||||
* cancelled.
|
||||
* * If a promise is returned, its resolved value will be
|
||||
* handled as one of the above.
|
||||
*
|
||||
*
|
||||
* @param {function} mutator the function which will make
|
||||
* changes to the domain object's model.
|
||||
* @param {number} [timestamp] timestamp to record for
|
||||
* this mutation (otherwise, system time will be
|
||||
* used)
|
||||
* @returns {Promise.<boolean>} a promise for the result
|
||||
* of the mutation; true if changes were made.
|
||||
* @memberof platform/core.MutationCapability#
|
||||
*/
|
||||
mutate: mutate,
|
||||
/**
|
||||
* Listen for mutations of this domain object's model.
|
||||
* The provided listener will be invoked with the domain
|
||||
* object's new model after any changes. To stop listening,
|
||||
* invoke the function returned by this method.
|
||||
* @param {Function} listener function to call on mutation
|
||||
* @returns {Function} a function to stop listening
|
||||
* @memberof platform/core.MutationCapability#
|
||||
*/
|
||||
listen: listen
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Listen for mutations of this domain object's model.
|
||||
* The provided listener will be invoked with the domain
|
||||
* object's new model after any changes. To stop listening,
|
||||
* invoke the function returned by this method.
|
||||
* @param {Function} listener function to call on mutation
|
||||
* @returns {Function} a function to stop listening
|
||||
* @memberof platform/core.MutationCapability#
|
||||
*/
|
||||
MutationCapability.prototype.listen = function (listener) {
|
||||
return this.mutationTopic.listen(listener);
|
||||
};
|
||||
|
||||
/**
|
||||
* Alias of `mutate`, used to support useCapability.
|
||||
*/
|
||||
MutationCapability.prototype.invoke =
|
||||
MutationCapability.prototype.mutate;
|
||||
|
||||
return MutationCapability;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ define(
|
||||
*
|
||||
* @param {PersistenceService} persistenceService the underlying
|
||||
* provider of persistence capabilities.
|
||||
* @param {string} SPACE the name of the persistence space to
|
||||
* @param {string} space the name of the persistence space to
|
||||
* use (this is an arbitrary string, useful in principle
|
||||
* for distinguishing different persistence stores from
|
||||
* one another.)
|
||||
@ -42,10 +42,60 @@ define(
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function PersistenceCapability(persistenceService, SPACE, domainObject) {
|
||||
function PersistenceCapability(persistenceService, space, domainObject) {
|
||||
// Cache modified timestamp
|
||||
var modified = domainObject.getModel().modified;
|
||||
this.modified = domainObject.getModel().modified;
|
||||
|
||||
this.domainObject = domainObject;
|
||||
this.space = space;
|
||||
this.persistenceService = persistenceService;
|
||||
}
|
||||
|
||||
// Utility function for creating promise-like objects which
|
||||
// resolve synchronously when possible
|
||||
function fastPromise(value) {
|
||||
return (value || {}).then ? value : {
|
||||
then: function (callback) {
|
||||
return fastPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist any changes which have been made to this
|
||||
* domain object's model.
|
||||
* @returns {Promise} a promise which will be resolved
|
||||
* if persistence is successful, and rejected
|
||||
* if not.
|
||||
*/
|
||||
PersistenceCapability.prototype.persist = function () {
|
||||
var domainObject = this.domainObject,
|
||||
modified = domainObject.getModel().modified;
|
||||
|
||||
// Update persistence timestamp...
|
||||
domainObject.useCapability("mutation", function (model) {
|
||||
model.persisted = modified;
|
||||
}, modified);
|
||||
|
||||
// ...and persist
|
||||
return this.persistenceService.updateObject(
|
||||
this.getSpace(),
|
||||
domainObject.getId(),
|
||||
domainObject.getModel()
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update this domain object to match the latest from
|
||||
* persistence.
|
||||
* @returns {Promise} a promise which will be resolved
|
||||
* when the update is complete
|
||||
*/
|
||||
PersistenceCapability.prototype.refresh = function () {
|
||||
var domainObject = this.domainObject,
|
||||
model = domainObject.getModel();
|
||||
|
||||
// Update a domain object's model upon refresh
|
||||
function updateModel(model) {
|
||||
@ -55,75 +105,28 @@ define(
|
||||
}, modified);
|
||||
}
|
||||
|
||||
// For refresh; update a domain object model, only if there
|
||||
// are no unsaved changes.
|
||||
function updatePersistenceTimestamp() {
|
||||
var modified = domainObject.getModel().modified;
|
||||
domainObject.useCapability("mutation", function (model) {
|
||||
model.persisted = modified;
|
||||
}, modified);
|
||||
}
|
||||
// Only update if we don't have unsaved changes
|
||||
return (model.modified === model.persisted) ?
|
||||
this.persistenceService.readObject(
|
||||
this.getSpace(),
|
||||
this.domainObject.getId()
|
||||
).then(updateModel) :
|
||||
fastPromise(false);
|
||||
};
|
||||
|
||||
// Utility function for creating promise-like objects which
|
||||
// resolve synchronously when possible
|
||||
function fastPromise(value) {
|
||||
return (value || {}).then ? value : {
|
||||
then: function (callback) {
|
||||
return fastPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Persist any changes which have been made to this
|
||||
* domain object's model.
|
||||
* @returns {Promise} a promise which will be resolved
|
||||
* if persistence is successful, and rejected
|
||||
* if not.
|
||||
* @memberof platform/core.PersistenceCapability#
|
||||
*/
|
||||
persist: function () {
|
||||
updatePersistenceTimestamp();
|
||||
return persistenceService.updateObject(
|
||||
SPACE,
|
||||
domainObject.getId(),
|
||||
domainObject.getModel()
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Update this domain object to match the latest from
|
||||
* persistence.
|
||||
* @returns {Promise} a promise which will be resolved
|
||||
* when the update is complete
|
||||
* @memberof platform/core.PersistenceCapability#
|
||||
*/
|
||||
refresh: function () {
|
||||
var model = domainObject.getModel();
|
||||
// Only update if we don't have unsaved changes
|
||||
return (model.modified === model.persisted) ?
|
||||
persistenceService.readObject(
|
||||
SPACE,
|
||||
domainObject.getId()
|
||||
).then(updateModel) :
|
||||
fastPromise(false);
|
||||
},
|
||||
/**
|
||||
* Get the space in which this domain object is persisted;
|
||||
* this is useful when, for example, decided which space a
|
||||
* newly-created domain object should be persisted to (by
|
||||
* default, this should be the space of its containing
|
||||
* object.)
|
||||
*
|
||||
* @returns {string} the name of the space which should
|
||||
* be used to persist this object
|
||||
* @memberof platform/core.PersistenceCapability#
|
||||
*/
|
||||
getSpace: function () {
|
||||
return SPACE;
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get the space in which this domain object is persisted;
|
||||
* this is useful when, for example, decided which space a
|
||||
* newly-created domain object should be persisted to (by
|
||||
* default, this should be the space of its containing
|
||||
* object.)
|
||||
*
|
||||
* @returns {string} the name of the space which should
|
||||
* be used to persist this object
|
||||
*/
|
||||
PersistenceCapability.prototype.getSpace = function () {
|
||||
return this.space;
|
||||
};
|
||||
|
||||
return PersistenceCapability;
|
||||
}
|
||||
|
@ -40,92 +40,80 @@ define(
|
||||
*
|
||||
* @memberof platform/core
|
||||
* @constructor
|
||||
* @implements {Capability}
|
||||
*/
|
||||
function RelationshipCapability($injector, domainObject) {
|
||||
var objectService,
|
||||
lastPromise = {},
|
||||
lastModified;
|
||||
|
||||
// Get a reference to the object service from $injector
|
||||
function injectObjectService() {
|
||||
objectService = $injector.get("objectService");
|
||||
return objectService;
|
||||
}
|
||||
|
||||
// Get a reference to the object service (either cached or
|
||||
// from the injector)
|
||||
function getObjectService() {
|
||||
return objectService || injectObjectService();
|
||||
}
|
||||
|
||||
// Promise this domain object's composition (an array of domain
|
||||
// object instances corresponding to ids in its model.)
|
||||
function promiseRelationships(key) {
|
||||
var model = domainObject.getModel(),
|
||||
ids;
|
||||
|
||||
// Package objects as an array
|
||||
function packageObject(objects) {
|
||||
return ids.map(function (id) {
|
||||
return objects[id];
|
||||
}).filter(function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
|
||||
// Clear cached promises if modification has occurred
|
||||
if (lastModified !== model.modified) {
|
||||
lastPromise = {};
|
||||
lastModified = model.modified;
|
||||
}
|
||||
|
||||
// Make a new request if needed
|
||||
if (!lastPromise[key]) {
|
||||
ids = (model.relationships || {})[key] || [];
|
||||
lastModified = model.modified;
|
||||
// Load from the underlying object service
|
||||
lastPromise[key] = getObjectService().getObjects(ids)
|
||||
.then(packageObject);
|
||||
}
|
||||
|
||||
return lastPromise[key];
|
||||
}
|
||||
|
||||
// List types of relationships which this object has
|
||||
function listRelationships() {
|
||||
var relationships =
|
||||
(domainObject.getModel() || {}).relationships || {};
|
||||
|
||||
// Check if this key really does expose an array of ids
|
||||
// (to filter out malformed relationships)
|
||||
function isArray(key) {
|
||||
return Array.isArray(relationships[key]);
|
||||
}
|
||||
|
||||
return Object.keys(relationships).filter(isArray).sort();
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* List all types of relationships exposed by this
|
||||
* object.
|
||||
* @returns {string[]} a list of all relationship types
|
||||
* @memberof platform/core.RelationshipCapability#
|
||||
*/
|
||||
listRelationships: listRelationships,
|
||||
/**
|
||||
* Request related objects, with a given relationship type.
|
||||
* This will typically require asynchronous lookup, so this
|
||||
* returns a promise.
|
||||
* @param {string} key the type of relationship
|
||||
* @returns {Promise.<DomainObject[]>} a promise for related
|
||||
* domain objects
|
||||
* @memberof platform/core.RelationshipCapability#
|
||||
*/
|
||||
getRelatedObjects: promiseRelationships
|
||||
this.injectObjectService = function () {
|
||||
this.objectService = $injector.get("objectService");
|
||||
};
|
||||
|
||||
this.lastPromise = {};
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all types of relationships exposed by this
|
||||
* object.
|
||||
* @returns {string[]} a list of all relationship types
|
||||
*/
|
||||
RelationshipCapability.prototype.listRelationships = function listRelationships() {
|
||||
var relationships =
|
||||
(this.domainObject.getModel() || {}).relationships || {};
|
||||
|
||||
// Check if this key really does expose an array of ids
|
||||
// (to filter out malformed relationships)
|
||||
function isArray(key) {
|
||||
return Array.isArray(relationships[key]);
|
||||
}
|
||||
|
||||
return Object.keys(relationships).filter(isArray).sort();
|
||||
};
|
||||
|
||||
/**
|
||||
* Request related objects, with a given relationship type.
|
||||
* This will typically require asynchronous lookup, so this
|
||||
* returns a promise.
|
||||
* @param {string} key the type of relationship
|
||||
* @returns {Promise.<DomainObject[]>} a promise for related
|
||||
* domain objects
|
||||
*/
|
||||
RelationshipCapability.prototype.getRelatedObjects = function (key) {
|
||||
var model = this.domainObject.getModel(),
|
||||
ids;
|
||||
|
||||
// Package objects as an array
|
||||
function packageObject(objects) {
|
||||
return ids.map(function (id) {
|
||||
return objects[id];
|
||||
}).filter(function (obj) {
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
|
||||
// Clear cached promises if modification has occurred
|
||||
if (this.lastModified !== model.modified) {
|
||||
this.lastPromise = {};
|
||||
this.lastModified = model.modified;
|
||||
}
|
||||
|
||||
// Make a new request if needed
|
||||
if (!this.lastPromise[key]) {
|
||||
ids = (model.relationships || {})[key] || [];
|
||||
this.lastModified = model.modified;
|
||||
// Lazily initialize object service now that we need it
|
||||
if (!this.objectService) {
|
||||
this.injectObjectService();
|
||||
}
|
||||
// Load from the underlying object service
|
||||
this.lastPromise[key] = this.objectService.getObjects(ids)
|
||||
.then(packageObject);
|
||||
}
|
||||
|
||||
return this.lastPromise[key];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Test to determine whether or not this capability should be exposed
|
||||
* by a domain object based on its model. Checks for the presence of
|
||||
|
Reference in New Issue
Block a user