Bug 486990 - Context Menu can be disabled by stopping propagation, r=enn, sr=neil

--HG--
extra : rebase_source : a425f116d1350ff1204f1b031754a262ec73f8b1
This commit is contained in:
Olli Pettay 2009-06-17 13:26:21 +03:00
parent 2f8e4451fb
commit b4d60fb950
13 changed files with 239 additions and 36 deletions

View File

@ -1557,6 +1557,14 @@ nsDOMEvent::ReportWrongPropertyAccessWarning(const char* aPropertyName)
"DOM Events");
}
NS_IMETHODIMP
nsDOMEvent::GetPreventDefault(PRBool* aReturn)
{
NS_ENSURE_ARG_POINTER(aReturn);
*aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
return NS_OK;
}
nsresult NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent *aEvent)

View File

@ -368,15 +368,6 @@ nsDOMUIEvent::GetIsChar(PRBool* aIsChar)
}
}
NS_IMETHODIMP
nsDOMUIEvent::GetPreventDefault(PRBool* aReturn)
{
NS_ENSURE_ARG_POINTER(aReturn);
*aReturn = mEvent && (mEvent->flags & NS_EVENT_FLAG_NO_DEFAULT);
return NS_OK;
}
NS_METHOD nsDOMUIEvent::GetCompositionReply(nsTextEventReply** aReply)
{
if((mEvent->message == NS_COMPOSITION_START) ||

View File

@ -71,6 +71,7 @@ public:
// Forward to nsDOMEvent
NS_FORWARD_TO_NSDOMEVENT
NS_FORWARD_NSIDOMNSEVENT(nsDOMEvent::)
protected:
// Internal helper functions

View File

@ -325,8 +325,6 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
if (!(aVisitor.mEvent->flags & NS_EVENT_FLAG_CANT_BUBBLE) || newTarget) {
if ((!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) ||
item->ForceContentDispatch()) &&
(!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) ||
aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) &&
!(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK,
createdELMs != nsEventListenerManager::sCreatedCount);

View File

@ -863,7 +863,8 @@ nsXBLBinding::InstallEventHandlers()
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
(curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
if (!systemEventGroup)
manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;
@ -901,7 +902,8 @@ nsXBLBinding::InstallEventHandlers()
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
(handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
if (!systemEventGroup)
manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;
@ -999,7 +1001,9 @@ nsXBLBinding::UnhookEventHandlers()
if (!manager) {
return;
}
PRBool isChromeDoc =
nsContentUtils::IsChromeDoc(mBoundElement->GetOwnerDoc());
nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
nsXBLPrototypeHandler* curr;
for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
@ -1028,7 +1032,8 @@ nsXBLBinding::UnhookEventHandlers()
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
(curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
if (!systemEventGroup)
manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;
@ -1056,7 +1061,8 @@ nsXBLBinding::UnhookEventHandlers()
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) {
if ((isChromeDoc || mBoundElement->IsInNativeAnonymousSubtree()) &&
(handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM))) {
if (!systemEventGroup)
manager->GetSystemEventGroupLM(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;

View File

@ -140,7 +140,8 @@
#include "nsFrameLoader.h"
#include "prlog.h"
#include "rdf.h"
#include "nsIDOM3EventTarget.h"
#include "nsIDOMEventGroup.h"
#include "nsIControllers.h"
// The XUL doc interface
@ -1564,6 +1565,17 @@ nsXULElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
aVisitor.mForceContentDispatch = PR_TRUE; //FIXME! Bug 329119
nsIAtom* tag = Tag();
if (IsRootOfNativeAnonymousSubtree() &&
(tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner) &&
(aVisitor.mEvent->message == NS_MOUSE_CLICK ||
aVisitor.mEvent->message == NS_MOUSE_DOUBLECLICK ||
aVisitor.mEvent->message == NS_XUL_COMMAND ||
aVisitor.mEvent->message == NS_CONTEXTMENU)) {
// Don't propagate these events from native anonymous scrollbar.
aVisitor.mCanHandle = PR_TRUE;
aVisitor.mParentTarget = nsnull;
return NS_OK;
}
if (aVisitor.mEvent->message == NS_XUL_COMMAND &&
aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this) &&
tag != nsGkAtoms::command) {
@ -2156,13 +2168,19 @@ PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
if (!listener) {
return;
}
nsCOMPtr<nsIDOMEventTarget> target =
nsCOMPtr<nsIDOM3EventTarget> target =
do_QueryInterface(static_cast<nsINode*>(aObject));
if (target) {
target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), listener,
PR_FALSE);
target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), listener,
PR_FALSE);
nsCOMPtr<nsIDOMEventGroup> systemGroup;
static_cast<nsPIDOMEventTarget*>(aObject)->
GetSystemEventGroup(getter_AddRefs(systemGroup));
if (systemGroup) {
target->RemoveGroupedEventListener(NS_LITERAL_STRING("mousedown"),
listener, PR_FALSE, systemGroup);
target->RemoveGroupedEventListener(NS_LITERAL_STRING("contextmenu"),
listener, PR_FALSE, systemGroup);
}
}
NS_RELEASE(listener);
}
@ -2184,13 +2202,17 @@ nsXULElement::AddPopupListener(nsIAtom* aName)
return NS_OK;
}
nsCOMPtr<nsIDOMEventGroup> systemGroup;
GetSystemEventGroup(getter_AddRefs(systemGroup));
NS_ENSURE_STATE(systemGroup);
nsresult rv = NS_NewXULPopupListener(this, isContext,
getter_AddRefs(popupListener));
if (NS_FAILED(rv))
return rv;
// Add the popup as a listener on this element.
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(static_cast<nsIContent *>(this)));
nsCOMPtr<nsIDOM3EventTarget> target(do_QueryInterface(static_cast<nsIContent *>(this)));
NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
rv = SetProperty(listenerAtom, popupListener, PopupListenerPropertyDtor,
PR_TRUE);
@ -2198,10 +2220,14 @@ nsXULElement::AddPopupListener(nsIAtom* aName)
// Want the property to have a reference to the listener.
nsIDOMEventListener* listener = nsnull;
popupListener.swap(listener);
if (isContext)
target->AddEventListener(NS_LITERAL_STRING("contextmenu"), listener, PR_FALSE);
else
target->AddEventListener(NS_LITERAL_STRING("mousedown"), listener, PR_FALSE);
if (isContext) {
target->AddGroupedEventListener(NS_LITERAL_STRING("contextmenu"),
listener, PR_FALSE, systemGroup);
} else {
target->AddGroupedEventListener(NS_LITERAL_STRING("mousedown"),
listener, PR_FALSE, systemGroup);
}
return NS_OK;
}

View File

@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES = test_bug330705-2.xul \
test_bug233643.xul \
test_bug486990.xul \
$(NULL)
_CHROME_FILES = \

View File

@ -0,0 +1,168 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=486990
-->
<window title="Mozilla Bug 486990"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="setTimeout(runTests, 0);">
<script type="application/javascript" src="/MochiKit/packed.js"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=486990"
target="_blank">Mozilla Bug 486990</a>
</body>
<div xmlns="http://www.w3.org/1999/xhtml">
<select size="5" id="select">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
</div>
<menupopup id="cm" onpopupshowing="popupShowing(event);">
<menuitem label="Mozilla" value="http://mozilla.org"/>
<menuitem label="Slashdot" value="http://slashdot.org"/>
<menuitem label="Sourceforge" value="http://sf.net"/>
<menuitem label="Freshmeat" value="http://freshmeat.net"/>
</menupopup>
<button label="test button" contextmenu="cm" id="testbutton"/>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 486990 **/
SimpleTest.waitForExplicitFinish();
var prevented = false;
var eventCount = 0;
function fooListener(evt) {
evt.preventDefault();
prevented = evt.getPreventDefault();
++eventCount;
};
var clickCount = 0;
var mouseDownCount = 0;
var mouseUpCount = 0;
function clickListener(evt) {
++clickCount;
}
function mouseDownListener(evt) {
++mouseDownCount;
}
function mouseUpListener(evt) {
++mouseUpCount;
}
var popupshowingcount = 0;
function popupShowing(evt) {
++popupshowingcount;
evt.preventDefault();
}
function contextMenuStopper(evt) {
evt.stopPropagation();
}
function contextMenuPreventer(evt) {
evt.preventDefault();
}
function allowDisableContextMenu(allow) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const prefSvcContractID = "@mozilla.org/preferences-service;1";
const prefSvcIID = Components.interfaces.nsIPrefService;
var prefs = Components.classes[prefSvcContractID].getService(prefSvcIID)
.getBranch("dom.event.contextmenu.");
try {
if (allow) {
prefs.clearUserPref("enabled");
} else {
prefs.setBoolPref("enabled", allow);
}
} catch(ex) {}
}
function runTests() {
document.addEventListener("foo", fooListener, true);
var e1 = document.createEvent("Event");
e1.initEvent("foo", true, true);
document.dispatchEvent(e1);
is(eventCount, 1, "Wrong event count");
ok(prevented, "Default handling should have been prevented.");
prevented = false;
var e2 = document.createEvent("Event");
e2.initEvent("foo", false, false);
document.dispatchEvent(e1);
is(eventCount, 2, "Wrong event count");
ok(prevented, "Default handling should have been prevented.");
var tb = document.getElementById("testbutton");
dispatchTrustedContextMenuEvent(tb);
is(popupshowingcount, 1, "Should have got 'popupShowing' event!");
tb.addEventListener("contextmenu", contextMenuStopper, true);
dispatchTrustedContextMenuEvent(tb);
is(popupshowingcount, 2, "Should have got 'popupShowing' event!");
tb.addEventListener("contextmenu", contextMenuPreventer, true);
dispatchTrustedContextMenuEvent(tb);
is(popupshowingcount, 2, "Should not have got 'popupShowing' event!");
allowDisableContextMenu(false);
dispatchTrustedContextMenuEvent(tb);
is(popupshowingcount, 3, "Should have got 'popupShowing' event!");
allowDisableContextMenu(true);
dispatchTrustedContextMenuEvent(tb);
is(popupshowingcount, 3, "Should not have got 'popupshowing' event!");
var s = document.getElementById("select");
s.addEventListener("click", clickListener, true);
s.addEventListener("mousedown", mouseDownListener, true);
s.addEventListener("mouseup", mouseUpListener, true);
synthesizeMouse(s, 1, 10, {}, window);
is(clickCount, 1, "Should have got click event!");
is(mouseDownCount, 1, "Should have got mousedown event!");
is(mouseUpCount, 1, "Should have got mouseup event!");
// Dispatch to scrollbar.
synthesizeMouse(s, s.getBoundingClientRect().right - 3, 10, {}, window);
is(clickCount, 1, "Should not have got click event!");
is(mouseDownCount, 2, "Should have got mousedown event!");
is(mouseUpCount, 2, "Should have got mouseup event!");
SimpleTest.finish();
}
function dispatchTrustedContextMenuEvent(target) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var e = document.createEvent("MouseEvent");
e.initMouseEvent("contextmenu", true, true, window, 0, 0, 0, 0, 0,
false, false, false, false, 2, null);
return target.dispatchEvent(e);
}
]]>
</script>
</window>

View File

@ -44,7 +44,7 @@
#endif
%}
[scriptable, uuid(e565d518-4510-407f-a3d9-3b4107549c6d)]
[scriptable, uuid(9be8096b-f795-4045-9664-0c275f36fe5b)]
interface nsIDOMNSEvent : nsISupports
{
const long MOUSEDOWN = 0x00000001;
@ -114,5 +114,7 @@ interface nsIDOMNSEvent : nsISupports
*/
void preventCapture();
boolean getPreventDefault();
readonly attribute boolean isTrusted;
};

View File

@ -37,16 +37,14 @@
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
#include "nsIDOMNSEvent.idl"
[scriptable, uuid(a6cf90c4-15b3-11d2-932e-00805f8add32)]
interface nsIDOMNSUIEvent : nsISupports
[scriptable, uuid(72c9f79c-98cd-4224-a467-86b59c0a38f7)]
interface nsIDOMNSUIEvent : nsIDOMNSEvent
{
const long SCROLL_PAGE_UP = -32768;
const long SCROLL_PAGE_DOWN = 32768;
boolean getPreventDefault();
readonly attribute long layerX;
readonly attribute long layerY;
readonly attribute long pageX;

View File

@ -283,6 +283,7 @@ members = [
'nsIDOMMouseEvent.screenX',
'nsIDOMNSEvent.originalTarget',
'nsIDOMNSEvent.preventCapture',
'nsIDOMNSEvent.getPreventDefault',
'nsIDOMKeyEvent.ctrlKey',
'nsIDOMKeyEvent.shiftKey',
'nsIDOMKeyEvent.keyCode',
@ -294,7 +295,6 @@ members = [
'nsIDOMMutationEvent.attrChange',
'nsIDOMMutationEvent.newValue',
'nsIDOMMutationEvent.prevValue',
'nsIDOMNSUIEvent.getPreventDefault',
'nsIDOMNSUIEvent.which',
'nsIDOMNSUIEvent.rangeParent',
'nsIDOMNSUIEvent.rangeOffset',

View File

@ -186,6 +186,12 @@ NS_IMETHODIMP nsSmartCardEvent::GetIsTrusted(PRBool *aIsTrusted)
return mNSEvent->GetIsTrusted(aIsTrusted);
}
NS_IMETHODIMP
nsSmartCardEvent::GetPreventDefault(PRBool* aReturn)
{
NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init");
return mNSEvent->GetPreventDefault(aReturn);
}
// IDOMEvent maps
NS_IMETHODIMP nsSmartCardEvent::GetType(nsAString & aType)

View File

@ -174,8 +174,6 @@
</implementation>
<handlers>
<handler event="contextmenu" action="event.preventDefault();"/>
<handler event="popupshowing" phase="target">
<![CDATA[
var array = [];