forked from mirrors/gecko-dev
Bug 448602 - Have a way to enumerate event listeners, r=bz
--HG-- extra : rebase_source : 77ed96b23db73ae78ed7f34ed231daf84fae1f54
This commit is contained in:
parent
881607eb48
commit
2d83c2550e
21 changed files with 676 additions and 26 deletions
|
|
@ -122,6 +122,7 @@
|
|||
@BINPATH@/components/commandlines.xpt
|
||||
@BINPATH@/components/composer.xpt
|
||||
@BINPATH@/components/content_base.xpt
|
||||
@BINPATH@/components/content_events.xpt
|
||||
@BINPATH@/components/content_canvas.xpt
|
||||
@BINPATH@/components/content_htmldoc.xpt
|
||||
@BINPATH@/components/content_html.xpt
|
||||
|
|
|
|||
|
|
@ -301,6 +301,13 @@
|
|||
#define NS_SYNCLOADDOMSERVICE_CONTRACTID \
|
||||
"@mozilla.org/content/syncload-dom-service;1"
|
||||
|
||||
#define NS_EVENTLISTENERSERVICE_CID \
|
||||
{ /* baa34652-f1f1-4185-b224-244ee82a413a */ \
|
||||
0xbaa34652, 0xf1f1, 0x4185, \
|
||||
{0xb2, 0x24, 0x24, 0x4e, 0xe8, 0x2a, 0x41, 0x3a } }
|
||||
#define NS_EVENTLISTENERSERVICE_CONTRACTID \
|
||||
"@mozilla.org/eventlistenerservice;1"
|
||||
|
||||
// {f96f5ec9-755b-447e-b1f3-717d1a84bb41}
|
||||
#define NS_PLUGINDOCUMENT_CID \
|
||||
{ 0xf96f5ec9, 0x755b, 0x447e, { 0xb1, 0xf3, 0x71, 0x7d, 0x1a, 0x84, 0xbb, 0x41 } }
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ VPATH = @srcdir@
|
|||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = content
|
||||
XPIDL_MODULE = content_events
|
||||
|
||||
EXPORTS = \
|
||||
nsMutationEvent.h \
|
||||
|
|
@ -57,5 +58,9 @@ EXPORTS = \
|
|||
nsPIDOMEventTarget.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIEventListenerService.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class nsIDOMEvent;
|
|||
class nsPIDOMEventTarget;
|
||||
class nsIScriptGlobalObject;
|
||||
class nsEventTargetChainItem;
|
||||
|
||||
template<class E> class nsCOMArray;
|
||||
|
||||
/**
|
||||
* About event dispatching:
|
||||
|
|
@ -230,6 +230,10 @@ public:
|
|||
* In other words, aEvent->target is only a property of the event and it has
|
||||
* nothing to do with the construction of the event target chain.
|
||||
* Neither aTarget nor aEvent is allowed to be nsnull.
|
||||
*
|
||||
* If aTargets is non-null, event target chain will be created, but
|
||||
* event won't be handled. In this case aEvent->message should be
|
||||
* NS_EVENT_TYPE_NULL.
|
||||
* @note Use this method when dispatching an nsEvent.
|
||||
*/
|
||||
static nsresult Dispatch(nsISupports* aTarget,
|
||||
|
|
@ -237,7 +241,8 @@ public:
|
|||
nsEvent* aEvent,
|
||||
nsIDOMEvent* aDOMEvent = nsnull,
|
||||
nsEventStatus* aEventStatus = nsnull,
|
||||
nsDispatchingCallback* aCallback = nsnull);
|
||||
nsDispatchingCallback* aCallback = nsnull,
|
||||
nsCOMArray<nsPIDOMEventTarget>* aTargets = nsnull);
|
||||
|
||||
/**
|
||||
* Dispatches an event.
|
||||
|
|
|
|||
|
|
@ -48,13 +48,15 @@ class nsIDOMEventTarget;
|
|||
class nsIDOMEventGroup;
|
||||
class nsIAtom;
|
||||
class nsPIDOMEventTarget;
|
||||
class nsIEventListenerInfo;
|
||||
template<class E> class nsCOMArray;
|
||||
|
||||
/*
|
||||
* Event listener manager interface.
|
||||
*/
|
||||
#define NS_IEVENTLISTENERMANAGER_IID \
|
||||
{ 0xadfdc265, 0xea1c, 0x4c0b, \
|
||||
{ 0x91, 0xca, 0x37, 0x67, 0x2c, 0x83, 0x92, 0x1f } }
|
||||
{ 0xac49ce4e, 0xaecf, 0x45db, \
|
||||
{ 0xa1, 0xe0, 0xea, 0x1d, 0x38, 0x73, 0x39, 0xa3 } }
|
||||
|
||||
class nsIEventListenerManager : public nsISupports {
|
||||
|
||||
|
|
@ -189,6 +191,12 @@ public:
|
|||
*/
|
||||
virtual PRUint32 MutationListenerBits() = 0;
|
||||
|
||||
/**
|
||||
* Sets aList to the list of nsIEventListenerInfo objects representing the
|
||||
* listeners managed by this listener manager.
|
||||
*/
|
||||
virtual nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList) = 0;
|
||||
|
||||
/**
|
||||
* Returns PR_TRUE if there is at least one event listener for aEventName.
|
||||
*/
|
||||
|
|
|
|||
89
content/events/public/nsIEventListenerService.idl
Normal file
89
content/events/public/nsIEventListenerService.idl
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Olli Pettay <Olli.Pettay@helsinki.fi> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIDOMEventListener.idl"
|
||||
|
||||
interface nsIDOMEventTarget;
|
||||
|
||||
/**
|
||||
* An instance of this interface describes how an event listener
|
||||
* was added to an event target.
|
||||
*/
|
||||
[scriptable, uuid(4f132988-4709-44e5-985c-9e16d0f7c954)]
|
||||
interface nsIEventListenerInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* The type of the event for which the listener was added.
|
||||
*/
|
||||
readonly attribute AString type;
|
||||
readonly attribute boolean capturing;
|
||||
readonly attribute boolean allowsUntrusted;
|
||||
readonly attribute boolean inSystemEventGroup;
|
||||
/**
|
||||
* Tries to serialize event listener to a string.
|
||||
* Returns null if serialization isn't possible
|
||||
* (for example with C++ listeners).
|
||||
*/
|
||||
AString toSource();
|
||||
};
|
||||
|
||||
[scriptable, uuid(551cac0f-31ed-45e0-8d67-bc0d6e117b31)]
|
||||
interface nsIEventListenerService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Returns an array of nsIEventListenerInfo objects.
|
||||
* If aEventTarget doesn't have any listeners, this returns null.
|
||||
*/
|
||||
void getListenerInfoFor(in nsIDOMEventTarget aEventTarget,
|
||||
out unsigned long aCount,
|
||||
[retval, array, size_is(aCount)] out
|
||||
nsIEventListenerInfo aOutArray);
|
||||
|
||||
/**
|
||||
* Returns an array of event targets.
|
||||
* aEventTarget will be at index 0.
|
||||
* The objects are the ones that would be used as DOMEvent.currentTarget while
|
||||
* dispatching an event to aEventTarget
|
||||
* @note Some events, especially 'load', may actually have a shorter
|
||||
* event target chain than what this methods returns.
|
||||
*/
|
||||
void getEventTargetChainFor(in nsIDOMEventTarget aEventTarget,
|
||||
out unsigned long aCount,
|
||||
[retval, array, size_is(aCount)] out
|
||||
nsIDOMEventTarget aOutArray);
|
||||
};
|
||||
|
||||
|
|
@ -74,6 +74,7 @@ CPPSRCS = \
|
|||
nsEventDispatcher.cpp \
|
||||
nsIMEStateManager.cpp \
|
||||
nsContentEventHandler.cpp \
|
||||
nsEventListenerService.cpp \
|
||||
nsDOMProgressEvent.cpp \
|
||||
nsDOMDataTransfer.cpp \
|
||||
nsDOMNotifyPaintEvent.cpp \
|
||||
|
|
|
|||
|
|
@ -200,11 +200,11 @@ public:
|
|||
|
||||
static void Shutdown();
|
||||
|
||||
static const char* GetEventName(PRUint32 aEventType);
|
||||
protected:
|
||||
|
||||
// Internal helper functions
|
||||
nsresult SetEventType(const nsAString& aEventTypeArg);
|
||||
static const char* GetEventName(PRUint32 aEventType);
|
||||
already_AddRefed<nsIDOMEventTarget> GetTargetFromFrame();
|
||||
nsresult ReportWrongPropertyAccessWarning(const char* aPropertyName);
|
||||
|
||||
|
|
|
|||
|
|
@ -427,11 +427,13 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
nsEvent* aEvent,
|
||||
nsIDOMEvent* aDOMEvent,
|
||||
nsEventStatus* aEventStatus,
|
||||
nsDispatchingCallback* aCallback)
|
||||
nsDispatchingCallback* aCallback,
|
||||
nsCOMArray<nsPIDOMEventTarget>* aTargets)
|
||||
{
|
||||
NS_ASSERTION(aEvent, "Trying to dispatch without nsEvent!");
|
||||
NS_ENSURE_TRUE(!NS_IS_EVENT_IN_DISPATCH(aEvent),
|
||||
NS_ERROR_ILLEGAL_VALUE);
|
||||
NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!");
|
||||
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(aTarget);
|
||||
#ifdef DEBUG
|
||||
|
|
@ -530,18 +532,27 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Event target chain is created. Handle the chain.
|
||||
nsEventChainPostVisitor postVisitor(preVisitor);
|
||||
rv = topEtci->HandleEventTargetChain(postVisitor,
|
||||
NS_EVENT_FLAG_BUBBLE |
|
||||
NS_EVENT_FLAG_CAPTURE,
|
||||
aCallback,
|
||||
PR_TRUE);
|
||||
|
||||
preVisitor.mEventStatus = postVisitor.mEventStatus;
|
||||
// If the DOM event was created during event flow.
|
||||
if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
|
||||
preVisitor.mDOMEvent = postVisitor.mDOMEvent;
|
||||
if (aTargets) {
|
||||
aTargets->Clear();
|
||||
nsEventTargetChainItem* item = targetEtci;
|
||||
while(item) {
|
||||
aTargets->AppendObject(item->CurrentTarget()->GetTargetForDOMEvent());
|
||||
item = item->mParent;
|
||||
}
|
||||
} else {
|
||||
// Event target chain is created. Handle the chain.
|
||||
nsEventChainPostVisitor postVisitor(preVisitor);
|
||||
rv = topEtci->HandleEventTargetChain(postVisitor,
|
||||
NS_EVENT_FLAG_BUBBLE |
|
||||
NS_EVENT_FLAG_CAPTURE,
|
||||
aCallback,
|
||||
PR_TRUE);
|
||||
|
||||
preVisitor.mEventStatus = postVisitor.mEventStatus;
|
||||
// If the DOM event was created during event flow.
|
||||
if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
|
||||
preVisitor.mDOMEvent = postVisitor.mDOMEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,9 @@
|
|||
#include "nsDOMJSUtils.h"
|
||||
#include "nsDOMScriptObjectHolder.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsEventListenerService.h"
|
||||
#include "nsDOMEvent.h"
|
||||
|
||||
#define EVENT_TYPE_EQUALS( ls, type, userType ) \
|
||||
(ls->mEventType && ls->mEventType == type && \
|
||||
|
|
@ -1383,6 +1386,74 @@ nsEventListenerManager::HasListeners()
|
|||
return !mListeners.IsEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(mTarget);
|
||||
NS_ENSURE_STATE(target);
|
||||
aList->Clear();
|
||||
PRUint32 count = mListeners.Length();
|
||||
for (PRUint32 i = 0; i < count; ++i) {
|
||||
const nsListenerStruct& ls = mListeners.ElementAt(i);
|
||||
PRBool capturing = !!(ls.mFlags & NS_EVENT_FLAG_CAPTURE);
|
||||
PRBool systemGroup = !!(ls.mGroupFlags & NS_EVENT_FLAG_SYSTEM_EVENT);
|
||||
PRBool allowsUntrusted = !!(ls.mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED);
|
||||
// If this is a script handler and we haven't yet
|
||||
// compiled the event handler itself
|
||||
if ((ls.mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && ls.mHandlerIsString) {
|
||||
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(ls.mListener);
|
||||
if (jslistener) {
|
||||
CompileEventHandlerInternal(jslistener->GetEventContext(),
|
||||
jslistener->GetEventScope(),
|
||||
jslistener->GetEventTarget(),
|
||||
ls.mTypeAtom,
|
||||
const_cast<nsListenerStruct*>(&ls),
|
||||
mTarget);
|
||||
}
|
||||
}
|
||||
if (ls.mTypeData) {
|
||||
// Handle special event listener interfaces, like nsIDOMFocusListener.
|
||||
for (PRInt32 j = 0; j < ls.mTypeData->numEvents; ++j) {
|
||||
const EventDispatchData* dispData = &(ls.mTypeData->events[j]);
|
||||
const char* eventName = nsDOMEvent::GetEventName(dispData->message);
|
||||
if (eventName) {
|
||||
NS_ConvertASCIItoUTF16 eventType(eventName);
|
||||
nsRefPtr<nsEventListenerInfo> info =
|
||||
new nsEventListenerInfo(eventType, ls.mListener, capturing,
|
||||
allowsUntrusted, systemGroup);
|
||||
NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
|
||||
aList->AppendObject(info);
|
||||
}
|
||||
}
|
||||
} else if (ls.mEventType == NS_USER_DEFINED_EVENT) {
|
||||
// Handle user defined event types.
|
||||
if (ls.mTypeAtom) {
|
||||
nsAutoString atomName;
|
||||
ls.mTypeAtom->ToString(atomName);
|
||||
const nsDependentSubstring& eventType =
|
||||
Substring(atomName, 2, atomName.Length() - 2);
|
||||
nsRefPtr<nsEventListenerInfo> info =
|
||||
new nsEventListenerInfo(eventType, ls.mListener, capturing,
|
||||
allowsUntrusted, systemGroup);
|
||||
NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
|
||||
aList->AppendObject(info);
|
||||
}
|
||||
} else {
|
||||
// Handle normal events.
|
||||
const char* eventName = nsDOMEvent::GetEventName(ls.mEventType);
|
||||
if (eventName) {
|
||||
NS_ConvertASCIItoUTF16 eventType(eventName);
|
||||
nsRefPtr<nsEventListenerInfo> info =
|
||||
new nsEventListenerInfo(eventType, ls.mListener, capturing,
|
||||
allowsUntrusted, systemGroup);
|
||||
NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
|
||||
aList->AppendObject(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEventListenerManager::HasUnloadListeners()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ public:
|
|||
|
||||
virtual PRBool HasListeners();
|
||||
|
||||
virtual nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
|
||||
|
||||
static PRUint32 GetIdentifierForEvent(nsIAtom* aEvent);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
|
|
|
|||
204
content/events/src/nsEventListenerService.cpp
Normal file
204
content/events/src/nsEventListenerService.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Olli Pettay <Olli.Pettay@helsinki.fi> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsEventListenerService.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIEventListenerManager.h"
|
||||
#include "nsPIDOMEventTarget.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsIJSEventListener.h"
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_1(nsEventListenerInfo, mListener)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEventListenerInfo)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(EventListenerInfo)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEventListenerInfo)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEventListenerInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerInfo::GetType(nsAString& aType)
|
||||
{
|
||||
aType = mType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerInfo::GetCapturing(PRBool* aCapturing)
|
||||
{
|
||||
*aCapturing = mCapturing;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerInfo::GetAllowsUntrusted(PRBool* aAllowsUntrusted)
|
||||
{
|
||||
*aAllowsUntrusted = mAllowsUntrusted;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerInfo::GetInSystemEventGroup(PRBool* aInSystemEventGroup)
|
||||
{
|
||||
*aInSystemEventGroup = mInSystemEventGroup;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsEventListenerService, nsIEventListenerService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerInfo::ToSource(nsAString& aResult)
|
||||
{
|
||||
aResult.SetIsVoid(PR_TRUE);
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
|
||||
if (wrappedJS) {
|
||||
JSObject* object = nsnull;
|
||||
wrappedJS->GetJSObject(&object);
|
||||
if (object) {
|
||||
nsCOMPtr<nsIThreadJSContextStack> stack =
|
||||
nsContentUtils::ThreadJSContextStack();
|
||||
if (stack) {
|
||||
JSContext* cx = nsnull;
|
||||
stack->GetSafeJSContext(&cx);
|
||||
if (cx && NS_SUCCEEDED(stack->Push(cx))) {
|
||||
JSAutoRequest ar(cx);
|
||||
jsval v = OBJECT_TO_JSVAL(object);
|
||||
JSString* str = JS_ValueToSource(cx, v);
|
||||
if (str) {
|
||||
aResult.Assign(nsDependentJSString(str));
|
||||
}
|
||||
stack->Pop(&cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
|
||||
if (jsl) {
|
||||
jsl->ToString(mType, aResult);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
|
||||
PRUint32* aCount,
|
||||
nsIEventListenerInfo*** aOutArray)
|
||||
{
|
||||
*aCount = 0;
|
||||
*aOutArray = nsnull;
|
||||
nsCOMArray<nsIEventListenerInfo> listenerInfos;
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(aEventTarget);
|
||||
if (target) {
|
||||
nsCOMPtr<nsIEventListenerManager> elm =
|
||||
target->GetListenerManager(PR_FALSE);
|
||||
if (elm) {
|
||||
elm->GetListenerInfo(&listenerInfos);
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 count = listenerInfos.Count();
|
||||
if (count == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aOutArray =
|
||||
static_cast<nsIEventListenerInfo**>(
|
||||
nsMemory::Alloc(sizeof(nsIEventListenerInfo*) * count));
|
||||
NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
NS_ADDREF((*aOutArray)[i] = listenerInfos[i]);
|
||||
}
|
||||
*aCount = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget,
|
||||
PRUint32* aCount,
|
||||
nsIDOMEventTarget*** aOutArray)
|
||||
{
|
||||
*aCount = 0;
|
||||
*aOutArray = nsnull;
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(aEventTarget);
|
||||
NS_ENSURE_ARG(target);
|
||||
nsEvent event(PR_TRUE, NS_EVENT_TYPE_NULL);
|
||||
nsCOMArray<nsPIDOMEventTarget> targets;
|
||||
nsresult rv = nsEventDispatcher::Dispatch(target, nsnull, &event,
|
||||
nsnull, nsnull, nsnull, &targets);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRInt32 count = targets.Count();
|
||||
if (count == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aOutArray =
|
||||
static_cast<nsIDOMEventTarget**>(
|
||||
nsMemory::Alloc(sizeof(nsPIDOMEventTarget*) * count));
|
||||
NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(targets[i]);
|
||||
(*aOutArray)[i] = target.forget().get();
|
||||
}
|
||||
*aCount = count;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewEventListenerService(nsIEventListenerService** aResult)
|
||||
{
|
||||
*aResult = new nsEventListenerService();
|
||||
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
76
content/events/src/nsEventListenerService.h
Normal file
76
content/events/src/nsEventListenerService.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Olli Pettay <Olli.Pettay@helsinki.fi> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsEventListenerService_h__
|
||||
#define nsEventListenerService_h__
|
||||
#include "nsIEventListenerService.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsString.h"
|
||||
#include "nsPIDOMEventTarget.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsEventListenerInfo : public nsIEventListenerInfo
|
||||
{
|
||||
public:
|
||||
nsEventListenerInfo(const nsAString& aType, nsIDOMEventListener* aListener,
|
||||
PRBool aCapturing, PRBool aAllowsUntrusted,
|
||||
PRBool aInSystemEventGroup)
|
||||
: mType(aType), mListener(aListener), mCapturing(aCapturing),
|
||||
mAllowsUntrusted(aAllowsUntrusted),
|
||||
mInSystemEventGroup(aInSystemEventGroup) {}
|
||||
virtual ~nsEventListenerInfo() {}
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsEventListenerInfo)
|
||||
NS_DECL_NSIEVENTLISTENERINFO
|
||||
protected:
|
||||
nsString mType;
|
||||
// nsReftPtr because that is what nsListenerStruct uses too.
|
||||
nsRefPtr<nsIDOMEventListener> mListener;
|
||||
PRPackedBool mCapturing;
|
||||
PRPackedBool mAllowsUntrusted;
|
||||
PRPackedBool mInSystemEventGroup;
|
||||
};
|
||||
|
||||
class nsEventListenerService : public nsIEventListenerService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEVENTLISTENERSERVICE
|
||||
};
|
||||
#endif
|
||||
|
|
@ -69,6 +69,7 @@ _TEST_FILES = \
|
|||
test_bug412567.html \
|
||||
test_bug443985.html \
|
||||
test_bug447736.html \
|
||||
test_bug448602.html \
|
||||
test_bug450876.html \
|
||||
test_bug456273.html \
|
||||
test_bug457672.html \
|
||||
|
|
|
|||
118
content/events/test/test_bug448602.html
Normal file
118
content/events/test/test_bug448602.html
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=448602
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 448602</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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=448602">Mozilla Bug 448602</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 448602 **/
|
||||
|
||||
|
||||
function runTests() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var els = Components.classes["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Components.interfaces.nsIEventListenerService);
|
||||
|
||||
// Event listener info tests
|
||||
var root = document.getElementById("testroot");
|
||||
var infos = els.getListenerInfoFor(root, {});
|
||||
is(infos.length, 0, "Element shouldn't have listeners (1)");
|
||||
|
||||
var listenerSource = 'alert(event);';
|
||||
root.setAttribute("onclick", listenerSource);
|
||||
infos = els.getListenerInfoFor(root, {});
|
||||
is(infos.length, 1, "Element should have listeners (1)");
|
||||
is(infos[0].toSource(), 'function onclick(event) {' + listenerSource + '}',
|
||||
"Unexpected serialization (1)");
|
||||
is(infos[0].type, "click", "Wrong type (1)");
|
||||
is(infos[0].capturing, false, "Wrong phase (1)");
|
||||
is(infos[0].allowsUntrusted, true, "Should allow untrusted events (1)");
|
||||
|
||||
root.removeAttribute("onclick");
|
||||
infos = els.getListenerInfoFor(root, {});
|
||||
is(infos.length, 0, "Element shouldn't have listeners (2)");
|
||||
|
||||
var l = function (e) { alert(e); };
|
||||
root.addEventListener("foo", l, true, true);
|
||||
root.addEventListener("foo", l, false, false);
|
||||
infos = els.getListenerInfoFor(root, {});
|
||||
is(infos.length, 2, "Element should have listeners (2)");
|
||||
is(infos[0].toSource(), "(function (e) {alert(e);})",
|
||||
"Unexpected serialization (2)");
|
||||
is(infos[0].type, "foo", "Wrong type (2)");
|
||||
is(infos[0].capturing, true, "Wrong phase (2)");
|
||||
is(infos[0].allowsUntrusted, true, "Should allow untrusted events (2)");
|
||||
is(infos[1].toSource(), "(function (e) {alert(e);})",
|
||||
"Unexpected serialization (3)");
|
||||
is(infos[1].type, "foo", "Wrong type (3)");
|
||||
is(infos[1].capturing, false, "Wrong phase (3)");
|
||||
is(infos[1].allowsUntrusted, false, "Shouldn't allow untrusted events (1)");
|
||||
|
||||
root.removeEventListener("foo", l, true);
|
||||
root.removeEventListener("foo", l, false);
|
||||
infos = els.getListenerInfoFor(root, {});
|
||||
is(infos.length, 0, "Element shouldn't have listeners (3)");
|
||||
|
||||
root.onclick = l;
|
||||
infos = els.getListenerInfoFor(root, {});
|
||||
is(infos.length, 1, "Element should have listeners (3)");
|
||||
is(infos[0].toSource(), '(function (e) {alert(e);})',
|
||||
"Unexpected serialization (4)");
|
||||
is(infos[0].type, "click", "Wrong type (4)");
|
||||
is(infos[0].capturing, false, "Wrong phase (4)");
|
||||
is(infos[0].allowsUntrusted, true, "Should allow untrusted events (3)");
|
||||
|
||||
// Event target chain tests
|
||||
var l2 = document.getElementById("testlevel2");
|
||||
var l3 = document.getElementById("testlevel3");
|
||||
var textnode = l3.firstChild;
|
||||
var chain = els.getEventTargetChainFor(textnode, {});
|
||||
ok(chain.length > 3, "Too short event target chain.");
|
||||
is(chain[0], textnode, "Wrong chain item (1)");
|
||||
is(chain[1], l3, "Wrong chain item (2)");
|
||||
is(chain[2], l2, "Wrong chain item (3)");
|
||||
is(chain[3], root, "Wrong chain item (4)");
|
||||
|
||||
var hasDocumentInChain = false;
|
||||
var hasWindowInChain = false;
|
||||
for (var i = 0; i < chain.length; ++i) {
|
||||
if (chain[i] == document) {
|
||||
hasDocumentInChain = true;
|
||||
} else if (chain[i] == window) {
|
||||
hasWindowInChain = true;
|
||||
}
|
||||
}
|
||||
|
||||
ok(hasDocumentInChain, "Should have document in event target chain!");
|
||||
ok(hasWindowInChain, "Should have window in event target chain!");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(runTests);
|
||||
</script>
|
||||
</pre>
|
||||
<div id="testroot">
|
||||
<div id="testlevel2">
|
||||
<div id="testlevel3">
|
||||
Test
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -465,6 +465,8 @@
|
|||
|
||||
#include "nsIDOMNSMouseEvent.h"
|
||||
|
||||
#include "nsIEventListenerService.h"
|
||||
|
||||
static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
||||
|
||||
static const char kDOMStringBundleURL[] =
|
||||
|
|
@ -1356,6 +1358,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
|
||||
NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
};
|
||||
|
||||
// Objects that shuld be constructable through |new Name();|
|
||||
|
|
@ -3764,6 +3768,10 @@ nsDOMClassInfo::Init()
|
|||
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(EventListenerInfo, nsIEventListenerInfo)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIEventListenerInfo)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
{
|
||||
PRUint32 i = NS_ARRAY_LENGTH(sClassInfoData);
|
||||
|
|
|
|||
|
|
@ -486,6 +486,8 @@ enum nsDOMClassInfoID {
|
|||
|
||||
eDOMClassInfo_ScrollAreaEvent_id,
|
||||
|
||||
eDOMClassInfo_EventListenerInfo_id,
|
||||
|
||||
// This one better be the last one in this list
|
||||
eDOMClassInfoIDCount
|
||||
};
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ class nsIDOMEventListener;
|
|||
class nsIAtom;
|
||||
|
||||
#define NS_IJSEVENTLISTENER_IID \
|
||||
{ 0xa6cf9118, 0x15b3, 0x11d2, \
|
||||
{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} }
|
||||
{ 0xe16e7146, 0x109d, 0x4f54, \
|
||||
{ 0x94, 0x78, 0xda, 0xc4, 0x3a, 0x71, 0x0b, 0x52 } }
|
||||
|
||||
// Implemented by script event listeners. Used to retrieve the
|
||||
// script object corresponding to the event target.
|
||||
|
|
@ -81,6 +81,8 @@ public:
|
|||
|
||||
virtual void SetEventName(nsIAtom* aName) = 0;
|
||||
|
||||
virtual void ToString(const nsAString& aEventName, nsAString& aResult) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~nsIJSEventListener()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,9 +51,9 @@
|
|||
#include "nsIMutableArray.h"
|
||||
#include "nsVariant.h"
|
||||
#include "nsIDOMBeforeUnloadEvent.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#include "nsPIDOMEventTarget.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#ifdef NS_DEBUG
|
||||
#include "nsDOMJSUtils.h"
|
||||
|
||||
#include "nspr.h" // PR_fprintf
|
||||
|
|
@ -140,6 +140,35 @@ nsJSEventListener::SetEventName(nsIAtom* aName)
|
|||
mEventName = aName;
|
||||
}
|
||||
|
||||
void
|
||||
nsJSEventListener::ToString(const nsAString& aEventName, nsAString& aResult)
|
||||
{
|
||||
aResult.Truncate();
|
||||
nsCOMPtr<nsIThreadJSContextStack> stack = nsContentUtils::ThreadJSContextStack();
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(mTarget);
|
||||
if (target && stack && mContext) {
|
||||
JSContext* cx = static_cast<JSContext*>(mContext->GetNativeContext());
|
||||
if (cx && NS_SUCCEEDED(stack->Push(cx))) {
|
||||
JSAutoRequest ar(cx);
|
||||
nsAutoString eventString = NS_LITERAL_STRING("on") + aEventName;
|
||||
nsCOMPtr<nsIAtom> atomName = do_GetAtom(eventString);
|
||||
nsScriptObjectHolder funcval(mContext);
|
||||
mContext->GetBoundEventHandler(mTarget, mScopeObject, atomName,
|
||||
funcval);
|
||||
jsval funval =
|
||||
OBJECT_TO_JSVAL(static_cast<JSObject*>(static_cast<void*>(funcval)));
|
||||
|
||||
JSString* str =
|
||||
JS_ValueToSource(static_cast<JSContext*>(mContext->GetNativeContext()),
|
||||
funval);
|
||||
if (str) {
|
||||
aResult.Assign(nsDependentJSString(str));
|
||||
}
|
||||
stack->Pop(&cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ public:
|
|||
// nsIJSEventListener interface
|
||||
virtual void SetEventName(nsIAtom* aName);
|
||||
|
||||
virtual void ToString(const nsAString& aEventName, nsAString& aResult);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSEventListener,
|
||||
nsIDOMEventListener)
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@
|
|||
#include "nsXULPopupManager.h"
|
||||
#include "nsFocusManager.h"
|
||||
|
||||
#include "nsIEventListenerService.h"
|
||||
// Transformiix stuff
|
||||
#include "nsXPathEvaluator.h"
|
||||
#include "txMozillaXSLTProcessor.h"
|
||||
|
|
@ -423,6 +424,8 @@ nsresult NS_NewXBLService(nsIXBLService** aResult);
|
|||
nsresult NS_NewContentPolicy(nsIContentPolicy** aResult);
|
||||
nsresult NS_NewDOMEventGroup(nsIDOMEventGroup** aResult);
|
||||
|
||||
nsresult NS_NewEventListenerService(nsIEventListenerService** aResult);
|
||||
|
||||
NS_IMETHODIMP NS_NewXULControllers(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
#define MAKE_CTOR(ctor_, iface_, func_) \
|
||||
|
|
@ -523,6 +526,7 @@ MAKE_CTOR(CreateXTFService, nsIXTFService, NS_NewXTF
|
|||
MAKE_CTOR(CreateXMLContentBuilder, nsIXMLContentBuilder, NS_NewXMLContentBuilder)
|
||||
#endif
|
||||
MAKE_CTOR(CreateContentDLF, nsIDocumentLoaderFactory, NS_NewContentDocumentLoaderFactory)
|
||||
MAKE_CTOR(CreateEventListenerService, nsIEventListenerService, NS_NewEventListenerService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWyciwygProtocolHandler)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsContentAreaDragDrop)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDataDocumentContentPolicy)
|
||||
|
|
@ -1443,12 +1447,16 @@ static const nsModuleComponentInfo gComponents[] = {
|
|||
"@mozilla.org/geolocation/service;1",
|
||||
nsGeolocationServiceConstructor },
|
||||
|
||||
{ "Focus Manager",
|
||||
NS_FOCUSMANAGER_CID,
|
||||
"@mozilla.org/focus-manager;1",
|
||||
CreateFocusManager },
|
||||
|
||||
|
||||
{ "Focus Manager",
|
||||
NS_FOCUSMANAGER_CID,
|
||||
"@mozilla.org/focus-manager;1",
|
||||
CreateFocusManager },
|
||||
{ "Event Listener Service",
|
||||
NS_EVENTLISTENERSERVICE_CID,
|
||||
NS_EVENTLISTENERSERVICE_CONTRACTID,
|
||||
CreateEventListenerService }
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE_WITH_CTOR(nsLayoutModule, gComponents, Initialize)
|
||||
|
|
|
|||
Loading…
Reference in a new issue