Resolved merge conflicts

This commit is contained in:
Henry
2016-05-12 16:14:31 -07:00
parent 5bf750c90c
commit 44f4a82fa1
37 changed files with 741 additions and 332 deletions

View File

@@ -46,10 +46,19 @@ define(
function returnToBrowse () {
var parent;
domainObject.getCapability("location").getOriginal().then(function (original) {
parent = original.getCapability("context").getParent();
parent.getCapability("action").perform("navigate");
});
//If the object existed already, navigate to refresh view
// with previous object state.
if (domainObject.getModel().persisted) {
domainObject.getCapability("action").perform("navigate");
} else {
//If the object was new, and user has cancelled, then
//navigate back to parent because nothing to show.
domainObject.getCapability("location").getOriginal().then(function (original) {
parent = original.getCapability("context").getParent();
parent.getCapability("action").perform("navigate");
});
}
}
return this.domainObject.getCapability("editor").cancel()
.then(returnToBrowse);
@@ -64,7 +73,8 @@ define(
CancelAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
domainObject.getCapability("status").get("editing");
domainObject.hasCapability('editor') &&
domainObject.getCapability('editor').isEditContextRoot();
};
return CancelAction;

View File

@@ -44,7 +44,7 @@ define(
* @constructor
* @implements {Action}
*/
function EditAction($location, navigationService, $log, $q, context) {
function EditAction($location, navigationService, $log, context) {
var domainObject = (context || {}).domainObject;
// We cannot enter Edit mode if we have no domain object to
@@ -63,7 +63,6 @@ define(
this.domainObject = domainObject;
this.$location = $location;
this.navigationService = navigationService;
this.$q = $q;
}
/**
@@ -89,8 +88,11 @@ define(
var domainObject = (context || {}).domainObject,
type = domainObject && domainObject.getCapability('type');
// Only allow creatable types to be edited
return type && type.hasFeature('creation') && !domainObject.getCapability('status').get('editing');
// Only allow editing of types that support it and are not already
// being edited
return type && type.hasFeature('creation') &&
domainObject.hasCapability('editor') &&
!domainObject.getCapability('editor').isEditContextRoot();
};
return EditAction;

View File

@@ -85,8 +85,9 @@ define(
SaveAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
domainObject.getModel().persisted !== undefined &&
domainObject.getCapability("status").get("editing");
domainObject.hasCapability('editor') &&
domainObject.getCapability('editor').isEditContextRoot() &&
domainObject.getModel().persisted !== undefined;
};
return SaveAction;

View File

@@ -135,8 +135,8 @@ define(
return copyService.perform(domainObject, parent, allowClone);
}
function cancelEditingAfterClone(clonedObject) {
return domainObject.getCapability("editor").cancel()
function commitEditingAfterClone(clonedObject) {
return domainObject.getCapability("editor").save()
.then(resolveWith(clonedObject));
}
@@ -144,7 +144,7 @@ define(
.then(doWizardSave)
.then(getParent)
.then(cloneIntoParent)
.then(cancelEditingAfterClone)
.then(commitEditingAfterClone)
.catch(resolveWith(false));
};
@@ -157,7 +157,8 @@ define(
SaveAsAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
domainObject.getCapability("status").get("editing") &&
domainObject.hasCapability('editor') &&
domainObject.getCapability('editor').isEditContextRoot() &&
domainObject.getModel().persisted === undefined;
};

View File

@@ -24,24 +24,42 @@ define(
[],
function () {
/**
* A capability that implements an editing 'session' for a domain
* object. An editing session is initiated via a call to .edit().
* Once initiated, any persist operations will be queued pending a
* subsequent call to [.save()](@link #save) or [.cancel()](@link
* #cancel).
* @param transactionService
* @param domainObject
* @constructor
*/
function EditorCapability(
transactionService,
dirtyModelCache,
domainObject
) {
this.transactionService = transactionService;
this.dirtyModelCache = dirtyModelCache;
this.domainObject = domainObject;
}
/**
* Initiate an editing session. This will start a transaction during
* which any persist operations will be deferred until either save()
* or cancel() are called.
*/
EditorCapability.prototype.edit = function () {
this.transactionService.startTransaction();
this.domainObject.getCapability('status').set('editing', true);
};
function isEditContextRoot (domainObject) {
return domainObject.getCapability('status').get('editing');
}
function isEditing (domainObject) {
return domainObject.getCapability('status').get('editing') ||
domainObject.hasCapability('context') && isEditing(domainObject.getCapability('context').getParent());
return isEditContextRoot(domainObject) ||
domainObject.hasCapability('context') &&
isEditing(domainObject.getCapability('context').getParent());
}
/**
@@ -53,6 +71,20 @@ define(
return isEditing(this.domainObject);
};
/**
* Is this the root editing object (ie. the object that the user
* clicked 'edit' on)?
* @returns {*}
*/
EditorCapability.prototype.isEditContextRoot = function () {
return isEditContextRoot(this.domainObject);
};
/**
* Save any changes from this editing session. This will flush all
* pending persists and end the current transaction
* @returns {*}
*/
EditorCapability.prototype.save = function () {
var domainObject = this.domainObject;
return this.transactionService.commit().then(function() {
@@ -62,6 +94,11 @@ define(
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
/**
* Cancel the current editing session. This will discard any pending
* persist operations
* @returns {*}
*/
EditorCapability.prototype.cancel = function () {
var domainObject = this.domainObject;
return this.transactionService.cancel().then(function(){
@@ -70,15 +107,14 @@ define(
});
};
/**
* @returns {boolean} true if there have been any domain model
* modifications since the last persist, false otherwise.
*/
EditorCapability.prototype.dirty = function () {
return this.dirtyModelCache.isDirty(this.domainObject);
return (this.domainObject.getModel().modified || 0) > (this.domainObject.getModel().persisted || 0);
};
EditorCapability.prototype.appliesTo = function(context) {
var domainObject = context.domainObject;
return domainObject && domainObject.getType().hasFeature("creation");
}
return EditorCapability;
}
);

View File

@@ -26,23 +26,30 @@ define(
function (TransactionalPersistenceCapability) {
'use strict';
function TransactionDecorator(
/**
* Wraps the [PersistenceCapability]{@link PersistenceCapability} with
* transactional capabilities.
* @param $q
* @param transactionService
* @param capabilityService
* @see TransactionalPersistenceCapability
* @constructor
*/
function TransactionCapabilityDecorator(
$q,
transactionService,
dirtyModelCache,
capabilityService
) {
this.capabilityService = capabilityService;
this.transactionService = transactionService;
this.dirtyModelCache = dirtyModelCache;
this.$q = $q;
}
/**
* Decorate PersistenceCapability to ignore persistence calls when a
* Decorate PersistenceCapability to queue persistence calls when a
* transaction is in progress.
*/
TransactionDecorator.prototype.getCapabilities = function (model) {
TransactionCapabilityDecorator.prototype.getCapabilities = function (model) {
var self = this,
capabilities = this.capabilityService.getCapabilities(model),
persistenceCapability = capabilities.persistence;
@@ -55,7 +62,6 @@ define(
return new TransactionalPersistenceCapability(
self.$q,
self.transactionService,
self.dirtyModelCache,
original,
domainObject
);
@@ -63,6 +69,6 @@ define(
return capabilities;
};
return TransactionDecorator;
return TransactionCapabilityDecorator;
}
);

View File

@@ -26,44 +26,51 @@ define(
function () {
'use strict';
/**
* Wraps persistence capability to enable transactions. Transactions
* will cause persist calls not to be invoked immediately, but
* rather queued until [EditorCapability.save()]{@link EditorCapability#save}
* or [EditorCapability.cancel()]{@link EditorCapability#cancel} are
* called.
* @memberof platform/commonUI/edit/capabilities
* @param $q
* @param transactionService
* @param persistenceCapability
* @param domainObject
* @constructor
*/
function TransactionalPersistenceCapability(
$q,
transactionService,
dirtyModelCache,
persistenceCapability,
domainObject
) {
this.transactionService = transactionService;
this.dirtyModelCache = dirtyModelCache;
this.persistenceCapability = Object.create(persistenceCapability);
this.persistenceCapability = persistenceCapability;
this.domainObject = domainObject;
this.$q = $q;
}
/**
* The wrapped persist function. If a transaction is active, persist
* will be queued until the transaction is committed or cancelled.
* @returns {*}
*/
TransactionalPersistenceCapability.prototype.persist = function () {
var domainObject = this.domainObject,
dirtyModelCache = this.dirtyModelCache;
if (this.transactionService.isActive() && !this.transactionService.isCommitting()) {
dirtyModelCache.markDirty(domainObject);
//Using $q here because need to return something
// from which 'catch' can be chained
if (this.transactionService.isActive()) {
this.transactionService.addToTransaction(
this.persistenceCapability.persist.bind(this.persistenceCapability),
this.persistenceCapability.refresh.bind(this.persistenceCapability)
);
//Need to return a promise from this function
return this.$q.when(true);
} else {
return this.persistenceCapability.persist().then(function (result) {
dirtyModelCache.markClean(domainObject);
return result;
});
return this.persistenceCapability.persist();
}
};
TransactionalPersistenceCapability.prototype.refresh = function () {
var domainObject = this.domainObject,
dirtyModelCache = this.dirtyModelCache;
return this.persistenceCapability.refresh().then(function (result) {
dirtyModelCache.markClean(domainObject);
return result;
});
return this.persistenceCapability.refresh();
};
TransactionalPersistenceCapability.prototype.getSpace = function () {

View File

@@ -73,7 +73,8 @@ define(
function isEditing(context) {
var domainObject = (context || {}).domainObject;
return domainObject
&& domainObject.getCapability('status').get('editing');
&& domainObject.hasCapability('editor')
&& domainObject.getCapability('editor').isEditContextRoot();
}
EditActionPolicy.prototype.allow = function (action, context) {

View File

@@ -34,6 +34,11 @@ define(
* from context menu of non-editable objects, when navigated object
* is being edited
* @constructor
* @param navigationService
* @param editModeBlacklist A blacklist of actions disallowed from
* context menu when navigated object is being edited
* @param nonEditContextBlacklist A blacklist of actions disallowed
* from context menu of non-editable objects, when navigated object
* @implements {Policy.<Action, ActionContext>}
*/
function EditContextualActionPolicy(navigationService, editModeBlacklist, nonEditContextBlacklist) {
@@ -51,7 +56,7 @@ define(
navigatedObject = this.navigationService.getNavigation(),
actionMetadata = action.getMetadata ? action.getMetadata() : {};
if (navigatedObject.getCapability("status").get("editing")) {
if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) {
if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()){
//Target is within the editing context
return this.editBlacklist.indexOf(actionMetadata.key) === -1;

View File

@@ -41,12 +41,11 @@ define(
EditNavigationPolicy.prototype.isDirty = function(domainObject) {
var navigatedObject = domainObject,
editorCapability = navigatedObject &&
navigatedObject.getCapability("editor"),
statusCapability = navigatedObject &&
navigatedObject.getCapability("status");
navigatedObject.getCapability("editor");
return statusCapability && statusCapability.get('editing') &&
editorCapability && editorCapability.dirty();
return editorCapability &&
editorCapability.isEditContextRoot() &&
editorCapability.dirty();
};
/**

View File

@@ -35,10 +35,13 @@ define([], function () {
EditableMovePolicy.prototype.allow = function (action, context) {
var domainObject = context.domainObject,
selectedObject = context.selectedObject,
key = action.getMetadata().key;
key = action.getMetadata().key,
isDomainObjectEditing = domainObject.hasCapability('editor') &&
domainObject.getCapability('editor').inEditContext();
if (key === 'move' && domainObject.hasCapability('editor') && domainObject.getCapability('editor').inEditContext()) {
return !!selectedObject && selectedObject.hasCapability('editor') && selectedObject.getCapability('editor').inEditContext();
if (key === 'move' && isDomainObjectEditing) {
return !!selectedObject && selectedObject.hasCapability('editor') &&
selectedObject.getCapability('editor').inEditContext();
}
// Like all policies, allow by default.

View File

@@ -136,7 +136,7 @@ define(
}
});
if (representedObject.getCapability('status').get('editing')){
if (representedObject.hasCapability('editor') && representedObject.getCapability('editor').isEditContextRoot()){
setEditing();
}
};

View File

@@ -1,47 +0,0 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define(
[],
function() {
function DirtyModelCache(topic) {
this.cache = {};
}
DirtyModelCache.prototype.get = function () {
return this.cache;
};
DirtyModelCache.prototype.isDirty = function (domainObject) {
return !!this.cache[domainObject.getId()];
};
DirtyModelCache.prototype.markDirty = function (domainObject) {
this.cache[domainObject.getId()] = domainObject;
};
DirtyModelCache.prototype.markClean = function (domainObject) {
delete this.cache[domainObject.getId()];
};
return DirtyModelCache;
});

View File

@@ -25,64 +25,90 @@ define(
function() {
/**
* Implements an application-wide transaction state. Once a
* transaction is started, calls to PersistenceCapability.persist()
* transaction is started, calls to
* [PersistenceCapability.persist()]{@link PersistenceCapability#persist}
* will be deferred until a subsequent call to
* TransactionService.commit() is made.
* [TransactionService.commit]{@link TransactionService#commit} is made.
*
* @memberof platform/commonUI/edit/services
* @param $q
* @constructor
*/
function TransactionService($q, dirtyModelCache) {
function TransactionService($q, $log) {
this.$q = $q;
this.$log = $log;
this.transaction = false;
this.committing = false;
this.cache = dirtyModelCache;
this.onCommits = [];
this.onCancels = [];
}
/**
* Starts a transaction. While a transaction is active all calls to
* [PersistenceCapability.persist](@link PersistenceCapability#persist)
* will be queued until [commit]{@link #commit} or [cancel]{@link
* #cancel} are called
*/
TransactionService.prototype.startTransaction = function () {
if (this.transaction)
console.error("Transaction already in progress")
if (this.transaction) {
//Log error because this is a programming error if it occurs.
this.$log.error("Transaction already in progress");
}
this.transaction = true;
};
/**
* @returns {boolean} If true, indicates that a transaction is in progress
*/
TransactionService.prototype.isActive = function () {
return this.transaction;
};
TransactionService.prototype.isCommitting = function () {
return this.committing;
/**
* Adds provided functions to a queue to be called on
* [.commit()]{@link #commit} or
* [.cancel()]{@link #commit}
* @param onCommit A function to call on commit
* @param onCancel A function to call on cancel
*/
TransactionService.prototype.addToTransaction = function (onCommit, onCancel) {
if (this.transaction) {
this.onCommits.push(onCommit);
if (onCancel) {
this.onCancels.push(onCancel);
}
} else {
//Log error because this is a programming error if it occurs.
this.$log.error("No transaction in progress");
}
};
/**
* All persist calls deferred since the beginning of the transaction
* will be committed. Any failures will be reported via a promise
* rejection.
* @returns {*}
* will be committed.
*
* @returns {Promise} resolved when all persist operations have
* completed. Will reject if any commit operations fail
*/
TransactionService.prototype.commit = function () {
var self = this;
cache = this.cache.get();
var self = this,
promises = [],
onCommit;
this.committing = true;
function keyToObject(key) {
return cache[key];
while (this.onCommits.length > 0) { // ...using a while in case some onCommit adds to transaction
onCommit = this.onCommits.pop();
try { // ...also don't want to fail mid-loop...
promises.push(onCommit());
} catch (e) {
this.$log.error("Error committing transaction.");
}
}
return this.$q.all(promises).then( function () {
self.transaction = false;
function objectToPromise(object) {
return object.getCapability('persistence').persist();
}
return this.$q.all(
Object.keys(cache)
.map(keyToObject)
.map(objectToPromise))
.then(function () {
self.transaction = false;
this.committing = false;
}).catch(function() {
return this.committing = false;
});
self.onCommits = [];
self.onCancels = [];
});
};
/**
@@ -95,23 +121,23 @@ define(
*/
TransactionService.prototype.cancel = function () {
var self = this,
cache = this.cache.get();
results = [],
onCancel;
function keyToObject(key) {
return cache[key];
while (this.onCancels.length > 0) {
onCancel = this.onCancels.pop();
try {
results.push(onCancel());
} catch (error) {
this.$log.error("Error committing transaction.");
}
}
return this.$q.all(results).then(function () {
self.transaction = false;
function objectToPromise(object) {
return self.$q.when(object.getModel().persisted && object.getCapability('persistence').refresh());
}
return this.$q.all(Object.keys(cache)
.map(keyToObject)
.map(objectToPromise))
.then(function () {
self.transaction = false;
this.committing = false;
});
self.onCommits = [];
self.onCancels = [];
});
};
return TransactionService;