Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Not so anonymous nodes

206 views
Skip to first unread message

John J. Barton

unread,
Oct 11, 2009, 1:54:20 PM10/11/09
to
I was surprised to discover that a node.firstChild can be anonymous:

var nodelist = document.getAnonymousNodes(node);
if (nodelist[0] == node.firstChild)
// !! DOM API gives anonymous nodes??

Am I mistaken? Can this be true? All we know about node is that it is
from a XUL document.

My goal is to enumerate over all of the nodes. I thought I just had
figured it out: walk over the anonymous nodes from the list above, then
the regular nodes. But I was assuming that the regular nodes start with
node.firstChild, and that does not seem to be the case.

jjb

Neil

unread,
Oct 11, 2009, 4:09:21 PM10/11/09
to
John J. Barton wrote:

> var nodelist = document.getAnonymousNodes(node);
> if (nodelist[0] == node.firstChild)
> // !! DOM API gives anonymous nodes??

I can't see how that could happen, although it would be interesting to
see what document.getBindingParent(node.firstChild) returns. I say that
because when you start using XBL heavily things get confusing very quickly.

Consider <foo><bar/></foo>. Now foo has an XBL binding whose contents
are <baz><children/></baz>. This means that an event targetted at <bar>
bubbles up through <baz> and then <foo>, which is confusing for <baz>,
as its hasChildNodes() returns false!

--
Warning: May contain traces of nuts.

Boris Zbarsky

unread,
Oct 11, 2009, 10:46:25 PM10/11/09
to
On 10/11/09 1:54 PM, John J. Barton wrote:
> I was surprised to discover that a node.firstChild can be anonymous:

It can't.

> var nodelist = document.getAnonymousNodes(node);
> if (nodelist[0] == node.firstChild)
> // !! DOM API gives anonymous nodes??

I think you were mislead by the name of the (sadly undocumented and
possibly mis-named) getAnonymousNodes method. I do apologize for this
mess of an API. I've documented getAnonymousNodes a bit, in hopes of
making its behavior more clear.

getAnonymousNodes returns non-null only if the element passed to it has
an XBL binding attached to it. In this case, it returns a nodelist
representing the children of this element in the flattened tree. This
list can include some of the element's actual DOM kids, as well as nodes
that come from the element's binding or nodes that come from bindings on
ancestors of the element.

For example, consider a binding with a <content> section that looks like
this:

<content>
<span xmlns="http://www.w3.org/1999/xhtml">Something before</span>
<children/>
</content>

If this binding is attached to an element, the getAnonymousNodes for
that element will be a nodelist containing the <span> followed by all
the element's kids (both its DOM kids, and kids coming from <children>
kids due to bindings on ancestors), in order.

> My goal is to enumerate over all of the nodes.

"all" in what sense?

> But I was assuming that the regular nodes start with node.firstChild

This assumption is correct.

-Boris

John J. Barton

unread,
Oct 11, 2009, 11:51:49 PM10/11/09
to
Boris Zbarsky wrote:
> On 10/11/09 1:54 PM, John J. Barton wrote:
>> I was surprised to discover that a node.firstChild can be anonymous:
>
> It can't.
>
>> var nodelist = document.getAnonymousNodes(node);
>> if (nodelist[0] == node.firstChild)
>> // !! DOM API gives anonymous nodes??
>
> I think you were mislead by the name of the (sadly undocumented and
> possibly mis-named) getAnonymousNodes method. I do apologize for this
> mess of an API. I've documented getAnonymousNodes a bit, in hopes of
> making its behavior more clear.

Where is it documented?

>
> getAnonymousNodes returns non-null only if the element passed to it has
> an XBL binding attached to it. In this case, it returns a nodelist
> representing the children of this element in the flattened tree. This

What is a "flattened tree"? You chopped it down or what? ;-)

> list can include some of the element's actual DOM kids, as well as nodes

Hmm..."some" is not a very encouraging word for an API.

> that come from the element's binding or nodes that come from bindings on
> ancestors of the element.

Huh?

>
> For example, consider a binding with a <content> section that looks like
> this:
>
> <content>
> <span xmlns="http://www.w3.org/1999/xhtml">Something before</span>
> <children/>
> </content>
>
> If this binding is attached to an element, the getAnonymousNodes for
> that element will be a nodelist containing the <span> followed by all
> the element's kids (both its DOM kids, and kids coming from <children>
> kids due to bindings on ancestors), in order.

Ok, so which of any of that would a xul developer want to see in Chromebug?

>
>> My goal is to enumerate over all of the nodes.
>
> "all" in what sense?

In the the sense of "every single one"? I didn't expect to have to also
add "and not a single extra one".

>
>> But I was assuming that the regular nodes start with node.firstChild
>
> This assumption is correct.

Ok, well that is one would be the only thing that makes sense here then.

jjb

Nickolay Ponomarev

unread,
Oct 12, 2009, 12:11:17 AM10/12/09
to John J. Barton, dev-pl...@lists.mozilla.org
On Mon, Oct 12, 2009 at 7:51 AM, John J. Barton <johnj...@johnjbarton.com
> wrote:

> Boris Zbarsky wrote:
>
>> I've documented getAnonymousNodes a bit, in hopes of making its behavior
>> more clear.
>>
>
> Where is it documented?
>

bz meant this: http://hg.mozilla.org/mozilla-central/rev/8d546f1d4a84
But you could update
https://developer.mozilla.org/en/XBL/XBL_1.0_Reference/DOM_Interfaces#getAnonymousNodesas
well :)

>
>
>> getAnonymousNodes returns non-null only if the element passed to it has an
>> XBL binding attached to it. In this case, it returns a nodelist
>> representing the children of this element in the flattened tree. This
>>
>
> What is a "flattened tree"? You chopped it down or what? ;-)
>

Google it, the definition in the XBL2 spec ("final flattened tree") is
accurate, although it uses XBL2 terminology. This is the tree with both
anonymous and real nodes (with all bindings applied).


> list can include some of the element's actual DOM kids, as well as nodes
>>
>
> Hmm..."some" is not a very encouraging word for an API.
>
> that come from the element's binding or nodes that come from bindings on
>> ancestors of the element.
>>
>
> Huh?
>

I guess bz hints at <children>'s behavior, it has interesting @include attr
and can be non-direct child of the bound element.


>
>> For example, consider a binding with a <content> section that looks like
>> this:
>>
>> <content>
>> <span xmlns="http://www.w3.org/1999/xhtml">Something before</span>
>> <children/>
>> </content>
>>
>> If this binding is attached to an element, the getAnonymousNodes for that
>> element will be a nodelist containing the <span> followed by all the
>> element's kids (both its DOM kids, and kids coming from <children> kids due
>> to bindings on ancestors), in order.
>>
>
> Ok, so which of any of that would a xul developer want to see in Chromebug?
>

Obviously a rhetorical question that will be followed by bz trying to
determine what does a "xul developer" want and so on... :)

Why don't you copy what the DOM Inspector does?

Nickolay

John J. Barton

unread,
Oct 12, 2009, 12:49:57 AM10/12/09
to
Nickolay Ponomarev wrote:
> On Mon, Oct 12, 2009 at 7:51 AM, John J. Barton <johnj...@johnjbarton.com
>> wrote:
>
>> Boris Zbarsky wrote:
>>
>>> I've documented getAnonymousNodes a bit, in hopes of making its behavior
>>> more clear.
>>>
>> Where is it documented?
>>
> bz meant this: http://hg.mozilla.org/mozilla-central/rev/8d546f1d4a84
> But you could update
> https://developer.mozilla.org/en/XBL/XBL_1.0_Reference/DOM_Interfaces#getAnonymousNodesas
> well :)
>
>>
>>> getAnonymousNodes returns non-null only if the element passed to it has an
>>> XBL binding attached to it. In this case, it returns a nodelist
>>> representing the children of this element in the flattened tree. This
>>>
>> What is a "flattened tree"? You chopped it down or what? ;-)
>>
> Google it, the definition in the XBL2 spec ("final flattened tree") is
> accurate, although it uses XBL2 terminology. This is the tree with both
> anonymous and real nodes (with all bindings applied).

So, getAnonymousNodes returns all of the nodes, that is the regular
nodes and the anonymous nodes, in one list, is that correct?

If I visit each node in the list returned by getAnonymousNodes, and call
getAnonymousNodes() on them, recursively, I will visit all of the nodes
once?

Specifically I would visit node.firstChild, node.firstChild.nextSibling,
etc?

I gather that there is no XBL equivalent to nextSibling? So given an
element that is a child, computing the sibling would require iterating
over the parent's nodelist from getAnonymousNodes(). (Firebug's HTML
panel uses nextSibling iteration).

jjb

Neil

unread,
Oct 12, 2009, 4:55:15 AM10/12/09
to
John J. Barton wrote:

> So, getAnonymousNodes returns all of the nodes, that is the regular
> nodes and the anonymous nodes, in one list, is that correct?

For elements with their own XBL anonymous nodes, yes. (As per my
previous post, elements can have anonymous children without necessarily
having an XBL binding.)

> If I visit each node in the list returned by getAnonymousNodes, and
> call getAnonymousNodes() on them, recursively, I will visit all of the
> nodes once?

You would not visit nodes more than once. Unfortunately you might not
visit some nodes at all.

> I gather that there is no XBL equivalent to nextSibling? So given an
> element that is a child, computing the sibling would require iterating
> over the parent's nodelist from getAnonymousNodes().

Worse, you would need to use the anonymous parent, which XBL1 doesn't
expose.

Boris Zbarsky

unread,
Oct 12, 2009, 11:09:16 AM10/12/09
to Eric Shepherd
On 10/12/09 12:11 AM, Nickolay Ponomarev wrote:
> But you could update
> https://developer.mozilla.org/en/XBL/XBL_1.0_Reference/DOM_Interfaces#getAnonymousNodes

Note that when I tried to do that last night devmo currently responded
with timeouts to every single request for anything other than the front
page.

And when I tried is just now, it responds with a connection drop to
attempts to log in.

Makes it rather hard to update the docs.

-Boris

Boris Zbarsky

unread,
Oct 12, 2009, 11:22:43 AM10/12/09
to
On 10/11/09 11:51 PM, John J. Barton wrote:
> Where is it documented?

Nickolay covered this.

>> getAnonymousNodes returns non-null only if the element passed to it
>> has an XBL binding attached to it. In this case, it returns a nodelist
>> representing the children of this element in the flattened tree. This
>
> What is a "flattened tree"? You chopped it down or what? ;-)

Nickolay mostly covered this too. Basically, the flattened tree is the
dom-like tree one uses to actually construct CSS boxes in the presence
of XBL. Its parent/child relationships have been modified by XBL
binding insertion points.

>> list can include some of the element's actual DOM kids, as well as nodes
>
> Hmm..."some" is not a very encouraging word for an API.

Well, it depends on the binding's details. If your binding has:

<content>
<children includes="span"/>
<foobar>
<children/>
</foobar>
</content>

then getAnonymousNodes will return the "span" children of the node, in
order, then the foobar element. The other children of the node will be
kids of the foobar in the flattened tree. This is really not a function
of the getAnonymousNodes API but of the flattened tree construction model.

>> that come from the element's binding or nodes that come from bindings
>> on ancestors of the element.
>
> Huh?

Consider this document:

<div>
<span>
</div>

And a binding that's applied to the <div> which has:

<content>
<hbox>
<foo/>
<children/>
</hbox>
</content>

And a binding that's applied to the <hbox> which has:

<content>
<bar/>
<children/>
</content>

Then getAnonymousNodes on the <hbox> will return a list containing the
<bar>, <foo>, <span> in that order. The <bar> comes from the hbox
binding, the <foo> is a DOM child of the hbox, the <span> comes from a
binding on an ancestor (and the binding parent, in this case, but in
general it would be some binding ancestor) of the hbox.

None of this is magic about getAnonymousNodes; all the magic is in the
XBL flattened tree construction.

> Ok, so which of any of that would a xul developer want to see in Chromebug?

A XUL developer is most likely to want to see the flattened tree kids
for an element. That means the contents of getAnonymousNodes if it's
non-null. If its null, they'd want to see the kids with all insertion
points under the element resolved. I don't believe there's a JS API for
getting this nodelist directly. DOM Inspector uses the
inIDeepTreeWalker component to walk over the flattened tree.

>> "all" in what sense?
>
> In the the sense of "every single one"? I didn't expect to have to also
> add "and not a single extra one".

Yes, but all nodes in the document? In some subtree? In some child
list? Something else?

You should probably seriously consider just doing what DOM Inspector
does here.

-Boris

Boris Zbarsky

unread,
Oct 12, 2009, 11:25:00 AM10/12/09
to
On 10/12/09 12:49 AM, John J. Barton wrote:
> So, getAnonymousNodes returns all of the nodes, that is the regular
> nodes and the anonymous nodes, in one list, is that correct?

No. It returns exactly what it returns. The nodes that should look
like the kids of the given node while constructing the box model. And
only if the node has a binding attached to it. Sometimes this list
includes some of the element's DOM kids. Sometimes it does not.

> If I visit each node in the list returned by getAnonymousNodes, and call
> getAnonymousNodes() on them, recursively, I will visit all of the nodes
> once?

No. See my previous mail.

> Specifically I would visit node.firstChild, node.firstChild.nextSibling,
> etc?

No.

> I gather that there is no XBL equivalent to nextSibling?

Not at the moment, though there was a bug on implementing flattened tree
traversal methods at some point.

You should seriously look into inIDeepTreeWalker.

-Boris

Boris Zbarsky

unread,
Oct 12, 2009, 11:26:02 AM10/12/09
to
On 10/12/09 4:55 AM, Neil wrote:
> Worse, you would need to use the anonymous parent, which XBL1 doesn't
> expose.

I believe inIDeepTreeWalker exposes this fine.

-Boris

John J. Barton

unread,
Oct 12, 2009, 12:12:36 PM10/12/09
to
Boris Zbarsky wrote:
> On 10/12/09 12:49 AM, John J. Barton wrote:
...

>> I gather that there is no XBL equivalent to nextSibling?
>
> Not at the moment, though there was a bug on implementing flattened tree
> traversal methods at some point.
>
> You should seriously look into inIDeepTreeWalker.

Thanks and thanks to Neil for all of your help. Unfortunately it sounds
like supporting anonymous nodes would be a much bigger effort than it
seemed when I started. I better re-assess the cost/benefit here.

jjb

Boris Zbarsky

unread,
Oct 12, 2009, 12:32:18 PM10/12/09
to
On 10/12/09 12:12 PM, John J. Barton wrote:
> Thanks and thanks to Neil for all of your help. Unfortunately it sounds
> like supporting anonymous nodes would be a much bigger effort than it
> seemed when I started. I better re-assess the cost/benefit here.

To be clear, it's impossible to sanely debug chrome without this feature.

-Boris

Boris Zbarsky

unread,
Oct 12, 2009, 12:43:46 PM10/12/09
to
On 10/12/09 12:32 PM, Boris Zbarsky wrote:
> To be clear, it's impossible to sanely debug chrome without this feature.

And to be even more clear, there are 672 non-anonymous nodes in the
Firefox UI. There are 5000-ish nodes total (anonymous and not).

-Boris

John J. Barton

unread,
Oct 12, 2009, 1:32:11 PM10/12/09
to

Well there are 2M firebug users and 4 users of Chromebug. I have to be
realistic about where to invest a week's time. Adding anonymous node
support may or may not change that dynamic. We use Chromebug on Firebug
all of the time and never found a need for the anonymous info. I have no
way to tell what features are essential and what impact could result
from adding stuff beyond what we need for Firebug debugging.

On the plus side, I did look into your suggestion. inIDeepTreeWalker
extends nsIDOMTreeWalker. Neither of these have MDC pages. I found zero
uses of inIDeepTreeWalker in mozilla-central.
http://mxr.mozilla.org/mozilla-central/search?string=inIDeepTreeWalker
The IDL for nsIDOMTreeWalker as a cryptic comment
// Introduced in DOM Level 2:
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/traversal/nsIDOMTreeWalker.idl#48
Eventually I discovered that the DOM Level 2 has an interface call
TreeWalker,
http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/traversal.html#TreeWalker
so that is what that comment must mean.
The method calls on TreeWalker look to be identical to the properties
used by Firebug for its HTML traversal. The only real difference is that
the state of the traversal is not carried in the model (node). To switch
means understanding the lifetime of the traversal in Firebug so that
the lifetime of the walker matches it, and understanding which flags to
set on the walker.

jjb

Shawn Wilsher

unread,
Oct 12, 2009, 1:25:19 PM10/12/09
to dev-pl...@lists.mozilla.org
On 10/12/09 10:32 AM, John J. Barton wrote:
> On the plus side, I did look into your suggestion. inIDeepTreeWalker
> extends nsIDOMTreeWalker. Neither of these have MDC pages. I found zero
> uses of inIDeepTreeWalker in mozilla-central.
That's because the DOM Inspector lives inside of it's own hg repository,
but you can find the one and only use of it in comm-central:
http://mxr.mozilla.org/comm-central/source/mozilla/extensions/inspector/resources/content/viewers/dom/dom.js#819

Cheers,

Shawn

Dan Mosedale

unread,
Oct 12, 2009, 1:49:34 PM10/12/09
to dev-pl...@lists.mozilla.org

And as far as "what would a XUL developer want", in my experience what
DOM Inspector does is more than sufficient. So making Firebug use the
same algorithm would be great...

Dan

John J. Barton

unread,
Oct 12, 2009, 2:54:13 PM10/12/09
to
Boris Zbarsky wrote:
...>

> You should seriously look into inIDeepTreeWalker.

I did. My reward:
"[JavaScript Error: "uncaught exception: [Exception... "Component
returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED)
[inIDeepTreeWalker.firstChild]"

http://mxr.mozilla.org/mozilla-central/source/layout/inspector/src/inDeepTreeWalker.cpp#181

jjb

Boris Zbarsky

unread,
Oct 12, 2009, 2:46:06 PM10/12/09
to
On 10/12/09 2:54 PM, John J. Barton wrote:
> I did. My reward:
> "[JavaScript Error: "uncaught exception: [Exception... "Component
> returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED)
> [inIDeepTreeWalker.firstChild]"
>
> http://mxr.mozilla.org/mozilla-central/source/layout/inspector/src/inDeepTreeWalker.cpp#181

Ah, hmm. It might only implement nextNode() and parentNode() traversal
at the moment. That shouldn't be all that hard to fix. File bugs on
any issues that block you?

As a note, this is a chicken and egg problem; I doubt you can get many
more chromebug users without having this working, and you're not
incentivised to get it working because chromebug is underused. In the
end, it all depends on what your goals for chromebug are, I guess.

-Boris

John J. Barton

unread,
Oct 12, 2009, 4:09:53 PM10/12/09
to
Boris Zbarsky wrote:
> On 10/12/09 2:54 PM, John J. Barton wrote:
>> I did. My reward:
>> "[JavaScript Error: "uncaught exception: [Exception... "Component
>> returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED)
>> [inIDeepTreeWalker.firstChild]"
>>
>> http://mxr.mozilla.org/mozilla-central/source/layout/inspector/src/inDeepTreeWalker.cpp#181
>>
>
> Ah, hmm. It might only implement nextNode() and parentNode() traversal
> at the moment. That shouldn't be all that hard to fix. File bugs on
> any issues that block you?

The bit of code the implements nextNode():
http://mxr.mozilla.org/mozilla-central/source/layout/inspector/src/inDeepTreeWalker.cpp#258
is a lot like the JS code I wrote when I thought I understood
getAnonymousNodes(). Are there any JS equivalents to:
(bindingManager = inLayoutUtils::GetBindingManagerFor(aNode))) {
bindingManager->GetAnonymousNodesFor(content,
getter_AddRefs(kids));
if (!kids)
bindingManager->GetContentListFor(content,
getter_AddRefs(kids));
?

>
> As a note, this is a chicken and egg problem; I doubt you can get many
> more chromebug users without having this working, and you're not
> incentivised to get it working because chromebug is underused. In the
> end, it all depends on what your goals for chromebug are, I guess.

Yes, though I think I've sorted out the issues with JS and with windows
in Chromebug enough for it to be useful for most extensions. I realize
that XBL binding is very important to mozilla application developers but
not so much for extensions. As for goals, I want Chromebug to be
Firebug for XUL, but that does not help me have enough time to achieve
that goal.

jjb

Boris Zbarsky

unread,
Oct 12, 2009, 4:07:22 PM10/12/09
to
On 10/12/09 4:09 PM, John J. Barton wrote:
> Are there any JS equivalents to:
> (bindingManager = inLayoutUtils::GetBindingManagerFor(aNode))) {

No.

> bindingManager->GetAnonymousNodesFor(content,
> getter_AddRefs(kids));

Yes. The getAnonymousNodes.

> if (!kids)
> bindingManager->GetContentListFor(content,
> getter_AddRefs(kids));

No, and this is the key problem that prevents a JS implementation not
using inIDeepTreeWalker from actually being able to walk all the nodes.

> Yes, though I think I've sorted out the issues with JS and with windows
> in Chromebug enough for it to be useful for most extensions. I realize
> that XBL binding is very important to mozilla application developers but
> not so much for extensions.

I'm not sure why that would be the case, exactly... Extensions use a
fair amount of XBL, not even including the built-in bindings they rely on.

-Boris

John J. Barton

unread,
Oct 15, 2009, 1:14:47 AM10/15/09
to

I looked into the DOM Inspector code so see if this was feasible. As far
as I can tell, the key bits, where we get the anonymous nodes, is down
in inIDOMView, a XUL tree view thing implemented in C++. The thing that
opens the view twisties to drill down seems to be selectElementInTree,
http://mxr.mozilla.org/comm-central/source/mozilla/extensions/inspector/resources/content/viewers/dom/dom.js#745
It uses the DOM Walker only to set up the selection. Then it uses
operations on inIDOMView to fill in, esp. ToggleOpenState which calls
ExpandNode, and that calls GetChildNodesFor(), then we arrive at
code very similar to what Boris already said was not accessible to JS:
http://mxr.mozilla.org/comm-central/source/mozilla/layout/inspector/src/inDOMView.cpp#1240

So I am afraid this too is a dead end, absent new C++ code.

jjb

Mike Shaver

unread,
Oct 15, 2009, 10:17:33 AM10/15/09
to John J. Barton, dev-pl...@lists.mozilla.org
On Thu, Oct 15, 2009 at 1:14 AM, John J. Barton
<johnj...@johnjbarton.com> wrote:
> So I am afraid this too is a dead end, absent new C++ code.

Do we have reason to believe that such new C++ code would be unwelcome?

Mike

Boris Zbarsky

unread,
Oct 15, 2009, 12:00:09 PM10/15/09
to
On 10/15/09 1:14 AM, John J. Barton wrote:
> So I am afraid this too is a dead end, absent new C++ code.

OK. Could we get a bug filed with a description of what you need to
make this work, whether it be more of the methods on inDeepTreeWalker
implemented or whether it be a getter for the flattened tree child list?
This should be trivial to fix on the Gecko end to give you the APIs
you need to make your end work.

-Boris

John J Barton

unread,
Oct 15, 2009, 8:01:35 PM10/15/09
to

I'm not sure what you want, here is what I did:
https://bugzilla.mozilla.org/show_bug.cgi?id=522601
jjb

Boris Zbarsky

unread,
Oct 15, 2009, 9:01:34 PM10/15/09
to
On 10/15/09 8:01 PM, John J Barton wrote:
> I'm not sure what you want, here is what I did:
> https://bugzilla.mozilla.org/show_bug.cgi?id=522601

I wanted you to describe what would make it easiest for you to implement
showing anonymous content. That bug report is fine in that regard.

-Boris

Boris Zbarsky

unread,
Oct 15, 2009, 9:16:07 PM10/15/09
to
On 10/15/09 9:01 PM, Boris Zbarsky wrote:
> I wanted you to describe what would make it easiest for you to implement
> showing anonymous content. That bug report is fine in that regard.

And to be clear, I wanted you to decide for yourself whether what you
want is to add functionality to inIDeepTreeWalker or whether you wanted
a function that takes an element and returns the list of its kids in the
flattened tree (similar to getAnonymousNodes, but doing the right thing
for all cases, including all the kids being no-anonymous, etc).

-Boris

John J. Barton

unread,
Oct 16, 2009, 11:41:46 AM10/16/09
to
The current code uses node.firstChild/node.nextSibling to walk the
regular tree. I thought we decided that the anonymous nodes don't
support that, so the next best thing is inIDeepTreeWalker, which is a
kind of side-table version of the these functions.

I don't actually understand the data model, so its hard for me to make
suggestions. From what I understand, this 'flattened' tree is the real
DOM tree, it has all of the nodes and they form a tree. But some of
these nodes are not HTML or XUL but some special kind 'anonymous'. In
the normal traversal, node.nextSibling will not return these special
'anonymous' nodes, but these special nodes can have non-special,
non-anonymous children, and those nodes have nextSibling, etc, creating
a little island of regular-treeness hiding behind the anonymous nodes.

The inIDeepTreeWalker grabs a node and unlocks its secrets, the special
nodes hiding in the tree, and travels through them including new areas
of normal nodes within the tree. A list method,
getAllChildrenAnonymousOrNot(), would also work if called consistently
down the tree. The only way for node.firstChild to work would be to have
a kind of 'god' mode that changes the property returned from
'regular-nodes-only' to 'all-kinds-please'.

I think the modal version would be horrible, the list adequate, and the
walker best. The walker, if its implementation were complete, would
actually follows the DOM standards, so the same code can be used for
regular and anonymous node and it makes the documentation easier.

jjb

Boris Zbarsky

unread,
Oct 16, 2009, 12:05:15 PM10/16/09
to
On 10/16/09 11:41 AM, John J. Barton wrote:
> The current code uses node.firstChild/node.nextSibling to walk the
> regular tree. I thought we decided that the anonymous nodes don't
> support that, so the next best thing is inIDeepTreeWalker, which is a
> kind of side-table version of the these functions.

Well, hold on. inIDeepTreeWalker is just an nsIDOMTreeWalker
implementation that walks the flattened tree, not the DOM tree.

Since inIDeepTreeWalker doesn't quite do what we need, we can fix it to
be closer to what you need. Or we can add methods along the lines of
.firstChild/.nextSibling but working on the flattened tree (though the
.nextSibling will be expensive; explicit iteration along a child
nodelist would be cheaper here).

> I don't actually understand the data model, so its hard for me to make
> suggestions. From what I understand, this 'flattened' tree is the real
> DOM tree, it has all of the nodes and they form a tree. But some of
> these nodes are not HTML or XUL but some special kind 'anonymous'.

OK, that last sentence is pretty much totally wrong. Up to there,
though, you were doing well. ;)

You have a DOM tree. Some of the nodes have XBL bindings applied. The
XBL bindings effectively perform a transformation to create a new DOM
tree called the flattened tree. See
http://www.mozilla.org/projects/xbl/xbl2.html#final0 for a description
with some examples. The transformation can basically add nodes into the
tree in various ways; the only invariant preserved by the transformation
that I can think of is that if nodes A and B are both in the DOM and A
is a descendant of B, then A will continue to be a descendant of B in
the flattened tree, if A is present in it at all.

> In the normal traversal, node.nextSibling will not return these special
> 'anonymous' nodes

The XBL model is that the original DOM tree and the flattened tree both
exist; DOM methods operate as normal on the original DOM tree. So
.nextSibling on a node in the original DOM tree will never return a node
added via XBL, yes.

> but these special nodes can have non-special, non-anonymous children, and those nodes have nextSibling, etc, creating
> a little island of regular-treeness hiding behind the anonymous nodes.

Correct, though this island is always reachable via
.firstChild/.nextSibling from the DOM.

That is, the anonymous nodes have these non-anonymous kids in the
flattented tree, but the parentNode of the non-anonymous kids is
whatever their DOM parent is, not the anonymous node that's the
flattened tree parent.

> The inIDeepTreeWalker grabs a node and unlocks its secrets, the special
> nodes hiding in the tree, and travels through them including new areas
> of normal nodes within the tree. A list method,
> getAllChildrenAnonymousOrNot(), would also work if called consistently
> down the tree.

Correct.

> The only way for node.firstChild to work would be to have
> a kind of 'god' mode that changes the property returned from
> 'regular-nodes-only' to 'all-kinds-please'.

Or by having a new document.getFirstFlattenedTreeChildFor() method or
something, yes.

> I think the modal version would be horrible, the list adequate, and the
> walker best. The walker, if its implementation were complete, would
> actually follows the DOM standards, so the same code can be used for
> regular and anonymous node and it makes the documentation easier.

OK, sounds good. Thanks for bearing with me; I know this stuff is messy
and underdocumented. And thanks for filing the bug on the walker!

-Boris, going off to fix the walker

John J. Barton

unread,
Oct 16, 2009, 12:40:05 PM10/16/09
to
Boris Zbarsky wrote:
> On 10/16/09 11:41 AM, John J. Barton wrote:
>> The current code uses node.firstChild/node.nextSibling to walk the
>> regular tree. I thought we decided that the anonymous nodes don't
>> support that, so the next best thing is inIDeepTreeWalker, which is a
>> kind of side-table version of the these functions.
>
> Well, hold on. inIDeepTreeWalker is just an nsIDOMTreeWalker
> implementation that walks the flattened tree, not the DOM tree.

But my point was that the DOM TreeWalker has firstChild()/nextSibling()
so it can stand-in for the link properties on a node.

>
> Since inIDeepTreeWalker doesn't quite do what we need, we can fix it to
> be closer to what you need. Or we can add methods along the lines of
> .firstChild/.nextSibling but working on the flattened tree (though the
> .nextSibling will be expensive; explicit iteration along a child
> nodelist would be cheaper here).

I guess this amounts to who holds the state of the iterator?

I don't think performance is such an issue for chromebug, the whole
point of Firebug's HTML panel code is to only walk any part of the tree
the user explicitly asks to see. The bad case is a tree with a very
widely branching node.

...


>
> That is, the anonymous nodes have these non-anonymous kids in the
> flattented tree, but the parentNode of the non-anonymous kids is
> whatever their DOM parent is, not the anonymous node that's the
> flattened tree parent.

Oh. So it's wackier than I thought.

Does/Should the niIDeepTreeWalker.parentNode() return the possibily
anonymous parent in the flattened tree? I hope yes; I guess we will
need it.

jjb

Boris Zbarsky

unread,
Oct 16, 2009, 12:32:32 PM10/16/09
to
On 10/16/09 12:40 PM, John J. Barton wrote:
> But my point was that the DOM TreeWalker has firstChild()/nextSibling()
> so it can stand-in for the link properties on a node.

Yes.

>> Since inIDeepTreeWalker doesn't quite do what we need, we can fix it
>> to be closer to what you need. Or we can add methods along the lines
>> of .firstChild/.nextSibling but working on the flattened tree (though
>> the .nextSibling will be expensive; explicit iteration along a child
>> nodelist would be cheaper here).
>
> I guess this amounts to who holds the state of the iterator?

Yeah.

> I don't think performance is such an issue for chromebug, the whole
> point of Firebug's HTML panel code is to only walk any part of the tree
> the user explicitly asks to see. The bad case is a tree with a very
> widely branching node.

Indeed. I do agree that for chromebug this is probably a non-issue.

> Does/Should the niIDeepTreeWalker.parentNode() return the possibily
> anonymous parent in the flattened tree? I hope yes; I guess we will need
> it.

Yes. parentNode() on the treewalker will give the parent of the
currentNode in the flattened tree (in the deep-tree-walker case) or the
DOM tree (in the standard DOM treewalker case, modulo the filter stuff;
I'm pretty sure that the deep-tree-walker ignores the filter stuff and
always does SHOW_ALL, but that's what you'd want here from the normal
DOM walker too).

-Boris

0 new messages