Bug 484775 - DocumentFragments and Attribute nodes should expose nsIDOMEventTarget to JS, r+sr=peterv

--HG--
extra : rebase_source : 7bce078904782a5a907eebbbff7b74a905cfa8c1
This commit is contained in:
Olli Pettay 2009-05-07 16:59:51 +03:00
parent 99bd11faa6
commit 4ade0eee29
9 changed files with 111 additions and 46 deletions

View File

@ -42,7 +42,6 @@
#include "nsCaseTreatment.h"
#include "nsChangeHint.h"
#include "nsINode.h"
#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
// Forward declarations
class nsIAtom;
@ -64,8 +63,8 @@ class nsISMILAttr;
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0x48cb2d6d, 0x9ccc, 0x4d0b, \
{ 0x8c, 0x07, 0x29, 0x96, 0xb5, 0xf9, 0x68, 0x55 } }
{ 0x3ca5afbe, 0x1052, 0x4682, \
{ 0x9f, 0xa0, 0x0e, 0x39, 0xe4, 0xf8, 0xef, 0x9d } }
/**
* A node of content in a document's content model. This interface
@ -755,19 +754,6 @@ public:
// PRInt32. We should really use PRUint32 instead.
virtual PRInt32 IntrinsicState() const;
/* The default script type (language) ID for this content.
All content must support fetching the default script language.
*/
virtual PRUint32 GetScriptTypeID() const
{ return nsIProgrammingLanguage::JAVASCRIPT; }
/* Not all content supports setting a new default language */
virtual nsresult SetScriptTypeID(PRUint32 aLang)
{
NS_NOTREACHED("SetScriptTypeID not implemented");
return NS_ERROR_NOT_IMPLEMENTED;
}
/**
* Get the ID of this content node (the atom corresponding to the
* value of the null-namespace attribute whose name is given by

View File

@ -45,6 +45,7 @@
#include "nsINodeInfo.h"
#include "nsCOMPtr.h"
#include "nsWrapperCache.h"
#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
class nsIContent;
class nsIDocument;
@ -239,8 +240,8 @@ private:
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x7bccc9bd, 0x30eb, 0x47c0, \
{ 0x8b, 0xc7, 0x6f, 0x19, 0x75, 0xc8, 0xe7, 0xd7 } }
{ 0xfc22c6df, 0x3e8e, 0x47c3, \
{ 0x96, 0xa6, 0xaf, 0x14, 0x3c, 0x05, 0x88, 0x68 } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -862,6 +863,21 @@ public:
nsIContent* const * mEnd;
};
/**
* The default script type (language) ID for this node.
* All nodes must support fetching the default script language.
*/
virtual PRUint32 GetScriptTypeID() const
{ return nsIProgrammingLanguage::JAVASCRIPT; }
/**
* Not all nodes support setting a new default language.
*/
NS_IMETHOD SetScriptTypeID(PRUint32 aLang)
{
NS_NOTREACHED("SetScriptTypeID not implemented");
return NS_ERROR_NOT_IMPLEMENTED;
}
protected:
// Override this function to create a custom slots class.

View File

@ -111,6 +111,12 @@ NS_INTERFACE_TABLE_HEAD(nsDOMAttribute)
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttribute)
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
new nsNodeSupportsWeakRefTearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
nsDOMEventRTTearoff::Create(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3EventTarget,
nsDOMEventRTTearoff::Create(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSEventTarget,
nsDOMEventRTTearoff::Create(this))
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Attr)
NS_INTERFACE_MAP_END
@ -731,8 +737,7 @@ nsDOMAttribute::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
nsresult
nsDOMAttribute::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
// We don't support event dispatching to attributes yet.
aVisitor.mCanHandle = PR_FALSE;
aVisitor.mCanHandle = PR_TRUE;
return NS_OK;
}
@ -747,7 +752,9 @@ nsDOMAttribute::DispatchDOMEvent(nsEvent* aEvent, nsIDOMEvent* aDOMEvent,
nsPresContext* aPresContext,
nsEventStatus* aEventStatus)
{
return NS_ERROR_NOT_IMPLEMENTED;
return nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode*>(this),
aEvent, aDOMEvent,
aPresContext, aEventStatus);
}
nsresult

View File

@ -1536,8 +1536,8 @@ nsDOMEventRTTearoff::mCachedEventTearoff[NS_EVENT_TEAROFF_CACHE_SIZE];
PRUint32 nsDOMEventRTTearoff::mCachedEventTearoffCount = 0;
nsDOMEventRTTearoff::nsDOMEventRTTearoff(nsIContent *aContent)
: mContent(aContent)
nsDOMEventRTTearoff::nsDOMEventRTTearoff(nsINode *aNode)
: mNode(aNode)
{
}
@ -1545,13 +1545,13 @@ nsDOMEventRTTearoff::~nsDOMEventRTTearoff()
{
}
NS_IMPL_CYCLE_COLLECTION_1(nsDOMEventRTTearoff, mContent)
NS_IMPL_CYCLE_COLLECTION_1(nsDOMEventRTTearoff, mNode)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventRTTearoff)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
NS_INTERFACE_MAP_END_AGGREGATED(mContent)
NS_INTERFACE_MAP_END_AGGREGATED(mNode)
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMEventRTTearoff,
nsIDOMEventTarget)
@ -1560,7 +1560,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsDOMEventRTTearoff,
LastRelease())
nsDOMEventRTTearoff *
nsDOMEventRTTearoff::Create(nsIContent *aContent)
nsDOMEventRTTearoff::Create(nsINode *aNode)
{
if (mCachedEventTearoffCount) {
// We have cached unused instances of this class, return a cached
@ -1569,13 +1569,13 @@ nsDOMEventRTTearoff::Create(nsIContent *aContent)
mCachedEventTearoff[--mCachedEventTearoffCount];
// Set the back pointer to the content object
tearoff->mContent = aContent;
tearoff->mNode = aNode;
return tearoff;
}
// The cache is empty, this means we haveto create a new instance.
return new nsDOMEventRTTearoff(aContent);
return new nsDOMEventRTTearoff(aNode);
}
// static
@ -1600,8 +1600,8 @@ nsDOMEventRTTearoff::LastRelease()
// could result in code that grabs a tearoff from the cache and we don't
// want to get reused while still being torn down.
// See bug 330526.
nsCOMPtr<nsIContent> kungFuDeathGrip;
kungFuDeathGrip.swap(mContent);
nsCOMPtr<nsINode> kungFuDeathGrip;
kungFuDeathGrip.swap(mNode);
// The refcount balancing and destructor re-entrancy protection
// code in Release() sets mRefCnt to 1 so we have to set it to 0
@ -1619,7 +1619,7 @@ nsDOMEventRTTearoff::GetDOM3EventTarget(nsIDOM3EventTarget **aTarget)
{
nsCOMPtr<nsIEventListenerManager> listener_manager;
nsresult rv =
mContent->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
mNode->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(listener_manager, aTarget);
@ -1628,14 +1628,14 @@ nsDOMEventRTTearoff::GetDOM3EventTarget(nsIDOM3EventTarget **aTarget)
NS_IMETHODIMP
nsDOMEventRTTearoff::GetScriptTypeID(PRUint32 *aLang)
{
*aLang = mContent->GetScriptTypeID();
return NS_OK;
*aLang = mNode->GetScriptTypeID();
return NS_OK;
}
NS_IMETHODIMP
nsDOMEventRTTearoff::SetScriptTypeID(PRUint32 aLang)
{
return mContent->SetScriptTypeID(aLang);
return mNode->SetScriptTypeID(aLang);
}
@ -1647,7 +1647,7 @@ nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
{
return
AddEventListener(aType, aListener, useCapture,
!nsContentUtils::IsChromeDoc(mContent->GetOwnerDoc()));
!nsContentUtils::IsChromeDoc(mNode->GetOwnerDoc()));
}
NS_IMETHODIMP
@ -1663,7 +1663,7 @@ nsDOMEventRTTearoff::DispatchEvent(nsIDOMEvent *aEvt, PRBool* _retval)
{
nsCOMPtr<nsIEventListenerManager> listener_manager;
nsresult rv =
mContent->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
mNode->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(listener_manager);
NS_ENSURE_STATE(target);
@ -1720,7 +1720,7 @@ nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
{
nsCOMPtr<nsIEventListenerManager> listener_manager;
nsresult rv =
mContent->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
mNode->GetListenerManager(PR_TRUE, getter_AddRefs(listener_manager));
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
@ -3198,7 +3198,7 @@ nsGenericElement::GetScriptTypeID() const
return (flags >> NODE_SCRIPT_TYPE_OFFSET) & 0x000F;
}
nsresult
NS_IMETHODIMP
nsGenericElement::SetScriptTypeID(PRUint32 aLang)
{
if ((aLang & 0x000F) != aLang) {

View File

@ -249,7 +249,7 @@ private:
// nsDOMEventRTTearoff::Create(). That's why the constructor and
// destrucor of this class is private.
nsDOMEventRTTearoff(nsIContent *aContent);
nsDOMEventRTTearoff(nsINode *aNode);
static nsDOMEventRTTearoff *mCachedEventTearoff[NS_EVENT_TEAROFF_CACHE_SIZE];
static PRUint32 mCachedEventTearoffCount;
@ -270,7 +270,7 @@ public:
* Use this static method to create instances of nsDOMEventRTTearoff.
* @param aContent the content to create a tearoff for
*/
static nsDOMEventRTTearoff *Create(nsIContent *aContent);
static nsDOMEventRTTearoff *Create(nsINode *aNode);
/**
* Call before shutdown to clear the cache and free memory for this class.
@ -297,7 +297,7 @@ private:
* Strong reference back to the content object from where an instance of this
* class was 'torn off'
*/
nsCOMPtr<nsIContent> mContent;
nsCOMPtr<nsINode> mNode;
};
/**
@ -426,7 +426,7 @@ public:
virtual PRBool MayHaveFrame() const;
virtual PRUint32 GetScriptTypeID() const;
virtual nsresult SetScriptTypeID(PRUint32 aLang);
NS_IMETHOD SetScriptTypeID(PRUint32 aLang);
virtual void DestroyContent();
virtual void SaveSubtreeState();

View File

@ -1284,15 +1284,15 @@ nsEventListenerManager::RemoveEventListener(const nsAString& aType,
NS_IMETHODIMP
nsEventListenerManager::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
{
nsCOMPtr<nsIContent> targetContent(do_QueryInterface(mTarget));
if (!targetContent) {
nsCOMPtr<nsINode> targetNode(do_QueryInterface(mTarget));
if (!targetNode) {
// nothing to dispatch on -- bad!
return NS_ERROR_FAILURE;
}
// XXX sXBL/XBL2 issue -- do we really want the owner here? What
// if that's the XBL document? Would we want its presshell? Or what?
nsCOMPtr<nsIDocument> document = targetContent->GetOwnerDoc();
nsCOMPtr<nsIDocument> document = targetNode->GetOwnerDoc();
// Do nothing if the element does not belong to a document
if (!document) {
@ -1308,7 +1308,7 @@ nsEventListenerManager::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
nsEventStatus status = nsEventStatus_eIgnore;
nsresult rv =
nsEventDispatcher::DispatchDOMEvent(targetContent, nsnull, aEvent,
nsEventDispatcher::DispatchDOMEvent(targetNode, nsnull, aEvent,
context, &status);
*_retval = (status != nsEventStatus_eConsumeNoDefault);
return rv;

View File

@ -2050,6 +2050,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDocumentFragment)
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Element, nsIDOMElement)
@ -2064,6 +2065,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMAttr)
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Attr)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Text, nsIDOMText)

View File

@ -97,6 +97,7 @@ _TEST_FILES = \
iframe_bug463000.html \
test_bug465263.html \
test_bug479143.html \
test_bug484775.html \
test_bug427744.html \
$(NULL)

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=484775
-->
<head>
<title>Test for Bug 484775</title>
<script type="application/javascript" src="/MochiKit/MochiKit.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=484775">Mozilla Bug 484775</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 484775 **/
var expectedTarget = null;
var expectedType = null;
var eventCount = 0;
function listener(evt) {
++eventCount;
ok(evt.type, expectedType, "Wrong event type!");
ok(evt.target, expectedTarget, "Wrong event type!");
}
expectedType = "TestEvent";
var event = document.createEvent("Event");
event.initEvent(expectedType, true, true);
ok(event.type, expectedType, "Wrong event type!");
var attr = document.createAttribute("attribute");
attr.addEventListener(expectedType, listener, false);
attr.dispatchEvent(event);
is(eventCount, 1, "Should have fired an event!");
attr.removeEventListener(expectedType, listener, false);
var df = document.createDocumentFragment();
df.addEventListener(expectedType, listener, false);
df.dispatchEvent(event);
is(eventCount, 2, "Should have fired an event!");
df.removeEventListener(expectedType, listener, false);
</script>
</pre>
</body>
</html>