mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 617532 - Implement UndoManager. r=ehsan
This commit is contained in:
parent
ba821b29a2
commit
7cd5470029
@ -64,7 +64,7 @@ var StarUI = {
|
||||
this._restoreCommandsState();
|
||||
this._itemId = -1;
|
||||
if (this._batching) {
|
||||
PlacesUtils.transactionManager.endBatch();
|
||||
PlacesUtils.transactionManager.endBatch(false);
|
||||
this._batching = false;
|
||||
}
|
||||
|
||||
@ -76,13 +76,13 @@ var StarUI = {
|
||||
case "remove": {
|
||||
// Remove all bookmarks for the bookmark's url, this also removes
|
||||
// the tags for the url.
|
||||
PlacesUtils.transactionManager.beginBatch();
|
||||
PlacesUtils.transactionManager.beginBatch(null);
|
||||
let itemIds = PlacesUtils.getBookmarksForURI(this._uriForRemoval);
|
||||
for (let i = 0; i < itemIds.length; i++) {
|
||||
let txn = new PlacesRemoveItemTransaction(itemIds[i]);
|
||||
PlacesUtils.transactionManager.doTransaction(txn);
|
||||
}
|
||||
PlacesUtils.transactionManager.endBatch();
|
||||
PlacesUtils.transactionManager.endBatch(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -235,7 +235,7 @@ var StarUI = {
|
||||
|
||||
beginBatch: function SU_beginBatch() {
|
||||
if (!this._batching) {
|
||||
PlacesUtils.transactionManager.beginBatch();
|
||||
PlacesUtils.transactionManager.beginBatch(null);
|
||||
this._batching = true;
|
||||
}
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ var BookmarkPropertiesPanel = {
|
||||
if (this._batching)
|
||||
return;
|
||||
|
||||
PlacesUtils.transactionManager.beginBatch();
|
||||
PlacesUtils.transactionManager.beginBatch(null);
|
||||
this._batching = true;
|
||||
},
|
||||
|
||||
@ -413,7 +413,7 @@ var BookmarkPropertiesPanel = {
|
||||
if (!this._batching)
|
||||
return;
|
||||
|
||||
PlacesUtils.transactionManager.endBatch();
|
||||
PlacesUtils.transactionManager.endBatch(false);
|
||||
this._batching = false;
|
||||
},
|
||||
|
||||
|
@ -1153,10 +1153,10 @@ XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ptm", function() {
|
||||
//// nsITransactionManager forwarders.
|
||||
|
||||
beginBatch: function()
|
||||
PlacesUtils.transactionManager.beginBatch(),
|
||||
PlacesUtils.transactionManager.beginBatch(null),
|
||||
|
||||
endBatch: function()
|
||||
PlacesUtils.transactionManager.endBatch(),
|
||||
PlacesUtils.transactionManager.endBatch(false),
|
||||
|
||||
doTransaction: function(txn)
|
||||
PlacesUtils.transactionManager.doTransaction(txn),
|
||||
|
@ -407,6 +407,7 @@ user_pref("app.update.enabled", false);
|
||||
user_pref("app.update.staging.enabled", false);
|
||||
user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
|
||||
user_pref("dom.w3c_touch_events.enabled", 1);
|
||||
user_pref("dom.undo_manager.enabled", true);
|
||||
// Set a future policy version to avoid the telemetry prompt.
|
||||
user_pref("toolkit.telemetry.prompted", 999);
|
||||
user_pref("toolkit.telemetry.notifiedOptOut", 999);
|
||||
|
@ -116,6 +116,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Link;
|
||||
class UndoManager;
|
||||
|
||||
// IID for the dom::Element interface
|
||||
#define NS_ELEMENT_IID \
|
||||
@ -695,6 +696,21 @@ public:
|
||||
nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().XMost()) :
|
||||
0;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool UndoScope()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void SetUndoScope(bool aUndoScope, mozilla::ErrorResult& aError)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void GetInnerHTML(nsAString& aInnerHTML,
|
||||
mozilla::ErrorResult& aError);
|
||||
virtual void SetInnerHTML(const nsAString& aInnerHTML,
|
||||
|
@ -166,6 +166,8 @@ class nsInlineEventHandlersTearoff;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class UndoManager;
|
||||
|
||||
class FragmentOrElement : public nsIContent
|
||||
{
|
||||
public:
|
||||
@ -312,6 +314,12 @@ public:
|
||||
*/
|
||||
nsDOMStringMap* mDataset; // [Weak]
|
||||
|
||||
/**
|
||||
* The .undoManager property.
|
||||
* @see nsGenericHTMLElement::GetUndoManager
|
||||
*/
|
||||
nsRefPtr<UndoManager> mUndoManager;
|
||||
|
||||
/**
|
||||
* SMIL Overridde style rules (for SMIL animation of CSS properties)
|
||||
* @see nsIContent::GetSMILOverrideStyle
|
||||
|
@ -90,6 +90,7 @@ class DocumentType;
|
||||
class DOMImplementation;
|
||||
class Element;
|
||||
class Link;
|
||||
class UndoManager;
|
||||
template<typename> class Sequence;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@ -1647,6 +1648,8 @@ public:
|
||||
*/
|
||||
virtual Element* LookupImageElement(const nsAString& aElementId) = 0;
|
||||
|
||||
virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager() = 0;
|
||||
|
||||
nsresult ScheduleFrameRequestCallback(nsIFrameRequestCallback* aCallback,
|
||||
int32_t *aHandle);
|
||||
void CancelFrameRequestCallback(int32_t aHandle);
|
||||
|
@ -101,6 +101,7 @@
|
||||
#include "nsAsyncDOMEvent.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "mozilla/dom/NodeListBinding.h"
|
||||
#include "mozilla/dom/UndoManager.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIXULDocument.h"
|
||||
@ -539,6 +540,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsInlineEventHandlersTearoff)
|
||||
FragmentOrElement::nsDOMSlots::nsDOMSlots()
|
||||
: nsINode::nsSlots(),
|
||||
mDataset(nullptr),
|
||||
mUndoManager(nullptr),
|
||||
mBindingParent(nullptr)
|
||||
{
|
||||
}
|
||||
@ -566,6 +568,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb,
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
|
||||
cb.NoteXPCOMChild(mAttributeMap.get());
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mUndoManager");
|
||||
cb.NoteXPCOMChild(mUndoManager.get());
|
||||
|
||||
if (aIsXUL) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers");
|
||||
cb.NoteXPCOMChild(mControllers);
|
||||
@ -590,6 +595,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
|
||||
if (aIsXUL)
|
||||
NS_IF_RELEASE(mControllers);
|
||||
mChildrenList = nullptr;
|
||||
mUndoManager = nullptr;
|
||||
if (mClassList) {
|
||||
mClassList->DropReference();
|
||||
mClassList = nullptr;
|
||||
|
@ -184,6 +184,7 @@
|
||||
#include "nsIAppsService.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/UndoManager.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsDOMCaretPosition.h"
|
||||
#include "nsIDOMHTMLTextAreaElement.h"
|
||||
@ -1679,6 +1680,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager)
|
||||
|
||||
// Traverse all our nsCOMArrays.
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
|
||||
@ -1736,6 +1738,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager)
|
||||
|
||||
tmp->mParentDocument = nullptr;
|
||||
|
||||
@ -2640,6 +2643,22 @@ nsDocument::GetAllowPlugins(bool * aAllowPlugins)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<UndoManager>
|
||||
nsDocument::GetUndoManager()
|
||||
{
|
||||
Element* rootElement = GetRootElement();
|
||||
if (!rootElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mUndoManager) {
|
||||
mUndoManager = new UndoManager(rootElement);
|
||||
}
|
||||
|
||||
nsRefPtr<UndoManager> undoManager = mUndoManager;
|
||||
return undoManager.forget();
|
||||
}
|
||||
|
||||
/* Return true if the document is in the focused top-level window, and is an
|
||||
* ancestor of the focused DOMWindow. */
|
||||
NS_IMETHODIMP
|
||||
|
@ -94,6 +94,12 @@ class nsDOMNavigationTiming;
|
||||
class nsWindowSizes;
|
||||
class nsHtml5TreeOpExecutor;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class UndoManager;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Right now our identifier map entries contain information for 'name'
|
||||
* and 'id' mappings of a given string. This is so that
|
||||
@ -569,6 +575,8 @@ public:
|
||||
|
||||
virtual nsresult GetAllowPlugins(bool* aAllowPlugins);
|
||||
|
||||
virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager();
|
||||
|
||||
virtual nsresult SetSubDocumentFor(Element* aContent,
|
||||
nsIDocument* aSubDoc);
|
||||
virtual nsIDocument* GetSubDocumentFor(nsIContent* aContent) const;
|
||||
@ -1349,6 +1357,8 @@ private:
|
||||
// Tracking for plugins in the document.
|
||||
nsTHashtable< nsPtrHashKey<nsIObjectLoadingContent> > mPlugins;
|
||||
|
||||
nsRefPtr<mozilla::dom::UndoManager> mUndoManager;
|
||||
|
||||
#ifdef DEBUG
|
||||
protected:
|
||||
bool mWillReparent;
|
||||
|
@ -1090,6 +1090,7 @@ GK_ATOM(u, "u")
|
||||
GK_ATOM(ul, "ul")
|
||||
GK_ATOM(underflow, "underflow")
|
||||
GK_ATOM(undetermined, "undetermined")
|
||||
GK_ATOM(undoscope, "undoscope")
|
||||
GK_ATOM(unload, "unload")
|
||||
GK_ATOM(unparsedEntityUri, "unparsed-entity-uri")
|
||||
GK_ATOM(upperFirst, "upper-first")
|
||||
|
@ -881,6 +881,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
|
||||
return NS_NewDOMBeforeUnloadEvent(aDOMEvent, aPresContext, nullptr);
|
||||
if (aEventType.LowerCaseEqualsLiteral("pagetransition"))
|
||||
return NS_NewDOMPageTransitionEvent(aDOMEvent, aPresContext, nullptr);
|
||||
if (aEventType.LowerCaseEqualsLiteral("domtransaction"))
|
||||
return NS_NewDOMDOMTransactionEvent(aDOMEvent, aPresContext, nullptr);
|
||||
if (aEventType.LowerCaseEqualsLiteral("scrollareaevent"))
|
||||
return NS_NewDOMScrollAreaEvent(aDOMEvent, aPresContext, nullptr);
|
||||
// FIXME: Should get spec to say what the right string is here! This
|
||||
|
@ -45,7 +45,9 @@ EXPORTS_mozilla/dom = \
|
||||
HTMLSharedListElement.h \
|
||||
HTMLSpanElement.h \
|
||||
HTMLTitleElement.h \
|
||||
HTMLUnknownElement.h
|
||||
HTMLUnknownElement.h \
|
||||
UndoManager.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
HTMLPropertiesCollection.cpp \
|
||||
@ -111,6 +113,7 @@ CPPSRCS = \
|
||||
nsIConstraintValidation.cpp \
|
||||
nsRadioVisitor.cpp \
|
||||
nsDOMStringMap.cpp \
|
||||
UndoManager.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_MEDIA
|
||||
|
1214
content/html/content/src/UndoManager.cpp
Normal file
1214
content/html/content/src/UndoManager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
104
content/html/content/src/UndoManager.h
Normal file
104
content/html/content/src/UndoManager.h
Normal file
@ -0,0 +1,104 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_UndoManager_h
|
||||
#define mozilla_dom_UndoManager_h
|
||||
|
||||
#include "mozilla/dom/UndoManagerBinding.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
class nsIUndoManagerTransaction;
|
||||
class nsITransactionManager;
|
||||
class nsIMutationObserver;
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
namespace dom {
|
||||
|
||||
class UndoManager : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
friend class TxnScopeGuard;
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(UndoManager)
|
||||
|
||||
explicit UndoManager(nsIContent* aNode);
|
||||
|
||||
void Transact(JSContext* aCx, nsIUndoManagerTransaction& aTransaction,
|
||||
bool aMerge, ErrorResult& aRv);
|
||||
void Undo(JSContext* aCx, ErrorResult& aRv);
|
||||
void Redo(JSContext* acx, ErrorResult& aRv);
|
||||
void Item(uint32_t aIndex,
|
||||
Nullable<nsTArray<nsRefPtr<nsIUndoManagerTransaction>>>& aItems,
|
||||
ErrorResult& aRv);
|
||||
uint32_t GetLength(ErrorResult& aRv);
|
||||
uint32_t GetPosition(ErrorResult& aRv);
|
||||
void ClearUndo(ErrorResult& aRv);
|
||||
void ClearRedo(ErrorResult& aRv);
|
||||
static bool PrefEnabled();
|
||||
void Disconnect();
|
||||
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mHostNode;
|
||||
}
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
|
||||
bool* aTriedToWrap)
|
||||
{
|
||||
return mozilla::dom::UndoManagerBinding::Wrap(aCx, aScope, this,
|
||||
aTriedToWrap);
|
||||
}
|
||||
|
||||
nsITransactionManager* GetTransactionManager();
|
||||
|
||||
protected:
|
||||
virtual ~UndoManager();
|
||||
nsCOMPtr<nsITransactionManager> mTxnManager;
|
||||
nsCOMPtr<nsIContent> mHostNode;
|
||||
|
||||
/**
|
||||
* Executes |aTransaction| as a manual transaction.
|
||||
*/
|
||||
void ManualTransact(nsIUndoManagerTransaction* aTransaction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Executes |aTransaction| as an automatic transaction.
|
||||
*/
|
||||
void AutomaticTransact(nsIUndoManagerTransaction* aTransaction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Appends the transactions in the undo transaction history at |aIndex|
|
||||
* to the array |aItems|.
|
||||
*/
|
||||
void ItemInternal(uint32_t aIndex,
|
||||
nsTArray<nsIUndoManagerTransaction*>& aItems,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Dispatches an event to the undo scope host.
|
||||
* @param aPreviousPosition The index of the transaction that
|
||||
* triggered the event.
|
||||
*/
|
||||
void DispatchTransactionEvent(JSContext* aCx, const nsAString& aType,
|
||||
uint32_t aPreviousPosition,
|
||||
ErrorResult& aRv);
|
||||
bool mInTransaction;
|
||||
bool mIsDisconnected;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -87,6 +87,7 @@
|
||||
#include "nsDOMMutationObserver.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/FromParser.h"
|
||||
#include "mozilla/dom/UndoManager.h"
|
||||
#include "mozilla/BloomFilter.h"
|
||||
|
||||
#include "HTMLPropertiesCollection.h"
|
||||
@ -981,6 +982,8 @@ nsGenericHTMLElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
{
|
||||
bool contentEditable = aNameSpaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::contenteditable;
|
||||
bool undoScope = aNameSpaceID == kNameSpaceID_None &&
|
||||
aName == nsGkAtoms::undoscope;
|
||||
bool accessKey = aName == nsGkAtoms::accesskey &&
|
||||
aNameSpaceID == kNameSpaceID_None;
|
||||
|
||||
@ -1006,6 +1009,11 @@ nsGenericHTMLElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
ChangeEditableState(change);
|
||||
}
|
||||
|
||||
if (undoScope) {
|
||||
rv = SetUndoScopeInternal(true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (accessKey && !aValue.IsEmpty()) {
|
||||
SetFlags(NODE_HAS_ACCESSKEY);
|
||||
RegAccessKey();
|
||||
@ -1032,6 +1040,10 @@ nsGenericHTMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
contentEditable = true;
|
||||
contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
|
||||
}
|
||||
else if (aAttribute == nsGkAtoms::undoscope) {
|
||||
nsresult rv = SetUndoScopeInternal(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else if (aAttribute == nsGkAtoms::accesskey) {
|
||||
// Have to unregister before clearing flag. See UnregAccessKey
|
||||
UnregAccessKey();
|
||||
@ -2065,6 +2077,78 @@ nsGenericHTMLElement::IsLabelable() const
|
||||
Tag() == nsGkAtoms::meter;
|
||||
}
|
||||
|
||||
already_AddRefed<UndoManager>
|
||||
nsGenericHTMLElement::GetUndoManager()
|
||||
{
|
||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
||||
if (slots && slots->mUndoManager) {
|
||||
nsRefPtr<UndoManager> undoManager = slots->mUndoManager;
|
||||
return undoManager.forget();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsGenericHTMLElement::UndoScope()
|
||||
{
|
||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
||||
return slots && slots->mUndoManager;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericHTMLElement::SetUndoScope(bool aUndoScope, mozilla::ErrorResult& aError)
|
||||
{
|
||||
nsresult rv = SetUndoScopeInternal(aUndoScope);
|
||||
if (NS_FAILED(rv)) {
|
||||
aError.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// The undoScope property must reflect the undoscope boolean attribute.
|
||||
if (aUndoScope) {
|
||||
rv = SetAttr(kNameSpaceID_None, nsGkAtoms::undoscope,
|
||||
NS_LITERAL_STRING(""), true);
|
||||
} else {
|
||||
rv = UnsetAttr(kNameSpaceID_None, nsGkAtoms::undoscope, true);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aError.Throw(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericHTMLElement::SetUndoScopeInternal(bool aUndoScope)
|
||||
{
|
||||
if (aUndoScope) {
|
||||
nsDOMSlots* slots = DOMSlots();
|
||||
if (!slots->mUndoManager) {
|
||||
slots->mUndoManager = new UndoManager(this);
|
||||
}
|
||||
} else {
|
||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
||||
if (slots && slots->mUndoManager) {
|
||||
// Clear transaction history and disconnect.
|
||||
ErrorResult rv;
|
||||
slots->mUndoManager->ClearRedo(rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
slots->mUndoManager->ClearUndo(rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
slots->mUndoManager->Disconnect();
|
||||
slots->mUndoManager = nullptr;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsGenericHTMLElement::PrefEnabled()
|
||||
|
@ -323,6 +323,9 @@ protected:
|
||||
nsresult SetTokenList(nsIAtom* aAtom, nsIVariant* aValue);
|
||||
public:
|
||||
nsresult SetContentEditable(const nsAString &aContentEditable);
|
||||
virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager();
|
||||
virtual bool UndoScope();
|
||||
virtual void SetUndoScope(bool aUndoScope, mozilla::ErrorResult& aError);
|
||||
nsresult GetDataset(nsISupports** aDataset);
|
||||
// Callback for destructor of of dataset to ensure to null out weak pointer.
|
||||
nsresult ClearDataset();
|
||||
@ -1022,6 +1025,8 @@ protected:
|
||||
*/
|
||||
bool IsEditableRoot() const;
|
||||
|
||||
nsresult SetUndoScopeInternal(bool aUndoScope);
|
||||
|
||||
private:
|
||||
void ChangeEditableState(int32_t aChange);
|
||||
};
|
||||
|
@ -242,6 +242,7 @@ MOCHITEST_FILES = \
|
||||
test_bug677463.html \
|
||||
test_bug682886.html \
|
||||
test_bug717819.html \
|
||||
test_undoManager.html \
|
||||
file_fullscreen-utils.js \
|
||||
file_fullscreen-api.html \
|
||||
file_fullscreen-api-keys.html \
|
||||
|
852
content/html/content/test/test_undoManager.html
Normal file
852
content/html/content/test/test_undoManager.html
Normal file
@ -0,0 +1,852 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=617532
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 617532</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=617532">Mozilla Bug 617532</a>
|
||||
<p id="display"></p>
|
||||
<div id="content"></div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 617532 **/
|
||||
|
||||
/**
|
||||
* Tests for typical use cases.
|
||||
*/
|
||||
|
||||
var content = document.getElementById("content");
|
||||
|
||||
// Test appending text to a text node.
|
||||
|
||||
var textAppend = {
|
||||
label: "textAppend",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.firstChild.appendData(" and more text");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([textAppend],
|
||||
[getTextMatchFunction("box with text"),
|
||||
getTextMatchFunction("box with text and more text")]);
|
||||
|
||||
// Test replacing text in a text node.
|
||||
|
||||
var textReplace = {
|
||||
label: "textReplace",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.firstChild.replaceData(0, 3, "div");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([textReplace],
|
||||
[getTextMatchFunction("box with text"),
|
||||
getTextMatchFunction("div with text")]);
|
||||
|
||||
// Test inserting text in a text node.
|
||||
|
||||
var textInsert = {
|
||||
label: "textInsert",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.firstChild.insertData(0, "a ");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([textInsert],
|
||||
[getTextMatchFunction("box with text"),
|
||||
getTextMatchFunction("a box with text")]);
|
||||
|
||||
// Test deleting text in a text node.
|
||||
|
||||
var textDelete = {
|
||||
label: "textDelete",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.firstChild.deleteData(3, 10);
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([textDelete],
|
||||
[getTextMatchFunction("box with text"),
|
||||
getTextMatchFunction("box")]);
|
||||
|
||||
// Test creating a new attribute.
|
||||
|
||||
var createAttribute = {
|
||||
label: "createAttribute",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.setAttribute("data-new", "new");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([createAttribute],
|
||||
[getAttrAbsentFunction("data-new"),
|
||||
getAttrIsFunction("data-new", "new")]);
|
||||
|
||||
// Test changing an attribute.
|
||||
|
||||
var changeAttribute = {
|
||||
label: "changeAttribute",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.setAttribute("data-test", "change");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([changeAttribute],
|
||||
[getAttrIsFunction("data-test", "test"),
|
||||
getAttrIsFunction("data-test", "change")]);
|
||||
|
||||
// Test remove an attribute.
|
||||
|
||||
var removeAttribute = {
|
||||
label: "removeAttribute",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.removeAttribute("data-test");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([removeAttribute],
|
||||
[getAttrIsFunction("data-test", "test"),
|
||||
getAttrAbsentFunction("data-test")]);
|
||||
|
||||
// Test remove an attribute.
|
||||
|
||||
var removeAttribute = {
|
||||
label: "removeAttribute",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.removeAttribute("data-test");
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([removeAttribute],
|
||||
[getAttrIsFunction("data-test", "test"),
|
||||
getAttrAbsentFunction("data-test")]);
|
||||
|
||||
// Test appending child element to box.
|
||||
|
||||
var appendChild = {
|
||||
label: "appendChild",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.appendChild(document.createElement("div"));
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([appendChild],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(2)]);
|
||||
|
||||
// Test appending document fragment with multiple elements to box.
|
||||
|
||||
var appendFragment = {
|
||||
label: "appendFragment",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
var fragment = document.createDocumentFragment();
|
||||
fragment.appendChild(document.createElement("div"));
|
||||
fragment.appendChild(document.createElement("div"));
|
||||
fragment.appendChild(document.createElement("div"));
|
||||
box.appendChild(fragment);
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([appendFragment],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(4)]);
|
||||
|
||||
// Test appending a child then removing a child.
|
||||
|
||||
var removeChild = {
|
||||
label: "removeChild",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.removeChild(box.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([removeChild],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(0)]);
|
||||
|
||||
// Test appending a child then removing a child.
|
||||
|
||||
var applyInnerHTML = {
|
||||
label: "applyInnerHTML",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.innerHTML = "<div>one</div><div>two</div><div>three</div>";
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([applyInnerHTML],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(3)]);
|
||||
|
||||
// Test multiple append children and multiple remove children.
|
||||
|
||||
testTransaction([appendChild, appendChild, appendChild, appendChild,
|
||||
removeChild, removeChild, removeChild],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(2),
|
||||
getChildCountFunction(3),
|
||||
getChildCountFunction(4),
|
||||
getChildCountFunction(5),
|
||||
getChildCountFunction(4),
|
||||
getChildCountFunction(3),
|
||||
getChildCountFunction(2)]);
|
||||
|
||||
/**
|
||||
* Creates a div element containing the text "box with text".
|
||||
* Has an id of "box". Has an attribute "data-test" with the value of "test".
|
||||
*/
|
||||
function createTextBoxElement() {
|
||||
var box = document.createElement("div");
|
||||
box.setAttribute("id", "box");
|
||||
box.setAttribute("data-test", "test");
|
||||
box.textContent = "box with text";
|
||||
return box;
|
||||
}
|
||||
|
||||
function getTextMatchFunction(matchText) {
|
||||
return function(box) {
|
||||
is(box.textContent, matchText, "Text content did not match expected content");
|
||||
}
|
||||
}
|
||||
|
||||
function getAttrAbsentFunction(attrName) {
|
||||
return function(box) {
|
||||
ok(!box.hasAttribute(attrName), "Element should not have attribute");
|
||||
}
|
||||
}
|
||||
|
||||
function getAttrIsFunction(attrName, attrValue) {
|
||||
return function(box) {
|
||||
is(box.getAttribute(attrName), attrValue, "Element attribute is not the expected value");
|
||||
}
|
||||
}
|
||||
|
||||
function getChildCountFunction(count) {
|
||||
return function(box) {
|
||||
is(box.childNodes.length, count, "Element has incorrect number of children");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test transactions by applying, undoing and redoing a sequence of transactions.
|
||||
* At each step the state of the host node is evaluated for the expected state.
|
||||
* @param transactions An array of transactions to apply.
|
||||
* @param evaluators An array of functions which take an element as its only argument
|
||||
* and evaluates the state of the element for correctness. The
|
||||
* nth transaction in the transactions array is evaluated by the
|
||||
* n+1th function in the evaluators array. The first element of
|
||||
* the evaluators array evaluates the initial state of the host
|
||||
* node. Thus there should always be one more element in the
|
||||
* evaluators array than the transactions array.
|
||||
* @param merges An optional set of integers indicating which indices in the transactions
|
||||
* array should be merged with the previous transaction.
|
||||
*/
|
||||
function testTransaction(transactions, evaluators, merges) {
|
||||
if (!merges) {
|
||||
merges = [];
|
||||
}
|
||||
|
||||
var box = createTextBoxElement();
|
||||
box.undoScope = true;
|
||||
content.appendChild(box);
|
||||
var manager = box.undoManager;
|
||||
|
||||
is(manager.length, 0, "Initial lenght of UndoManager should be 0");
|
||||
is(manager.position, 0, "Initial position of UndoManager should be 0");
|
||||
|
||||
// Apply transactions and ensure the contents of the box have the
|
||||
// expected values.
|
||||
var expectedLength = 0;
|
||||
for (var i = 0; i < transactions.length; i++) {
|
||||
var merge = merges.indexOf(i) == -1 ? false : true;
|
||||
if (!merge || i == 0) {
|
||||
expectedLength++;
|
||||
}
|
||||
manager.transact(transactions[i], merge);
|
||||
evaluators[i+1](box);
|
||||
// Length and position should increase by 1.
|
||||
is(manager.length, expectedLength, "UndoManager length is incorrect after transaction");
|
||||
is(manager.position, 0, "UndoManager position is incorrect after transaction");
|
||||
}
|
||||
|
||||
// Undo all the transactions and make sure the content of box is the
|
||||
// expected content.
|
||||
var expectedPosition = 0;
|
||||
for (var i = transactions.length - 1; i >= 0; i--) {
|
||||
// Don't evaluate if the transaction was merged.
|
||||
if (merges.indexOf(i) == -1) {
|
||||
expectedPosition++;
|
||||
manager.undo();
|
||||
evaluators[i](box);
|
||||
// Length and position should decrease by one.
|
||||
is(manager.length, expectedLength, "UndoManager length should not change after undo");
|
||||
is(manager.position, expectedPosition, "UndoManager position is incorrect after undo");
|
||||
}
|
||||
}
|
||||
|
||||
// Redo all the transactions and make sure the content of the box is
|
||||
// the expected content.
|
||||
for (var i = 0; i < transactions.length; i++) {
|
||||
// Don't evaluate if the next transaction was merged into the current transaction.
|
||||
if (merges.indexOf(i+1) == -1) {
|
||||
expectedPosition--;
|
||||
manager.redo();
|
||||
evaluators[i+1](box);
|
||||
// Length and position should increase by 1.
|
||||
is(manager.length, expectedLength, "UndoManager length should not change after redo");
|
||||
is(manager.position, expectedPosition, "UndoManager position is incorrect after redo");
|
||||
}
|
||||
}
|
||||
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
testUndoRedoOnEmptyManager(0, 1);
|
||||
testUndoRedoOnEmptyManager(1, 0);
|
||||
testUndoRedoOnEmptyManager(2, 1);
|
||||
testUndoRedoOnEmptyManager(1, 2);
|
||||
testUndoRedoOnEmptyManager(2, 2);
|
||||
|
||||
/**
|
||||
* Test undo/redo when there is no undo transactions.
|
||||
* Makes sure that nothing bad happens (eg. crash) and that position and length
|
||||
* don't change.
|
||||
*/
|
||||
function testUndoRedoOnEmptyManager(numUndo, numRedo) {
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
box.undoScope = true;
|
||||
var manager = box.undoManager;
|
||||
|
||||
for (var i = 0; i < numUndo; i++) {
|
||||
manager.undo();
|
||||
is(manager.length, 0, "Undo should not change number of transacstions");
|
||||
is(manager.position, 0, "Undo should not change position");
|
||||
}
|
||||
|
||||
for (var i = 0; i < numRedo; i++) {
|
||||
manager.redo();
|
||||
is(manager.length, 0, "Undo should not change number of transacstions");
|
||||
is(manager.position, 0, "Undo should not change position");
|
||||
}
|
||||
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
// Test item()
|
||||
|
||||
testItem(10, 0);
|
||||
testItem(10, 1);
|
||||
testItem(10, 10);
|
||||
testItem(10, 5);
|
||||
testItem(1, 1);
|
||||
|
||||
/**
|
||||
* Create a UndoManager with numTxns transactions and calls undo numUndo
|
||||
* times. Ensures that items are in the correct order.
|
||||
*/
|
||||
function testItem(numTxns, numUndo) {
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
box.undoScope = true;
|
||||
var manager = box.undoManager;
|
||||
|
||||
for (var i = 0; i < numTxns; i++) {
|
||||
var dummyTxn = {label: null, execute: function(){}, value: i};
|
||||
manager.transact(dummyTxn, false);
|
||||
}
|
||||
|
||||
for (var i = 0; i < numUndo; i++) {
|
||||
manager.undo();
|
||||
}
|
||||
|
||||
for (var i = 0; i < manager.length; i++) {
|
||||
var txns = manager.item(i);
|
||||
is(txns[0].value, numTxns - i - 1, "item() returned the incorrect transaction");
|
||||
}
|
||||
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
testClearUndoRedoGetItem(10, 10, true);
|
||||
testClearUndoRedoGetItem(1, 1, true);
|
||||
testClearUndoRedoGetItem(1, 0, true);
|
||||
testClearUndoRedoGetItem(10, 0, true);
|
||||
testClearUndoRedoGetItem(10, 6, true);
|
||||
testClearUndoRedoGetItem(10, 10, false);
|
||||
testClearUndoRedoGetItem(1, 1, false);
|
||||
testClearUndoRedoGetItem(1, 0, false);
|
||||
testClearUndoRedoGetItem(10, 0, false);
|
||||
testClearUndoRedoGetItem(10, 6, false);
|
||||
|
||||
/**
|
||||
* Test clear undo/redo and ensure that item() returns the correct transaction.
|
||||
*/
|
||||
function testClearUndoRedoGetItem(numTxns, numUndo, clearRedo) {
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
box.undoScope = true;
|
||||
var manager = box.undoManager;
|
||||
|
||||
for (var i = 0; i < numTxns; i++) {
|
||||
var dummyTxn = {label: null, execute: function(){}, value: i};
|
||||
manager.transact(dummyTxn, false);
|
||||
}
|
||||
|
||||
for (var i = 0; i < numUndo; i++) {
|
||||
manager.undo();
|
||||
}
|
||||
|
||||
is(manager.length, numTxns, "UndoManager has incorrect number of transactions");
|
||||
is(manager.position, numUndo, "UndoManager has incorrect position");
|
||||
|
||||
// Check for the correct length and position.
|
||||
if (clearRedo) {
|
||||
manager.clearRedo();
|
||||
is(manager.position, 0, "UndoManager is incorrect position after clearRedo")
|
||||
is(manager.length, numTxns - numUndo, "UndoManager has incorrect number of transactions after clearRedo");
|
||||
} else {
|
||||
manager.clearUndo();
|
||||
is(manager.position, numUndo, "UndoManager should be at position 0 after clearUndo");
|
||||
is(manager.length, numUndo, "UndoManager has incorrect number of transactions after clearUndo");
|
||||
}
|
||||
|
||||
// Check that the most recent transaction (if one exists) is the correct one.
|
||||
if (manager.length > 0) {
|
||||
var newestTxn = manager.item(0)[0];
|
||||
if (clearRedo) {
|
||||
is(newestTxn.value + 1, numTxns - numUndo, "item() returned the incorrect transaction after clearRedo");
|
||||
} else {
|
||||
is(newestTxn.value + 1, numTxns, "item() returned the incorrect transaction after clearUndo");
|
||||
}
|
||||
}
|
||||
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
testOutOfBoundsItem(0, -1);
|
||||
testOutOfBoundsItem(0, 0);
|
||||
testOutOfBoundsItem(0, 1);
|
||||
testOutOfBoundsItem(1, -1);
|
||||
testOutOfBoundsItem(1, 1);
|
||||
testOutOfBoundsItem(2, 2);
|
||||
testOutOfBoundsItem(2, 3);
|
||||
|
||||
/**
|
||||
* Out of bound access to item.
|
||||
*/
|
||||
function testOutOfBoundsItem(numTxns, itemNum) {
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
box.undoScope = true;
|
||||
var manager = box.undoManager;
|
||||
|
||||
for (var i = 0; i < numTxns; i++) {
|
||||
var dummyTxn = {label: null, execute: function(){}};
|
||||
manager.transact(dummyTxn, false);
|
||||
}
|
||||
|
||||
is(null, manager.item(itemNum), "Accessing out of bounds item should return null.");
|
||||
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should not be able to access undoManager from within a transaction.
|
||||
*/
|
||||
|
||||
var accessUndoManagerLength = {
|
||||
label: "accessUndoManagerLength",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
is(0, box.undoManager.length, "Length should not change until after transaction is executed.");
|
||||
}
|
||||
};
|
||||
|
||||
transactExpectNoException(accessUndoManagerLength);
|
||||
|
||||
var accessUndoManagerPosition = {
|
||||
label: "accessUndoManagerPosition",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
is(0, box.undoManager.position, "Position should not change until after transaction is executed.");
|
||||
}
|
||||
};
|
||||
|
||||
transactExpectNoException(accessUndoManagerPosition);
|
||||
|
||||
var accessUndoManagerUndo = {
|
||||
label: "accessUndoManagerUndo",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.undoManager.undo();
|
||||
}
|
||||
};
|
||||
|
||||
transactExpectException(accessUndoManagerUndo);
|
||||
|
||||
var accessUndoManagerRedo = {
|
||||
label: "accessUndoManagerRedo",
|
||||
executeAutomatic: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.undoManager.redo();
|
||||
}
|
||||
};
|
||||
|
||||
transactExpectException(accessUndoManagerRedo);
|
||||
|
||||
function transactExpectNoException(transaction) {
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
box.undoScope = true;
|
||||
try {
|
||||
box.undoManager.transact(transaction, false);
|
||||
ok(true, "Transaction should not cause UndoManager to throw an exception.");
|
||||
} catch (ex) {
|
||||
ok(false, "Transaction should not cause UndoManager to throw an exception.");
|
||||
}
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
function transactExpectException(transaction) {
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
box.undoScope = true;
|
||||
try {
|
||||
box.undoManager.managedTransaction(transaction);
|
||||
ok(false, "Transaction should cause UndoManager to throw an exception.");
|
||||
} catch (ex) {
|
||||
ok(true, "Transaction should cause UndoManager to throw an exception.");
|
||||
}
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be able to access other undoManager from within a transaction.
|
||||
*/
|
||||
|
||||
modifyOtherManager(accessUndoManagerLength);
|
||||
modifyOtherManager(accessUndoManagerPosition);
|
||||
modifyOtherManager(accessUndoManagerUndo);
|
||||
modifyOtherManager(accessUndoManagerRedo);
|
||||
|
||||
function modifyOtherManager(transaction) {
|
||||
var otherElement = document.createElement('div');
|
||||
var box = createTextBoxElement();
|
||||
content.appendChild(box);
|
||||
content.appendChild(otherElement);
|
||||
otherElement.undoScope = true;
|
||||
box.undoScope = true;
|
||||
try {
|
||||
otherElement.undoManager.transact(transaction, false);
|
||||
ok(true, "Should not throw exception when UndoManager accesses other undo manager");
|
||||
} catch (ex) {
|
||||
ok(false, "Should not throw exception when UndoManager accesses other undo manager");
|
||||
}
|
||||
content.removeChild(box);
|
||||
content.removeChild(otherElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for usage of undo manager with modifications to the host node outside
|
||||
* of the manager. Such usage is not supported but it should not cause bad
|
||||
* things to happen (eg. crash).
|
||||
*/
|
||||
|
||||
// Remove the last characters from text, so that the deleteData range is out of bounds.
|
||||
function removeLastCharactersExternal(element) {
|
||||
element.firstChild.deleteData(3, 10);
|
||||
}
|
||||
|
||||
testExternalMutation(removeLastCharactersExternal, textInsert);
|
||||
testExternalMutation(removeLastCharactersExternal, textAppend);
|
||||
|
||||
// Change attribute value.
|
||||
function changeAttributeExternal(element) {
|
||||
element.setAttribute("data-test", "bad");
|
||||
}
|
||||
|
||||
testExternalMutation(changeAttributeExternal, createAttribute);
|
||||
testExternalMutation(changeAttributeExternal, changeAttribute);
|
||||
testExternalMutation(changeAttributeExternal, removeAttribute);
|
||||
|
||||
function removeAttributeExternal(element) {
|
||||
element.removeAttribute("data-test");
|
||||
}
|
||||
|
||||
testExternalMutation(removeAttributeExternal, createAttribute);
|
||||
testExternalMutation(removeAttributeExternal, changeAttribute);
|
||||
testExternalMutation(removeAttributeExternal, removeAttribute);
|
||||
|
||||
// removing children
|
||||
function removeAllChildrenExternal(element) {
|
||||
while (element.firstChild) {
|
||||
element.removeChild(element.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
testExternalMutation(removeAllChildrenExternal, appendChild);
|
||||
testExternalMutation(removeAllChildrenExternal, applyInnerHTML);
|
||||
|
||||
// Insert child
|
||||
function appendChildExternal(element) {
|
||||
var newElement = document.createElement("span");
|
||||
element.appendChild(newElement);
|
||||
}
|
||||
|
||||
testExternalMutation(appendChildExternal, appendChild);
|
||||
testExternalMutation(appendChildExternal, applyInnerHTML);
|
||||
|
||||
function testExternalMutation(externalMutation, transaction) {
|
||||
var box = createTextBoxElement();
|
||||
box.undoScope = true;
|
||||
content.appendChild(box);
|
||||
box.undoManager.transact(transaction, false);
|
||||
externalMutation(box);
|
||||
|
||||
try {
|
||||
box.undoManager.undo();
|
||||
ok(true, "Should not throw exception when undo is called on the transaction manager");
|
||||
} catch (ex) {
|
||||
ok(false, "Should not throw exception when undo is called on the transaction manager");
|
||||
}
|
||||
|
||||
try {
|
||||
box.undoManager.redo();
|
||||
ok(true, "Should not throw exception when redo is called on the transaction manager");
|
||||
} catch (ex) {
|
||||
ok(false, "Should not throw exception when redo is called on the transaction manager");
|
||||
}
|
||||
|
||||
content.removeChild(box);
|
||||
}
|
||||
|
||||
// Tests for manual transactions.
|
||||
var appendChildManual = {
|
||||
label: "appendChild",
|
||||
execute: function() {
|
||||
this.element = document.createElement("div");
|
||||
this.redo();
|
||||
},
|
||||
redo: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.appendChild(this.element);
|
||||
},
|
||||
undo: function() {
|
||||
var box = document.getElementById("box");
|
||||
box.removeChild(this.element);
|
||||
}
|
||||
};
|
||||
|
||||
testTransaction([appendChildManual],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(2)]);
|
||||
|
||||
testTransaction([appendChildManual, appendChild],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(2),
|
||||
getChildCountFunction(3)]);
|
||||
|
||||
testTransaction([appendChild, appendChildManual, appendChild],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(2),
|
||||
getChildCountFunction(3),
|
||||
getChildCountFunction(4)]);
|
||||
|
||||
// Tests for merge
|
||||
|
||||
testTransaction([appendChild, appendChild, appendChild],
|
||||
[getChildCountFunction(1),
|
||||
getChildCountFunction(2),
|
||||
getChildCountFunction(3),
|
||||
getChildCountFunction(4)],
|
||||
[1]);
|
||||
|
||||
// Passing invalid objects to transact.
|
||||
|
||||
transactExpectException({});
|
||||
transactExpectException({label: "hi"});
|
||||
transactExpectException({label: "hi", executeAutomatic: null});
|
||||
transactExpectException({label: "hi", execute: null});
|
||||
transactExpectException({label: "hi", executeAutomatic: 1});
|
||||
transactExpectException({label: "hi", execute: 1});
|
||||
transactExpectException({label: "hi", execute: function() {}, redo: null});
|
||||
|
||||
// make sure the document undomanager exists.
|
||||
|
||||
ok(document.undoManager, "Document should have an undo manager.");
|
||||
|
||||
// Make sure that the UndoManager only records transactions within scope.
|
||||
|
||||
var parent = document.createElement("div");
|
||||
var child = document.createElement("div");
|
||||
parent.appendChild(child);
|
||||
parent.undoScope = true;
|
||||
child.undoScope = true;
|
||||
|
||||
var innerHTMLToBye = {
|
||||
label: "hiToBye",
|
||||
executeAutomatic: function() {
|
||||
child.innerHTML = "bye";
|
||||
}
|
||||
};
|
||||
|
||||
child.innerHTML = "hello";
|
||||
parent.undoManager.transact(innerHTMLToBye, false);
|
||||
parent.undoManager.undo();
|
||||
|
||||
// The parent undo manager should not have recorded transactions for the children.
|
||||
// Thus the innerHTML should not have been undone.
|
||||
is(child.innerHTML, "bye", "Inner HTML of child should not be undone because it is not in parent scope.");
|
||||
|
||||
// Disconnect test.
|
||||
var dummyNode = document.createElement("div");
|
||||
dummyNode.undoScope = true;
|
||||
var dummyManager = dummyNode.undoManager;
|
||||
dummyManager.transact({label: null, execute: function() {}}, false);
|
||||
dummyNode.undoScope = false;
|
||||
is(dummyManager.length, 0, "All transactions should be cleared.");
|
||||
|
||||
try {
|
||||
dummyManager.transact({label: null, execute: function() {}}, false);
|
||||
ok(false, "Should not be able to transact in disconnected UndoManager.");
|
||||
} catch (ex) {
|
||||
ok(true, "Should not be able to transact in disconnected UndoManager.");
|
||||
}
|
||||
|
||||
// Undo call before and after undo/redo.
|
||||
dummyNode = document.createElement("div");
|
||||
dummyNode.undoScope = true;
|
||||
dummyNode.innerHTML = "hello";
|
||||
|
||||
var undoRedoTransaction = {
|
||||
label: "undoRedoTransaction",
|
||||
undoCall: 0,
|
||||
redoCall: 0,
|
||||
executeAutomatic: function () {
|
||||
dummyNode.innerHTML = "bye";
|
||||
},
|
||||
undo: function() {
|
||||
is(dummyNode.innerHTML, "hello", "redo should be called after transaction is undone.");
|
||||
this.undoCall++;
|
||||
},
|
||||
redo: function() {
|
||||
is(dummyNode.innerHTML, "bye", "redo should be called after transaction is redone.");
|
||||
this.redoCall++;
|
||||
}
|
||||
};
|
||||
|
||||
dummyNode.undoManager.transact(undoRedoTransaction, false);
|
||||
is(undoRedoTransaction.undoCall, 0, "undo should not have been called yet.");
|
||||
is(undoRedoTransaction.redoCall, 0, "redo should not have been called yet.");
|
||||
dummyNode.undoManager.undo();
|
||||
is(undoRedoTransaction.undoCall, 1, "undo should be called once.");
|
||||
is(undoRedoTransaction.redoCall, 0, "redo should not have been called yet.");
|
||||
dummyNode.undoManager.redo();
|
||||
is(undoRedoTransaction.undoCall, 1, "undo should be called once.");
|
||||
is(undoRedoTransaction.redoCall, 1, "redo should be called once.");
|
||||
|
||||
// Attribute setting.
|
||||
var dummyNode = document.createElement("div");
|
||||
ok(!dummyNode.undoManager, "UndoManager should not exist for element without undoscope attribute.");
|
||||
dummyNode.setAttribute("undoscope", "");
|
||||
ok(dummyNode.undoManager, "UndoManager should exist for element with undoscope attribute.");
|
||||
dummyNode.removeAttribute("undoscope");
|
||||
ok(!dummyNode.undoManager, "UndoManager should not exist for element without undoscope attribute.");
|
||||
|
||||
dummyNode = document.createElement("div");
|
||||
dummyNode.undoScope = true;
|
||||
is(dummyNode.getAttribute("undoscope"), "", "undoscope attribute should reflect undoScope property.");
|
||||
dummyNode.undoScope = false;
|
||||
ok(!dummyNode.hasAttribute("undoscope"), "undoscope attribute should not exist if undoScope property is false.");
|
||||
|
||||
// Event test
|
||||
dummyNode = document.createElement("div");
|
||||
dummyNode.undoScope = true;
|
||||
|
||||
var transactionOne = {
|
||||
transactCount: 0,
|
||||
undoCount: 0,
|
||||
redoCount: 0,
|
||||
label: "transactionOne",
|
||||
execute: function() {},
|
||||
};
|
||||
|
||||
var transactionTwo = {
|
||||
transactCount: 0,
|
||||
undoCount: 0,
|
||||
redoCount: 0,
|
||||
label: "transactionTwo",
|
||||
execute: function() {},
|
||||
};
|
||||
|
||||
var transactionThree = {
|
||||
transactCount: 0,
|
||||
undoCount: 0,
|
||||
redoCount: 0,
|
||||
label: "transactionThree",
|
||||
execute: function() {},
|
||||
};
|
||||
|
||||
dummyNode.addEventListener("DOMTransaction", function(e) { e.transactions[0].transactCount++; });
|
||||
dummyNode.addEventListener("undo", function(e) { e.transactions[0].undoCount++; });
|
||||
dummyNode.addEventListener("redo", function(e) { e.transactions[0].redoCount++; });
|
||||
|
||||
dummyNode.undoManager.transact(transactionOne, false);
|
||||
checkTransactionEvents(transactionOne, 1, 0, 0);
|
||||
dummyNode.undoManager.transact(transactionTwo, false);
|
||||
checkTransactionEvents(transactionTwo, 1, 0, 0);
|
||||
dummyNode.undoManager.transact(transactionThree, false);
|
||||
checkTransactionEvents(transactionThree, 1, 0, 0);
|
||||
|
||||
// Should do nothing, no events dispatched.
|
||||
dummyNode.undoManager.redo();
|
||||
checkTransactionEvents(transactionThree, 1, 0, 0);
|
||||
|
||||
dummyNode.undoManager.undo();
|
||||
checkTransactionEvents(transactionThree, 1, 1, 0);
|
||||
|
||||
dummyNode.undoManager.redo();
|
||||
checkTransactionEvents(transactionThree, 1, 1, 1);
|
||||
|
||||
dummyNode.undoManager.undo();
|
||||
checkTransactionEvents(transactionThree, 1, 2, 1);
|
||||
|
||||
dummyNode.undoManager.undo();
|
||||
checkTransactionEvents(transactionTwo, 1, 1, 0);
|
||||
|
||||
dummyNode.undoManager.undo();
|
||||
checkTransactionEvents(transactionOne, 1, 1, 0);
|
||||
|
||||
// Should do nothing, no events dispatched.
|
||||
dummyNode.undoManager.undo();
|
||||
checkTransactionEvents(transactionOne, 1, 1, 0);
|
||||
|
||||
function checkTransactionEvents(transaction, expectedTransact, expectedUndo, expectedRedo) {
|
||||
is(transaction.transactCount, expectedTransact, "DOMTransaction event was dispatched an unexpected number of times.");
|
||||
is(transaction.undoCount, expectedUndo, "undo event was dispatched an unexpected number of times.");
|
||||
is(transaction.redoCount, expectedRedo, "redo event was dispatched an unexpected number of times.");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -293,6 +293,16 @@ DOMInterfaces = {
|
||||
'workers': True,
|
||||
},
|
||||
|
||||
'DOMTransaction': [
|
||||
{
|
||||
'nativeType': 'nsIUndoManagerTransaction',
|
||||
}],
|
||||
|
||||
'UndoManager': [
|
||||
{
|
||||
'implicitJSContext' : [ 'undo', 'redo', 'transact' ]
|
||||
}],
|
||||
|
||||
'FormData': [
|
||||
{
|
||||
'nativeType': 'nsFormData'
|
||||
|
@ -31,6 +31,7 @@ XPIDLSRCS = \
|
||||
nsIDOMMutationEvent.idl \
|
||||
nsIDOMDragEvent.idl \
|
||||
nsIDOMDataTransfer.idl \
|
||||
nsIDOMDOMTransactionEvent.idl \
|
||||
nsIDOMPopupBlockedEvent.idl \
|
||||
nsIDOMBeforeUnloadEvent.idl \
|
||||
nsIDOMSmartCardEvent.idl \
|
||||
|
25
dom/interfaces/events/nsIDOMDOMTransactionEvent.idl
Normal file
25
dom/interfaces/events/nsIDOMDOMTransactionEvent.idl
Normal file
@ -0,0 +1,25 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsIDOMEvent.idl"
|
||||
|
||||
interface nsIVariant;
|
||||
|
||||
[scriptable, builtinclass, uuid(f57f7c46-d420-4f32-a61b-0eb585d30ee1)]
|
||||
interface nsIDOMDOMTransactionEvent : nsIDOMEvent
|
||||
{
|
||||
readonly attribute nsIVariant transactions;
|
||||
|
||||
void initDOMTransactionEvent(in DOMString typeArg,
|
||||
in boolean canBubbleArg,
|
||||
in boolean canCancelArg,
|
||||
in nsIVariant transactions);
|
||||
};
|
||||
|
||||
dictionary DOMTransactionEventInit : EventInit
|
||||
{
|
||||
nsIVariant transactions;
|
||||
};
|
||||
|
@ -84,6 +84,7 @@ SDK_XPIDLSRCS = \
|
||||
nsIDOMHTMLVideoElement.idl \
|
||||
nsIDOMHTMLAudioElement.idl \
|
||||
nsIDOMValidityState.idl \
|
||||
nsIUndoManagerTransaction.idl \
|
||||
nsIDOMMozBrowserFrame.idl \
|
||||
$(NULL)
|
||||
|
||||
|
17
dom/interfaces/html/nsIUndoManagerTransaction.idl
Normal file
17
dom/interfaces/html/nsIUndoManagerTransaction.idl
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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"
|
||||
|
||||
[scriptable, uuid(3802f155-e0f5-49ba-9972-e1aadcf2fdf0)]
|
||||
interface nsIUndoManagerTransaction : nsISupports
|
||||
{
|
||||
attribute DOMString label;
|
||||
void executeAutomatic();
|
||||
void execute();
|
||||
void undo();
|
||||
void redo();
|
||||
};
|
||||
|
@ -513,6 +513,8 @@ var interfaceNamesInGlobalScope =
|
||||
"CameraManager",
|
||||
"CSSSupportsRule",
|
||||
"MozMobileCellInfo",
|
||||
"UndoManager",
|
||||
"DOMTransactionEvent",
|
||||
"MozCanvasPrintState",
|
||||
"TCPSocket",
|
||||
"MozTimeManager",
|
||||
|
20
dom/webidl/DOMTransaction.webidl
Normal file
20
dom/webidl/DOMTransaction.webidl
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
callback interface DOMTransaction {
|
||||
attribute DOMString label;
|
||||
void executeAutomatic();
|
||||
void execute();
|
||||
void undo();
|
||||
void redo();
|
||||
};
|
||||
|
@ -377,7 +377,16 @@ partial interface Document {
|
||||
*/
|
||||
Element? elementFromPoint (float x, float y);
|
||||
//(Not implemented)CaretPosition? caretPositionFromPoint (float x, float y);
|
||||
/*};
|
||||
/*
|
||||
};
|
||||
|
||||
http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html
|
||||
partial interface Document {
|
||||
*/
|
||||
[Pref="dom.undo_manager.enabled"]
|
||||
readonly attribute UndoManager? undoManager;
|
||||
/*
|
||||
};
|
||||
|
||||
http://dev.w3.org/2006/webapi/selectors-api2/#interface-definitions
|
||||
partial interface Document {
|
||||
|
@ -169,6 +169,16 @@ partial interface Element {
|
||||
/*
|
||||
};
|
||||
|
||||
// http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html
|
||||
partial interface Element {
|
||||
*/
|
||||
[Pref="dom.undo_manager.enabled"]
|
||||
readonly attribute UndoManager? undoManager;
|
||||
[SetterThrows,Pref="dom.undo_manager.enabled"]
|
||||
attribute boolean undoScope;
|
||||
/*
|
||||
};
|
||||
|
||||
// http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
|
||||
partial interface Element {
|
||||
*/
|
||||
|
26
dom/webidl/UndoManager.webidl
Normal file
26
dom/webidl/UndoManager.webidl
Normal file
@ -0,0 +1,26 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
interface DOMTransaction;
|
||||
|
||||
[PrefControlled]
|
||||
interface UndoManager {
|
||||
[Throws] void transact(DOMTransaction transaction, boolean merge);
|
||||
[Throws] void undo();
|
||||
[Throws] void redo();
|
||||
[Throws] sequence<DOMTransaction>? item(unsigned long index);
|
||||
[Throws] readonly attribute unsigned long length;
|
||||
[Throws] readonly attribute unsigned long position;
|
||||
[Throws] void clearUndo();
|
||||
[Throws] void clearRedo();
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ webidl_files = \
|
||||
DOMSettableTokenList.webidl \
|
||||
DOMStringMap.webidl \
|
||||
DOMTokenList.webidl \
|
||||
DOMTransaction.webidl \
|
||||
DynamicsCompressorNode.webidl \
|
||||
Element.webidl \
|
||||
EventHandler.webidl \
|
||||
@ -111,6 +112,7 @@ webidl_files = \
|
||||
TextEncoder.webidl \
|
||||
URL.webidl \
|
||||
WebSocket.webidl \
|
||||
UndoManager.webidl \
|
||||
XMLHttpRequest.webidl \
|
||||
XMLHttpRequestEventTarget.webidl \
|
||||
XMLHttpRequestUpload.webidl \
|
||||
|
@ -869,7 +869,7 @@ nsEditor::BeginTransaction()
|
||||
BeginUpdateViewBatch();
|
||||
|
||||
if (mTxnMgr) {
|
||||
mTxnMgr->BeginBatch();
|
||||
mTxnMgr->BeginBatch(nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -879,7 +879,7 @@ NS_IMETHODIMP
|
||||
nsEditor::EndTransaction()
|
||||
{
|
||||
if (mTxnMgr) {
|
||||
mTxnMgr->EndBatch();
|
||||
mTxnMgr->EndBatch(false);
|
||||
}
|
||||
|
||||
EndUpdateViewBatch();
|
||||
|
@ -55,10 +55,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=471319
|
||||
// Test 3: Undoing a batched transaction where both end points of the
|
||||
// transaction are the bogus node - the bogus node should still be
|
||||
// recognized as bogus
|
||||
t1Editor.transactionManager.beginBatch();
|
||||
t1Editor.transactionManager.beginBatch(null);
|
||||
t1.value = "mozilla";
|
||||
t1.value = "";
|
||||
t1Editor.transactionManager.endBatch();
|
||||
t1Editor.transactionManager.endBatch(false);
|
||||
t1Editor.undo(1);
|
||||
ok(!t1.value,
|
||||
"recreated <br> from undo transaction recognized as bogus");
|
||||
|
@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsITransaction;
|
||||
|
||||
/*
|
||||
@ -14,7 +15,7 @@ interface nsITransaction;
|
||||
* Undo or Redo stacks as well as any auto-aggregated children that a
|
||||
* transaction may have.
|
||||
*/
|
||||
[scriptable, uuid(97f863f3-f886-11d4-9d39-0060b0f8baff)]
|
||||
[scriptable, uuid(d007ceff-c978-486a-b697-384ca01997be)]
|
||||
|
||||
interface nsITransactionList : nsISupports
|
||||
{
|
||||
@ -43,6 +44,13 @@ interface nsITransactionList : nsISupports
|
||||
*/
|
||||
nsITransaction getItem(in long aIndex);
|
||||
|
||||
/**
|
||||
* getData() returns the data (of type nsISupports array) associated with
|
||||
* the transaction list.
|
||||
*/
|
||||
void getData(in long aIndex, [optional] out unsigned long aLength,
|
||||
[array, size_is(aLength), retval] out nsISupports aData);
|
||||
|
||||
/**
|
||||
* getNumChildrenForItem() returns the number of child (auto-aggreated)
|
||||
* transactions the item at aIndex has.
|
||||
|
@ -20,7 +20,7 @@
|
||||
* This interface is implemented by an object that wants to
|
||||
* manage/track transactions.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(58e330c2-7b48-11d2-98b9-00805f297d89)]
|
||||
[scriptable, builtinclass, uuid(c77763df-0fb9-41a8-8074-8e882f605755)]
|
||||
interface nsITransactionManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -51,19 +51,34 @@ interface nsITransactionManager : nsISupports
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Clears the undo stack only.
|
||||
*/
|
||||
void clearUndoStack();
|
||||
|
||||
/**
|
||||
* Clears the redo stack only.
|
||||
*/
|
||||
void clearRedoStack();
|
||||
|
||||
/**
|
||||
* Turns on the transaction manager's batch mode, forcing all transactions
|
||||
* executed by the transaction manager's doTransaction() method to be
|
||||
* aggregated together until EndBatch() is called. This mode allows an
|
||||
* application to execute and group together several independent transactions
|
||||
* so they can be undone with a single call to undoTransaction().
|
||||
* @param aData An arbitrary nsISupports object that is associated with the
|
||||
* batch. Can be retrieved from nsITransactionList.
|
||||
*/
|
||||
void beginBatch();
|
||||
void beginBatch(in nsISupports aData);
|
||||
|
||||
/**
|
||||
* Turns off the transaction manager's batch mode.
|
||||
* @param aAllowEmpty If true, a batch containing no children will be
|
||||
* pushed onto the undo stack. Otherwise, ending a batch with no
|
||||
* children will result in no transactions being pushed on the undo stack.
|
||||
*/
|
||||
void endBatch();
|
||||
void endBatch(in boolean aAllowEmpty);
|
||||
|
||||
/**
|
||||
* The number of items on the undo stack.
|
||||
@ -90,6 +105,19 @@ interface nsITransactionManager : nsISupports
|
||||
*/
|
||||
attribute long maxTransactionCount;
|
||||
|
||||
/**
|
||||
* Combines the transaction at the top of the undo stack (if any) with the
|
||||
* preceding undo transaction (if any) into a batch transaction. Thus,
|
||||
* a call to undoTransaction() will undo both transactions.
|
||||
*/
|
||||
void batchTopUndo();
|
||||
|
||||
/**
|
||||
* Removes the transaction at the top of the undo stack (if any) without
|
||||
* transacting.
|
||||
*/
|
||||
void removeTopUndo();
|
||||
|
||||
/**
|
||||
* Returns an AddRef'd pointer to the transaction at the top of the
|
||||
* undo stack. Callers should be aware that this method could return
|
||||
|
@ -32,6 +32,7 @@ NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(nsTransactionItem)
|
||||
NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(nsTransactionItem)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTransactionItem)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
|
||||
if (tmp->mRedoStack) {
|
||||
tmp->mRedoStack->DoUnlink();
|
||||
@ -42,6 +43,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTransactionItem)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTransactionItem)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
|
||||
if (tmp->mRedoStack) {
|
||||
tmp->mRedoStack->DoTraverse(cb);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define nsTransactionItem_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nscore.h"
|
||||
@ -17,6 +18,7 @@ class nsTransactionStack;
|
||||
|
||||
class nsTransactionItem
|
||||
{
|
||||
nsCOMArray<nsISupports> mData;
|
||||
nsCOMPtr<nsITransaction> mTransaction;
|
||||
nsTransactionStack *mUndoStack;
|
||||
nsTransactionStack *mRedoStack;
|
||||
@ -40,6 +42,11 @@ public:
|
||||
virtual nsresult UndoTransaction(nsTransactionManager *aTxMgr);
|
||||
virtual nsresult RedoTransaction(nsTransactionManager *aTxMgr);
|
||||
|
||||
nsCOMArray<nsISupports>& GetData()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
virtual nsresult UndoChildren(nsTransactionManager *aTxMgr);
|
||||
|
@ -87,6 +87,42 @@ NS_IMETHODIMP nsTransactionList::ItemIsBatch(int32_t aIndex, bool *aIsBatch)
|
||||
return item->GetIsBatch(aIsBatch);
|
||||
}
|
||||
|
||||
/* void getData (in long aIndex,
|
||||
[optional] out unsigned long aLength,
|
||||
[array, size_is (aLength), retval]
|
||||
out nsISupports aData); */
|
||||
NS_IMETHODIMP nsTransactionList::GetData(int32_t aIndex,
|
||||
uint32_t *aLength,
|
||||
nsISupports ***aData)
|
||||
{
|
||||
nsCOMPtr<nsITransactionManager> txMgr = do_QueryReferent(mTxnMgr);
|
||||
|
||||
NS_ENSURE_TRUE(txMgr, NS_ERROR_FAILURE);
|
||||
|
||||
nsRefPtr<nsTransactionItem> item;
|
||||
|
||||
if (mTxnStack) {
|
||||
item = mTxnStack->GetItem(aIndex);
|
||||
} else if (mTxnItem) {
|
||||
nsresult result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
}
|
||||
|
||||
nsCOMArray<nsISupports>& data = item->GetData();
|
||||
|
||||
nsISupports** ret = static_cast<nsISupports**>(NS_Alloc(data.Count() *
|
||||
sizeof(nsISupports*)));
|
||||
|
||||
for (int32_t i = 0; i < data.Count(); i++) {
|
||||
NS_ADDREF(ret[i] = data[i]);
|
||||
}
|
||||
|
||||
*aLength = data.Count();
|
||||
*aData = ret;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsITransaction getItem (in long aIndex); */
|
||||
NS_IMETHODIMP nsTransactionList::GetItem(int32_t aIndex, nsITransaction **aItem)
|
||||
{
|
||||
|
@ -76,14 +76,14 @@ nsTransactionManager::DoTransaction(nsITransaction *aTransaction)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = BeginTransaction(aTransaction);
|
||||
result = BeginTransaction(aTransaction, nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
DidDoNotify(aTransaction, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = EndTransaction();
|
||||
result = EndTransaction(false);
|
||||
|
||||
nsresult result2 = DidDoNotify(aTransaction, result);
|
||||
|
||||
@ -216,7 +216,7 @@ nsTransactionManager::Clear()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::BeginBatch()
|
||||
nsTransactionManager::BeginBatch(nsISupports* aData)
|
||||
{
|
||||
nsresult result;
|
||||
|
||||
@ -237,7 +237,7 @@ nsTransactionManager::BeginBatch()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = BeginTransaction(0);
|
||||
result = BeginTransaction(0, aData);
|
||||
|
||||
nsresult result2 = DidBeginBatchNotify(result);
|
||||
|
||||
@ -248,7 +248,7 @@ nsTransactionManager::BeginBatch()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::EndBatch()
|
||||
nsTransactionManager::EndBatch(bool aAllowEmpty)
|
||||
{
|
||||
nsCOMPtr<nsITransaction> ti;
|
||||
nsresult result;
|
||||
@ -286,7 +286,7 @@ nsTransactionManager::EndBatch()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = EndTransaction();
|
||||
result = EndTransaction(aAllowEmpty);
|
||||
|
||||
nsresult result2 = DidEndBatchNotify(result);
|
||||
|
||||
@ -455,6 +455,50 @@ nsTransactionManager::GetRedoList(nsITransactionList **aTransactionList)
|
||||
return (! *aTransactionList) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionManager::BatchTopUndo()
|
||||
{
|
||||
if (mUndoStack.GetSize() < 2) {
|
||||
// Not enough transactions to merge into one batch.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<nsTransactionItem> lastUndo;
|
||||
nsRefPtr<nsTransactionItem> previousUndo;
|
||||
|
||||
lastUndo = mUndoStack.Pop();
|
||||
MOZ_ASSERT(lastUndo, "There should be at least two transactions.");
|
||||
|
||||
previousUndo = mUndoStack.Peek();
|
||||
MOZ_ASSERT(previousUndo, "There should be at least two transactions.");
|
||||
|
||||
nsresult result = previousUndo->AddChild(lastUndo);
|
||||
|
||||
// Transfer data from the transactions that is going to be
|
||||
// merged to the transaction that it is being merged with.
|
||||
nsCOMArray<nsISupports>& lastData = lastUndo->GetData();
|
||||
nsCOMArray<nsISupports>& previousData = previousUndo->GetData();
|
||||
NS_ENSURE_TRUE(previousData.AppendObjects(lastData), NS_ERROR_UNEXPECTED);
|
||||
lastData.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionManager::RemoveTopUndo()
|
||||
{
|
||||
nsRefPtr<nsTransactionItem> lastUndo;
|
||||
|
||||
lastUndo = mUndoStack.Peek();
|
||||
if (!lastUndo) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
lastUndo = mUndoStack.Pop();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::AddListener(nsITransactionListener *aListener)
|
||||
{
|
||||
@ -471,14 +515,14 @@ nsTransactionManager::RemoveListener(nsITransactionListener *aListener)
|
||||
return mListeners.RemoveObject(aListener) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::ClearUndoStack()
|
||||
{
|
||||
mUndoStack.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::ClearRedoStack()
|
||||
{
|
||||
mRedoStack.Clear();
|
||||
@ -717,7 +761,8 @@ nsTransactionManager::DidMergeNotify(nsITransaction *aTop,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionManager::BeginTransaction(nsITransaction *aTransaction)
|
||||
nsTransactionManager::BeginTransaction(nsITransaction *aTransaction,
|
||||
nsISupports *aData)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
@ -725,6 +770,11 @@ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction)
|
||||
// We could use a factory that pre-allocates/recycles transaction items.
|
||||
nsRefPtr<nsTransactionItem> tx = new nsTransactionItem(aTransaction);
|
||||
|
||||
if (aData) {
|
||||
nsCOMArray<nsISupports>& data = tx->GetData();
|
||||
data.AppendObject(aData);
|
||||
}
|
||||
|
||||
if (!tx) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -742,7 +792,7 @@ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionManager::EndTransaction()
|
||||
nsTransactionManager::EndTransaction(bool aAllowEmpty)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
@ -753,7 +803,7 @@ nsTransactionManager::EndTransaction()
|
||||
|
||||
nsCOMPtr<nsITransaction> tint = tx->GetTransaction();
|
||||
|
||||
if (!tint) {
|
||||
if (!tint && !aAllowEmpty) {
|
||||
int32_t nc = 0;
|
||||
|
||||
// If we get here, the transaction must be a dummy batch transaction
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsTransactionStack.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsITransactionManager.h"
|
||||
#include "nsTransactionStack.h"
|
||||
@ -51,9 +52,6 @@ public:
|
||||
/* nsITransactionManager method implementations. */
|
||||
NS_DECL_NSITRANSACTIONMANAGER
|
||||
|
||||
/* nsTransactionManager specific methods. */
|
||||
virtual nsresult ClearUndoStack(void);
|
||||
virtual nsresult ClearRedoStack(void);
|
||||
already_AddRefed<nsITransaction> PeekUndoStack();
|
||||
already_AddRefed<nsITransaction> PeekRedoStack();
|
||||
|
||||
@ -78,8 +76,9 @@ public:
|
||||
private:
|
||||
|
||||
/* nsTransactionManager specific private methods. */
|
||||
virtual nsresult BeginTransaction(nsITransaction *aTransaction);
|
||||
virtual nsresult EndTransaction(void);
|
||||
virtual nsresult BeginTransaction(nsITransaction *aTransaction,
|
||||
nsISupports *aData);
|
||||
virtual nsresult EndTransaction(bool aAllowEmpty);
|
||||
};
|
||||
|
||||
#endif // nsTransactionManager_h__
|
||||
|
@ -613,7 +613,7 @@ public:
|
||||
return NS_OK;
|
||||
|
||||
if (mFlags & BATCH_FLAG) {
|
||||
result = mTXMgr->BeginBatch();
|
||||
result = mTXMgr->BeginBatch(nullptr);
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
@ -647,7 +647,7 @@ public:
|
||||
i, mLevel, result);
|
||||
|
||||
if (mFlags & BATCH_FLAG)
|
||||
mTXMgr->EndBatch();
|
||||
mTXMgr->EndBatch(false);
|
||||
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -659,7 +659,7 @@ public:
|
||||
i, mLevel, result);
|
||||
|
||||
if (mFlags & BATCH_FLAG)
|
||||
mTXMgr->EndBatch();
|
||||
mTXMgr->EndBatch(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -672,7 +672,7 @@ public:
|
||||
tx->Release();
|
||||
|
||||
if (mFlags & BATCH_FLAG)
|
||||
mTXMgr->EndBatch();
|
||||
mTXMgr->EndBatch(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -681,7 +681,7 @@ public:
|
||||
}
|
||||
|
||||
if (mFlags & BATCH_FLAG)
|
||||
mTXMgr->EndBatch();
|
||||
mTXMgr->EndBatch(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2700,7 +2700,7 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Make sure an unbalanced call to EndBatch() with empty undo stack
|
||||
* Make sure an unbalanced call to EndBatch(false) with empty undo stack
|
||||
* throws an error!
|
||||
*
|
||||
*******************************************************************/
|
||||
@ -2719,10 +2719,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (result != NS_ERROR_FAILURE) {
|
||||
fail("EndBatch() returned unexpected status. (%d)\n", result);
|
||||
fail("EndBatch(false) returned unexpected status. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2740,7 +2740,7 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
passed("Test unbalanced EndBatch() with empty undo stack");
|
||||
passed("Test unbalanced EndBatch(false) with empty undo stack");
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
@ -2763,10 +2763,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2784,10 +2784,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2818,10 +2818,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2864,10 +2864,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2917,10 +2917,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2949,10 +2949,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
tx->Release();
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3021,10 +3021,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3064,10 +3064,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3107,10 +3107,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3150,24 +3150,24 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3323,15 +3323,15 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
* Make sure an unbalanced call to EndBatch() throws an error and
|
||||
* Make sure an unbalanced call to EndBatch(false) throws an error and
|
||||
* doesn't affect the undo and redo stacks!
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (result != NS_ERROR_FAILURE) {
|
||||
fail("EndBatch() returned unexpected status. (%d)\n", result);
|
||||
fail("EndBatch(false) returned unexpected status. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3363,7 +3363,7 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
passed("Test effect of unbalanced EndBatch() on undo and redo stacks");
|
||||
passed("Test effect of unbalanced EndBatch(false) on undo and redo stacks");
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
@ -3373,10 +3373,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3408,10 +3408,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3451,10 +3451,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3511,10 +3511,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3636,10 +3636,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3652,10 +3652,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
tx->Release();
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3739,10 +3739,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3755,10 +3755,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
tx->Release();
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3870,10 +3870,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3886,10 +3886,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
tx->Release();
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4082,10 +4082,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4097,10 +4097,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
tx->Release();
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4167,10 +4167,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mgr->BeginBatch();
|
||||
result = mgr->BeginBatch(nullptr);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("BeginBatch() failed. (%d)\n", result);
|
||||
fail("BeginBatch(nullptr) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4182,10 +4182,10 @@ quick_batch_test(TestTransactionFactory *factory)
|
||||
|
||||
tx->Release();
|
||||
|
||||
result = mgr->EndBatch();
|
||||
result = mgr->EndBatch(false);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
fail("EndBatch() failed. (%d)\n", result);
|
||||
fail("EndBatch(false) failed. (%d)\n", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ simple_events = [
|
||||
'UserProximityEvent',
|
||||
'CustomEvent',
|
||||
'PageTransitionEvent',
|
||||
'DOMTransactionEvent',
|
||||
'PopStateEvent',
|
||||
'HashChangeEvent',
|
||||
'CloseEvent',
|
||||
|
@ -119,8 +119,8 @@ add_test(function test_create_folder_with_description() {
|
||||
|
||||
// This checks that calling undoTransaction on an "empty batch" doesn't
|
||||
// undo the previous transaction (getItemTitle will fail)
|
||||
txnManager.beginBatch();
|
||||
txnManager.endBatch();
|
||||
txnManager.beginBatch(null);
|
||||
txnManager.endBatch(false);
|
||||
txnManager.undoTransaction();
|
||||
|
||||
let folderId = observer._itemAddedId;
|
||||
|
Loading…
Reference in New Issue
Block a user