diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index fe5488055ace..73792021b3ac 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -3131,8 +3131,38 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, if (mCurrentTarget) { mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus)); const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface(); - suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE); activeContent = mCurrentTarget->GetContent(); + + // In some cases, we do not want to even blur the current focused + // element. Those cases are: + // 1. -moz-user-focus CSS property is set to 'ignore'; + // 2. Element with NS_EVENT_STATE_DISABLED + // (aka :disabled pseudo-class for HTML element); + // 3. XUL control element has the disabled property set to 'true'. + // + // We can't use nsIFrame::IsFocusable() because we want to blur when + // we click on a visibility: none element. + // We can't use nsIContent::IsFocusable() because we want to blur when + // we click on a non-focusable element like a
. + // We have to use |aEvent->target| to not make sure we do not check an + // anonymous node of the targeted element. + suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE); + + if (!suppressBlur) { + nsCOMPtr element = do_QueryInterface(aEvent->target); + suppressBlur = element && + element->State().HasState(NS_EVENT_STATE_DISABLED); + } + + if (!suppressBlur) { + nsCOMPtr xulControl = + do_QueryInterface(aEvent->target); + if (xulControl) { + bool disabled; + xulControl->GetDisabled(&disabled); + suppressBlur = disabled; + } + } } nsIFrame* currFrame = mCurrentTarget; diff --git a/content/events/test/Makefile.in b/content/events/test/Makefile.in index 47fc574c49d6..67584a5f97fd 100644 --- a/content/events/test/Makefile.in +++ b/content/events/test/Makefile.in @@ -101,6 +101,7 @@ MOCHITEST_FILES = \ test_dragstart.html \ test_bug812744.html \ test_addEventListenerExtraArg.html \ + test_focus_disabled.html \ $(NULL) MOCHITEST_CHROME_FILES = \ diff --git a/content/events/test/test_focus_disabled.html b/content/events/test/test_focus_disabled.html new file mode 100644 index 000000000000..afa19f9f57c7 --- /dev/null +++ b/content/events/test/test_focus_disabled.html @@ -0,0 +1,124 @@ + + + + + + Test for Bug 375008 + + + + + +Mozilla Bug 375008 +

+
+
+ +
+ +
+ + + + + + + + +
+ +
+ + + + + + + + + +
+ + + + +
+
+
+
+ + diff --git a/dom/tests/mochitest/chrome/child_focus_frame.html b/dom/tests/mochitest/chrome/child_focus_frame.html index 89f2a8179647..d7f0ff63cda0 100644 --- a/dom/tests/mochitest/chrome/child_focus_frame.html +++ b/dom/tests/mochitest/chrome/child_focus_frame.html @@ -18,7 +18,7 @@
This is a scrollable area with some sufficiently long text contained within it.
- + 1 2 @@ -47,9 +47,9 @@
abc
- - -s + + +s diff --git a/dom/tests/mochitest/chrome/window_focus.xul b/dom/tests/mochitest/chrome/window_focus.xul index 73a5e2248e10..bab772948c7f 100644 --- a/dom/tests/mochitest/chrome/window_focus.xul +++ b/dom/tests/mochitest/chrome/window_focus.xul @@ -22,8 +22,8 @@ var fm = Components.classes["@mozilla.org/focus-manager;1"]. const kChildDocumentRootIndex = 13; const kBeforeTabboxIndex = 34; const kTabbableSteps = 38; -const kFocusSteps = 18; -const kNoFocusSteps = 15; +const kFocusSteps = 26; +const kNoFocusSteps = 7; const kOverflowElementIndex = 27; var gTestStarted = false; @@ -530,8 +530,8 @@ function startTest() { ctrlKey : true } : { altKey : true }; // test accesskeys - var keys = ["t26", "t19", "t22", "t29", "t15", "t17", "n14", - "t4", "o1", "o9", "n6"]; + var keys = ["t26", "t19", "t22", "t29", "t15", "t17", "n6", + "t4", "o1", "o9", "n4"]; for (var k = 0; k < keys.length; k++) { var key = String.fromCharCode(65 + k); @@ -556,19 +556,19 @@ function startTest() expectFocusShift(function () synthesizeMouse(getById("ad"), 2, 2, { }, gChildWindow), null, getById("t29"), true, "mouse on html label with content inside"); expectFocusShift(function () synthesizeMouse(getById("ag"), 2, 2, { }, gChildWindow), - null, getById("n14"), true, "mouse on html label with for attribute"); + null, getById("n6"), true, "mouse on html label with for attribute"); gLastFocusMethod = 0; expectFocusShift(function () synthesizeMouse(getById("aj"), 2, 2, { }), null, getById("o9"), true, "mouse on xul label with content inside"); expectFocusShift(function () synthesizeMouse(getById("ak"), 2, 2, { }), - null, getById("n6"), true, "mouse on xul label with control attribute"); + null, getById("n4"), true, "mouse on xul label with control attribute"); // test accesskeys that shouldn't work k = "o".charCodeAt(0); while (k++ < "v".charCodeAt(0)) { var key = String.fromCharCode(k); expectFocusShift(function () synthesizeKey(key, accessKeyDetails), - window, getById("n6"), false, "non accesskey " + key); + window, getById("n4"), false, "non accesskey " + key); } gLastFocusMethod = -1; @@ -1614,7 +1614,7 @@ SimpleTest.waitForFocus(startTest); The elements with ids starting with t are focusable and in the taborder. The elements with ids starting with o are: odd numbered ids - focusable but not part of the tab order - even numbered ids - not focusable with -moz-user-focus: ignore + even numbered ids - not focusable with -moz-user-focus: ignore or disabled The elements with ids starting with n are: odd numbered ids - not focusable with -moz-user-focus: none even numbered ids - focusable but not part of the tab order @@ -1647,10 +1647,10 @@ SimpleTest.waitForFocus(startTest);