PDA

View Full Version : Looping (recusing) through a HTML List



Bob90
06-01-2007, 03:45 PM
What is the best (Or at least a better) way to recurse through a HTML OL UL Element.

So far I have this, but it doesn't work and I don't know why.


function navNode(obj) {
var results = [];
var x=0;
while(obj.childNodes[x]) {
if(obj.childNodes[x].tagName == 'li') {
results[x] = "li"
}
else if(obj.childNodes[x].tagName == 'ul' || obj.childNodes[x].tagName == 'ol') {
results[x] = navNode(obj.childNodes[x])
}
x++
}
return results;
}


Any help would be appreciated.
:)

Trinithis
06-01-2007, 04:05 PM
EDIT: Added brace

Here's some code that fetches all the UL, OL, LI descendents of an element in no particular order. I'll batch up one that will go through the descendents in branching order in a couple minutes.


function navNode(obj) {
var results = [];
var ol = obj.getElementsByTagName("ol");
for(var i=0; i<ol.length; i++) {
results[results.length] = ol[i];
}
var ul = obj.getElementsByTagName("ul");
for(var i=0; i<ul.length; i++) {
results[results.length] = ul[i];
}
var li = obj.getElementsByTagName("li");
for(var i=0; i<li.length; i++) {
results[results.length] = li[i];
}
return results;
}

jscheuer1
06-01-2007, 04:25 PM
Disclaimer: This is not offered as a solution, just as an explanation of some of the factors involved. Trinithis' idea of getting the elements by tagName is a better approach overall. But, Trinithis forgot the opening brace on the function.

The original approach might work out if an additional test is added to avoid text nodes:


if(obj.childNodes[x].tagName && obj.childNodes[x].tagName == 'li')

This would also need to be done with the other test. And, the incrementing length of the results array would need to be broken out from the incrementing childNodes length. Oh, and when testing tagName, you must allow for variations in case:


function navNode(obj) {
var results = [];
var x=0;
while(obj.childNodes[x]) {
if(obj.childNodes[x].tagName && obj.childNodes[x].tagName.toLowerCase() == 'li') {
results[results.length] = "li"
}
else if(obj.childNodes[x].tagName && obj.childNodes[x].tagName.toLowerCase() == 'ul' || obj.childNodes[x].tagName.toLowerCase() == 'ol') {
results[results.length] = navNode(obj.childNodes[x])
}
x++
}
return results;
}

But, this still doesn't take into account that it appears (can't be 100&#37; sure without seeing the markup), at least as though some of the elements you are looking for are the original element's children's children and you haven't set it up to look for/deal with those until after they are found, which they never would be.

Trinithis
06-01-2007, 05:02 PM
jscheuer1: node.tagName always returns uppercase tags

I finished making my improved navNode. It walks down the node in a sequential fashion.


function navNode(obj) {
var results = [];
for(var i=0; i<obj.childNodes.length; i++) {
if(obj.childNodes[i].tagName=="OL" || obj.childNodes[i].tagName=="UL" || obj.childNodes[i].tagName=="LI") {
results[results.length] = obj.childNodes[i];
var temp = navNode(obj.childNodes[i]);
if(temp.length) results = results.concat(temp);
}
}
return results;
}


For something like:


<ol id="list1">
<li>
<ol>
<li>
0
</li>
<ul>
<li>
1
</li>
<li>
2
</li>
<li>
3
</li>
</ul>
</ol>
</li>
<li>
4
</li>
</ol>

my new navNode returns: [object HTMLLIElement],[object HTMLOListElement],[object HTMLLIElement],[object HTMLUListElement],[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement]

vs.

my old one returning: [object HTMLOListElement],[object HTMLUListElement],[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement]

jscheuer1
06-01-2007, 05:09 PM
Nice looking function, Trinithis.

Can you be 100&#37; sure of the case in all browsers? I can't. I don't have enough browsers around to know for sure. It is a simple matter to convert to one case or the other for testing purposes. And, I still wonder, what about text nodes? When looping through children, these can be pesky in Mozilla based browsers, possibly others.

Trinithis
06-01-2007, 05:15 PM
EDIT: jscheuer1, theroetically tagName returns uppercase tag names. I read this in a book called "JavaScript Bible", and it says tagName is supported in Mac/WinIE4+, NN6+, Moz1+, Safari1+.

It seems as if text nodes have a tagName of undefined in both my IE6 and FF1, causing no issue there. And yeah, I suppose my function won't work if the browser does not support DOM nodes or whatever.

Bob90
06-01-2007, 07:13 PM
Hey, thank you both.

Text nodes are definitely undefined and Mozilla says .tagName is lowercase for XHTML (Or any XML based language) and uppercase for HTML. Wierd.

http://developer.mozilla.org/en/docs/DOM:element.tagName

Bob90
06-01-2007, 07:58 PM
I'm having problems with IE (Suprise! ;) )
It doesn't seem to recognise UL and OL within other OL ULs?


So far I have...


function navNode(obj) {
var results = [];
for(var i=0; i<obj.childNodes.length; i++) {
var tgNm = obj.childNodes[i].tagName? obj.childNodes[i].tagName.toUpperCase(): undefined;
alert(tgNm);
if(tgNm=="OL" || tgNm=="UL") {
results[results.length] = obj.childNodes[i];
var temp = this.navNode(obj.childNodes[i]);
if(temp.length) results = results;
}
else if(tgNm=="LI") {
results[results.length] = obj.childNodes[i];
}
}
return results;
}

Acting on...

<ul id="makeRadial">
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home2" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home2" rollover="crystalclear/x40/house.png"></a></li>
<ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<ol>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
</ol>
</ul>
<ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
</ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
</ul>

IE only sees the top level LI items of the first UL.

Trinithis
06-01-2007, 08:28 PM
With your code, FF returns an array of length 10, IE returns length 8.

With my code, both return length 22.



var tgNm = obj.childNodes[i].tagName? obj.childNodes[i].tagName.toUpperCase(): undefined;
//No point in making tgNm undefined, just make it an empty string.
var tgNm = obj.childNodes[i].tagName? obj.childNodes[i].tagName.toUpperCase(): "";


Looking at your original first-post code, it looks like you only want the LI elements. If that is the case, just use


navNode(obj){return obj.getElementsByTagName("li");}


If you want to filter out some of the tags, try


function navNode(obj) {
var results = [];
for(var i=0; i<obj.childNodes.length; i++) {
var tgNm = obj.childNodes[i].tagName?obj.childNodes[i].tagName.toUpperCase():"";
if(tgNm=="OL" || tgNm=="UL" || tgNm=="LI") {
if(tgNm!="OL") results[results.length] = obj.childNodes[i]; //Or something like that if you don't want OL for instance.
results = results.concat(navNode(obj.childNodes[i])); //I took out the temp because errors don't seem to arise when concatenating an empty array to another.
}
}
return results;
}

If you need more help, I guess you can clarify what exactly you want this function to return and/or do.

Twey
06-01-2007, 09:10 PM
Text nodes are definitely undefined and Mozilla says .tagName is lowercase for XHTML (Or any XML based language) and uppercase for HTML. Wierd.Not weird at all. SGML (and thus HTML) is case-insensitive, and traditionally .tagName has been upper-case. XML, however, is all lower-case, so .tagName (or .nodeName) must be lower-case.

As Trinithis says, all that's necessary is:
obj.getElementsByTagName("li");That will get any <li> elements under obj, even if they're in another tag.

jscheuer1
06-02-2007, 06:17 AM
Yeah, I knew there was a reason, or rather just have the instincts to tell me that upper or lower case cannot simply be assumed for the tagName property.

I also agree, that if all that is wanted are the li's, getElementsByTagName('li') - a case insensitive method, is best. Even if other tags are required, I like getElementsByTagName() if it can possibly do the required work, as it is so much more straightforward than looping nodes.

Now, about these tagName properties. I thought if they were undefined, that might break the script. It would screw up numbering things in some cases. But, the big problem with undefined in one browser being OK is that other browsers might barf on them. Instinct again. It very rarely hurts to make sure that a property you are testing exists before evaluating its value. On the other hand, if you test for the value of a property that does not exist, then you almost always will have trouble. Never assume that just because it's OK in this or that browser(s), that it will be OK in all.

Twey
06-02-2007, 07:54 AM
Now, about these tagName properties. I thought if they were undefined, that might break the script.The script checked first that .tagName == "li". If tagName is undefined, it doesn't equal "li".
On the other hand, if you test for the value of a property that does not exist, then you almost always will have trouble.Testing against undefined is fine. Problems would only occur if one were to attempt to use a property, such as .length. Undefined is just an object, using it (apart from attempting to perform a property set or lookup) won't cause any problems.

jscheuer1
06-02-2007, 08:48 AM
My point was though, with something like a tagName property, where there is no tag, where there can never be a tagName, if it is undefined in one browser, in some other it may be non-existent. The tagName property of a text node, regardless of how any particular browser views it, is non-existent. Hence, testing that the property exists first is merely prudent.

Twey
06-02-2007, 04:02 PM
My point was though, with something like a tagName property, where there is no tag, where there can never be a tagName, if it is undefined in one browser, in some other it may be non-existent.That's what undefined means. ECMAScript allows reference of properties up to one level down for exactly this sort of purpose.

jscheuer1
06-02-2007, 04:50 PM
That's what undefined means. ECMAScript allows reference of properties up to one level down for exactly this sort of purpose.

What ECMAScript allows and what happens in any given browser are not always the same thing. Didn't you just mention that this does not happen so gracefully if it is the width of a text node? I suppose you could say that is more than one level down, but it isn't written that way:


node.tagName

and:


node.width

look to be the same depth. Looks inconsistent and may even be. To have a tagName, you need to be a tag - two levels. In any case as I said, it almost never hurts to test, but it can often mess you up if the property or method doesn't exist and you haven't tested for it first.

Twey
06-02-2007, 05:37 PM
What ECMAScript allows and what happens in any given browser are not always the same thing.Not in this case.
Didn't you just mention that this does not happen so gracefully if it is the width of a text node?Erm, not to my knowledge.
I suppose you could say that is more than one level down, but it isn't written that way:
node.tagNameand:
node.widthNo, that's definitely only one level, and there's nothing wrong with either of those, they'll simply return undefined.
To have a tagName, you need to be a tag - two levels.What? Assuming that obj is a valid object, accessing and comparing any property on obj is a valid operation, defined or not, whether it be width, tagName, or fishGenus.
In any case as I said, it almost never hurts to test, but it can often mess you up if the property or method doesn't exist and you haven't tested for it first.Again, as I said, if it doesn't exist it is undefined. All that needs to be tested (if there is a chance it could be undefined) is the base object.

Bob90
06-02-2007, 10:19 PM
I really didn't explain myself well; just a case of me wanting to learn, but asking the wrong questions.

I want to make an array for each level of the list. (Or a structured array)



<ul id="makeRadial">
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home2" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home2" rollover="crystalclear/x40/house.png"></a></li>
<ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<ol>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
</ol>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
</ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
</ul>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home3" rollover="crystalclear/x40/house.png"></a></li>
<li><a href="http://www.robertgarford.com" target="_self"></a><img src="crystalclear/x40/house.png" title="Home4" rollover="crystalclear/x40/house.png"></a></li>
</ul>


So, in my previous example 4 arrays would be produced,
1 - Level 0, 8 elements, 2 Sub Levels connected
2 - Level 1, 7 elements, 1 Sub level connected
3 - Level 2, 4 elements
4 - Level 1, 4 elements

Any advice would be great.

:)

p.s. This is connected to my radial menu. Each li or ul represents a level of the menu. each li is a node.

Twey
06-02-2007, 11:25 PM
Ah, something like this:
function parseList(list) {
var ret = [], t;
for(var i = 0, e = list.childNodes; i < e.length; ++i)
// John, note the check for tagName's existence
// since we're accessing property toLowerCase
if(t = (e[i].tagName && e[i].tagName.toLowerCase()))
if(t === "li")
ret.push(e[i]);
else if(t === "ol" || t === "ul")
ret.push(parseList(e[i]));
return ret;
}

jscheuer1
06-03-2007, 02:59 AM
This looks a bit odd to me, I'm not saying it is wrong :



if(t = (e[i].tagName && e[i].tagName.toLowerCase()))

My instinct would be to use:


if(e[i].tagName && (t=e[i].tagName.toLowerCase()))

I suppose they could be equivalent. The method I wrote looks more specific to me though, as far as what the value of t would be and under what circumstances.

jscheuer1
06-03-2007, 03:38 AM
Oh, and getting back to testing for existence. You've pretty much proved my point in that, it may be fine to ignore this at one level of depth, but how do you know that you will stop there, or that you will not add another level later? I stand by what I said:


it almost never hurts to test, but it can often mess you up if the property or method doesn't exist and you haven't tested for it first

Trinithis
06-03-2007, 07:00 AM
I want to make an array for each level of the list. (Or a structured array)
[ . . . ]
So, in my previous example 4 arrays would be produced,
1 - Level 0, 8 elements, 2 Sub Levels connected
2 - Level 1, 7 elements, 1 Sub level connected
3 - Level 2, 4 elements
4 - Level 1, 4 elements


How about this?


function parseList(o) {
var a = [];
function augmentA(o, a) {
var x = a.length;
a[x] = [];
a[x].$ = [];
for(var i=0, c=o.childNodes, n; i<c.length; i++) {
n = c[i].tagName?c[i].tagName.toLowerCase():"";
if(n==="li") a[x].$[a[x].$.length] = c[i];
if(n==="ol" || n==="ul") a[x] = augmentA(c[i], a[x]);
}
return a;
}
augmentA(o, a);
return a;
}


In this case parseList(document.getElementById("makeRadial")) returns a tiered array that resembles the leveled output you want.

(a[x] represents your level 0, and a[x][y][z] represents your level 2 for instance.)

a[0].length == 2
a[0][0].length == 1
a[0][0][0].length == 0
a[0][1].length == 0

a[0].$.length == 8
a[0][0].$.length == 7
a[0][0][0].$.length == 4
a[0][1].$.length == 4

If you like this, feel free to change the $ to something else (such as "lists" or "els" or something) if you want.

BTW, Twey's code needs a ) here, as seen as bolded.

ret.push(parseList(e[i]));

Twey
06-03-2007, 01:04 PM
It does, I've edited the original to avoid confusion.
Trinithis, the outer function is kind of pointless, and I'm not sure if that will work in IE -- it may count as conditional function declaration. It basically does what my code does, but in a more roundabout fashion using references rather than returns.
This looks a bit odd to me, I'm not saying it is wrong :
if(t = (e[i].tagName && e[i].tagName.toLowerCase()))My instinct would be to use:
if(e[i].tagName && (t=e[i].tagName.toLowerCase()))I suppose they could be equivalent. The method I wrote looks more specific to me though, as far as what the value of t would be and under what circumstances.No, yours will break. If you follow mine through:
if(t = (e[i].tagName && e[i].tagName.toLowerCase())If e[i].tagName does not exist (is undefined), it will be falsy and the check will end, returning undefined or an empty string so t becomes undefined. If tagName is not falsy, however, we assume it to be a string (a fair assumption) and call its toLowerCase() property, which is then returned by the condition and assigned to t. Your code is all very well and good, but t is only defined once, outside the loop, and it fails to reset the value of t if the tagName does not exist: the script will try to act on the previous value of t and almost certainly break.
Oh, and getting back to testing for existence. You've pretty much proved my point in that, it may be fine to ignore this at one level of depth, but how do you know that you will stop there, or that you will not add another level later?Then one should check where necessary, not where it is not. In my script, it was necessary; in yours, it was unnecessary overhead.

Trinithis
06-03-2007, 03:37 PM
The outer function is basically to soley define a[]. I suppose I could remove the outer loop for something like this:

if(a===undefined) var a = [];

The main difference between our codes, I think is that mine provides an better interface to access the next level down; all you need to do is tack on another dimension to the array after checking the previous dimension's length>0.

Yours on the other hand provides a better way of seeing where the next level down happens, such as a[4].

Edit: You're right about it not working correctly in IE, but for a different reason. It does not pick up the UL or OL tags. Will try to fix.

Twey
06-03-2007, 04:03 PM
Huh? Mine produces pretty much the same output as yours. For the HTML:
<ul>
<li>item1</li>
<li>item2</li>
<ul>
<li>item3</li>
<li>item4</li>
</ul>
<ul>
<li>item5</li>
<li>item6</li>
<ul>
<li>item7</li>
<li>item8</li>
</ul>
<ul>
<li>item9</li>
<li>item10</li>
</ul>
</ul>
</ul>Mine should produce:
[
item1,
item2,
[
item3,
item4
],
[
item5,
item6
[
item7,
item8
]
[
item9,
item10
]
]
]Yours should produce:
{
'$' : [
item1,
item2
],
1 : {
'$' : [
item3,
item4
]
},
2 : {
'$' : [
item5,
item6
],
1 : {
'$' : [
item7,
item8
],
1 : {
'$' : [
item9,
item10
]
}
}
}
}I don't see the advantage your format offers over mine...
The outer function is basically to soley define a[]. I suppose I could remove the outer loop for something like this:You could also use a closure, recurse as I did, or make augmentA() the outer function and make the a argument optional, in which case an empty array is used instead.

Trinithis
06-03-2007, 04:05 PM
IE6 (maybe 7 too) won't do radialMenu's childNodes correctly. It is not getting its textNodes and its UL and OL tags. This is problematic for both Twey's and my code.


What advantage is it supposed to provide?
Perhaps it doesn't provide an advantage, but I personally think it is easier to visualize this model for this case. I guess it is so you can dig deeper into the array without knowing where you are. It's more of a branching-tiered structure vs. a direct-branching structure if that makes any sense. Each indice is a tier and you can acess the tier's components through $. (Mind you, not through a direct array because that would bring up a subtier.) With yours in order to go to the next level down, you have to explicity provide the array's indice that branches out. Maybe I'm not making sense, but in all, they do quite similar things; it's just that they provide different interfaces to do it.

Twey
06-03-2007, 04:30 PM
Perhaps it doesn't provide an advantage, but I personally think it is easier to visualize this model for this case.I found it astonishingly difficult to grasp, although I guess this is a matter of taste. It also doesn't preserve the order between the <ul>s and the <li>s.

Bob90
06-03-2007, 06:50 PM
Hi,

Thanks to both of you.
I won't have time to check them out for a few days as I have exams.
They both look good, but I will check out the IE problem.