diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js index aac5de49e5..4f79d11787 100644 --- a/platform/commonUI/edit/bundle.js +++ b/platform/commonUI/edit/bundle.js @@ -222,7 +222,8 @@ define([ "policyService", "dialogService", "creationService", - "copyService" + "copyService", + "transactionService" ], "priority": "mandatory" }, diff --git a/platform/commonUI/edit/src/actions/SaveAsAction.js b/platform/commonUI/edit/src/actions/SaveAsAction.js index 9c34c06c9a..4c4206b8a6 100644 --- a/platform/commonUI/edit/src/actions/SaveAsAction.js +++ b/platform/commonUI/edit/src/actions/SaveAsAction.js @@ -44,6 +44,7 @@ define([ dialogService, creationService, copyService, + transactionService, context ) { this.domainObject = (context || {}).domainObject; @@ -54,6 +55,7 @@ define([ this.dialogService = dialogService; this.creationService = creationService; this.copyService = copyService; + this.transactionService = transactionService; } /** @@ -111,6 +113,8 @@ define([ var self = this, domainObject = this.domainObject, copyService = this.copyService, + transactionService = this.transactionService, + cancelOldTransaction, dialog = new SaveInProgressDialog(this.dialogService); function doWizardSave(parent) { @@ -156,6 +160,16 @@ define([ .then(resolveWith(clonedObject)); } + function restartTransaction(object) { + cancelOldTransaction = transactionService.restartTransaction(); + return object; + } + + function doCancelOldTransaction(object) { + cancelOldTransaction(); + return object; + } + function onFailure() { hideBlockingDialog(); return false; @@ -165,8 +179,10 @@ define([ .then(doWizardSave) .then(showBlockingDialog) .then(getParent) + .then(restartTransaction) .then(cloneIntoParent) .then(commitEditingAfterClone) + .then(doCancelOldTransaction) .then(hideBlockingDialog) .catch(onFailure); }; diff --git a/platform/commonUI/edit/src/services/TransactionService.js b/platform/commonUI/edit/src/services/TransactionService.js index 8d6c465959..00bc96e1dd 100644 --- a/platform/commonUI/edit/src/services/TransactionService.js +++ b/platform/commonUI/edit/src/services/TransactionService.js @@ -140,9 +140,38 @@ define( }); }; + /** + * Clear and restart the active transaction. + * + * This neither cancels nor commits the active transaction; + * instead, it returns a function that can be used to cancel that + * transaction. + * + * @returns {Function} a function to cancel the prior transaction + * @private + */ + TransactionService.prototype.restartTransaction = function () { + var oldOnCancels = this.onCancels; + + this.onCommits = []; + this.onCancels = []; + + return function () { + while (oldOnCancels.length > 0) { + var onCancel = oldOnCancels.pop(); + try { + onCancel(); + } catch (error) { + this.$log.error("Error cancelling transaction."); + } + } + }; + }; + TransactionService.prototype.size = function () { return this.onCommits.length; }; return TransactionService; - }); + } +); diff --git a/platform/commonUI/edit/test/actions/SaveAsActionSpec.js b/platform/commonUI/edit/test/actions/SaveAsActionSpec.js index 37e35aa5af..850e18ecca 100644 --- a/platform/commonUI/edit/test/actions/SaveAsActionSpec.js +++ b/platform/commonUI/edit/test/actions/SaveAsActionSpec.js @@ -34,6 +34,7 @@ define( mockCopyService, mockParent, mockUrlService, + mockTransactionService, actionContext, capabilities = {}, action; @@ -119,11 +120,26 @@ define( ["urlForLocation"] ); + mockTransactionService = jasmine.createSpyObj( + "transactionService", + ["restartTransaction"] + ); + mockTransactionService.restartTransaction + .andReturn(jasmine.createSpy()); + actionContext = { domainObject: mockDomainObject }; - action = new SaveAsAction(undefined, undefined, mockDialogService, undefined, mockCopyService, actionContext); + action = new SaveAsAction( + undefined, + undefined, + mockDialogService, + undefined, + mockCopyService, + mockTransactionService, + actionContext + ); spyOn(action, "getObjectService"); action.getObjectService.andReturn(mockObjectService);