diff --git a/platform/commonUI/edit/src/EditController.js b/platform/commonUI/edit/src/EditController.js index 758988330b..8c859ab126 100644 --- a/platform/commonUI/edit/src/EditController.js +++ b/platform/commonUI/edit/src/EditController.js @@ -9,11 +9,15 @@ define( "use strict"; /** - * + * Controller which is responsible for populating the scope for + * Edit mode; introduces an editable version of the currently + * navigated domain object into the scope. * @constructor */ function EditController($scope, navigationService) { function setNavigation(domainObject) { + // Wrap the domain object such that all mutation is + // confined to edit mode (until Save) $scope.navigatedObject = domainObject && new EditableDomainObject(domainObject); } diff --git a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js index 1d3584ff34..f1b442f85a 100644 --- a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js @@ -1,52 +1,71 @@ /*global define*/ -/** - * Wrapper for both "context" and "composition" capabilities; - * ensures that any domain objects reachable in Edit mode - * are also wrapped as EditableDomainObjects - */ + 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 EditableContextCapability( contextCapability, editableObject, domainObject, - factory + cache ) { 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 typeof obj.getId === 'function' && + 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) ? - factory.getEditableObject(obj) : + cache.getEditableObject(obj) : obj; } - function makeEditable(obj) { - return Array.isArray(obj) ? - obj.map(makeEditableObject) : - makeEditableObject(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); } - // Replace all methods; return only editable domain objects. + // 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 () { - var result = contextCapability[k].apply( + return wrapResult(contextCapability[k].apply( capability, arguments - ); - - return result.then ? // promise-like - result.then(makeEditable) : - makeEditable(result); + )); }; }); diff --git a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js index 17357d12d6..8d39b61992 100644 --- a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js @@ -1,16 +1,21 @@ /*global define*/ -/** - * Editable Persistence Capability. Overrides the persistence capability - * normally exhibited by a domain object to ensure that changes made - * during edit mode are not immediately stored to the database or other - * backing storage. - */ + define( function () { 'use strict'; - return function EditablePersistenceCapability( + /** + * Editable Persistence Capability. Overrides the persistence capability + * normally exhibited by a domain object to ensure that changes made + * during edit mode are not immediately stored to the database or other + * backing storage. + * + * 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. + */ + function EditablePersistenceCapability( persistenceCapability, editableObject, domainObject, @@ -25,6 +30,8 @@ define( }; return persistence; - }; + } + + return EditablePersistenceCapability; } ); \ No newline at end of file diff --git a/platform/commonUI/edit/src/capabilities/EditorCapability.js b/platform/commonUI/edit/src/capabilities/EditorCapability.js index 921c57f8c0..7956ac26ee 100644 --- a/platform/commonUI/edit/src/capabilities/EditorCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditorCapability.js @@ -1,19 +1,24 @@ -/*global define*/ +/*global define,Promise*/ -/** - * Implements "save" and "cancel" as capabilities of - * the object. In editing mode, user is seeing/using - * a copy of the object (an EditableDomainObject) - * which is disconnected from persistence; the Save - * and Cancel actions can use this capability to - * propagate changes from edit mode to the underlying - * actual persistable object. - */ define( [], function () { 'use strict'; + + /** + * Implements "save" and "cancel" as capabilities of + * the object. In editing mode, user is seeing/using + * a copy of the object (an EditableDomainObject) + * which is disconnected from persistence; the Save + * and Cancel actions can use this capability to + * propagate changes from edit mode to the underlying + * actual persistable object. + * + * 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 EditorCapability( persistenceCapability, editableObject, @@ -21,31 +26,52 @@ define( cache ) { + // Update the underlying, "real" domain object's model + // with changes made to the copy used for editing. function doMutate() { return domainObject.useCapability('mutation', function () { return editableObject.getModel(); }); } + // Persist the underlying domain object function doPersist() { return persistenceCapability.persist(); } + // Save any other objects that have been modified in the cache. + // IMPORTANT: This must not be called until after this object + // has been marked as clean. function saveOthers() { return cache.saveAll(); } + // Indicate that this object has been saved. function markClean() { return cache.markClean(editableObject); } return { + /** + * Save any changes that have been made to this domain object + * (as well as to others that might have been retrieved and + * modified during the editing session) + * @returns {Promise} a promise that will be fulfilled after + * persistence has completed. + */ save: function () { return Promise.resolve(doMutate()) .then(doPersist) .then(markClean) .then(saveOthers); }, + /** + * Cancel editing; Discard any changes that have been made to + * this domain object (as well as to others that might have + * been retrieved and modified during the editing session) + * @returns {Promise} a promise that will be fulfilled after + * cancellation has completed. + */ cancel: function () { return Promise.resolve(undefined); }