Bug 534833 - click event is occasionally lost in text form controls when focus event changes the value of the control, r=roc

--HG--
extra : rebase_source : 9c90b0ed41ab12c38d264edc839227cdd0d8817f
This commit is contained in:
Olli Pettay 2010-01-25 11:21:33 +02:00
parent b1dfdbc219
commit 72d240fc9b
4 changed files with 185 additions and 5 deletions

View File

@ -969,8 +969,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEventStateManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGestureDownContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGestureDownFrameOwner);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastLeftMouseDownContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastLeftMouseDownContentParent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastMiddleMouseDownContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastMiddleMouseDownContentParent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastRightMouseDownContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastRightMouseDownContentParent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mActiveContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHoverContent);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDragOverContent);
@ -987,8 +990,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEventStateManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGestureDownContent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGestureDownFrameOwner);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastLeftMouseDownContent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastLeftMouseDownContentParent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastMiddleMouseDownContent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastMiddleMouseDownContentParent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastRightMouseDownContent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastRightMouseDownContentParent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mActiveContent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHoverContent);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDragOverContent);
@ -3721,6 +3727,12 @@ nsEventStateManager::UpdateDragDataTransfer(nsDragEvent* dragEvent)
}
}
nsIContent* GetParentContentForMouseTarget(nsIContent* aContent)
{
return aContent && aContent->IsInNativeAnonymousSubtree() ?
aContent->GetParent() : nsnull;
}
nsresult
nsEventStateManager::SetClickCount(nsPresContext* aPresContext,
nsMouseEvent *aEvent,
@ -3733,42 +3745,54 @@ nsEventStateManager::SetClickCount(nsPresContext* aPresContext,
case nsMouseEvent::eLeftButton:
if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
mLastLeftMouseDownContent = mouseContent;
mLastLeftMouseDownContentParent =
GetParentContentForMouseTarget(mouseContent);
} else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
if (mLastLeftMouseDownContent == mouseContent) {
if (mLastLeftMouseDownContent == mouseContent ||
mLastLeftMouseDownContentParent == mouseContent) {
aEvent->clickCount = mLClickCount;
mLClickCount = 0;
} else {
aEvent->clickCount = 0;
}
mLastLeftMouseDownContent = nsnull;
mLastLeftMouseDownContentParent = nsnull;
}
break;
case nsMouseEvent::eMiddleButton:
if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
mLastMiddleMouseDownContent = mouseContent;
mLastMiddleMouseDownContentParent =
GetParentContentForMouseTarget(mouseContent);
} else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
if (mLastMiddleMouseDownContent == mouseContent) {
if (mLastMiddleMouseDownContent == mouseContent ||
mLastMiddleMouseDownContentParent == mouseContent) {
aEvent->clickCount = mMClickCount;
mMClickCount = 0;
} else {
aEvent->clickCount = 0;
}
// XXX Why we don't clear mLastMiddleMouseDownContent here?
mLastMiddleMouseDownContent = nsnull;
mLastMiddleMouseDownContentParent = nsnull;
}
break;
case nsMouseEvent::eRightButton:
if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
mLastRightMouseDownContent = mouseContent;
mLastRightMouseDownContentParent =
GetParentContentForMouseTarget(mouseContent);
} else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
if (mLastRightMouseDownContent == mouseContent) {
if (mLastRightMouseDownContent == mouseContent ||
mLastRightMouseDownContentParent == mouseContent) {
aEvent->clickCount = mRClickCount;
mRClickCount = 0;
} else {
aEvent->clickCount = 0;
}
// XXX Why we don't clear mLastRightMouseDownContent here?
mLastRightMouseDownContent = nsnull;
mLastRightMouseDownContentParent = nsnull;
}
break;
}

View File

@ -360,8 +360,11 @@ protected:
PRPackedBool mGestureDownMeta;
nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
nsCOMPtr<nsIContent> mLastLeftMouseDownContentParent;
nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
nsCOMPtr<nsIContent> mLastMiddleMouseDownContentParent;
nsCOMPtr<nsIContent> mLastRightMouseDownContent;
nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
nsCOMPtr<nsIContent> mActiveContent;
nsCOMPtr<nsIContent> mHoverContent;

View File

@ -82,6 +82,7 @@ _TEST_FILES = \
test_bug502818.html \
test_bug508479.html \
test_bug517851.html \
test_bug534833.html \
$(NULL)
_CHROME_FILES = \

View File

@ -0,0 +1,152 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=534833
-->
<head>
<title>Test for Bug 534833</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<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 onload="runTests()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=534833">Mozilla Bug 534833</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 534833 **/
SimpleTest.waitForExplicitFinish();
var input1GotClick = 0;
var input2GotClick = 0;
var textarea1GotClick = 0;
var textarea2GotClick = 0;
var div1GotClick = 0;
var div2GotClick = 0;
var tests = [ { element: "text", clickText: true },
{ element: "text2", clickText: false },
{ element: "area", clickText: true },
{ element: "area2", clickText: false },
{ element: "d", clickText: true },
{ element: "d", clickText: false },
{ element: "d2", clickText: true },
{ element: "d2", clickText: false }
];
function nextTest_() {
if (!tests.length) {
finishTests();
return;
}
var test = tests.shift();
var el = document.getElementById(test.element);
el.scrollIntoView(true);
if (test.clickText) {
synthesizeMouse(el, 5, 5, {type : "mousedown" });
synthesizeMouse(el, 5, 5, {type : "mouseup" });
} else {
synthesizeMouse(el, el.getBoundingClientRect().width - 5, 5, {type : "mousedown" });
synthesizeMouse(el, el.getBoundingClientRect().width - 5, 5, {type : "mouseup" });
}
nextTest();
}
function nextTest() {
document.getElementById("initialfocus").focus();
setTimeout(nextTest_, 100);
}
function runTests() {
var t = document.getElementById("text");
var t2 = document.getElementById("text2");
var a = document.getElementById("area");
var a2 = document.getElementById("area2");
var d = document.getElementById("d");
var d2 = document.getElementById("d2");
// input 1
t.onfocus = function(e) {
t.value = "";
}
t.onclick = function(e) {
++input1GotClick;
}
// input 2
t2.onfocus = function(e) {
t2.value = "";
}
t2.onclick = function(e) {
++input2GotClick;
}
// textarea 1
a.onfocus = function(e) {
a.value = "";
}
a.onclick = function(e) {
++textarea1GotClick;
}
// textarea 2
a2.onfocus = function(e) {
a2.value = "";
}
a2.onclick = function(e) {
++textarea2GotClick;
}
// div 1
var c = 0;
d.onmousedown = function(e) {
d.textContent = (++c) + " / click before or after |";
}
d.onclick = function(e) {
++div1GotClick;
}
// div 2
var c2 = 0;
d2.onmousedown = function(e) {
d2.firstChild.data = (++c2) + " / click before or after |";
}
d2.onclick = function(e) {
++div2GotClick;
}
nextTest();
}
function finishTests() {
is(input1GotClick, 1, "input element should have got a click!");
is(input2GotClick, 1, "input element should have got a click! (2)");
is(textarea1GotClick, 1, "textarea element should have got a click!");
is(textarea2GotClick, 1, "textarea element should have got a click! (2)");
is(div1GotClick, 1, "div element's content text was replaced, it should have got 1 click!");
is(div2GotClick, 2, "div element's content text was modified, it should have got 2 clicks!");
SimpleTest.finish();
}
</script>
</pre>
<input type="text" id="initialfocus"><br>
<input type="text" id="text" value="click before |" style="width: 95%;"><br>
<input type="text" id="text2" value="click after |" style="width: 95%;">
<br>
<textarea id="area" rows="2" style="width: 95%;">
click before
|
</textarea><br>
<textarea id="area2" rows="2" style="width: 95%;">
click after |
</textarea>
<div id="d" style="border: 1px solid black;">click before or after |</div>
<div id="d2" style="border: 1px solid black;">click before or after |</div>
</body>
</html>