Bug 1128787 part.2 nsHTMLDocument should clear focus before making itself editable when designMode is enabled and it makes the focused content non-focusable r=smaug+enndeakin

This commit is contained in:
Masayuki Nakano 2015-04-21 15:27:10 +09:00
parent 49d482da52
commit d9544ae02d
5 changed files with 259 additions and 46 deletions

View File

@ -18,4 +18,7 @@ support-files =
[test_bug617528.xul]
[test_bug679494.xul]
[test_bug930374-chrome.html]
[test_bug1128787-1.html]
[test_bug1128787-2.html]
[test_bug1128787-3.html]
[test_eventctors.xul]

View File

@ -0,0 +1,54 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1128787
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1128787</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1128787 **/
SimpleTest.waitForExplicitFinish();
window.onload = function (aEvent) {
var blurEventFired = false;
var input = document.getElementsByTagName("input")[0];
input.addEventListener("blur", function (aEvent) {
input.removeEventListener("blur", arguments.callee);
ok(true, "input element gets blur event correctly");
var utils = SpecialPowers.getDOMWindowUtils(window);
is(utils.IMEStatus, utils.IME_STATUS_ENABLED, "IME should be enabled");
SimpleTest.executeSoon(function () {
document.designMode = "off";
// XXX Should be fixed.
todo_is(utils.IMEStatus, utils.IME_STATUS_DISABLED, "IME should be disabled");
SimpleTest.finish();
});
});
document.designMode = "on";
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1128787">Mozilla Bug 1128787</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<input type="button"/>
<script>
var input = document.getElementsByTagName("input")[0];
input.focus();
</script>
<pre id="test">
</pre>
</body>
</html>

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1128787
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1128787</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1128787 **/
SimpleTest.waitForExplicitFinish();
window.onload = function (aEvent) {
var blurEventFired = false;
var input = document.getElementsByTagName("input")[0];
input.addEventListener("blur", function (aEvent) {
input.removeEventListener("blur", arguments.callee);
ok(true, "input element gets blur event correctly");
var utils = SpecialPowers.getDOMWindowUtils(window);
is(utils.IMEStatus, utils.IME_STATUS_ENABLED, "IME should be enabled");
SimpleTest.executeSoon(function () {
document.designMode = "off";
// XXX Should be fixed.
todo_is(utils.IMEStatus, utils.IME_STATUS_DISABLED, "IME should be disabled");
SimpleTest.finish();
});
});
document.designMode = "on";
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1128787">Mozilla Bug 1128787</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<p contenteditable="true"></p>
<input type="button"/>
<script>
var input = document.getElementsByTagName("input")[0];
input.focus();
</script>
<pre id="test">
</pre>
</body>
</html>

View File

@ -0,0 +1,54 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1128787
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1128787</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1128787 **/
SimpleTest.waitForExplicitFinish();
window.onload = function (aEvent) {
var blurEventFired = false;
var input = document.getElementsByTagName("input")[0];
input.addEventListener("blur", function (aEvent) {
input.removeEventListener("blur", arguments.callee);
ok(true, "input element gets blur event correctly");
var utils = SpecialPowers.getDOMWindowUtils(window);
is(utils.IMEStatus, utils.IME_STATUS_ENABLED, "IME should be enabled");
is(document.designMode, "on",
"designMode should be \"on\" when blur event caused by enabling designMode is fired");
document.designMode = "off";
is(document.designMode, "off",
"designMode should become \"off\" even if it's reset by the blur event handler caused by enabling designMode");
todo_is(utils.IMEStatus, utils.IME_STATUS_DISABLED, "IME should be disabled");
SimpleTest.finish();
});
document.designMode = "on";
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1128787">Mozilla Bug 1128787</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<input type="button"/>
<script>
var input = document.getElementsByTagName("input")[0];
input.focus();
</script>
<pre id="test">
</pre>
</body>
</html>

View File

@ -110,6 +110,9 @@
#include "nsCharsetSource.h"
#include "nsIStringBundle.h"
#include "nsDOMClassInfo.h"
#include "nsFocusManager.h"
#include "nsIFrame.h"
#include "nsIContent.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -2723,7 +2726,7 @@ nsHTMLDocument::EditingStateChanged()
}
if (mEditingState == eSettingUp || mEditingState == eTearingDown) {
// XXX We shouldn't recurse.
// XXX We shouldn't recurse
return NS_OK;
}
@ -2787,12 +2790,91 @@ nsHTMLDocument::EditingStateChanged()
bool makeWindowEditable = mEditingState == eOff;
bool updateState = false;
bool spellRecheckAll = false;
bool putOffToRemoveScriptBlockerUntilModifyingEditingState = false;
nsCOMPtr<nsIEditor> editor;
{
EditingState oldState = mEditingState;
nsAutoEditingState push(this, eSettingUp);
nsCOMPtr<nsIPresShell> presShell = GetShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
// Before making this window editable, we need to modify UA style sheet
// because new style may change whether focused element will be focusable
// or not.
nsCOMArray<nsIStyleSheet> agentSheets;
rv = presShell->GetAgentStyleSheets(agentSheets);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri),
NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<CSSStyleSheet> sheet;
rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
NS_ENSURE_TRUE(sheet, rv);
bool result = agentSheets.AppendObject(sheet);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// Should we update the editable state of all the nodes in the document? We
// need to do this when the designMode value changes, as that overrides
// specific states on the elements.
if (designMode) {
// designMode is being turned on (overrides contentEditable).
rv = NS_NewURI(getter_AddRefs(uri),
NS_LITERAL_STRING("resource://gre/res/designmode.css"));
NS_ENSURE_SUCCESS(rv, rv);
rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
NS_ENSURE_TRUE(sheet, rv);
result = agentSheets.AppendObject(sheet);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
updateState = true;
spellRecheckAll = oldState == eContentEditable;
}
else if (oldState == eDesignMode) {
// designMode is being turned off (contentEditable is still on).
RemoveFromAgentSheets(agentSheets,
NS_LITERAL_STRING("resource://gre/res/designmode.css"));
updateState = true;
}
rv = presShell->SetAgentStyleSheets(agentSheets);
NS_ENSURE_SUCCESS(rv, rv);
presShell->ReconstructStyleData();
// Adjust focused element with new style but blur event shouldn't be fired
// until mEditingState is modified with newState.
nsAutoScriptBlocker scriptBlocker;
if (designMode) {
nsCOMPtr<nsPIDOMWindow> focusedWindow;
nsIContent* focusedContent =
nsFocusManager::GetFocusedDescendant(window, false,
getter_AddRefs(focusedWindow));
if (focusedContent) {
nsIFrame* focusedFrame = focusedContent->GetPrimaryFrame();
bool clearFocus = focusedFrame ? !focusedFrame->IsFocusable() :
!focusedContent->IsFocusable();
if (clearFocus) {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->ClearFocus(window);
// If we need to dispatch blur event, we should put off after
// modifying mEditingState since blur event handler may change
// designMode state again.
putOffToRemoveScriptBlockerUntilModifyingEditingState = true;
}
}
}
}
if (makeWindowEditable) {
// Editing is being turned on (through designMode or contentEditable)
// Turn on editor.
@ -2808,61 +2890,26 @@ nsHTMLDocument::EditingStateChanged()
if (!editor)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIPresShell> presShell = GetShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
// If we're entering the design mode, put the selection at the beginning of
// the document for compatibility reasons.
if (designMode && oldState == eOff) {
editor->BeginningOfDocument();
}
nsCOMArray<nsIStyleSheet> agentSheets;
rv = presShell->GetAgentStyleSheets(agentSheets);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<CSSStyleSheet> sheet;
rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
NS_ENSURE_TRUE(sheet, rv);
bool result = agentSheets.AppendObject(sheet);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// Should we update the editable state of all the nodes in the document? We
// need to do this when the designMode value changes, as that overrides
// specific states on the elements.
if (designMode) {
// designMode is being turned on (overrides contentEditable).
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/designmode.css"));
NS_ENSURE_SUCCESS(rv, rv);
rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
NS_ENSURE_TRUE(sheet, rv);
result = agentSheets.AppendObject(sheet);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
updateState = true;
spellRecheckAll = oldState == eContentEditable;
if (putOffToRemoveScriptBlockerUntilModifyingEditingState) {
nsContentUtils::AddScriptBlocker();
}
else if (oldState == eDesignMode) {
// designMode is being turned off (contentEditable is still on).
RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
updateState = true;
}
rv = presShell->SetAgentStyleSheets(agentSheets);
NS_ENSURE_SUCCESS(rv, rv);
presShell->ReconstructStyleData();
}
mEditingState = newState;
if (putOffToRemoveScriptBlockerUntilModifyingEditingState) {
nsContentUtils::RemoveScriptBlocker();
// If mEditingState is overwritten by another call and already disabled
// the editing, we shouldn't keep making window editable.
if (mEditingState == eOff) {
return NS_OK;
}
}
if (makeWindowEditable) {
// Set the editor to not insert br's on return when in p