...

View Full Version : Detecting nested lists by traversing nodes



matbergman
02-22-2006, 06:31 PM
I want to simplify my markup by elimating IDs, and relying on traversing the document tree to detect the presence of specific tags.

I am creating a flyout navigation with a set of nested HTML lists, CSS, and a bit of JavaScript. My protype functions fine, and the HTML that generates the navigation (sans styles and scripts) looks something like this:

<ul>
<li onMouseOver="flyout('flyout_1');"><a href="#">Navigation item 1</a>
<ul id="flyout_1">
<li><a href="#">Navigation item 1.1</a></li>
<li><a href="#">Navigation item 1.2</a></li>
</ul>
</li>
<li><a href="#">Navigation item 2</a></li>
</ul>

This example relies on the getElementById() method to display the nested <ul>. It works by passing the ID of the hidden list in the "flyout" function so that JavaScript can control the DISPLAY property of that element. I want to eliminate the IDs in the tags, and instead identify nested lists by traversing the document's nodes and utilizing the getElementsByTagName() method. Ideally, if a list item is moused over, the script would detect if a child <ul> tag exists, and if so, set the child list's display from "none" to "block".

Here's some non-functioning pseudo-code to suggest what I'm trying to accomplish:
var children = document.getElementsByTagName("ul").childNodes;
for (i=0; i<children.length; i++) {
if (children[i]=="ul") {display the list}
}

Of course, my existing script that utilizes the getElementsById() method works fine. I've built several of these navigations for my clients, but I'm always looking for ways to streamline the markup aspect of my projects, and traversing the document tree seems to be a potentially powerful solution. I have accomplished something similar in XSLT before, but my attempts to do the same in JavaScript have not been successful. Is my goal possible?

SpirtOfGrandeur
02-22-2006, 07:05 PM
You should really use CSS menu's (google for suckerfish) but if you must have it then like this is the way it would go.

HTML
<ul>
<li onMouseOver="flyout(this);"><a href="#">Navigation item 1</a>
<ul>
<li><a href="#">Navigation item 1.1</a></li>
<li><a href="#">Navigation item 1.2</a></li>
</ul>
</li>
<li><a href="#">Navigation item 2</a></li>
</ul>

JS
function flyout( obj ) {
var aUL = obj.getElementsByTagName('ul');
if ( aUL.length > 0 ) {
//The first one (aUL[0]) holds your top level child
}
}

matbergman
02-25-2006, 01:06 AM
Thanks for your quick response. It exactly answered my question about traversing nodes.

I should have been more clear and stated that my list-based flyout navigation is based on the Suckerfish nav (actually, multi-level Son of Suckerfish dropdowns). I'm using DOM scripting to add additonal control over the menu, including a delay before dropdowns close, arrows next to links if sub-flyouts exist for it, and Internet Explorer enhancements. In keeping with the spirit of the Suckerfish dropdowns, I want to keep my markup pristine.

Related question: How can I pass the node values in a setTimeout()? Example: I can run my "closeFlyout" function (it's fired with an onmouseout event) this way:
function flyout( obj ) {
var aUL = obj.getElementsByTagName('ul');
if ( aUL.length > 0 ) {
closeFlyouts(this);
}
}

function closeFlyouts(obj) {
var passedUL = obj.getElementsByTagName("ul");
//modify flyout display
}

However, when I attempt the same thing with a setTimeout(), the parameter is translated literally and the function fails:
function flyout( obj ) {
var aUL = obj.getElementsByTagName('ul');
if ( aUL.length > 0 ) {
t = setTimeout("closeFlyouts("+this+")",500);
}
}

Is there some sort of evaluation or translation step I'm missing?

Weirdan
03-01-2006, 04:16 PM
Related question: How can I pass the node values in a setTimeout()?
you can use closure for that:



function closeFlyouts(obj) {
var passedUL = obj.getElementsByTagName("ul");
//modify flyout display
}

function flyout( obj ) {
var me = this;
var aUL = obj.getElementsByTagName('ul');
if ( aUL.length > 0 ) {
t = setTimeout(function() {closeFlyouts(me);},500);
}
}

vwphillips
03-04-2006, 10:54 PM
Extract that organises the IL UL nesting for the list
see my site search for List Menu


function zxcInitList(zxcid,zxcsimg,zxcline){
zxcsimg=zxcsimg||['','',''];
zxcp=document.getElementById(zxcid);
// zxcp.ary fields - 0 = id, 1 = .nu, 2 = line attributes, 3 = displayed items, 4 = line objects, 5 on = master LIs
zxcp.ary=[zxcp,[],zxcline,[],[]];
var zxcary=[];
var zxcels=zxcp.getElementsByTagName('*')||zxcp.all;
for (var zxc0=0;zxc0<zxcels.length;zxc0++){
if (zxcels[zxc0].tagName.toUpperCase()=='LI'){
zxcels[zxc0].style.listStyleImage='url('+zxcsimg[0]+')';
zxcAddEvent(zxcels[zxc0],'zxcDisplay','click');
}
if (zxcels[zxc0].tagName.toUpperCase()=='UL'||zxcels[zxc0].tagName.toUpperCase()=='LI'){
zxcary.push(zxcels[zxc0]);
}
if (zxcels[zxc0].tagName.toUpperCase()=='UL'){
zxcels[zxc0].ary=[];
}
if (zxcels[zxc0].tagName.toUpperCase()=='LI'){
zxcels[zxc0].parentNode.ary.push(zxcels[zxc0]);
}
}
for (var zxc1=1;zxc1<zxcary.length;zxc1++){
if (zxcary[zxc1].tagName.toUpperCase()=='UL'&&zxcary[zxc1-1].tagName.toUpperCase()=='LI'){
zxcary[zxc1-1].slave=zxcary[zxc1];
zxcary[zxc1-1].nu=zxc1;
zxcp.ary.push(zxcary[zxc1-1]);
zxcary[zxc1-1].ary=zxcp.ary;
zxcary[zxc1-1].style.cursor=zxcCursor;
}
}
for (var zxc2=5;zxc2<zxcp.ary.length;zxc2++){
zxcp.ary[zxc2].level=0;
zxcobj=zxcp.ary[zxc2];
while (zxcobj.parentNode!=zxcp){
zxcp.ary[zxc2].level++;
zxcobj=zxcobj.parentNode;
}
zxcp.ary[zxc2].slave.level=zxcp.ary[zxc2].level;
zxcp.ary[zxc2].slave.style.display='none';
zxcp.ary[zxc2].img=zxcsimg;
zxcp.ary[zxc2].style.listStyleImage='url('+zxcsimg[1]+')';
}
if (zxcGetCookie(zxcid)){
zxcookie=zxcGetCookie(zxcid).split('|');
for (var zxc4=0;zxc4<zxcookie.length;zxc4++){
for (var zxc5=5;zxc5<zxcp.ary.length;zxc5++){
if (zxcp.ary[zxc5].nu==zxcookie[zxc4]){
zxcp.ary[zxc5].slave.style.display='';
zxcp.ary[1].push(zxcp.ary[zxc5].nu);
zxcp.ary[zxc5].style.listStyleImage='url('+zxcsimg[2]+')';
}
}
}
zxcSetFormCookie(zxcid,zxcp.ary[1].join('|'));
}
if (zxcp.ary[2]&&window['zxcLines']){
zxcLines(zxcp.ary);
}
}



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum