Bug 1747923 - Clean up CalTransactionManager promise usage. r=darktrojan
Differential Revision: https://phabricator.services.mozilla.com/D134887 --HG-- extra : amend_source : 17951c498ee24da63595d47091494430dcf1e79a
This commit is contained in:
Родитель
02ca7bd37a
Коммит
06e6133d73
|
@ -12,6 +12,7 @@ var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm")
|
|||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
CalEvent: "resource:///modules/CalEvent.jsm",
|
||||
CalTodo: "resource:///modules/CalTodo.jsm",
|
||||
CalTransactionManager: "resource:///modules/CalTransactionManager.jsm",
|
||||
});
|
||||
|
||||
/* exported modifyEventWithDialog, undo, redo, setContextPartstat */
|
||||
|
@ -635,15 +636,6 @@ function promptOccurrenceModification(aItem, aNeedsFuture, aAction) {
|
|||
|
||||
// Undo/Redo code
|
||||
|
||||
/**
|
||||
* Helper to return the transaction manager service.
|
||||
*
|
||||
* @return The calITransactionManager service.
|
||||
*/
|
||||
function getTransactionMgr() {
|
||||
return Cc["@mozilla.org/calendar/transactionmanager;1"].getService(Ci.calITransactionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and commit a transaction with the given arguments to the transaction
|
||||
* manager. Also updates the undo/redo menu.
|
||||
|
@ -653,29 +645,22 @@ function getTransactionMgr() {
|
|||
* @param aItem The new item to add/modify/delete
|
||||
* @param aCalendar The calendar to do the transaction on
|
||||
* @param aOldItem (optional) some actions require an old item
|
||||
* @param aListener (optional) the listener to call when complete.
|
||||
* @param aObserver (optional) the observer to call when complete.
|
||||
* @param aExtResponse (optional) JS object with additional parameters for sending itip messages
|
||||
* (see also description of checkAndSend in calItipUtils.jsm)
|
||||
*/
|
||||
function doTransaction(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse = null) {
|
||||
function doTransaction(aAction, aItem, aCalendar, aOldItem, aObserver, aExtResponse = null) {
|
||||
// This is usually a user-initiated transaction, so make sure the calendar
|
||||
// this transaction is happening on is visible.
|
||||
ensureCalendarVisible(aCalendar);
|
||||
|
||||
// Now use the transaction manager to execute the action
|
||||
let manager = getTransactionMgr();
|
||||
manager.createAndCommitTxn(
|
||||
aAction,
|
||||
aItem,
|
||||
aCalendar,
|
||||
aOldItem,
|
||||
aListener ? aListener : null,
|
||||
aExtResponse
|
||||
);
|
||||
let manager = CalTransactionManager.getInstance();
|
||||
manager.createAndCommitTxn(aAction, aItem, aCalendar, aOldItem, aObserver, aExtResponse);
|
||||
|
||||
// If a batch transaction is active, do not update the menu as
|
||||
// endBatchTransaction() will take care of that.
|
||||
if (manager.wrappedJSObject && manager.wrappedJSObject.batchActive) {
|
||||
if (manager && manager.batchActive) {
|
||||
return;
|
||||
}
|
||||
updateUndoRedoMenu();
|
||||
|
@ -686,7 +671,7 @@ function doTransaction(aAction, aItem, aCalendar, aOldItem, aListener, aExtRespo
|
|||
*/
|
||||
function undo() {
|
||||
if (canUndo()) {
|
||||
getTransactionMgr().undo();
|
||||
CalTransactionManager.getInstance().undo();
|
||||
updateUndoRedoMenu();
|
||||
}
|
||||
}
|
||||
|
@ -696,7 +681,7 @@ function undo() {
|
|||
*/
|
||||
function redo() {
|
||||
if (canRedo()) {
|
||||
getTransactionMgr().redo();
|
||||
CalTransactionManager.getInstance().redo();
|
||||
updateUndoRedoMenu();
|
||||
}
|
||||
}
|
||||
|
@ -706,7 +691,7 @@ function redo() {
|
|||
* times, which nests transactions.
|
||||
*/
|
||||
function startBatchTransaction() {
|
||||
getTransactionMgr().beginBatch();
|
||||
CalTransactionManager.getInstance().beginBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -715,7 +700,7 @@ function startBatchTransaction() {
|
|||
* startBatchTransaction and this call.
|
||||
*/
|
||||
function endBatchTransaction() {
|
||||
getTransactionMgr().endBatch();
|
||||
CalTransactionManager.getInstance().endBatch();
|
||||
updateUndoRedoMenu();
|
||||
}
|
||||
|
||||
|
@ -724,14 +709,14 @@ function endBatchTransaction() {
|
|||
* at all).
|
||||
*/
|
||||
function canUndo() {
|
||||
return getTransactionMgr().canUndo();
|
||||
return CalTransactionManager.getInstance().canUndo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the last undone operation can be redone.
|
||||
*/
|
||||
function canRedo() {
|
||||
return getTransactionMgr().canRedo();
|
||||
return CalTransactionManager.getInstance().canRedo();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3163,8 +3163,9 @@ function onCommandSave(aIsClosing) {
|
|||
// before the call is complete. In that case, we do need a progress bar and
|
||||
// the ability to cancel the operation though.
|
||||
let listener = {
|
||||
QueryInterface: ChromeUtils.generateQI(["calIOperationListener"]),
|
||||
onOperationComplete(aCalendar, aStatus, aOpType, aId, aItem) {
|
||||
onTransactionComplete(aItem) {
|
||||
let aId = aItem.id;
|
||||
let aCalendar = aItem.calendar;
|
||||
// Check if the current window has a calendarItem first, because in case of undo
|
||||
// window refers to the main window and we would get a 'calendarItem is undefined' warning.
|
||||
if (!aIsClosing && "calendarItem" in window) {
|
||||
|
@ -3172,8 +3173,7 @@ function onCommandSave(aIsClosing) {
|
|||
// times. We need to make sure we're receiving the update on the right calendar.
|
||||
if (
|
||||
(!window.calendarItem.id || aId == window.calendarItem.id) &&
|
||||
aCalendar.id == window.calendarItem.calendar.id &&
|
||||
Components.isSuccessCode(aStatus)
|
||||
aCalendar.id == window.calendarItem.calendar.id
|
||||
) {
|
||||
if (window.calendarItem.recurrenceId) {
|
||||
// TODO This workaround needs to be removed in bug 396182
|
||||
|
@ -3224,11 +3224,11 @@ function onCommandDeleteItem() {
|
|||
} else {
|
||||
let deleteListener = {
|
||||
// when deletion of item is complete, close the dialog
|
||||
onOperationComplete(aCalendar, aStatus, aOperationType, aId, aDetail) {
|
||||
onTransactionComplete(item) {
|
||||
// Check if the current window has a calendarItem first, because in case of undo
|
||||
// window refers to the main window and we would get a 'calendarItem is undefined' warning.
|
||||
if ("calendarItem" in window) {
|
||||
if (aId == window.calendarItem.id && Components.isSuccessCode(aStatus)) {
|
||||
if (item.id == window.calendarItem.id) {
|
||||
cancelItem();
|
||||
} else {
|
||||
eventDialogCalendarObserver.observe(window.calendarItem.calendar);
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsITransactionManager;
|
||||
interface calICalendar;
|
||||
interface calIItemBase;
|
||||
interface calIOperationListener;
|
||||
|
||||
/**
|
||||
* calITransactionManager is a service designed to handle nsITransactions
|
||||
* regarding the calendar. It is here as a service so that we can keep the
|
||||
* transactions around without holding onto the whole global js scope+window.
|
||||
*/
|
||||
[scriptable, uuid(1d529847-d292-4222-b066-b8b17a794d62)]
|
||||
interface calITransactionManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* @param aAction The Action to execute. This can be one of:
|
||||
* * add Adds an item
|
||||
* * modify Modfifies an item
|
||||
* * delete Deletes an item
|
||||
* * move Move an item from one calendar to the
|
||||
* next. With this operation, aCalendar is
|
||||
* the calendar that the event should be
|
||||
* moved to.
|
||||
* @param aCalendar The Calendar to execute the transaction on
|
||||
* @param aItem The changed item for this transaction. This item
|
||||
* should be immutable
|
||||
* @param aOldItem The Item in its original form. Only needed for
|
||||
* modify.
|
||||
* @param aListener The listener to call when the transaction has
|
||||
* completed. This parameter can be null.
|
||||
* @param aExtResponse JS object to provide additional parameters to prepare an itip message.
|
||||
Valid attributes are:
|
||||
* * responseMode A value as defined for calIItipItem.autoResponse
|
||||
*/
|
||||
void createAndCommitTxn(in AUTF8String aAction,
|
||||
in calIItemBase aItem,
|
||||
in calICalendar aCalendar,
|
||||
in calIItemBase aOldItem,
|
||||
in calIOperationListener aListener,
|
||||
in jsval aExtResponse);
|
||||
|
||||
/**
|
||||
* Signals the transaction manager that a series of transactions are going
|
||||
* to be performed, but that, for the purposes of undo and redo, they should
|
||||
* all be regarded as a single transaction. See also
|
||||
* nsITransactionManager::beginBatch
|
||||
*/
|
||||
void beginBatch();
|
||||
|
||||
/**
|
||||
* Ends the batch transaction in process. See also
|
||||
* nsITransactionManager::endBatch
|
||||
*/
|
||||
void endBatch();
|
||||
|
||||
/**
|
||||
* Undo the last transaction in the transaction manager's stack
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/**
|
||||
* Returns true if it is possible to undo a transaction at this time
|
||||
*/
|
||||
boolean canUndo();
|
||||
|
||||
/**
|
||||
* Redo the last transaction
|
||||
*/
|
||||
void redo();
|
||||
|
||||
/**
|
||||
* Returns true if it is possible to redo a transaction at this time
|
||||
*/
|
||||
boolean canRedo();
|
||||
|
||||
/**
|
||||
* A reference to the transaction manager for calendar operations
|
||||
*/
|
||||
readonly attribute nsITransactionManager transactionManager;
|
||||
};
|
|
@ -41,7 +41,6 @@ XPIDL_SOURCES += [
|
|||
"calITimezone.idl",
|
||||
"calITimezoneProvider.idl",
|
||||
"calITodo.idl",
|
||||
"calITransactionManager.idl",
|
||||
"calIWeekInfoService.idl",
|
||||
]
|
||||
|
||||
|
|
|
@ -6,26 +6,89 @@ var EXPORTED_SYMBOLS = ["CalTransactionManager", "CalTransaction"];
|
|||
|
||||
var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
|
||||
|
||||
// These commands expect an old and newer copy of the item.
|
||||
const updateActions = ["modify", "move"];
|
||||
const OP_ADD = Ci.calIOperationListener.ADD;
|
||||
const OP_MODIFY = Ci.calIOperationListener.MODIFY;
|
||||
const OP_DELETE = Ci.calIOperationListener.DELETE;
|
||||
|
||||
function CalTransactionManager() {
|
||||
this.wrappedJSObject = this;
|
||||
if (!this.transactionManager) {
|
||||
this.transactionManager = Cc["@mozilla.org/transactionmanager;1"].createInstance(
|
||||
Ci.nsITransactionManager
|
||||
);
|
||||
let transactionManager = null;
|
||||
|
||||
/**
|
||||
* CalTransactionManager is designed to handle nsITransactions regarding the
|
||||
* calendar.
|
||||
*/
|
||||
class CalTransactionManager {
|
||||
/**
|
||||
* Indicates whether batch mode as described in nsITransactionManager is active.
|
||||
* @type {boolean}
|
||||
*/
|
||||
batchActive = false;
|
||||
|
||||
/**
|
||||
* Contains the CalTransactions that are part of the batch when batch mode is
|
||||
* active.
|
||||
* @type {CalTransaction[]}
|
||||
*/
|
||||
batchTransactions = [];
|
||||
|
||||
/**
|
||||
* A reference to the transaction manager for calendar operations.
|
||||
* @type {nsITransactionManager}
|
||||
*/
|
||||
transactionManager = Cc["@mozilla.org/transactionmanager;1"].createInstance(
|
||||
Ci.nsITransactionManager
|
||||
);
|
||||
|
||||
/**
|
||||
* Provides a singleton instance of CalTransactionManger.
|
||||
* @return {CalTransactionManager}
|
||||
*/
|
||||
static getInstance() {
|
||||
if (!transactionManager) {
|
||||
transactionManager = new CalTransactionManager();
|
||||
}
|
||||
return transactionManager;
|
||||
}
|
||||
}
|
||||
|
||||
CalTransactionManager.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI(["calITransactionManager"]),
|
||||
classID: Components.ID("{1d529847-d292-4222-b066-b8b17a794d62}"),
|
||||
batchActive: false,
|
||||
batchTransactions: [],
|
||||
transactionManager: null,
|
||||
createAndCommitTxn(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse) {
|
||||
let txn = new CalTransaction(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse);
|
||||
_checkWritable(transaction) {
|
||||
// If the transaction is null it is possible the last transaction was a
|
||||
// batch transaction. Check the transactions we cached because
|
||||
// nsITransactionManager does not provide a way to query them all.
|
||||
return !transaction && this.batchTransactions.length
|
||||
? this.batchTransactions.every(trn => trn.wrappedJSObject.canWrite())
|
||||
: transaction.wrappedJSObject.canWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ExtResponse
|
||||
* @property {number} responseMode One of the calIItipItem.autoResponse values.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} action The action to execute. This can
|
||||
* be one of:
|
||||
* * add Adds an item
|
||||
* * modify Modfifies an item
|
||||
* * delete Deletes an item
|
||||
* * move Move an item from one calendar to
|
||||
* the next. With this operation,
|
||||
* calendar is the calendar that the
|
||||
* event should be moved to.
|
||||
* @param {calICalendar} calendar The Calendar to execute the transaction on.
|
||||
* @param {calIItemBase} item The changed item for this transaction.
|
||||
* This item should be immutable.
|
||||
* @param {calIItemBase} oldItem The item in its original form.
|
||||
* Only needed for modify.
|
||||
* @param {CalTransactionObserver} [observer] The observer to call when the
|
||||
* transaction has completed.
|
||||
* @param {ExtResponse} [extResponse] Object to provide additional
|
||||
* parameters to prepare an itip
|
||||
* message.
|
||||
*/
|
||||
createAndCommitTxn(action, item, calendar, oldItem, observer, extResponse) {
|
||||
let txn = new CalObservableTransaction(
|
||||
CalTransaction.createTransaction(action, item, calendar, oldItem, extResponse),
|
||||
observer
|
||||
);
|
||||
if (this.batchActive) {
|
||||
// nsITransactionManager.peek(Undo|Redo)Stack can return null if a batch
|
||||
// transaction is at the top of the stack. To avoid being mislead by this,
|
||||
|
@ -33,239 +96,299 @@ CalTransactionManager.prototype = {
|
|||
this.batchTransactions.push(txn);
|
||||
}
|
||||
this.transactionManager.doTransaction(txn);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the transaction manager that a series of transactions are going
|
||||
* to be performed, but that, for the purposes of undo and redo, they should
|
||||
* all be regarded as a single transaction. See also
|
||||
* nsITransactionManager::beginBatch
|
||||
*/
|
||||
beginBatch() {
|
||||
this.transactionManager.beginBatch(null);
|
||||
this.batchActive = true;
|
||||
this.batchTransactions = [];
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the batch transaction in process. See also
|
||||
* nsITransactionManager::endBatch
|
||||
*/
|
||||
endBatch() {
|
||||
this.transactionManager.endBatch(false);
|
||||
this.batchActive = false;
|
||||
},
|
||||
|
||||
checkWritable(transaction) {
|
||||
// If the transaction is null it is possible the last transaction was a
|
||||
// batch transaction. Check the transactions we cached because
|
||||
// nsITransactionManager does not provide a way to query them all.
|
||||
return !transaction && this.batchTransactions.length
|
||||
? this.batchTransactions.every(transactionCanWrite)
|
||||
: transactionCanWrite(transaction);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the last transaction in the transaction manager's stack
|
||||
*/
|
||||
undo() {
|
||||
this.transactionManager.undoTransaction();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if it is possible to undo a transaction at this time
|
||||
* @return {boolean}
|
||||
*/
|
||||
canUndo() {
|
||||
return (
|
||||
this.transactionManager.numberOfUndoItems > 0 &&
|
||||
this.checkWritable(this.transactionManager.peekUndoStack())
|
||||
this._checkWritable(this.transactionManager.peekUndoStack())
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo the last transaction
|
||||
*/
|
||||
redo() {
|
||||
this.transactionManager.redoTransaction();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if it is possible to redo a transaction at this time
|
||||
* @return {boolean}
|
||||
*/
|
||||
canRedo() {
|
||||
return (
|
||||
this.transactionManager.numberOfRedoItems > 0 &&
|
||||
this.checkWritable(this.transactionManager.peekRedoStack())
|
||||
this._checkWritable(this.transactionManager.peekRedoStack())
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
function CalTransaction(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse) {
|
||||
this.wrappedJSObject = this;
|
||||
this.mAction = aAction;
|
||||
this.mItem = aItem;
|
||||
this.mCalendar = aCalendar;
|
||||
this.mOldItem = aOldItem;
|
||||
this.mListener = aListener;
|
||||
this.mExtResponse = aExtResponse;
|
||||
}
|
||||
}
|
||||
|
||||
var calTransactionClassID = Components.ID("{fcb54c82-2fb9-42cb-bf44-1e197a55e520}");
|
||||
var calTransactionInterfaces = ["nsITransaction", "calIOperationListener"];
|
||||
CalTransaction.prototype = {
|
||||
classID: calTransactionClassID,
|
||||
QueryInterface: ChromeUtils.generateQI(calTransactionInterfaces),
|
||||
/**
|
||||
* CalTransaction is the base nsITransaction implementation used to make
|
||||
* calendar modifications undoable/redoable.
|
||||
*
|
||||
* @implements nsITransaction
|
||||
*/
|
||||
class CalTransaction {
|
||||
/**
|
||||
* @type {CalTransaction}
|
||||
*/
|
||||
wrappedJSObject = this;
|
||||
|
||||
mAction: null,
|
||||
mCalendar: null,
|
||||
mItem: null,
|
||||
mOldItem: null,
|
||||
mOldCalendar: null,
|
||||
mListener: null,
|
||||
mIsDoTransaction: false,
|
||||
mExtResponse: null,
|
||||
/**
|
||||
* @type {Function}
|
||||
*/
|
||||
QueryInterface = ChromeUtils.generateQI(["nsITransaction"]);
|
||||
|
||||
_onError(opType, item, error) {
|
||||
if (this.mListener) {
|
||||
this.mListener.onOperationComplete(item.calendar, error.result, opType, item.id, error);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
isTransient = false;
|
||||
|
||||
_onSuccess(opType, item) {
|
||||
cal.itip.checkAndSend(
|
||||
opType,
|
||||
item,
|
||||
this.mIsDoTransaction ? this.mOldItem : this.mItem,
|
||||
this.mExtResponse
|
||||
);
|
||||
/**
|
||||
* @type {calICalendar}
|
||||
*/
|
||||
calendar = null;
|
||||
|
||||
if (opType == Ci.calIOperationListener.ADD || opType == Ci.calIOperationListener.MODIFY) {
|
||||
if (this.mIsDoTransaction) {
|
||||
this.mItem = item;
|
||||
} else {
|
||||
this.mOldItem = item;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @type {calIItemBase}
|
||||
*/
|
||||
item = null;
|
||||
|
||||
if (this.mListener) {
|
||||
this.mListener.onOperationComplete(item.calendar, Cr.NS_OK, opType, item.id, item);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @type {calIItemBase}
|
||||
*/
|
||||
oldItem = null;
|
||||
|
||||
onOperationComplete(aCalendar, aStatus, aOperationType, aId, aDetail) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
cal.itip.checkAndSend(
|
||||
aOperationType,
|
||||
aDetail,
|
||||
this.mIsDoTransaction ? this.mOldItem : this.mItem,
|
||||
this.mExtResponse
|
||||
);
|
||||
/**
|
||||
* @type {calICalendar}
|
||||
*/
|
||||
oldCalendar = null;
|
||||
|
||||
if (aOperationType == Ci.calIOperationListener.MODIFY) {
|
||||
if (this.mIsDoTransaction) {
|
||||
this.mItem = aDetail;
|
||||
} else {
|
||||
this.mOldItem = aDetail;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.mListener) {
|
||||
this.mListener.onOperationComplete(aCalendar, aStatus, aOperationType, aId, aDetail);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @type {ExtResponse}
|
||||
*/
|
||||
extResponse = null;
|
||||
|
||||
onGetResult(aCalendar, aStatus, aItemType, aDetail, aItems) {
|
||||
if (this.mListener) {
|
||||
this.mListener.onGetResult(aCalendar, aStatus, aItemType, aDetail, aItems);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {calIItemBase} item
|
||||
* @param {calICalendar} calendar
|
||||
* @param {calIItemBase?} oldItem
|
||||
* @param {object?} extResponse
|
||||
*/
|
||||
constructor(item, calendar, oldItem, extResponse) {
|
||||
this.item = item;
|
||||
this.calendar = calendar;
|
||||
this.oldItem = oldItem;
|
||||
this.extResponse = extResponse;
|
||||
}
|
||||
|
||||
doTransaction() {
|
||||
this.mIsDoTransaction = true;
|
||||
switch (this.mAction) {
|
||||
/**
|
||||
* Creates a CalTransaction instance based on the action desired.
|
||||
* @param {string} action - One of "add","modify" or "delete"
|
||||
* @param {calIItemBase} item - The item the operation is taking place on.
|
||||
* @param {calICalendar} calendar - The target calendar for the operation.
|
||||
* @param {calIItemBase} [oldItem] - The old item (for modifications).
|
||||
* @param {ExtResponse} [extResponse] - Passed to checkAndSend().
|
||||
*/
|
||||
static createTransaction(action, item, calendar, oldItem, extResponse) {
|
||||
switch (action) {
|
||||
case "add":
|
||||
this.mCalendar.addItem(this.mItem).then(
|
||||
item => this._onSuccess(Ci.calIOperationListener.ADD, item),
|
||||
e => this._onError(Ci.calIOperationListener.ADD, this.mItem, e)
|
||||
);
|
||||
break;
|
||||
return new CalAddTransaction(item, calendar, oldItem, extResponse);
|
||||
case "modify":
|
||||
if (this.mItem.calendar.id == this.mOldItem.calendar.id) {
|
||||
this.mCalendar
|
||||
.modifyItem(cal.itip.prepareSequence(this.mItem, this.mOldItem), this.mOldItem)
|
||||
.then(
|
||||
item => this._onSuccess(Ci.calIOperationListener.MODIFY, item),
|
||||
e => this._onError(Ci.calIOperationListener.MODIFY, this.mItem, e)
|
||||
);
|
||||
} else {
|
||||
this.mOldCalendar = this.mOldItem.calendar;
|
||||
this.mCalendar.addItem(this.mItem).then(
|
||||
item => {
|
||||
this._onSuccess(Ci.calIOperationListener.ADD, item);
|
||||
return this.mOldItem.calendar.deleteItem(this.mOldItem).then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.DELETE, this.mOldItem),
|
||||
e => this._onError(Ci.calIOperationListener.DELETE, this.mOldItem, e)
|
||||
);
|
||||
},
|
||||
e => this._onError(Ci.calIOperationListener.ADD, this.mOldItem, e)
|
||||
);
|
||||
}
|
||||
break;
|
||||
return new CalModifyTransaction(item, calendar, oldItem, extResponse);
|
||||
case "delete":
|
||||
this.mCalendar.deleteItem(this.mItem).then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.DELETE, this.mItem),
|
||||
e => this._onError(Ci.calIOperationListener.DELETE, this.mItem, e)
|
||||
);
|
||||
|
||||
break;
|
||||
return new CalDeleteTransaction(item, calendar, oldItem, extResponse);
|
||||
default:
|
||||
throw new Components.Exception("Invalid action specified", Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
},
|
||||
|
||||
undoTransaction() {
|
||||
this.mIsDoTransaction = false;
|
||||
switch (this.mAction) {
|
||||
case "add":
|
||||
this.mCalendar.deleteItem(this.mItem).then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.DELETE, this.mItem),
|
||||
e => this._onError(Ci.calIOperationListener.DELETE, this.mItem, e)
|
||||
throw new Components.Exception(
|
||||
`Invalid action specified "${action}"`,
|
||||
Cr.NS_ERROR_ILLEGAL_VALUE
|
||||
);
|
||||
break;
|
||||
case "modify":
|
||||
if (this.mOldItem.calendar.id == this.mItem.calendar.id) {
|
||||
this.mCalendar
|
||||
.modifyItem(cal.itip.prepareSequence(this.mOldItem, this.mItem), this.mItem)
|
||||
.then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.MODIFY, this.mOldItem),
|
||||
e => this._onError(Ci.calIOperationListener.MODIFY, this.mOldItem, e)
|
||||
);
|
||||
} else {
|
||||
this.mCalendar.deleteItem(this.mItem).then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.DELETE, this.mItem),
|
||||
e => this._onError(Ci.calIOperationListener.DELETE, this.mItem, e)
|
||||
);
|
||||
this.mOldCalendar.addItem(this.mOldItem).then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.ADD, this.mOldItem),
|
||||
e => this._onError(Ci.calIOperationListener.ADD, this.mOldItem, e)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "delete":
|
||||
this.mCalendar.addItem(this.mItem).then(
|
||||
() => this._onSuccess(Ci.calIOperationListener.ADD, this.mItem),
|
||||
e => this._onError(Ci.calIOperationListener.ADD, this.mItem, e)
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new Components.Exception("Invalid action specified", Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_dispatch(opType, item, oldItem) {
|
||||
cal.itip.checkAndSend(opType, item, oldItem, this.extResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the calendar of the transaction's target item can be written to.
|
||||
* @return {boolean}
|
||||
*/
|
||||
canWrite() {
|
||||
if (itemWritable(this.item)) {
|
||||
return this instanceof CalModifyTransaction ? itemWritable(this.oldItem) : true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
doTransaction() {}
|
||||
|
||||
undoTransaction() {}
|
||||
|
||||
redoTransaction() {
|
||||
this.doTransaction();
|
||||
},
|
||||
|
||||
isTransient: false,
|
||||
}
|
||||
|
||||
merge(aTransaction) {
|
||||
// No support for merging
|
||||
return false;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the calendar of a transaction's item can be written to.
|
||||
*
|
||||
* @param {nsITransaction} transaction - Must be a wrapped CalTransaction.
|
||||
*
|
||||
* @return {boolean}
|
||||
* CalAddTransaction handles undo/redo for additions.
|
||||
*/
|
||||
function transactionCanWrite(transaction) {
|
||||
let calTrans = transaction && transaction.wrappedJSObject;
|
||||
if (calTrans && canWrite(calTrans.mItem)) {
|
||||
return updateActions.includes(transaction.mAction) ? canWrite(transaction.mOldItem) : true;
|
||||
class CalAddTransaction extends CalTransaction {
|
||||
async doTransaction() {
|
||||
let item = await this.calendar.addItem(this.item);
|
||||
this._dispatch(OP_ADD, item, this.oldItem);
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
async undoTransaction() {
|
||||
await this.calendar.deleteItem(this.item);
|
||||
this._dispatch(OP_DELETE, this.item, this.item);
|
||||
this.oldItem = this.item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CalModifyTransaction handles undo/redo for modifications.
|
||||
*/
|
||||
class CalModifyTransaction extends CalTransaction {
|
||||
async doTransaction() {
|
||||
let item;
|
||||
if (this.item.calendar.id == this.oldItem.calendar.id) {
|
||||
item = await this.calendar.modifyItem(
|
||||
cal.itip.prepareSequence(this.item, this.oldItem),
|
||||
this.oldItem
|
||||
);
|
||||
this._dispatch(OP_MODIFY, item, this.oldItem);
|
||||
} else {
|
||||
this.oldCalendar = this.oldItem.calendar;
|
||||
item = await this.calendar.addItem(this.item);
|
||||
this._dispatch(OP_ADD, item, this.oldItem);
|
||||
await this.oldItem.calendar.deleteItem(this.oldItem);
|
||||
this._dispatch(OP_DELETE, this.oldItem, this.oldItem);
|
||||
}
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
async undoTransaction() {
|
||||
if (this.oldItem.calendar.id == this.item.calendar.id) {
|
||||
await this.calendar.modifyItem(cal.itip.prepareSequence(this.oldItem, this.item), this.item);
|
||||
this._dispatch(OP_MODIFY, this.oldItem, this.oldItem);
|
||||
} else {
|
||||
await this.calendar.deleteItem(this.item);
|
||||
this._dispatch(OP_DELETE, this.item, this.item);
|
||||
await this.oldCalendar.addItem(this.oldItem);
|
||||
this._dispatch(OP_ADD, this.oldItem, this.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CalDeleteTransaction handles undo/redo for deletions.
|
||||
*/
|
||||
class CalDeleteTransaction extends CalTransaction {
|
||||
async doTransaction() {
|
||||
await this.calendar.deleteItem(this.item);
|
||||
this._dispatch(OP_DELETE, this.item, this.oldItem);
|
||||
}
|
||||
|
||||
async undoTransaction() {
|
||||
await this.calendar.addItem(this.item);
|
||||
this._dispatch(OP_ADD, this.item, this.item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer for CalTransaction execution.
|
||||
* @type {Object} CalTransactionObserver
|
||||
* @property {CalTransactionObserverHandler?} onTransctionComplete
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback CalTransactionObserverHandler
|
||||
* @param {calIItemBase} item
|
||||
* @param {calIItemBase?} oldItem
|
||||
*/
|
||||
|
||||
/**
|
||||
* CalObservableTransaction allows a transaction's undo/redo execution to be
|
||||
* observed by other objects. This is needed because the actual execution
|
||||
* transaction execution takes place in lower level code and is more or less
|
||||
* opaque to scripts.
|
||||
*/
|
||||
class CalObservableTransaction extends CalTransaction {
|
||||
/**
|
||||
* @type {CalTransaction}
|
||||
*/
|
||||
_transaction;
|
||||
|
||||
/**
|
||||
* @type {CalTransactionObserver}
|
||||
*/
|
||||
_observer;
|
||||
|
||||
/**
|
||||
* @param {CalTransaction} transaction
|
||||
* @param {CalTransactionObserver} observer
|
||||
*/
|
||||
constructor(transaction, observer) {
|
||||
super(null, null, null, null);
|
||||
this._transaction = transaction;
|
||||
this._observer = observer;
|
||||
}
|
||||
|
||||
canWrite() {
|
||||
return this._transaction.canWrite();
|
||||
}
|
||||
|
||||
async doTransaction() {
|
||||
await this._transaction.doTransaction();
|
||||
this?._observer?.onTransactionComplete(this._transaction.item, this._transaction.oldItem);
|
||||
}
|
||||
|
||||
async undoTransaction() {
|
||||
await this._transaction.undoTransaction();
|
||||
this?._observer?.onTransactionComplete(this._transaction.item, this._transaction.oldItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,7 +396,7 @@ function transactionCanWrite(transaction) {
|
|||
*
|
||||
* @param {calIItemBase} item
|
||||
*/
|
||||
function canWrite(item) {
|
||||
function itemWritable(item) {
|
||||
return (
|
||||
item &&
|
||||
item.calendar &&
|
||||
|
|
|
@ -120,18 +120,6 @@ Classes = [
|
|||
'jsm': 'resource:///modules/CalRelation.jsm',
|
||||
'constructor': 'CalRelation',
|
||||
},
|
||||
{
|
||||
'cid': '{fcb54c82-2fb9-42cb-bf44-1e197a55e520}',
|
||||
'contract_ids': ['@mozilla.org/calendar/transaction;1'],
|
||||
'jsm': 'resource:///modules/CalTransactionManager.jsm',
|
||||
'constructor': 'CalTransaction',
|
||||
},
|
||||
{
|
||||
'cid': '{1d529847-d292-4222-b066-b8b17a794d62}',
|
||||
'contract_ids': ['@mozilla.org/calendar/transactionmanager;1'],
|
||||
'jsm': 'resource:///modules/CalTransactionManager.jsm',
|
||||
'constructor': 'CalTransactionManager',
|
||||
},
|
||||
{
|
||||
'cid': '{7af51168-6abe-4a31-984d-6f8a3989212d}',
|
||||
'contract_ids': ['@mozilla.org/calendar/todo;1'],
|
||||
|
|
|
@ -12,12 +12,11 @@ var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm")
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
CalEvent: "resource:///modules/CalEvent.jsm",
|
||||
CalTransactionManager: "resource:///modules/CalTransactionManager.jsm",
|
||||
});
|
||||
|
||||
const calendar = CalendarTestUtils.createCalendar("Undo Redo Test");
|
||||
const calTransManager = Cc["@mozilla.org/calendar/transactionmanager;1"].getService(
|
||||
Ci.calITransactionManager
|
||||
).wrappedJSObject;
|
||||
const calTransManager = CalTransactionManager.getInstance();
|
||||
|
||||
/**
|
||||
* Checks the value of the "disabled" property for items in either the "Edit"
|
||||
|
|
|
@ -15,12 +15,11 @@ var { mailTestUtils } = ChromeUtils.import("resource://testing-common/mailnews/M
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
CalTodo: "resource:///modules/CalTodo.jsm",
|
||||
CalTransactionManager: "resource:///modules/CalTransactionManager.jsm",
|
||||
});
|
||||
|
||||
const calendar = CalendarTestUtils.createCalendar("Undo Redo Test", "memory");
|
||||
const calTransManager = Cc["@mozilla.org/calendar/transactionmanager;1"].getService(
|
||||
Ci.calITransactionManager
|
||||
).wrappedJSObject;
|
||||
const calTransManager = CalTransactionManager.getInstance();
|
||||
|
||||
/**
|
||||
* Checks the value of the "disabled" property for items in either the "Edit"
|
||||
|
|
Загрузка…
Ссылка в новой задаче