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

--HG--
extra : rebase_source : e2b9af17e5857dcc0a6781e254e45fdb790c9a9e
This commit is contained in:
Masayuki Nakano 2018-07-05 19:44:23 +09:00
parent a051633346
commit 2b43129579
5 changed files with 96 additions and 8 deletions

View File

@ -167,12 +167,13 @@ 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");
@ -180,8 +181,17 @@ public:
~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 {
@ -193,7 +203,7 @@ public:
private:
TextEditor* mTextEditor;
bool mPreviousEnabled;
int32_t mNumberOfMaximumTransactions;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};

View File

@ -388,12 +388,22 @@ public:
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();
}
/**
@ -424,8 +434,6 @@ public:
if (!mTransactionManager) {
return true;
}
// XXX Even we clear the transaction manager, IsUndoRedoEnabled() keep
// returning true...
return mTransactionManager->DisableUndoRedo();
}
bool ClearUndoRedo()

View File

@ -279,6 +279,7 @@ skip-if = os == 'android'
[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

View File

@ -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>

View File

@ -48,6 +48,8 @@ public:
return mRedoStack.GetSize();
}
int32_t NumberOfMaximumTransactions() const { return mMaxTransactionCount; }
bool EnableUndoRedo(int32_t aMaxTransactionCount = -1);
bool DisableUndoRedo()
{