mirror of
https://github.com/nasa/openmct.git
synced 2025-06-16 14:18:16 +00:00
[Edit] Utilize model cache
Utilize model cache, permitting object models in edit mode to be reused across multiple distinct instances with unique contexts (unique contexts are necessary to avoid ambiguity in the Remove action, WTD-473). To avoid infinite digest cycles as a consequence of this, refactor context/composition capability wrappers such that the former is idempotent (since idempotence is no longer ensured by the EditableDomainObjectCache) to avoid infinite digest errors in Edit mode.
This commit is contained in:
@ -0,0 +1,36 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
|
||||||
|
define(
|
||||||
|
['./EditableLookupCapability'],
|
||||||
|
function (EditableLookupCapability) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for the "composition" capability;
|
||||||
|
* ensures that any domain objects reachable in Edit mode
|
||||||
|
* are also wrapped as EditableDomainObjects.
|
||||||
|
*
|
||||||
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
|
* associated cache; the constructor signature is particular
|
||||||
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
*/
|
||||||
|
return function EditableCompositionCapability(
|
||||||
|
contextCapability,
|
||||||
|
editableObject,
|
||||||
|
domainObject,
|
||||||
|
cache
|
||||||
|
) {
|
||||||
|
// This is a "lookup" style capability (it looks up other
|
||||||
|
// domain objects), but we do not want to return the same
|
||||||
|
// specific value every time (composition may change)
|
||||||
|
return new EditableLookupCapability(
|
||||||
|
contextCapability,
|
||||||
|
editableObject,
|
||||||
|
domainObject,
|
||||||
|
cache,
|
||||||
|
false // Not idempotent
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
|
|
||||||
define(
|
define(
|
||||||
[],
|
['./EditableLookupCapability'],
|
||||||
function () {
|
function (EditableLookupCapability) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for both "context" and "composition" capabilities;
|
* Wrapper for the "context" capability;
|
||||||
* ensures that any domain objects reachable in Edit mode
|
* ensures that any domain objects reachable in Edit mode
|
||||||
* are also wrapped as EditableDomainObjects.
|
* are also wrapped as EditableDomainObjects.
|
||||||
*
|
*
|
||||||
@ -21,55 +21,15 @@ define(
|
|||||||
domainObject,
|
domainObject,
|
||||||
cache
|
cache
|
||||||
) {
|
) {
|
||||||
var capability = Object.create(contextCapability);
|
// This is a "lookup" style capability (it looks up other
|
||||||
|
// domain objects), and it should be idempotent
|
||||||
// Check for domain object interface. If something has these
|
return new EditableLookupCapability(
|
||||||
// three methods, we assume it's a domain object.
|
contextCapability,
|
||||||
function isDomainObject(obj) {
|
editableObject,
|
||||||
return obj !== undefined &&
|
domainObject,
|
||||||
typeof obj.getId === 'function' &&
|
cache,
|
||||||
typeof obj.getModel === 'function' &&
|
true // Not idempotent
|
||||||
typeof obj.getCapability === 'function';
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Check an object returned by the wrapped capability; if it
|
|
||||||
// is a domain object, we want to make it editable and/or get
|
|
||||||
// it from the cache of editable domain objects. This will
|
|
||||||
// prevent changes made in edit mode from modifying the actual
|
|
||||||
// underlying domain object.
|
|
||||||
function makeEditableObject(obj) {
|
|
||||||
return isDomainObject(obj) ?
|
|
||||||
cache.getEditableObject(obj) :
|
|
||||||
obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap a returned value (see above); if it's an array, wrap
|
|
||||||
// all elements.
|
|
||||||
function makeEditable(returnValue) {
|
|
||||||
return Array.isArray(returnValue) ?
|
|
||||||
returnValue.map(makeEditableObject) :
|
|
||||||
makeEditableObject(returnValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap a returned value (see above); if it's a promise, wrap
|
|
||||||
// the resolved value.
|
|
||||||
function wrapResult(result) {
|
|
||||||
return result.then ? // promise-like
|
|
||||||
result.then(makeEditable) :
|
|
||||||
makeEditable(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap all methods; return only editable domain objects.
|
|
||||||
Object.keys(contextCapability).forEach(function (k) {
|
|
||||||
capability[k] = function () {
|
|
||||||
return wrapResult(contextCapability[k].apply(
|
|
||||||
capability,
|
|
||||||
arguments
|
|
||||||
));
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return capability;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -0,0 +1,97 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for both "context" and "composition" capabilities;
|
||||||
|
* ensures that any domain objects reachable in Edit mode
|
||||||
|
* are also wrapped as EditableDomainObjects.
|
||||||
|
*
|
||||||
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
|
* associated cache; the constructor signature is particular
|
||||||
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
*/
|
||||||
|
return function EditableLookupCapability(
|
||||||
|
contextCapability,
|
||||||
|
editableObject,
|
||||||
|
domainObject,
|
||||||
|
cache,
|
||||||
|
idempotent
|
||||||
|
) {
|
||||||
|
var capability = Object.create(contextCapability);
|
||||||
|
|
||||||
|
// Check for domain object interface. If something has these
|
||||||
|
// three methods, we assume it's a domain object.
|
||||||
|
function isDomainObject(obj) {
|
||||||
|
return obj !== undefined &&
|
||||||
|
typeof obj.getId === 'function' &&
|
||||||
|
typeof obj.getModel === 'function' &&
|
||||||
|
typeof obj.getCapability === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check an object returned by the wrapped capability; if it
|
||||||
|
// is a domain object, we want to make it editable and/or get
|
||||||
|
// it from the cache of editable domain objects. This will
|
||||||
|
// prevent changes made in edit mode from modifying the actual
|
||||||
|
// underlying domain object.
|
||||||
|
function makeEditableObject(obj) {
|
||||||
|
return isDomainObject(obj) ?
|
||||||
|
cache.getEditableObject(obj) :
|
||||||
|
obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap a returned value (see above); if it's an array, wrap
|
||||||
|
// all elements.
|
||||||
|
function makeEditable(returnValue) {
|
||||||
|
return Array.isArray(returnValue) ?
|
||||||
|
returnValue.map(makeEditableObject) :
|
||||||
|
makeEditableObject(returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap a returned value (see above); if it's a promise, wrap
|
||||||
|
// the resolved value.
|
||||||
|
function wrapResult(result) {
|
||||||
|
return result.then ? // promise-like
|
||||||
|
result.then(makeEditable) :
|
||||||
|
makeEditable(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a wrapped version of a function, which ensures
|
||||||
|
// all results are editable domain objects.
|
||||||
|
function wrapFunction(fn) {
|
||||||
|
return function () {
|
||||||
|
return wrapResult(contextCapability[fn].apply(
|
||||||
|
capability,
|
||||||
|
arguments
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap a method such that it only delegates once.
|
||||||
|
function oneTimeFunction(fn) {
|
||||||
|
return function () {
|
||||||
|
var result = wrapFunction(fn).apply(this, arguments);
|
||||||
|
capability[fn] = function () {
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap a method of this capability
|
||||||
|
function wrapMethod(fn) {
|
||||||
|
capability[fn] =
|
||||||
|
(idempotent ? oneTimeFunction : wrapFunction)(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap all methods; return only editable domain objects.
|
||||||
|
Object.keys(contextCapability).forEach(wrapFunction);
|
||||||
|
|
||||||
|
return capability;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
@ -53,9 +53,8 @@ define(
|
|||||||
|
|
||||||
// Constructor for EditableDomainObject, which adheres
|
// Constructor for EditableDomainObject, which adheres
|
||||||
// to the same shared cache.
|
// to the same shared cache.
|
||||||
function EditableDomainObjectImpl(domainObject) {
|
function EditableDomainObjectImpl(domainObject, model) {
|
||||||
var model = JSON.parse(JSON.stringify(domainObject.getModel())),
|
var editableObject = Object.create(domainObject);
|
||||||
editableObject = Object.create(domainObject);
|
|
||||||
|
|
||||||
// Only provide the cloned model.
|
// Only provide the cloned model.
|
||||||
editableObject.getModel = function () { return model; };
|
editableObject.getModel = function () { return model; };
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
* @module editor/object/editable-domain-object-cache
|
* @module editor/object/editable-domain-object-cache
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
function () {
|
["./EditableModelCache"],
|
||||||
|
function (EditableModelCache) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +33,7 @@ define(
|
|||||||
* @memberof module:editor/object/editable-domain-object-cache
|
* @memberof module:editor/object/editable-domain-object-cache
|
||||||
*/
|
*/
|
||||||
function EditableDomainObjectCache(EditableDomainObject) {
|
function EditableDomainObjectCache(EditableDomainObject) {
|
||||||
var cache = {},
|
var cache = new EditableModelCache(),
|
||||||
dirty = {};
|
dirty = {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -44,9 +45,10 @@ define(
|
|||||||
* @returns {DomainObject} the domain object in an editable form
|
* @returns {DomainObject} the domain object in an editable form
|
||||||
*/
|
*/
|
||||||
getEditableObject: function (domainObject) {
|
getEditableObject: function (domainObject) {
|
||||||
var id = domainObject.getId();
|
return new EditableDomainObject(
|
||||||
return (cache[id] =
|
domainObject,
|
||||||
cache[id] || new EditableDomainObject(domainObject));
|
cache.getCachedModel(domainObject)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Mark an editable domain object (presumably already cached)
|
* Mark an editable domain object (presumably already cached)
|
||||||
|
Reference in New Issue
Block a user