Closed Bug 164482 (XMLEvents) Opened 22 years ago Closed 20 years ago

Tracking: XML Events

Categories

(Core :: DOM: Events, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: mdubinko, Assigned: smaug)

References

()

Details

(Keywords: helpwanted)

Attachments

(1 file, 5 obsolete files)

"XML Events" is a W3C specification to provide XML languages with the ability to
integrate declarative event listeners and event handlers.

This is a core technology needed by XHTML 2.0 and XForms. In the future, SVG and
SMIL will possibly adopt this technique also.
Blocks: xhtml2
Blocks: xforms
The XBL implementation also uses declarative events, and that code could be reused to 
implement XML events in about 2-3 hours. :)
Any XBL hackers out there willing to write a prototype?
xah:  I don't see how we can get this in for Mozilla 1.3, considering XML 
Events is still a W3C Working Draft...  I think it's extremely premature to add 
the mozilla1.3 keyword at this stage.
Right! Thanks.
Keywords: mozilla1.3
:) W3C has advanced XML Events to Candidate Rec.  To exit that stage, it needs a
working implementation which doesn't rely on XForms.

I'm willing to consider helping to develop this (I've been having a lot of fun
with XBL lately).  I don't think I could quite do it in "2-3 hours"...
I may not be able to do this properly after all.  The ev:listener element is
totally optional.  I could bind to that, but not to all Element nodes, at least
not in a way which I'd expect m.o to accept.
ajvincent:

In the absense of an ev:listener element, the minimum you need is an ev:event
attribute on an element. So a stylesheet to set up the binding properly could
look something like:

@namespace url("http://www.w3.org/2001/xml-events"); 

listener,
*[event] {
  -moz-binding: url(xml-events.xml#listener);
}


This will attach the binding to any ev:listener element or any element with the
ev:event attribute, which is exactly what is needed.

I've just finished off a Java implementation of XML Events and was thinking of
having a shot at this as well, if you want a hand with anything then please let
me know as I'd be happy to help - XML Events support in Moz would rock.
Not good enough.  

(1) You'd need a CSS @namespace rule (it's a Mozilla-specific rule) for the 
ev:listener element, and that would have to be in a separate CSS stylesheet 
than the generic approach you're talking.

(2) If you use a -moz-binding property on the more generic one, it will 
override any other -moz-binding which would normally exist on the element.  
This is really, really bad.

I already thought of that.
> (1) You'd need a CSS @namespace rule

Like the one above? :)

> (2) If you use a -moz-binding property on the more generic one, it will 
> override any other -moz-binding which would normally exist on the element.  

Ah yes, you're right.

I played around with document.addBinding(), but that mostly seems to make Moz
crash. Perhaps getting a custom event fired when XML Event elements/attrs are
found (like the way the link toolbar works) might be a solution - although that
seems like a pretty big hack.
Actually, I figured out a way to do the observer strictly with XBL.  We only
need to have <xbl:element/> enabled.  (Bug 98712)

[ev|event], [ev|xbl_binding] {
  -moz-binding("events.xml#missingListener");
}

<binding id="missingListener">
  <content>
    <ev:listener/>
    <element/>
  </content>
  <implementation>
    <constructor><![CDATA[
        this.setAttributeNS("http://www.w3.org/2001/xml-events", "xbl_binding",
"previousAnonymousNode");
        var listenerNode = document.getAnonymousNodes(this)[0];
        for (var j = 0; j < this.attributes.length; j++) {
          var attr = this.attributes.item(j);
          if ((attr.namespaceURI ==
"http://www.w3.org/2001/xml-events")&&(attr.localName != "xbl_binding")) {
            this.removeAttributeNode(attr);
            listenerNode.setAttribute(attr.localName, attr.nodeValue);
          }
        }
    ]]></constructor>
  </implementation>
</binding>

What that would do is create for <node ev:event="foo" bar="baz"><child1/></node>
is the following tree:

<node bar="baz" ev:xbl_binding="previousAnonymousNode">
  <ev:listener event="foo"/>
  <child1/>
</node>

The ev:xbl_binding attribute makes sure the binding remains in force despite
removal of other XML Events attributes.

That handles sections 3.1 and 3.2; what are we going to do about section 3.3? 
3.3.1, examples 1 and 3, look like something we've tried hard to avoid, namely,
IE's approach to events.
Bug 204961, if it's valid, may give a solution for XML Events handlers.
XML Events are now a W3C recommendation:
<http://www.w3.org/TR/2003/REC-xml-events-20031014/>, any chance this is going
to work soon?
.
Assignee: joki → events
Depends on: 204961
QA Contact: vladimire → ian
This can happen only with some traction on bugs that block this bug.  However, I
am not sure bug 204961 blocks this bug, given Hixie's final comment there.  How
about bug 98712, should that be a blocker of this bug?

/be
I don't know of any bugs that would block us from implementing XML Events.

XML Events should be implemented natively (possibly using code very similar to 
XBL's, according to Hyatt). XML Events shouldn't be implemented using XBL.
No longer depends on: 204961
Assignee: events → smaug
Reassigned bug to show that we are active on the bug.  Already working on a test
implementation (native) with Smaug and Sicking.
Pretty much everything should be implemented.
But this needs *testing* and also some clarifications from HTML/XML Events WG.
Some testcases: http://www.cs.helsinki.fi/u/pettay/moztests/xmlevents/
The patch does not work with XUL or SVG elements.
Sorry the spam. 
I meant to say that XML Events can't be defined inside XUL/SVG elements. 
But using for example <xe:listener/> -element it is possible to
bind listeners/handlers to XUL elements.
Comment on attachment 146976 [details] [diff] [review]
The current (test?) implementation. 

This is an unsolicited code review from the perspective of someone who knows
XML Events from the QA perspective, but doesn't know much about our code base
at all. Apologies for the many misunderstandings I'm sure to have about what
your code did.

Overall comment: You need more comments, preferably pointing to specific
sections of the XML Events spec at appropriate points to explain what is going
on and why. (I don't mean comment every line, just give the reader an overview
of what blocks of code are doing so that you don't have to be an XML Events
expert to work it out.)


>+  void Unfinish();

Could you put some comments somewhere explaining what "finished" means in this
context? It isn't clear in an initial reading.


>+  if (nameSpaceID == kNameSpaceID_XMLEvents) //for <xe:listener/>
>+    nameSpaceID = kNameSpaceID_None;
>+  else
>+    nameSpaceID = kNameSpaceID_XMLEvents;

It didn't look like you ever actually checked that it was an XML Events
"listener" element.

The following:

   <ev:handler event=""> ... </ev:handler>

...shouldn't do _anything_ in this implementation, especially not be treated as
an <ev:listener>.


>+    if (aContent->HasAttr(nameSpaceID, nsHTMLAtoms::handler)) {
>+      aContent->GetAttr(nameSpaceID, nsHTMLAtoms::handler, handlerURI);
>+      if (handlerURI.IsEmpty())
>+        return PR_FALSE;

Why do you bail if the handler attribute is empty? If the handler attribute is
empty, that means that the handler is the entire document (assuming the baseURI
at that point is the current document).


>+    if (aContent->HasAttr(nameSpaceID, nsHTMLAtoms::target)) {
>+      aContent->GetAttr(nameSpaceID, nsHTMLAtoms::target, targetIdref);
>+      if (targetIdref.IsEmpty())
>+        return PR_FALSE;

Again, why bail if it is empty? As far as I can tell, if it is blank, that
means the event target must also have a blank ID (although the spec is not
overly clear about this).


>+    if (!hasObserver) {
	...
>+    }
>+    else {
	...
>+        doc->GetElementById(observerID, getter_AddRefs(el));

This won't work because the XML Events node might be added or removed before or
after the element with the ID. Basically when "observer" is set you will have
to track all changes to IDs in the document in order to make sure you are
tracking which element you are supposed to be listening to. (As far as I can
tell from the extremely vague and underspecified spec.)


>+    if (target) {
>+      nsCOMPtr<nsIDOMEventTarget> eventTarget = ...

Again, the way to handle "target" is to check, whenever the event listener is
fired, whether the target actually has the correct ID, and to only run the
event handler _if_ it has that ID. This attribute should not, IMHO, have any
effect on the registration part.

Note in particular that the _target_ has nothing to do with the _observer_
which is the node you want to be registering the event upon.


>+            aManager->RemoveXMLEventsContent(aContent);

Could you explain what this does? (And why?)


>+  if (mStopPropagation)
>+    aEvent->StopPropagation();
>+  if (mCancelDefault)
>+    aEvent->PreventDefault();

From the spec, I think this should be done _after_ the event handler code is
fired. But the spec is a bit vague. (It does make a difference since you can
tell whether the event is cancelled or not from script.)


>+        if (!mHandler.IsEmpty() && StringBeginsWith(mHandler, NS_LITERAL_STRING("#")))
>+            doc->GetElementById(Substring(mHandler, 1, mHandler.Length() -1 ), 
>+                                getter_AddRefs(domhandler));

This is wrong. The fragment identifier need not be present, the fragment
identifier might not be an ID (it depends on the document type, e.g. it could
be XPointer), the above doesn't handle xml:base and other base URI changing
features, the above wouldn't handle the case where the given URI is the URI of
the current document with a fragment identifier on the end, etc.

It also doesn't handle the important case of having the event handler be in a
completely different document, e.g. for event handler reuse.


>+  if (aNameSpaceID == kNameSpaceID_XMLEvents) {
>+    XMLEventsListener::InitXMLEventsListener(aDocument, this, aContent);
>+  }

Will this unregister event handlers on previous nodes as appropriate?


>+    //Is this right, if the ID attribute is not in the empty namespace?

Elements can have one ID, it shouldn't matter if that ID is from a namespaced
attribute (e.g. <foo xml:id="">) or from a non namespaced one (e.g. <html:foo
id="">).

It wasn't completely clear from the code but I assume this section is checking
to see if the element specified by observer="" is having its ID changed?


>+  // Check whether we should be executing the script
>+  nsCOMPtr<nsIContent> el(do_QueryInterface(aElement));
>+  if (el && el->HasAttr(kNameSpaceID_None, nsHTMLAtoms::declare))
>+    return FireErrorNotification(NS_ERROR_NOT_AVAILABLE, aElement, aObserver);

This seems non-compliant, but I'm not sure. What is the "declare" attribute?


>+  const char *gEventArgv[] = {"event"};

Why "event"?


>+ * The Initial Developer of the Original Code is
>+ * Netscape Communications Corporation.

This should be you.
This is still just a test implementation, nothing to review actually.
But thank you Hixie for your comments!

Currently my idea is to not to support external
handler (~The Basic XML Events Profile).
Is that reasonable?

BTW. one huge bug, load/unload events :(
The load/unload is a bug in Mozilla.
Those events use wrong target.
> ------- Additional Comments From ian@hixie.ch  2004-04-25 07:18 PDT -------
> (From update of attachment 146976 [details] [diff] [review])
> This is an unsolicited code review from the perspective of someone who knows
> XML Events from the QA perspective, but doesn't know much about our code base
> at all. Apologies for the many misunderstandings I'm sure to have about what
> your code did.
> 
> Overall comment: You need more comments, preferably pointing to specific
> sections of the XML Events spec at appropriate points to explain what is going
> on and why. (I don't mean comment every line, just give the reader an overview
> of what blocks of code are doing so that you don't have to be an XML Events
> expert to work it out.)

I know. Comment, comments...

> 
> 
> 
>>+  void Unfinish();
> 
> 
> Could you put some comments somewhere explaining what "finished" means in this
> context? It isn't clear in an initial reading.

XML Events Listener is not 'finished' if it cannot be registered to any 
observer. For example if the observer does not exist yet or anymore.
XMLEventsManager has a list of (unfinished) elements which contains XML Events
declarations.
I'll change the name of the function, maybe SetIncomplete

> 
> 
> 
>>+  if (nameSpaceID == kNameSpaceID_XMLEvents) //for <xe:listener/>
>>+    nameSpaceID = kNameSpaceID_None;
>>+  else
>>+    nameSpaceID = kNameSpaceID_XMLEvents;
> 
> 
> It didn't look like you ever actually checked that it was an XML Events
> "listener" element.
> 
> The following:
> 
>    <ev:handler event=""> ... </ev:handler>
> 
> ...shouldn't do _anything_ in this implementation, especially not be treated
> as
> an <ev:listener>.

This is a bug or feature. Where does it read that it should not work that
way?

> 
> 
> 
>>+    if (aContent->HasAttr(nameSpaceID, nsHTMLAtoms::handler)) {
>>+      aContent->GetAttr(nameSpaceID, nsHTMLAtoms::handler, handlerURI);
>>+      if (handlerURI.IsEmpty())
>>+        return PR_FALSE;
> 
> 
> Why do you bail if the handler attribute is empty? If the handler attribute is
> empty, that means that the handler is the entire document (assuming the 
> baseURI
> at that point is the current document).
> 
Oh, I haven't think about having the whole document as a handler.

> 
> 
>>+    if (aContent->HasAttr(nameSpaceID, nsHTMLAtoms::target)) {
>>+      aContent->GetAttr(nameSpaceID, nsHTMLAtoms::target, targetIdref);
>>+      if (targetIdref.IsEmpty())
>>+        return PR_FALSE;
> 
> 
> Again, why bail if it is empty? As far as I can tell, if it is blank, that
> means the event target must also have a blank ID (although the spec is not
> overly clear about this).

The ID should be "(Letter | '_' | ':') (NameChar)*"

> 
> 
> 
>>+    if (!hasObserver) {
> 
> 	...
> 
>>+    }
>>+    else {
> 
> 	...
> 
>>+        doc->GetElementById(observerID, getter_AddRefs(el));
> 
> 
> This won't work because the XML Events node might be added or removed before 
> or
> after the element with the ID. Basically when "observer" is set you will have
> to track all changes to IDs in the document in order to make sure you are
> tracking which element you are supposed to be listening to. (As far as I can
> tell from the extremely vague and underspecified spec.)

This implementation is actually trying to track all the changes to the IDs.
That is the reason why the XMLEventsManager is a nsIDocumentObserver.

> 
> 
> 
>>+    if (target) {
>>+      nsCOMPtr<nsIDOMEventTarget> eventTarget = ...
> 
> 
> Again, the way to handle "target" is to check, whenever the event listener is
> fired, whether the target actually has the correct ID, and to only run the
> event handler _if_ it has that ID. This attribute should not, IMHO, have any
> effect on the registration part.
> 

You are missreading my poorly selected variable names.
That target is actually observer ;)

> Note in particular that the _target_ has nothing to do with the _observer_
> which is the node you want to be registering the event upon.
> 
> 
> 
>>+            aManager->RemoveXMLEventsContent(aContent);
> 
> 
> Could you explain what this does? (And why?)
> 

If the XML Events declaration was registered to some other EventTarget, 
this function call removes it. I should change the function name

> 
> 
>>+  if (mStopPropagation)
>>+    aEvent->StopPropagation();
>>+  if (mCancelDefault)
>>+    aEvent->PreventDefault();
> 
> 
> From the spec, I think this should be done _after_ the event handler code is
> fired. But the spec is a bit vague. (It does make a difference since you can
> tell whether the event is cancelled or not from script.)
> 

Well, this is not specified anywhere, the script handlers are not specified at all.

3.5.Event Handlers
"
...
It is however recognized that two methods are likely to occur often: scripting 
(such as XHTML's <script> element) and declarative markup using XML elements 
(such as WML's <onevent> element). A companion specification will provide markup 
to support these methods."

I haven't see that 'companion specification'.


> 
> 
>>+        if (!mHandler.IsEmpty() && StringBeginsWith(mHandler, 
>>NS_LITERAL_STRING("#")))
>>+            doc->GetElementById(Substring(mHandler, 1, mHandler.Length() -1 ), 
>>+                                getter_AddRefs(domhandler));
> 
> 
> This is wrong. The fragment identifier need not be present, the fragment
> identifier might not be an ID (it depends on the document type, e.g. it could
> be XPointer), the above doesn't handle xml:base and other base URI changing
> features, the above wouldn't handle the case where the given URI is the URI of
> the current document with a fragment identifier on the end, etc.
> 
> It also doesn't handle the important case of having the event handler be in a
> completely different document, e.g. for event handler reuse.

this is a kind of XML Events basic, it is only possible to use handlers which
are defined within the same document.
(That XPointer sounds interesting.)
I'd like to implement also some kind of inline script handler, maybe:
<xe:listener event="click" observer="some_id" 
handler="javascript:doSomething();"/>


> 
> 
> 
>>+  if (aNameSpaceID == kNameSpaceID_XMLEvents) {
>>+    XMLEventsListener::InitXMLEventsListener(aDocument, this, aContent);
>>+  }
> 
> 
> Will this unregister event handlers on previous nodes as appropriate?

Yes.

> 
> 
> 
>>+    //Is this right, if the ID attribute is not in the empty namespace?
> 
> 
> Elements can have one ID, it shouldn't matter if that ID is from a namespaced
> attribute (e.g. <foo xml:id="">) or from a non namespaced one (e.g. <html:foo
> id="">).
> 

Actually that was a comment related to the nsIContent's GetIDAttributeName().
It returns only an nsIAtom, not namespace + localname.

> It wasn't completely clear from the code but I assume this section is checking
> to see if the element specified by observer="" is having its ID changed?

Yes.

> 
> 
> 
>>+  // Check whether we should be executing the script
>>+  nsCOMPtr<nsIContent> el(do_QueryInterface(aElement));
>>+  if (el && el->HasAttr(kNameSpaceID_None, nsHTMLAtoms::declare))
>>+    return FireErrorNotification(NS_ERROR_NOT_AVAILABLE, aElement, 
>>aObserver);
> 
> 
> This seems non-compliant, but I'm not sure. What is the "declare" attribute?

From XHTML 2.0. It is needed to prevent the execution of the handler scripts
during pageload.

> 
> 
> 
>>+  const char *gEventArgv[] = {"event"};
> 
> 
> Why "event"?

Also used in "HTML events", at least in Mozilla.

> 
> 
> 
>>+ * The Initial Developer of the Original Code is
>>+ * Netscape Communications Corporation.
> 
> 
> This should be you.

I just copy-pasted something ;)


Just wanted you guys to know about bug 238773, which's about refactoring  
nsDOMEvent and adding DOM 3 events. DOM 3 events use the XML events namespace,  
so in this regard, our goals are similar. Wonder how many conflict we'll  
have :)  
Here is the latest patch. 
The load/unload events do not work due the bug 99820.
Not so clean testcases can be found in
http://www.cs.helsinki.fi/u/pettay/moztests/xmlevents/

It is not defined in any specification how the <script> element should
work with XML Events. This patch is using syntax from X+V 
http://www.voicexml.org/specs/multimodal/x+v/12/index.html.

Steven Pemberton:
"The 'declare="declare"' trick was more a way of making HTML script
elements sort-of work with XML Events, but it isn't pretty. That is why the
XML Handlers spec needs to be finished to properly support <script> with XML
Events."

We could also leave out the <script> handlers, and add only the support
for handlers which implement the nsIDOMXMLEventsHandler. This way it could be
possible to start to create some kind (probably XBL based) implementation of
the XForms Basic.

This implementation supports dynamic attribute changes so that
it is possible to add, modify and remove XML Events declaration using 
JavaScript/DOM. This is also a feature which is not specified anywhere.
Attachment #146976 - Attachment is obsolete: true
Attachment #151007 - Flags: review?(jst)
Comment on attachment 151007 [details] [diff] [review]
First patch for review and comments.

These are some things I noticed.  jst may have some additional comments.

>--- content/base/src/nsDocument.h	27 May 2004 22:08:36 -0000	3.233
>+++ content/base/src/nsDocument.h	10 Jun 2004 18:33:15 -0000
>@@ -562,16 +564,17 @@
> 
>   nsSupportsHashtable* mBoxObjectTable;
> 
>   nsSupportsHashtable mContentWrapperHash;
> 
>   nsCOMPtr<nsICSSLoader> mCSSLoader;
>   nsRefPtr<nsHTMLStyleSheet> mAttrStyleSheet;
>   nsCOMPtr<nsIHTMLCSSStyleSheet> mStyleAttrStyleSheet;
>+  nsCOMPtr<nsXMLEventsManager> mXMLEventsManager;

You should use nsRefPtr here since this is a concrete class pointer.

>--- content/base/src/nsDocument.cpp	28 May 2004 05:18:46 -0000	3.504
>+++ content/base/src/nsDocument.cpp	10 Jun 2004 18:33:22 -0000
>@@ -666,16 +666,27 @@
>   }
> 
>   mNodeInfoManager = new nsNodeInfoManager();
>   NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
> 
>   return mNodeInfoManager->Init(this);
> }
> 
>+//XML Events
>+void nsDocument::AddXMLEventsContent(nsIContent * aXMLEventsElement) {
>+  if (!mXMLEventsManager) {
>+    mXMLEventsManager = new nsXMLEventsManager();
>+    if (mXMLEventsManager)
>+      AddObserver(mXMLEventsManager);
>+  }
>+  if (mXMLEventsManager)
>+    mXMLEventsManager->AddXMLEventsContent(this, aXMLEventsElement);
>+}
>+

I'm generally not in favor of extra nsresult error returns but in this case I'd
use one to propagate an allocation failure.  For example:

nsresult
nsDocument::AddXMLEventsContent(nsIContent *aXMLEventsElement)
{
  if (!mXMLEventsManager) {
    mXMLEventsManager = new nsXMLEventsManager();
    NS_ENSURE_TRUE(mXMLEventsManager, NS_ERROR_OUT_OF_MEMORY);

    AddObserver(mXMLEventsManager);
  }
  mXMLEventsManager->AddXMLEventsContent(this, aXMLEventsElement);
  return NS_OK;
}


>--- content/base/src/nsScriptLoader.cpp	13 May 2004 18:34:16 -0000	1.61
>+++ content/base/src/nsScriptLoader.cpp	10 Jun 2004 18:33:22 -0000
>@@ -368,16 +368,21 @@
>                                  aObserver);
>   }
> 
>   // Check whether we should be executing scripts at all for this document
>   if (!mDocument->IsScriptEnabled()) {
>     return FireErrorNotification(NS_ERROR_NOT_AVAILABLE, aElement, aObserver);
>   }
>   
>+  // Check whether we should be executing the script
>+  nsCOMPtr<nsIContent> el(do_QueryInterface(aElement));
>+  if (el && el->HasAttr(kNameSpaceID_None, nsHTMLAtoms::declare))
>+    return FireErrorNotification(NS_ERROR_NOT_AVAILABLE, aElement, aObserver);
>+  

Consolidate this nsIContent QI with the one down further in the function so we
don't have to do it twice.

Also, would it make sense to just not execute an inline <script> if there is an
ev:event attribute, rather than worry about declare?

>--- content/base/src/nsGenericElement.cpp	22 May 2004 22:14:57 -0000	3.335
>+++ content/base/src/nsGenericElement.cpp	10 Jun 2004 18:33:26 -0000
>@@ -3291,17 +3271,18 @@
>     NS_ENSURE_SUCCESS(rv, rv);
>   }
> 
>   if (mDocument) {
>     nsCOMPtr<nsIXBLBinding> binding;
>     mDocument->GetBindingManager()->GetBinding(this, getter_AddRefs(binding));
>     if (binding)
>       binding->AttributeChanged(aName, aNamespaceID, PR_FALSE, aNotify);
>-
>+    if (aNamespaceID == kNameSpaceID_XMLEvents || mNodeInfo->NamespaceID() == kNameSpaceID_XMLEvents)
>+      mDocument->AddXMLEventsContent(this);

If I'm understanding the patch correctly, this bit is for handling <listener>
elements.  It's not very obvious though.  A couple of questions:

- Would it be better to do this in nsXMLElement?
- Doesn't doing this here in SetAttr cause AddXMLEventsContent to be called
once for each attribute on the listener element?

>--- content/html/content/src/nsGenericHTMLElement.cpp	2 Jun 2004 00:24:59 -0000	1.511
>+++ content/html/content/src/nsGenericHTMLElement.cpp	10 Jun 2004 18:33:37 -0000
>@@ -1697,17 +1697,18 @@
>       if (!aOldValue.IsEmpty()) {
>         mutation.mPrevAttrValue = do_GetAtom(aOldValue);
>       }
>       mutation.mAttrChange = modType;
>       nsEventStatus status = nsEventStatus_eIgnore;
>       HandleDOMEvent(nsnull, &mutation, nsnull,
>                      NS_EVENT_FLAG_INIT, &status);
>     }
>-
>+    if (aNamespaceID == kNameSpaceID_XMLEvents)
>+      mDocument->AddXMLEventsContent(this);

And this bit is for handling ev:* attributes on HTML elements. A couple of
questions here too:

- I don't see anything that says this is only valid for HTML elements; why not
have this in nsGenericElement?
- Won't this also fire once for each ev: attribute on the element?  Is there
something that prevents that from creating multiple listeners?

In general, as far as adding to SetAttr, we definitely want to avoid doing more
work than we need to during document construction (while still responding to
dynamic setting of the attribute).  One approach would be to do the work in
SetAttr only if aNotify is true, and then also do it in SetParent, which will
be called once the attributes are all added during load.  

>--- content/html/content/src/nsHTMLScriptElement.cpp	18 May 2004 20:58:11 -0000	1.75
>+++ content/html/content/src/nsHTMLScriptElement.cpp	10 Jun 2004 18:33:38 -0000
>@@ -357,17 +362,19 @@
>   virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
> 
> protected:
>   PRBool IsOnloadEventForWindow();
> 
>   PRUint32 mLineNumber;
>   PRPackedBool mIsEvaluated;
>   PRPackedBool mEvaluating;
>-
>+  PRPackedBool mXMLEventsNeedsCompilation;

Would it make sense to just unroot and null out mXMLEventsHandler when we need
to recompile, rather than adding an extra variable? Are you deferring freeing
it for some reason?

>@@ -650,8 +678,98 @@
> 
>   // But we'll only set mIsEvaluated if we did really load or evaluate
>   // something
>   if (HasAttr(kNameSpaceID_None, nsHTMLAtoms::src) ||
>       mAttrsAndChildren.ChildCount()) {
>     mIsEvaluated = PR_TRUE;
>   }
> }
>+
>+/* void handleXMLEvents (in nsIDOMEvent event); */
>+NS_IMETHODIMP nsHTMLScriptElement::HandleXMLEvents(nsIDOMEvent *aEvent)
>+{  
>+  nsresult rv;

Style nits: don't declare rv up here, declare it as close to where it's used as
you can.  Also try to follow the function declaration style in this source
file, where the return type (NS_IMETHODIMP here) is on a separate line.

Also, some blank lines in this function would make the code more readable
(after |if| blocks, etc).

>+  if (!aEvent) 
>+    return NS_OK;
>+  /*
>+  The 'this' in script is the same as the event.currentTarget.
>+  */

Use C++ comments please, particularly for 1 line comments.

>+  nsCOMPtr<nsIDOMEventTarget> currentTarget;
>+  aEvent->GetCurrentTarget(getter_AddRefs(currentTarget));
>+  nsCOMPtr<nsIContent> targetContent;
>+  if (currentTarget) {
>+    nsCOMPtr<nsIDOMElement> targetElement = do_QueryInterface(currentTarget);
>+    if (targetElement)
>+        targetContent = do_QueryInterface(currentTarget);
>+  }
>+  if (!targetContent)
>+    return NS_OK;;
>+  nsString script;
>+  GetText(script);
>+  if (script.IsEmpty())
>+    return NS_OK;
>+  PRUint32 lineNumber = 0;
>+  GetLineNumber(&lineNumber);
>+  nsIScriptContext *scriptContext = nsnull;
>+  nsCOMPtr<nsIDocument> doc = GetDocument();

I don't think you need a strong reference here.

>+  if (doc) {
>+    nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
>+    if (sgo)
>+      scriptContext = sgo->GetContext();
>+  }
>+  if (!scriptContext)
>+    return NS_OK;

If this is an unexpected condition you may want to add an
NS_ASSERTION/NS_ERROR.

jst would know a lot more about whether the rest of this function is correct.

>--- dom/public/idl/events/Makefile.in	17 Apr 2004 21:50:09 -0000	1.16
>+++ dom/public/idl/events/Makefile.in	10 Jun 2004 18:33:38 -0000
>@@ -60,11 +60,12 @@
> 	$(NULL)
> 
> XPIDLSRCS =					\
> 	nsIDOMNSEvent.idl			\
> 	nsIDOMKeyEvent.idl			\
> 	nsIDOMMutationEvent.idl			\
> 	nsIDOMNSUIEvent.idl			\
> 	nsIDOMPopupBlockedEvent.idl		\
>+	nsIDOMXMLEventsHandler.idl		\

We should probably not call this nsIDOMXMLEventsHandler, since it doesn't come
from or extend a DOM interface.  I'd suggest moving it to content/base/public
and calling it just nsIXMLEventsHandler.  If there's a way we could do this
without adding an extra interface that would be great.

>--- /dev/null	2003-01-30 12:24:37.000000000 +0200
>+++ content/events/src/nsXMLEventsManager.cpp	2004-06-10 21:25:05.000000000 +0300
>+PRBool nsXMLEventsListener::InitXMLEventsListener(nsIDocument * aDocument,
>+                                                  nsXMLEventsManager * aManager,
>+                                                  nsIContent * aContent)
>+{
>+  PRInt32 nameSpaceID;
>+  aContent->GetNameSpaceID(&nameSpaceID);
>+  //for <xe:listener/>, right now no check for the element name

I think we should check for this rather than assuming.	It's pretty cheap to do
so, just change to a NodeInfo Equals() check and you can check the namespace
and tag at the same time.

>+  if (nameSpaceID == kNameSpaceID_XMLEvents)
>+    nameSpaceID = kNameSpaceID_None;
>+  else
>+    nameSpaceID = kNameSpaceID_XMLEvents;
>+  if (aContent->HasAttr(nameSpaceID, nsHTMLAtoms::_event)) {

Rather than wrapping the whole remainder of the function in an |if|, I'd just
do an early return here if we don't have the attribute.  Also, since we get the
attribute immediately after this, just get it here... it won't cost you any
more in the case where the attribute isn't there.

>+    aContent->GetAttr(nameSpaceID, nsHTMLAtoms::_event, eventType);
>+    if (aContent->HasAttr(nameSpaceID, nsHTMLAtoms::handler)) {

Same here, just skip the HasAttr() and call GetAttr().

>+      hasHandlerURI = PR_TRUE;
>+      aContent->GetAttr(nameSpaceID, nsHTMLAtoms::handler, handlerURIStr);
>+      nsCAutoString handlerRef;
>+      nsCOMPtr<nsIURI> handlerURI;
>+      PRBool equals = PR_FALSE;
>+      nsCOMPtr<nsIURI> docURI = aDocument->GetDocumentURI();

Don't need a strong reference here.

>+      nsIURI *baseURI = aDocument->GetBaseURI();
>+      nsresult rv = NS_NewURI( getter_AddRefs(handlerURI), handlerURIStr, nsnull, baseURI);
>+      if (NS_SUCCEEDED(rv)) {
>+        nsCOMPtr<nsIURL> handlerURL(do_QueryInterface(handlerURI));
>+        if (handlerURL) {
>+          handlerURL->GetRef(handlerRef);
>+          handlerURL->SetRef(EmptyCString());
>+          //We support only XML Events Basic.
>+          docURI->Equals(handlerURL, &equals);
>+          if(equals) {

Space after 'if'.

>+            NS_ConvertUTF8toUTF16 handlerRefAString(handlerRef);

You don't need to have this as a variable exactly, just put it as an argument:

doc->GetElementById(NS_ConvertUTF8toUTF16(handlerRef),
getter_AddRefs(domhandler));

The above comment about avoiding HasAttr + GetAttr applies to the whole section
below this too.  HasAttr() is useful for avoiding a string copy when all you
care about is whether there's a value, but if you want the value anyway, just
call GetAttr() and check the return code.

>+    nsCOMPtr<nsIContent> observer;
>+    if (!hasObserver) {
>+      if (!hasHandlerURI) //Parent should be the observer
>+        observer = aContent->GetParent();
>+      else //We have the handler, so this is the observer
>+        observer = aContent;
>+    }
>+    else if (!observerID.IsEmpty()){

space before brace.

>+nsXMLEventsListener::nsXMLEventsListener(nsXMLEventsManager * aManager,
>+                                         nsIContent * aElement,
>+                                         nsIContent * aObserver,
>+                                         nsIContent * aHandler,
>+                                         const nsAString& aEvent,
>+                                         PRBool aPhase,
>+                                         PRBool aStopPropagation,
>+                                         PRBool aCancelDefault,
>+                                         const nsAString& aTarget)
>+{
>+  mManager = aManager;
>+  mElement = aElement;
>+  mObserver = aObserver;
>+  mHandler = aHandler;
>+  mEvent = aEvent;
>+  mPhase = aPhase;
>+  mStopPropagation = aStopPropagation;
>+  mCancelDefault = aCancelDefault;
>+  mTarget = aTarget;

I generally prefer member initializers for this, i.e.

					  const nsAString& aTarget)
 : mManager(aManager),
   mElement(aElement),
   ...
  {

>+}
>+
>+nsXMLEventsListener::~nsXMLEventsListener()
>+{
>+  mElement = nsnull;
>+  mObserver = nsnull;

nsCOMPtr's do not need to be explicitly nulled out on destruction; they will
release their reference when they are destroyed.  Or are you avoiding a cycle
of some sort here? (If that's the case, please comment on it).

>+}
>+
>+void nsXMLEventsListener::Unregister()
>+{
>+  if (mObserver) {
>+    nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mObserver);

do_QueryInterface is null-safe; just check the result.

>+NS_IMETHODIMP
>+nsXMLEventsListener::HandleEvent(nsIDOMEvent* aEvent)
>+{
>+  if (!aEvent) 
>+    return NS_OK;
>+  nsCOMPtr<nsIDOMEvent> event(aEvent);
>+  if (!mTarget.IsEmpty()) {
>+    nsCOMPtr<nsIDOMEventTarget> target;
>+    aEvent->GetTarget(getter_AddRefs(target));
>+    if (target) {
>+      nsCOMPtr<nsIStyledContent> targetEl(do_QueryInterface(target));
>+      if (targetEl) {
>+        nsCOMPtr<nsIAtom> id;
>+        targetEl->GetID(getter_AddRefs(id));
>+        if (id) {
>+          if (!id->Equals(mTarget))

Might be better to atomize mTarget when we are created?

>+            return NS_OK;
>+        }
>+        else
>+          return NS_OK;
>+      }
>+      else
>+        return NS_OK;
>+    }
>+    else
>+      return NS_OK;;
>+  }

I think you could shorten this a bit (and probably make gcc generate better
code) by setting a boolean if the target matched and then checking it outside
of all the nested if's.

>+NS_IMPL_QUERY_INTERFACE1(nsXMLEventsManager, nsIDocumentObserver)
>+NS_IMPL_ADDREF(nsXMLEventsManager)
>+NS_IMPL_RELEASE(nsXMLEventsManager)

you can just say:
NS_IMPL_ISUPPORTS1(nsXMLEventsManager, nsIDocumentObserver)

>+void 
>+nsXMLEventsManager::EndLoad(nsIDocument* aDocument)
>+{
>+  nsCOMPtr<nsIContent> cur;

This should just be a raw pointer.

>+  for (int i = 0; i < mIncomplete.Count(); ++i) {
>+    cur = mIncomplete[i];
>+    /*If this succeeds, the object will be removed from the mIncomplete*/

Change to C++-style comment, and this should be ".... be removed from
mIncomplete".
Comment on attachment 151007 [details] [diff] [review]
First patch for review and comments.

This is looking good, but bryners comments need to be answerd. I'll happily
review an updated patch once available, but r- for this one.
Attachment #151007 - Flags: review?(jst) → review-
Alias: XMLEvents
(responses to earlier comments in response to my earlier comments, sorry for the
dramatic delay)

>> The following:
>> 
>>    <ev:handler event=""> ... </ev:handler>
>> 
>> ...shouldn't do _anything_ in this implementation, especially not be treated
>> as an <ev:listener>.
> 
> This is a bug or feature. Where does it read that it should not work that
> way?

The spec does not define an <ev:handler> element, so element-partition
attributes on that element cannot have any official semantics.


>>>+  // Check whether we should be executing the script
>>>+  nsCOMPtr<nsIContent> el(do_QueryInterface(aElement));
>>>+  if (el && el->HasAttr(kNameSpaceID_None, nsHTMLAtoms::declare))
>>>+    return FireErrorNotification(NS_ERROR_NOT_AVAILABLE, aElement, 
>>>aObserver);
>> 
>> This seems non-compliant, but I'm not sure. What is the "declare" attribute?
> 
> From XHTML 2.0. It is needed to prevent the execution of the handler scripts
> during pageload.

XHTML2 attributes do not apply to XHTML1 content.
>>> This seems non-compliant, but I'm not sure. What is the "declare" attribute?
>> 
>> From XHTML 2.0. It is needed to prevent the execution of the handler scripts
>> during pageload.

>XHTML2 attributes do not apply to XHTML1 content.

You are absolutely right.  Having a <script> element be a XML Event handler in
the first place is a function of XHTML 2.0 (and others like SVG).  XML Events
itself doesn't provide for specific handlers, rather it defines how handlers can
be set.  What handlers can be is up to the implementing technology (XForms,
XHTML 2.0, X+V, SVG, etc.)  It just happens that most of the examples use
<script> elements as handlers.

We put in the ability for a <script> element to be a handler because that is
going to be the most prevelent way that XML Events will be used.  While it is
XHTML 2, it can stand on its own without other XHTML 2 pieces and will bring
value to the XML Events implementation which can be realized now and doesn't
have to wait until X+V, SVG, etc. are implemented in Mozilla.  But like Smaug
said, we can easily remove the <script> handler altogether.

>Also, would it make sense to just not execute an inline <script> if there is an
>ev:event attribute, rather than worry about declare?

we thought that we could honestly see situations where an author could have a
script handler that he'd want to run during page load as well as being an event
handler, so bringing along the "declare=declare" attribute was a natural step. 
This way the author could control whether the script ran during page load or not
and we wouldn't be changing how <script> elements are processed in some
undocumented manner.  While using the declare attribute isn't exactly XHTML 1.x,
it is consistent with the specs available from the XHTML WG in general.

So I guess what we need answered is -> is it more desireable to strictly adhere
to the standards and save the <script> handler until another implementation
(like SVG or X+V) needs it?  Or should we leave it in so that authors can use
XML Events today?
(In reply to comment #29)
> We put in the ability for a <script> element to be a handler because that is
> going to be the most prevelent way that XML Events will be used.

It seems more likely that XML events would be used in the context of XForms,
with an <action> block.  The main problem with declare=, as I see it, is just
that it's incompatible with other UA's that would execute the script as soon as
it's loaded.  That's all speculation though, since I'm not aware of any other
browsers that implement XML Events.

I would like to suggest another way we could allow users to hook up handlers in
XHTML though, separate from <script>.  If the handler points to an element that
implements the DOM2 EventListener interface via an XBL binding, we should invoke
that listener.  I like the idea of javascript: inline script handlers as well.

I'd say for now we should get the core support in and then worry about <script>.
Yes I think we shouldn't support <html:script> as far as XML Events goes. There 
is no reason in the specs to do this, it isn't backwards compatible, and frankly 
I can't see any real use case; using DOM event listener registrations is easier.

We should do what bryner describes, namely we should treat any node that 
implements EventListener as being a valid XML Events handler. On those elements 
it should just use that interface to handle the event. On any other element it 
shouldn't do anything. Then when we do things like XForms actions, we just make 
that element implement EventListener and it all Just Works.

For testing we can either invent a <mozilla:handler> element (or a <xul:handler> 
element maybe) that implemnts EventListener, or use XBL to make an element that 
does so.
Attached patch v2 (obsolete) — Splinter Review
Sorry this delay, my PC was broken (and now I don't have good network
connections here in summer cottage :) ).

Anyway I removed the <script> thing. Now the only way to use XMLEvents is to
use XBL to implement DOM2 EventListener. 

Bryner, are you working on this too?
Attachment #151007 - Attachment is obsolete: true
Attachment #152431 - Flags: review?(bryner)
Comment on attachment 152431 [details] [diff] [review]
v2

>--- ../orig/mozilla/content/html/content/src/nsGenericHTMLElement.cpp	2004-06-25 15:25:57.000000000 +0300
>+++ content/html/content/src/nsGenericHTMLElement.cpp	2004-07-05 22:46:47.000000000 +0300
>@@ -1702,18 +1702,19 @@ nsGenericHTMLElement::SetAttrAndNotify(P
>       if (!aOldValue.IsEmpty()) {
>         mutation.mPrevAttrValue = do_GetAtom(aOldValue);
>       }
>       mutation.mAttrChange = modType;
>       nsEventStatus status = nsEventStatus_eIgnore;
>       HandleDOMEvent(nsnull, &mutation, nsnull,
>                      NS_EVENT_FLAG_INIT, &status);
>     }
>-
>     if (aNotify) {
>+      if (aNamespaceID == kNameSpaceID_XMLEvents)
>+        mDocument->AddXMLEventsContent(this);
>       mDocument->AttributeChanged(this, aNamespaceID, aAttribute, modType);

I still think this should be in nsGenericElement.

>--- ../orig/mozilla/content/base/src/nsGenericElement.cpp	2004-06-25 15:25:57.000000000 +0300
>+++ content/base/src/nsGenericElement.cpp	2004-07-05 19:43:18.000000000 +0300
>@@ -1747,16 +1747,21 @@ nsGenericElement::SetDocument(nsIDocumen
> void
> nsGenericElement::SetParent(nsIContent* aParent)
> {
>   nsIContent::SetParent(aParent);
>   if (aParent) {
>     nsIContent* bindingPar = aParent->GetBindingParent();
>     if (bindingPar)
>       SetBindingParent(bindingPar);
>+    if ((mNodeInfo->NamespaceID() != kNameSpaceID_XMLEvents &&
>+         this->HasAttr(kNameSpaceID_XMLEvents, nsHTMLAtoms::_event)) ||
>+        (mNodeInfo->NamespaceID() == kNameSpaceID_XMLEvents &&
>+         this->HasAttr(kNameSpaceID_None, nsHTMLAtoms::_event)))
>+      mDocument->AddXMLEventsContent(this);
>   }
> }

1. This should be in nsXMLElement
2. Null check mDocument; the parent can be set before the element is added to a
document.
3. To handle the case where the parent is set before the document, you'll need
to hook into SetDocument as well but be careful to only call
AddXMLEventsContent once between the two methods on a  normal document load. 
Here's what I'd suggest:

void
nsXMLElement::SetParent(nsIContent* aParent)
{
  nsIContent *oldParent = GetParent();
  nsGenericElement::SetParent(aParent);
  if (mDocument && oldParent != GetParent() &&
      mNodeInfo->Equals(nsHTMLAtoms::listener, kNameSpaceID_XMLEvents))
    mDocument->AddXMLEventsContent(this);
}

void
nsXMLElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
			  PRBool aCompileEventHandlers
{
  nsIDocument *oldDocument = mDocument;
  nsGenericElement::SetDocument(aDocument, aDeep, aCompileEventHandlers);

  if (mDocument && oldDocument != mDocument && GetParent() &&
      mNodeInfo->Equals(nsHTMLAtoms::listener, kNameSpaceID_XMLEvents))
    mDocument->AddXMLEventsContent(this);
}


>--- ../orig/mozilla/content/events/src/Makefile.in	2004-04-18 00:52:14.000000000 +0300
>+++ content/events/src/Makefile.in	2004-07-05 14:11:43.000000000 +0300
>@@ -56,23 +56,28 @@ REQUIRES	= xpcom \
> 		  xpconnect \
> 		  docshell \
> 		  pref \
> 		  view \
> 		  necko \
> 		  unicharutil \
> 		  $(NULL)
> 
>+EXPORTS		= \
>+		nsXMLEventsManager.h \
>+		$(NULL)
>+

Hm, this should probably not be exported (sorry I didn't catch that before). 
content/events/src should already be in the include path in
content/base/src/Makefile.in; add it to content/xml/content/src/Makefile.in if
you need to.

>--- /dev/null	2003-01-30 12:24:37.000000000 +0200
>+++ content/events/src/nsXMLEventsManager.h	2004-07-05 16:53:29.000000000 +0300
>+  nsString mTarget;

I would still suggest converting mTarget to an atom since it's only ever used
in an atom comparison.


>--- /dev/null	2003-01-30 12:24:37.000000000 +0200
>+++ content/events/src/nsXMLEventsManager.cpp	2004-07-06 19:04:48.000000000 +0300

>+        //We support only XML Events Basic.
>+        docURI->Equals(handlerURL, &equals);
>+        if (equals) {
>+          nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(aDocument));
>+          if (doc) {
>+            nsCOMPtr<nsIDOMElement> domhandler;
>+            doc->GetElementById(NS_ConvertUTF8toUTF16(handlerRef),
>+                                getter_AddRefs(domhandler));
>+            if (domhandler)

This 'if' can go away.


>+  else if (!observerID.IsEmpty()) {
>+    nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(aDocument));
>+    if (doc) {
>+      nsCOMPtr<nsIDOMElement> el;
>+      doc->GetElementById(observerID, getter_AddRefs(el));
>+      if (el)

same.

>+    }
>+  }
>+  nsCOMPtr<nsIDOMEventTarget> eventObserver;
>+  if (observer)

and here.



>+NS_IMPL_ISUPPORTS1(nsXMLEventsListener, nsIDOMEventListener)
>+NS_IMETHODIMP
>+nsXMLEventsListener::HandleEvent(nsIDOMEvent* aEvent)
>+{
>+  if (!aEvent) 
>+    return NS_OK;
>+  PRBool targetMatched = PR_TRUE;
>+  nsCOMPtr<nsIDOMEvent> event(aEvent);
>+  if (!mTarget.IsEmpty()) {
>+    nsCOMPtr<nsIDOMEventTarget> target;
>+    aEvent->GetTarget(getter_AddRefs(target));
>+    if (target) {

same.

>+      nsCOMPtr<nsIStyledContent> targetEl(do_QueryInterface(target));
>+      if (targetEl) {
>+        nsCOMPtr<nsIAtom> id;
>+        targetEl->GetID(getter_AddRefs(id));
>+        if (id && !id->Equals(mTarget)) 
>+          targetMatched = PR_FALSE;
>+      }
>+    }
>+  }
>+  if (!targetMatched)
>+    return NS_OK;
>+  if (mHandler) {

same.

Looking pretty good, I think one more patch and this should be ready to land.
Attachment #152431 - Flags: review?(bryner) → review-
Attached patch v3 (obsolete) — Splinter Review
I added NS_NewXMLEventsElement function. It just sets the name of the id 
attribute for ev:listener elements.

nsXMLEventsManager.h is still exported, it is easier than changing all
the places where nsDocument.h is used.

The check for XML Events attributes must be in both nsGenericElement and in
nsGenericHTMLElement (nsGenericHTMLElement has its own implementation for
SetAttr). But I moved the check so that the element will be recognized
as an XML Event declaration during parsing if it contains ev:event attribute.
The dynamic change is handled by the nsIDocumentObserver.
Attachment #152431 - Attachment is obsolete: true
Attachment #152552 - Flags: review?(bryner)
Smaug: why do you have to include nsXMLEventsManager.h before the nsRefPtr
member declaration in nsDocument.h?  Latest advice says you should not need that.

/be
Comment on attachment 152552 [details] [diff] [review]
v3

Just one very minor nit:

>--- ../orig/mozilla/content/xml/content/src/nsXMLElement.cpp	2004-05-23 01:14:58.000000000 +0300
>+++ content/xml/content/src/nsXMLElement.cpp	2004-07-07 23:33:01.000000000 +0300
>+void
>+nsXMLElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
>+			  PRBool aCompileEventHandlers)

Get rid of the hard tabs here.

r=bryner with that fixed - no need to post a new patch.  Looks good!
Attachment #152552 - Flags: review?(bryner) → review+
Attachment #152552 - Flags: superreview?(jst)
Comment on attachment 152552 [details] [diff] [review]
v3

Sorry, this patch cannot handle the
parent.appendChild(parent.removeChild(aChild))
testcase. New patch coming.
Attachment #152552 - Attachment is obsolete: true
Attachment #152552 - Flags: superreview?(jst)
Attached patch v4 (obsolete) — Splinter Review
This fixes the bug in previous patch. 
nsXMLEventsElement is now a real class so that the nsXMLElement
stays cleaner and faster.
Attachment #152776 - Flags: review?(bryner)
Attachment #152776 - Flags: superreview?(jst)
Attachment #152776 - Flags: review?(bryner)
Attachment #152776 - Flags: review+
Comment on attachment 152776 [details] [diff] [review]
v4

- In content/events/src/nsXMLEventsManager.cpp:

+class nsXMLEventsElement : public nsXMLElement {
+public:
+  nsXMLEventsElement(nsINodeInfo *aNodeInfo);
+  virtual ~nsXMLEventsElement();
+  NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsXMLElement::)
+  virtual nsIAtom *GetIDAttributeName() const;
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, 
+			    nsIAtom* aPrefix, const nsAString& aValue,
+			    PRBool aNotify);
+};
+
+nsXMLEventsElement::nsXMLEventsElement(nsINodeInfo *aNodeInfo)
+  : nsXMLElement(aNodeInfo)
+{
+}
...

This really doesn't seem to belong in this file. Create nsXMLEventsElement.cpp
and move the nsXMLEventsElement code into that file to keep a cleaner
separation between the event implementation and the XML events manager.

- In nsXMLEventsElement::GetIDAttributeName():

+  if (mNodeInfo->NameAtom() == nsHTMLAtoms::listener)

Use mNodeInfo->Equals(nsHTMLAtoms::listener) here (and in all other places
where you do this same thing), and in other places too. It's inline, so no
overhead in calling Equals() over getting the atom out of the nodeinfo.

+nsresult
+NS_NewXMLEventsElement(nsIContent** aInstancePtrResult, nsINodeInfo
*aNodeInfo) {

Method opening brace on its own line, like in the rest of the code you're
adding here.

- In nsXMLEventsListener::InitXMLEventsListener():

+  PRBool hasObserver = PR_FALSE;
...
+  if (aContent->GetAttr(nameSpaceID, nsHTMLAtoms::observer, observerID) !=
+      NS_CONTENT_ATTR_NOT_THERE)
+    hasObserver = PR_TRUE;

Maybe move the declaration of hasObserver down here and simply initialize it
to:

+  PRBool hasObserver =
+    aContent->GetAttr(nameSpaceID, nsHTMLAtoms::observer, observerID) !=
+    NS_CONTENT_ATTR_NOT_THERE)

+  nsAutoString phase;
+  if (aContent->GetAttr(nameSpaceID, nsHTMLAtoms::phase, phase) !=
+      NS_CONTENT_ATTR_NOT_THERE) {
+    if (phase.Equals(NS_LITERAL_STRING("capture")))
+      capture = PR_TRUE;
+  }

Same idea here, move the declaration of capture down here and intialize it to:

+  PRBool capture =
+    aContent->GetAttr(nameSpaceID, nsHTMLAtoms::phase, phase) !=
+    NS_CONTENT_ATTR_NOT_THERE &&
+    phase.Equals(NS_LITERAL_STRING("capture"));

... and same thing for all the other pieces of code that basically do the same
as above.

- In nsXMLEventsListener::Unregister():

+  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mObserver);
+  if (target) {
+    target->RemoveEventListener(mEvent, this, mPhase);
+    mObserver = nsnull;
+  }

Don't you want to null out mObserver even if it can't be QI'ed to
nsIDOMEventTarget here? I.e. move the mObserver = nsnull outside the if check.

- In nsXMLEventsListener::HandleEvent():

+  if (!aEvent) 
+    return NS_OK;

Is this not worthy of an exception? I.e. return NS_ERROR_INVALID_ARG or
somesuch.

- In nsXMLEventsManager::AttributeChanged():

+	 //If we are adding the ID attribute, we must check whether we can 
+	 //add new listeners
+	 EndLoad(aDocument);

This just seems wrong (even though it is correct). How about splitting out the
code in EndLoad() into a method with a name that makes more sense, and calling
that method from here, and from EndLoad() (and from ContentInserted() etc too)?

sr=jst with that.
Attachment #152776 - Flags: superreview?(jst) → superreview+
Could someone check this in?
Attachment #152776 - Attachment is obsolete: true
Checking in...
Status: NEW → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
This patch adds nsIDocument::AddXMLEventsContent without any comment. I'm
currently trying to figure out what it does and the lack of comments in this
relatively-new and reviewed code is wasting time, let alone going again the
style guidelines ("Use JavaDoc-style comments in any new class header files.").

Can the author add useful comments to all interfaces this patch touches?
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: