473,395 Members | 2,467 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Dom walking for dummies

Hi guys!

I'm working on a little javascriptlet/greasemonkey script, and I've run
into a challenge that I think can be solved with walking the DOM, but I
feel like I'm kludging my way through and wondering if there might be a
better answer out there.

Here's the problem: I want to insertCell(0) into an existing table, but
the table doesn't have a NAME or ID. I don't have the option of adding
these (it's for Wikipedia) and would like to programatically navigate
my way to the table. The table is inside a FORM element that _does_
have an ID, so it's pretty close to a known entry point. I was
originally planning on using .firstChild a few times in a nested
sequence to work my way down to the table, but it's proving trickier
than I thought it would, hence my question here.

Here's the relevant snippet of HTML I'm working with:

---------
<form id="blockip" method="post"
action="/w/index.php?title=Special:Blockip&amp;action=submit" >
<table border='0'>
<tr>
<td align="right">User:</td>
<td align="left">
---------

I want to insertCell(0) a new cell into the first TR in the table, then
setAttribute it to a rowspan of 8. My original foray into walking (or
perhaps stumbling is a better choice) the DOM was something like this:
var parent_form = document.getElementById('blockip');
var spectable = parent_form.firstChild;
var spectr = spectable.firstChild;
var newcell = spectr.firstChild.insertCell(0);

It matches the nesting shown above, but it feels kludgy and has the
added benefit of not working.

For you folks out there that might find themselves in the same sort of
situation (you can't add the ID to the existing table, but you need to
interact with it), how would you resolve this? Am I on the right path,
or is there a smarter way to get from point A to point B?

The end result is that I want to add a cell to the far left of the
table then insert a select element I'm currently jamming underneath
into it for better presentation.

Thanks!

Ben

Dec 20 '06 #1
8 2090
Ben Hallert wrote:
Hi guys!

I'm working on a little javascriptlet/greasemonkey script, and I've run
into a challenge that I think can be solved with walking the DOM, but I
feel like I'm kludging my way through and wondering if there might be a
better answer out there.

Here's the problem: I want to insertCell(0) into an existing table, but
the table doesn't have a NAME or ID. I don't have the option of adding
these (it's for Wikipedia) and would like to programatically navigate
my way to the table. The table is inside a FORM element that _does_
have an ID, so it's pretty close to a known entry point. I was
originally planning on using .firstChild a few times in a nested
sequence to work my way down to the table, but it's proving trickier
than I thought it would, hence my question here.

Here's the relevant snippet of HTML I'm working with:

---------
<form id="blockip" method="post"
action="/w/index.php?title=Special:Blockip&amp;action=submit" >
<table border='0'>
<tr>
<td align="right">User:</td>
<td align="left">
---------

I want to insertCell(0) a new cell into the first TR in the table, then
setAttribute it to a rowspan of 8. My original foray into walking (or
perhaps stumbling is a better choice) the DOM was something like this:
var parent_form = document.getElementById('blockip');
var spectable = parent_form.firstChild;
var spectr = spectable.firstChild;
var newcell = spectr.firstChild.insertCell(0);

It matches the nesting shown above, but it feels kludgy and has the
added benefit of not working.

For you folks out there that might find themselves in the same sort of
situation (you can't add the ID to the existing table, but you need to
interact with it), how would you resolve this? Am I on the right path,
or is there a smarter way to get from point A to point B?

The end result is that I want to add a cell to the far left of the
table then insert a select element I'm currently jamming underneath
into it for better presentation.

Thanks!

Ben
You're on the right track it looks like. Traverse the DOM while looking
for entities with an ID that matches the one you know for the form.
Then traverse down while looking for the nested tags you know will be
there. e.g. tr and td. Here's a snippet I have written that won't apply
directly, but I think it will give you some insight.

function changeLinks(selAttributes, assignVal){
var aAttribNames = selAttributes.split(',');
var alltags=document.getElementsByTagName("a") ?
document.getElementsByTagName("a") : document.all;

for (i=0; i<alltags.length; i++){
// this modifies every link
for (j=0; j<aAttribNames.length; j++){
if (alltags[i].href && alltags[i].href.length) {
eval("alltags[i].style."+aAttribNames[j]+"='"+assignVal+"'");
}
}

//changeLinks('linkColor', '#FF0000');
//only modify links with an id set

if(alltags[i].id) {
if (alltags[i].id.substr(0,alltags[i].id.length)=='IDOFTHEFORM'){
if (alltags[i].innerHTML && alltags[i].innerHTML.length) {
//document.getElementById('statusDiv').innerHTML+=al ltags[i].innerText;
if (alltags[i].canHaveChildren) {
for (j=0; j<alltags[i].childNodes.length; j++){
if(alltags[i].childNodes[j].nodeName == 'IMG') {
//alert(alltags[i].childNodes[j].getAttribute('src'));
alltags[i].childNodes[j].src =
'http://127.0.0.1/myspace/images/767235372_s.jpg';
var thingie = "alltags[i]";
while (eval(thingie+".parentElement.tagName") != "HTML" ) {
thingie+='.parentElement';
document.getElementById('dumper').innerText+=eval( thingie+".parentNode.style.borderColor");
document.getElementById('dumper').innerHtml+='<br> ';
//alert(alltags[i].parentElement.tagName);
}
}
}
}
}
}
}
}
}

Dec 20 '06 #2


On Dec 20, 7:11 am, "Ben Hallert" <ben.hall...@gmail.comwrote:
Hi guys!

I'm working on a little javascriptlet/greasemonkey script, and I've run
into a challenge that I think can be solved with walking the DOM, but I
feel like I'm kludging my way through and wondering if there might be a
better answer out there.

Here's the problem: I want to insertCell(0) into an existing table, but
the table doesn't have a NAME or ID. I don't have the option of adding
these (it's for Wikipedia) and would like to programatically navigate
my way to the table. The table is inside a FORM element that _does_
have an ID, so it's pretty close to a known entry point. I was
originally planning on using .firstChild a few times in a nested
sequence to work my way down to the table, but it's proving trickier
than I thought it would, hence my question here.

Here's the relevant snippet of HTML I'm working with:

---------
<form id="blockip" method="post"
action="/w/index.php?title=Special:Blockip&amp;action=submit" >
<table border='0'>
<tr>
<td align="right">User:</td>
<td align="left">
---------
>
I want to insertCell(0) a new cell into the first TR in the table, then
setAttribute it to a rowspan of 8. My original foray into walking (or
perhaps stumbling is a better choice) the DOM was something like this:
var parent_form = document.getElementById('blockip');
var spectable = parent_form.firstChild;
var spectr = spectable.firstChild;
var newcell = spectr.firstChild.insertCell(0);
You said you have;
<form>
<table>
<tr>
<td></td>
<td></td>
....
</tr>
....
</table>
....
</form>

You first select the Form = <form>
Then you take the firstChild = <table>
Then you take the firstChild again = <tr>
Then you take the firstChild yet again = <td>

To my knowledge "insertCell" works on Table-Rows (TR) and not
Table-Cells (TD).
>
It matches the nesting shown above, but it feels kludgy and has the
added benefit of not working.

For you folks out there that might find themselves in the same sort of
situation (you can't add the ID to the existing table, but you need to
interact with it), how would you resolve this? Am I on the right path,
or is there a smarter way to get from point A to point B?

The end result is that I want to add a cell to the far left of the
table then insert a select element I'm currently jamming underneath
into it for better presentation.

Thanks!

Ben
Dec 20 '06 #3
[on] wrote:
<snip>
You said you have;
<form>
<table>
<tr>
<td></td>
<td></td>
....
</tr>
....
</table>
....
</form>

You first select the Form = <form>
Then you take the firstChild = <table>
Then you take the firstChild again = <tr>
<snip>

What happened to the TBODY implied in HTML (but not in XHTML, where it
is optional)?

Richard.
Dec 20 '06 #4
Ben Hallert wrote:
<form id="blockip" method="post"
action="/w/index.php?title=Special:Blockip&amp;action=submit" >
<table border='0'>

Grag the form with
var form = document.getElementById('blockip');
then use getElementsByTagName on the element e.g.
if (form) {
var firstTable = form.getElementsByTagName('table')[0];
if (firstTable) {
// now you can look for firstTables.rows[0]
}
}

Other ways to access stuff in a Greasemonkey script are XPath (over
HTML) using document.evaluate as in a Greasemonkey script you know you
have support for that in Mozilla (or Opera 9).


--

Martin Honnen
http://JavaScript.FAQTs.com/
Dec 20 '06 #5
[on] wrote:
>
You first select the Form = <form>
Then you take the firstChild = <table>
Then you take the firstChild again = <tr>
Then you take the firstChild yet again = <td>
You cannot be sure this ancestry is correct. Quite often the
"firstChild" is white space.
Mick
Dec 20 '06 #6
pangea33 wrote:
<snip>
function changeLinks(selAttributes, assignVal){
var aAttribNames = selAttributes.split(',');
It is recommended that code not be posted indented with tabs. Sequences
of spaces should be used instead (preferably not that many per tab). The
width of a tab on the viewer's set-up is capable of varying
considerably, from zero to equivalents of 8 or more spaces (which is far
too many for each level of indentation when posted to news, where line
wrapping at 80ish characters is not unusual).
var alltags=document.getElementsByTagName("a") ?
document.getElementsByTagName("a") : document.all;
That is a very bizarre line of code. Instead of making a decision based
upon whether or not the browser environment supports a -
document.getElementsByTagName - it is making its decision on whether or
not a call to - document.getElementsByTagName('a') - returns an object
or not. But - document.getElementsByTagName - is specified as always
returning a NodeList, even if it may be an empty NodeList. Thus the -
document.all - alternative will never be taken, and if an environment
does not provide - document.getElementsByTagName - the attempt to call
that method will have the4 code error-out at that point ensuring that -
document.all - cannot serve as an alternative for older browsers.
for (i=0; i<alltags.length; i++){
Using a loop counter that has not been declared as a function local
variable is a dangerous habit. The veritable effectively becomes global
and when that error is made in one location it is often repeated in
another, with the consequence that if code in a loop calls another
function that runs another loop using the same global counter variable
the counter in the 'outer' loop will have the wrong value when the
called function returns. The general programming axiom that no variable
should ever be given more scope than it absolutely needs applies to
javascript as much as it does to any other language (even if the
scopeing units in javascript are as coarse as being at the function
definition level).
// this modifies every link
for (j=0; j<aAttribNames.length; j++){
if (alltags[i].href && alltags[i].href.length) {
Given the number of times - alltags[i] - is to be resolved in the
following code it would be a good idea to assigned a reference to the
element to a local variable. That is, with:-

var link;

- declared at the top of the function (at the top purely for style
reasons), here inside the loop the assignment:-

link = alltags[i];

- would avoid having to resolve the - i - property of the - alltags -
collection repeatedly.

When you test - alltags[i].href - the value of that property is
type-converted to boolean. If the element has no - href - property that
value is Undefined, which type-converts to boolean false. However, when
the element has an - href - property that property is a string
primitive. Empty string primitives (those with a length of zero)
type-convert to boolean false, while non-empty strings type-convert to
boolean true. This mans that the following - alltags[i].href.length - is
utterly redundant as its value is numeric and the number zero
type-converts to false while all non-zero (and non-NaN, which string
lengths cannot be) type-convert to true. Whenever the second test would
evaluate to false the first test had already evaluated to false,
short-circuiting the logical AND expression and preventing the
evaluation of the second expression.
eval("alltags[i].style."+aAttribNames[j]+"='"+assignVal+"'");
There is almost no need to ever use - eval - in javascript, particularly
with property accessors. Generally the use of - eval - with dot-notation
property accessors follows from an ignorance of bracket notation
property accessors. See:-

<URL: http://jibbering.com/faq/faq_notes/square_brackets.html >

The equivalent (but shorter and faster) code without the - eval - would
be:-

alltags[i].style[aAttribNames[j]] =' assignVal;

(or, given the proposed use of a local reference to - alltags[i] -:-

link.style[aAttribNames[j]] =' assignVal;

)
}
}

//changeLinks('linkColor', '#FF0000');
//only modify links with an id set

if(alltags[i].id) {
if (alltags[i].id.substr(0,alltags[i].id.length)=='IDOFTHEFORM'){
if (alltags[i].innerHTML && alltags[i].innerHTML.length) {
//document.getElementById('statusDiv').innerHTML+=al ltags[i].innerText;
if (alltags[i].canHaveChildren) {
for (j=0; j<alltags[i].childNodes.length; j++){
Another undeclared loop counter.
if(alltags[i].childNodes[j].nodeName == 'IMG') {
//alert(alltags[i].childNodes[j].getAttribute('src'));
alltags[i].childNodes[j].src =
'http://127.0.0.1/myspace/images/767235372_s.jpg';
var thingie = "alltags[i]";
This is another odd thing to be doing as it was always possible to
assign the value of - alltags[i] - to a variable.
while (eval(thingie+".parentElement.tagName") != "HTML" ) {
But that was being done to allow this second needless use of - eval -.
If the - link = alltags[i]; - assignment had been made then the - eval -
could have been - eval('link.parentElement.tagName') -, which instantly
reveals why it is pointless, as it can be directly replaced with -
link.parentElement.tagName - to the same effect (but again shorter and
faster), though - alltags[i].parentElement.tagName - would also have
worked without the - eval -.

Incidentally, - parentElement - is a proprietary Microsoft property. The
DOM standard equivalent is - parentNode -. The most recent Microsoft
browser that did not support - paraentNdoe - was IE 4, and IE 4
errored-out at the - document.getElementsByTagName("a") - call because
it has no - document.getElementsByTagName - method.
thingie+='.parentElement';
document.getElementById('dumper').innerText+=eval( thingie+".parentNode.s
tyle.borderColor");
document.getElementById('dumper').innerHtml+='<br> ';
//alert(alltags[i].parentElement.tagName);
}
<snip>

Without the - eval - above the loop logic here becomes:-

while(link.parentNode.tagName != "HTML" ) {
link = link.parentNode;
document.getElementById('dumper').innerText +=
link.parentNode.style.borderColor;
document.getElementById('dumper').innerHtml += '<br>';
}

- and another unnecessary - eval - is avoided.

Richard.
Dec 20 '06 #7
Great responses! I'll try out some of the techniques suggested and
report back. Very promising looking stuff, thanks!

Ben

Dec 20 '06 #8
All of the responses were very helpful! I ended up using Mr. Honnen's
method and it worked right out of the gate. I ran into something
interesting that I wanted to share. When I did a view-source on the
page, it gave me one structure (the one I posted above), but when I
used the Firebug extension to view the table directly, it indicated a
TBODY element was parent to the TRs. So I wrote it to use the
getElementsByName method to walk from the known form element that had
the ID down to the table, tbody, then TR. Once there, I created a
newcell object with insertCell then appendChild'd my click menu into
it. It worked perfectly.

I've put the full code of my script at
http://en.wikipedia.org/wiki/User:Ch...reasemonkey.js

Thanks a bunch!

Ben

Dec 20 '06 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

60
by: K. G. Suarez | last post by:
Hello everyone. I am new to programming and my uncle gave me a copy of "C For Dummies 2nd Edition". I am up to chapter 9 right now. He probably saw me struggling with "The C Programming...
1
by: Zachary Hartnett | last post by:
I was trying to write a routine this morning that would open a given assembly, walk the inheritance tree of classes in the assembly, and provide a list of classes in the assembly that inherit from...
10
by: Roy Lawson | last post by:
Can anyone explain the difference between RowStateFilter and RowFilter properties of the DataView objects in simple terms? I am going through a Transcender practice exam and just when I think I...
3
by: maigork | last post by:
C All-In-One Desk Reference For Dummies.pdf if it exist can anyone tell me where i can dovnload it? Thank you verry much!!!!
2
by: Carlo Stonebanks | last post by:
I have the infamous GoF Design Patterns boo - it's been sittin gon my shelf for years. I have a huge reading list and find this book a rather dry read and am always putting it off. I have...
2
by: Shelly | last post by:
I know C, C++ and Java. I have been using "procedural" PHP. I get the list of classes for PHP, but I need a "PHP OOP for Dummies" on how to implement these. Any pointers to a tutotial? Shelly
5
by: TrulyUnusualdotcom | last post by:
I'm reading PHP & MySQL for Dummies 2nd edition...ya ya I know..lame. Anyway I got to the part about walking through an array and I just can't seem to figure out what this would be used for. What...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.