DOMNodeInserted -> Was #id inserted?

M

Matt Kruse

Using a document listener on DOMNodeInserted, I'm trying to determine
if an element with id="x" was inserted. So either the
event.target.id=="x" or a child element of the one inserted
has .id=="x".

What is the best way to determine if #x is a child of the inserted
element?

Currently I'm doing:
if ( element.querySelectorAll("#x").length==1 )

But that limits my browser compatibility. I'd like to support Firefox
< 3.5, which lacks querySelectorAll.

Matt Kruse
 
M

Martin Honnen

Matt said:
Using a document listener on DOMNodeInserted, I'm trying to determine
if an element with id="x" was inserted. So either the
event.target.id=="x" or a child element of the one inserted
has .id=="x".

What is the best way to determine if #x is a child of the inserted
element?

Currently I'm doing:
if ( element.querySelectorAll("#x").length==1 )

But that limits my browser compatibility. I'd like to support Firefox
< 3.5, which lacks querySelectorAll.

Well
element.getElementsByTagName('*')
gives you alld descendant elements, you could then iterate over that
node list and look for an element with the id you are interested in.
That should work back to Firefox 1.0 or IE 6 (which you are probably not
interested in anyway with using mutation events).
Firefox also supports XPath over HTML DOMs so you could also try to
solve that with XPath e.g.
element.ownerDocument.evaluate('descendant-or-self::*[@id = "' +
yourId + '"]', element, null, 9, null).singleNodeValue !== null
should tell you whether "element" itself or one of the descendant
elements has the id attribute.
 
T

Thomas 'PointedEars' Lahn

Matt said:
Using a document listener on DOMNodeInserted, I'm trying to determine
if an element with id="x" was inserted. So either the
event.target.id=="x" or a child element of the one inserted
has .id=="x".

What is the best way to determine if #x is a child of the inserted
element?

Determine if #x's parent is the inserted element (`parentNode' property).


PointedEars
 
M

Matt Kruse

Determine if #x's parent is the inserted element (`parentNode' property).

I thought of this too, obviously, but it has the drawbacks of:
1. You may have to look through the parentNode chain all the way up to
the root document before realizing it's not a match, which seems
inefficient
2. If #x already existed in the doc somewhere else, you're going to be
inspecting this chain for no good reason

It seems that element.getElementById() would be handy in this case,
but perhaps performance using any of these methods would be fast
enough that trying to optimize is pointless.

Matt Kruse
 
T

Thomas 'PointedEars' Lahn

Matt said:
I thought of this too, obviously, but it has the drawbacks of:
1. You may have to look through the parentNode chain all the way up to
the root document

You mean root _element_. You may not have to, since not all element types
may be descendants of all others.
before realizing it's not a match, which seems inefficient

A linked list lookup is certainly not more inefficient than a tree search.
2. If #x already existed in the doc somewhere else, you're going to be
inspecting this chain for no good reason

If #x already existed in the document somewhere else, you have a design
problem to solve first.
It seems that element.getElementById() would be handy in this case,

It is. BTDT.
but perhaps performance using any of these methods would be fast
enough that trying to optimize is pointless.

Perhaps not.


PointedEars
 
M

Matt Kruse

Matt said:
What is the best way to determine if #x is a child of the inserted
element?
Firefox also supports XPath over HTML DOMs so you could also try to
solve that with XPath e.g.
   element.ownerDocument.evaluate('descendant-or-self::*[@id = "' +
yourId + '"]', element, null, 9, null).singleNodeValue !== null

Good idea, I went ahead and tested these three:

function containsId1(el,id) {
return (el.ownerDocument.evaluate('descendant-or-self::*[@id = "' +id
+ '"]', el, null, 9, null).singleNodeValue !== null);
}
function containsId2(el,id) {
return (el.querySelectorAll('#'+id).length==1);
}
function containsId3(el,id) {
var o = document.getElementById(id);
if (o) {
if (id===o.id) { return true; }
while (o=o.parentNode) {
if (id===o.id) { return true; }
}
}
return false;
}

It turns out that the XPath approach is about 100ms slower over 5,000
iterations of a simple test case (insignificant), and the other two
are practically equal. So I guess there is no reason not to use the
last approach, which is the most backwards-compatible.

Matt Kruse
 
S

SAM

Le 5/27/10 3:07 PM, Matt Kruse a écrit :
Using a document listener on DOMNodeInserted, I'm trying to determine
if an element with id="x" was inserted.

alert(document.getElementById('x'))

alert(typeof document.getElementById('x') != 'undefined')
So either the event.target.id=="x"
or a child element of the one inserted
has .id=="x".

??? as you can have only ONE element of same id in a html body
why do you search more than this 'x' ?

What is the best way to determine if #x is a child of the inserted
element?

?? how does-it inserted ?
I mean the container or the element of id 'x'

Currently I'm doing:
if ( element.querySelectorAll("#x").length==1 )

I don't know what that element.querySelectorAll is.

But that limits my browser compatibility. I'd like to support Firefox
< 3.5, which lacks querySelectorAll.

If you search an id use gEBY (see above)



If there is more than one element with same id
correct in first your page or the appli creating it.
 
M

Matt Kruse

function containsId3(el,id) {
        var o = document.getElementById(id);
        if (o) {
                if (id===o.id) { return true; }
                while (o=o.parentNode) {
                        if (id===o.id) { return true; }
                }
        }
        return false;
}

Oops, posted the version with obviously logical snafu. Fixed:

function containsId3(el,id) {
var o = document.getElementById(id);
if (o) {
do {
if (o==el) { return true; }
} while (o=o.parentNode);
}
return false;
}

Matt Kruse
 
G

Garrett Smith

No, to determine if #x is a child of the inserted element, the simplest
approach is to compare the inserted element to x's parentNode.

To determine if #x is a *descendant* of the inserted element is a
different task. It is not a difficult one; and many recent browsers
supply functionality

You wrote that you are using a DOMNodeInserted mutation event. Perhaps
that is not the best choice here.

What are you trying to do?
 
T

Thomas 'PointedEars' Lahn

Garrett said:
No, to determine if #x is a child of the inserted element, the simplest
approach is to compare the inserted element to x's parentNode.
[...]
What are you trying to do?

Will you *please* learn to post.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Matt said:
function containsId1(el,id) {
return (el.ownerDocument.evaluate('descendant-or-self::*[@id = "' +id
+ '"]', el, null, 9, null).singleNodeValue !== null);
}
function containsId2(el,id) {
return (el.querySelectorAll('#'+id).length==1);
}
function containsId3(el,id) {
var o = document.getElementById(id);
if (o) {
if (id===o.id) { return true; }
while (o=o.parentNode) {
if (id===o.id) { return true; }
}
}
return false;
}

It turns out that the XPath approach is about 100ms slower over 5,000
iterations of a simple test case (insignificant), and the other two
are practically equal. So I guess there is no reason not to use the
last approach, which is the most backwards-compatible.

Told you :)


PointedEars
 
M

Matt Kruse

No, to determine if #x is a child of the inserted element, the simplest
approach is to compare the inserted element to x's parentNode.
To determine if #x is a *descendant* of the inserted element is a
different task. It is not a difficult one; and many recent browsers
supply functionality

Yes, I meant descendant, not direct child.
You wrote that you are using a DOMNodeInserted mutation event. Perhaps
that is not the best choice here.
What are you trying to do?

I'm actually writing script to manipulate Facebook. When objects with
certain id's are injected into the page, I want to manipulate them.
Since Facebook's navigation scheme is a mess, catching node insertions
and seeing if a given id has been inserted works well.

Matt Kruse
 
G

Garrett Smith

Yes, I meant descendant, not direct child.


I'm actually writing script to manipulate Facebook. When objects with
certain id's are injected into the page, I want to manipulate them.
Since Facebook's navigation scheme is a mess, catching node insertions
and seeing if a given id has been inserted works well.

I'm still a little fuzzy on the big picture, so this may not help.

Check to see if #x exists prior to appending the container. If it does,
the container not contain #x (unless the container has removed #x and
appends it to itself at that time).

Otherwise, after appending the container, check to see if #x exists. If
it does, then the container contains it.

var x = document.getElementById("x");
addContainer();
containerHasX = !x && document.getElementById("x");

Mutation events have been known to hurt performance. I'm not up on the
details of which mutation events hurt performance in which browsers.
Generally I avoid mutation event because they don't work in IE <= 8.

Garrett
 
T

Thomas 'PointedEars' Lahn

Garrett said:
I'm actually writing script to manipulate Facebook. When objects with
certain id's are injected into the page, I want to manipulate them.
Since Facebook's navigation scheme is a mess, catching node insertions
and seeing if a given id has been inserted works well.

I'm still a little fuzzy on the big picture, so this may not help.

Check to see if #x exists prior to appending the container. If it does,
the container not contain #x (unless the container has removed #x and
appends it to itself at that time).
YGCIB.

[...]
Mutation events have been known to hurt performance. I'm not up on the
details of which mutation events hurt performance in which browsers.
Generally I avoid mutation event because they don't work in IE <= 8.

Polling the status of the document tree very likely hurts performance a lot
more than listening to mutation events. Granted, polling is more
compatible, but there is no good reason to do that where mutation events are
supported. And you don't seem to have noticed that the problem has already
been solved satisfactorily.


PointedEars
 
M

Matt Kruse

Check to see if #x exists prior to appending the container. If it does,
the container not contain #x (unless the container has removed #x and
appends it to itself at that time).

I am not appending the container. Facebook's code is. I am just trying
to trap the insertion of content and do something with it. That's why
I'm relying on the mutation events, because I can't hook into their
code and it's near impossible to comprehend even if I could.
Mutation events have been known to hurt performance. I'm not up on the
details of which mutation events hurt performance in which browsers.

I've not experienced any performance problems yet. It certain beats
repeatedly polling document.getElementById() to see if something was
inserted, which certainly has its own problems.

One frustration I do have is that DOMNodeInsertedIntoDocument does not
bubble like DOMNodeInserted does. Since I only watch to catch actual
insertions and not moving around of elements, I'd prefer the former
but I have to use the latter and process every insertion event.
Generally I avoid mutation event because they don't work in IE <= 8.

I'd never used them before wandering into the wonderful world of
Greasemonkey where all I care about is Firefox/Chrome. It's a lovely
place. :)

Matt Kruse
 
G

Garrett Smith

I am not appending the container. Facebook's code is. I am just trying
to trap the insertion of content and do something with it. That's why
I'm relying on the mutation events, because I can't hook into their
code and it's near impossible to comprehend even if I could.

OK, so apparently there is there no way to know when FB appends the
container.

If #x will be only inserted at most once, then once it is inserted, the
callback that was listening for that, be it a facebook event, a mutation
event, or an event of your own design, can be removed.
I've not experienced any performance problems yet. It certain beats
repeatedly polling document.getElementById() to see if something was
inserted, which certainly has its own problems.

One frustration I do have is that DOMNodeInsertedIntoDocument does not
bubble like DOMNodeInserted does. Since I only watch to catch actual
insertions and not moving around of elements, I'd prefer the former
but I have to use the latter and process every insertion event.

If the callback does not find #x, then it exits. Once #x is found, the
callback gets the information it needs and unregisters itself.
I'd never used them before wandering into the wonderful world of
Greasemonkey where all I care about is Firefox/Chrome. It's a lovely
place. :)

Greasemonkey? Does is actually work now? I remember all sorts of
problems with it. For some reason guys at Yahoo love it. I remember guys
going out of there way to keep old versions of Firefox just to avoid the
problems with it not working in the upgrade.
 
M

Matt Kruse

OK, so apparently there is there no way to know when FB appends the
container.
True.

If #x will be only inserted at most once, then once it is inserted, the
callback that was listening for that, be it a facebook event, a mutation
event, or an event of your own design, can be removed.

Unfortunately, they do some strange ajax navigation stuff. Containers
get added, then removed, seemingly at random. My goal is to trap the
cases where the containers exist, and insert my content. If they get
removed and added again as the user navigates, add the stuff again. So
I keep my listeners around.
Greasemonkey? Does is actually work now? I remember all sorts of
problems with it. For some reason guys at Yahoo love it. I remember guys
going out of there way to keep old versions of Firefox just to avoid the
problems with it not working in the upgrade.

It works great for me. Not sure of what issues exist. FWIW,
http://BetterFacebook.net is the code I'm tinkering with. It's evolved
into kind of a sloppy mess right now, but I'm re-writing portions of
it to better use these mutation events in an attempt to make it more
robust.

Matt Kruse
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top