Bug 1473515 - Make AutoDisableUndo restores enabled state of undo/redo with previous number of maximum transactions r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 05 Jul 2018 19:44:23 +0900
changeset 814498 312faaf630540f6b2a0c2ba21abae820bde276f7
parent 814497 fd58df5110c9a80a3dc3ed77d05eacd0a0efc261
push id115237
push usermasayuki@d-toybox.com
push dateThu, 05 Jul 2018 14:30:24 +0000
reviewersm_kato
bugs1473515
milestone63.0a1
Bug 1473515 - Make AutoDisableUndo restores enabled state of undo/redo with previous number of maximum transactions r?m_kato Calling EditorBase::EnableUndoRedo() without argument means that editor supports unlimited undo/redo stack. AutoDisableUndo class calls it without argument when it needs to restore undo/redo feature. However, <input type="text"> and <textarea> limits number of maximum transactions up to 1,000, perhaps for footprint. So, AutoDisableUndo should store the last number of maximum transactions before disabling undo/redo from the constructor. MozReview-Commit-ID: CoI6ZXyTd3X
dom/html/nsTextEditorState.cpp
editor/libeditor/EditorBase.h
editor/libeditor/tests/mochitest.ini
editor/libeditor/tests/test_undo_redo_stack_after_setting_value.html
editor/txmgr/TransactionManager.h
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -162,43 +162,53 @@ private:
 };
 
 class MOZ_RAII AutoDisableUndo final
 {
 public:
   explicit AutoDisableUndo(TextEditor* aTextEditor
                            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     : mTextEditor(aTextEditor)
-    , mPreviousEnabled(true)
+    , mNumberOfMaximumTransactions(0)
   {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     MOZ_ASSERT(mTextEditor);
 
-    mPreviousEnabled = mTextEditor->IsUndoRedoEnabled();
+    mNumberOfMaximumTransactions =
+      mTextEditor ? mTextEditor->NumberOfMaximumTransactions() : 0;
     DebugOnly<bool> disabledUndoRedo = mTextEditor->DisableUndoRedo();
     NS_WARNING_ASSERTION(disabledUndoRedo,
       "Failed to disable undo/redo transactions");
   }
 
   ~AutoDisableUndo()
   {
-    if (mPreviousEnabled) {
-      DebugOnly<bool> enabledUndoRedo = mTextEditor->EnableUndoRedo();
+    // Don't change enable/disable of undo/redo if it's enabled after
+    // it's disabled by the constructor because we shouldn't change
+    // the maximum undo/redo count to the old value.
+    if (mTextEditor->IsUndoRedoEnabled()) {
+      return;
+    }
+    // If undo/redo was enabled, mNumberOfMaximumTransactions is -1 or lager
+    // than 0.  Only when it's 0, it was disabled.
+    if (mNumberOfMaximumTransactions) {
+      DebugOnly<bool> enabledUndoRedo =
+        mTextEditor->EnableUndoRedo(mNumberOfMaximumTransactions);
       NS_WARNING_ASSERTION(enabledUndoRedo,
         "Failed to enable undo/redo transactions");
     } else {
       DebugOnly<bool> disabledUndoRedo = mTextEditor->DisableUndoRedo();
       NS_WARNING_ASSERTION(disabledUndoRedo,
         "Failed to disable undo/redo transactions");
     }
   }
 
 private:
   TextEditor* mTextEditor;
-  bool mPreviousEnabled;
+  int32_t mNumberOfMaximumTransactions;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*static*/
 bool
 nsITextControlElement::GetWrapPropertyEnum(nsIContent* aContent,
   nsITextControlElement::nsHTMLTextWrap& aWrapProp)
 {
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -384,21 +384,31 @@ public:
     return mTransactionManager ? mTransactionManager->NumberOfUndoItems() : 0;
   }
   size_t NumberOfRedoItems() const
   {
     return mTransactionManager ? mTransactionManager->NumberOfRedoItems() : 0;
   }
 
   /**
+   * Returns number of maximum undo/redo transactions.
+   */
+  int32_t NumberOfMaximumTransactions() const
+  {
+    return mTransactionManager ?
+             mTransactionManager->NumberOfMaximumTransactions() : 0;
+  }
+
+  /**
    * Returns true if this editor can store transactions for undo/redo.
    */
   bool IsUndoRedoEnabled() const
   {
-    return !!mTransactionManager;
+    return mTransactionManager &&
+           mTransactionManager->NumberOfMaximumTransactions();
   }
 
   /**
    * Return true if it's possible to undo/redo right now.
    */
   bool CanUndo() const
   {
     return IsUndoRedoEnabled() && NumberOfUndoItems() > 0;
@@ -419,18 +429,16 @@ public:
     }
     return mTransactionManager->EnableUndoRedo(aMaxTransactionCount);
   }
   bool DisableUndoRedo()
   {
     if (!mTransactionManager) {
       return true;
     }
-    // XXX Even we clear the transaction manager, IsUndoRedoEnabled() keep
-    //     returning true...
     return mTransactionManager->DisableUndoRedo();
   }
   bool ClearUndoRedo()
   {
     if (!mTransactionManager) {
       return true;
     }
     return mTransactionManager->ClearUndoRedo();
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -274,15 +274,16 @@ skip-if = os == 'android'
 [test_inlineTableEditing.html]
 [test_insertParagraph_in_inline_editing_host.html]
 [test_keypress_untrusted_event.html]
 [test_objectResizing.html]
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
+[test_undo_redo_stack_after_setting_value.html]
 [test_backspace_vs.html]
 [test_css_chrome_load_access.html]
 skip-if = toolkit == 'android' # chrome urls not available due to packaging
 [test_selection_move_commands.html]
 [test_pasteImgTextarea.html]
 skip-if = toolkit == 'android' # bug 1299578
 [test_execCommandPaste_noTarget.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_undo_redo_stack_after_setting_value.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1473515
+-->
+<html>
+<head>
+  <title>Test for Bug 1473515</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.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=1473515">Mozilla Bug 1473515</a>
+<p id="display"></p>
+<div id="content" style="display: none;">
+
+</div>
+
+<input id="input">
+<textarea id="textarea"></textarea>
+
+<pre id="test">
+
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  let editableElements = [
+    document.getElementById("input"),
+    document.getElementById("textarea"),
+  ];
+  for (let editableElement of editableElements) {
+    editableElement.focus();
+    synthesizeKey("a");
+    synthesizeKey("c");
+    synthesizeKey("KEY_ArrowLeft");
+    synthesizeKey("b");
+    let editor = SpecialPowers.wrap(editableElement).editor;
+    let transactionManager = editor.transactionManager;
+    is(transactionManager.numberOfUndoItems, 2,
+       editableElement.tagName + ": Initially, there should be 2 undo items");
+    // Defined as nsITextControlElement::DEFAULT_UNDO_CAP
+    is(transactionManager.maxTransactionCount, 1000,
+       editableElement.tagName + ": Initially, transaction manager should be able to have 1,000 undo items");
+    editableElement.value = "def";
+    is(transactionManager.numberOfUndoItems, 0,
+       editableElement.tagName + ": After setting value, all undo items must be deleted");
+    is(transactionManager.maxTransactionCount, 1000,
+       editableElement.tagName + ": After setting value, maximum transaction count should be restored to the previous value");
+    synthesizeKey("a");
+    synthesizeKey("z", { accelKey: true });
+    is(editableElement.value, "def",
+       editableElement.tagName + ": undo should work after setting value");
+
+    // Disable undo/redo.
+    editor.enableUndo(0);
+    is(transactionManager.maxTransactionCount, 0,
+       editableElement.tagName + ": Transaction manager should not be able to have undo items");
+    editableElement.value = "hij";
+    is(transactionManager.maxTransactionCount, 0,
+       editableElement.tagName + ": Transaction manager should not be able to have undo items after setting value");
+  }
+  SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
--- a/editor/txmgr/TransactionManager.h
+++ b/editor/txmgr/TransactionManager.h
@@ -43,16 +43,18 @@ public:
   {
     return mUndoStack.GetSize();
   }
   size_t NumberOfRedoItems() const
   {
     return mRedoStack.GetSize();
   }
 
+  int32_t NumberOfMaximumTransactions() const { return mMaxTransactionCount; }
+
   bool EnableUndoRedo(int32_t aMaxTransactionCount = -1);
   bool DisableUndoRedo()
   {
     return EnableUndoRedo(0);
   }
   bool ClearUndoRedo()
   {
     if (NS_WARN_IF(!mDoStack.IsEmpty())) {