Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 5 of 5
  1. #1
    New to the CF scene
    Join Date
    Feb 2006
    Location
    Richmond, CA
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Detecting nested lists by traversing nodes

    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?

  • #2
    Regular Coder
    Join Date
    May 2005
    Location
    Michigan, USA
    Posts
    566
    Thanks
    0
    Thanked 0 Times in 0 Posts
    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
    Code:
    <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
    Code:
    function flyout( obj ) {
    	var aUL = obj.getElementsByTagName('ul');
    	if ( aUL.length > 0 ) {
    		//The first one (aUL[0]) holds your top level child
    	}
    }
    Note: I do not test code. I just write it off the top of my head. There might be bugs in it! But if any thing I gave you the overall theory of what you need to accomplish. Also there are plenty of other ways to accomplish this same thing. I just gave one example of it. Other ways might be faster and more efficient.

  • #3
    New to the CF scene
    Join Date
    Feb 2006
    Location
    Richmond, CA
    Posts
    3
    Thanks
    0
    Thanked 0 Times in 0 Posts
    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?

  • #4
    New Coder
    Join Date
    Mar 2003
    Location
    Somewhere far beyond
    Posts
    99
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Related question: How can I pass the node values in a setTimeout()?
    you can use closure for that:
    Code:
    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);
       }
    }
    WBR, Weirdan.

  • #5
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,518
    Thanks
    3
    Thanked 506 Times in 493 Posts
    Extract that organises the IL UL nesting for the list
    see my site search for List Menu

    Code:
    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);
     }
    }
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •