Get all href values in <ul> group and compare with current url

Discussion in 'Javascript' started by michael, May 3, 2005.

  1. michael

    michael Guest

    Is it possible to get all href URLs contained in a unordered list and place
    them in an array?
    Or in fact two different arrays, differently named one for each <ul> group?

    <ul>
    <li><a href="lemurs.html">Lemurs</a></li>
    <li><a href="chameleons.html">Chameleons</a></li>
    </ul>

    <ul>
    <li><a href="sharks.html">Sharks</a></li>
    <li><a href="crocs.html">Crocodiles</a></li>
    </ul>

    I want to fetch an array of the links within a <ul> group, and
    document.write the above, but with class variable in which I can
    set a different value, depending on if the current url filename matches
    exactly any one of the links within the <ul> group the <li> belongs to.

    More specifically, I would like to ...

    document.write('<li class'+myvariable+'>')
    |
    ... class 'green' or 'blue' -------'
    depending on whether filename in any href contained
    in an <li> of the <ul> group it is in.
    If an exact match is found, write out green, if not blue.

    The file name portion of the current URL I simply get through:

    var f = window.location.href;
    file = i.substring (f.lastIndexOf('/') +1);

    It is for drop-down nav-system whereby all list items would of a ul group
    would appear either one of two colours as specified in css properties. All
    links are internal links on the same domain so one would always match.

    I could naturally do it all by having a pre-typed list of all filenames and
    run each <li> through an if statement before writing it out. But as there
    will be many <li>'s I would prefer a more typeless method if possible.

    Many thanks for any tips!

    Michael

    --
    (1) Everything depends.
    (2) Nothing is always.
    (3) Everything is sometimes.
    michael, May 3, 2005
    #1
    1. Advertising

  2. michael

    Jerome Bei Guest

    Try this:

    <script>
    uls = document.getElementsByTagName("UL");
    for (var u=0; u<uls.length; u++) {
    alert("entering list ["+u+"]");
    lis=uls.getElementsByTagName("LI");
    for (var i=0; i<lis.length; i++) {
    if (lis.childNodes[0] && lis.childNodes[0].href) {
    alert("found link ["+lis.childNodes[0].href+"]");
    }
    }
    }
    </script>

    (Testes on IE 6.0 only)

    --Jerome
    Jerome Bei, May 3, 2005
    #2
    1. Advertising

  3. michael

    michael Guest

    Jerome Bei wrote:

    > Try this:
    >
    > <script>
    > uls = document.getElementsByTagName("UL");
    > for (var u=0; u<uls.length; u++) {
    > alert("entering list ["+u+"]");
    > lis=uls.getElementsByTagName("LI");
    > for (var i=0; i<lis.length; i++) {
    > if (lis.childNodes[0] && lis.childNodes[0].href) {
    > alert("found link ["+lis.childNodes[0].href+"]");
    > }
    > }
    > }
    > </script>
    >
    > (Testes on IE 6.0 only)
    >
    > --Jerome


    Works nicely, fetches the links if there are, and it works on Mozilla too.

    Thanks!
    Michael

    -
    The human animal differs from the lesser primates in his passion for
    lists of "Ten Best".
    -- H. Allen Smith
    michael, May 4, 2005
    #3
  4. michael

    RobG Guest

    michael wrote:
    > Jerome Bei wrote:
    >
    >
    >>Try this:
    >>
    >><script>
    >> uls = document.getElementsByTagName("UL");
    >> for (var u=0; u<uls.length; u++) {
    >> alert("entering list ["+u+"]");
    >> lis=uls.getElementsByTagName("LI");
    >> for (var i=0; i<lis.length; i++) {
    >> if (lis.childNodes[0] && lis.childNodes[0].href) {


    If anything is inserted between the <li> and <a> tags, even a space,
    this will fail as the <a> element will no longer be the first child
    of the <li>.

    Probably better to use a recursive function to go down the tree from
    the <li> to see if it has an <a> element as a descendant.

    >> alert("found link ["+lis.childNodes[0].href+"]");
    >> }
    >> }
    >> }
    >></script>
    >>
    >>(Testes on IE 6.0 only)
    >>
    >>--Jerome

    >
    >
    > Works nicely, fetches the links if there are, and it works on Mozilla too.


    But will fall over if you insert anything between the <li> and <a>
    tags, as that will insert another element and the parent/child
    relationship is broken. Below is a script that runs down the tree
    to the first <a> and returns that (if there is one).


    <script type="text/javascript">
    function getULs() {
    var h, i, u, lena, lenb, lis, uls;
    uls = document.getElementsByTagName("UL");
    for ( u=0, lena=uls.length; u<lena; u++) {
    alert("entering list [" + u + "]");
    lis = uls.getElementsByTagName("LI");
    for (i=0, lenb=lis.length; i<lenb; i++) {
    if ( (h = hasAchild(lis)) ) {
    alert("found link [" + h.id + "]");
    }
    }
    }
    }

    // Given an element ref, descend element tree until an <a> is found
    // Return a reference to the element or null if not found
    function hasAchild(x){
    isA = false; // global
    if (x.nodeName == 'A') {
    isA = x;
    return isA; // Stop descent on first A element
    }
    for (var i=0; i<x.childNodes.length; i++) {
    // Descend if not found an A yet
    if (!isA) hasAchild(x.childNodes);
    }
    return isA;
    }

    </script>
    </head>
    <body id="theBody">
    <ul>
    <li><span>spacer</span> <a id="a0" href="blah" onclick="getULs();
    return false;">the ref</a></li>
    <li><a id="a1" href="blah" onclick="getULs(); return false;">the
    ref</a></li>
    <li>no ref</li>
    </ul>


    --
    Rob
    RobG, May 4, 2005
    #4
  5. michael

    RobG Guest

    RobG wrote:
    > michael wrote:

    [...]
    >
    > // Given an element ref, descend element tree until an <a> is found
    > // Return a reference to the element or null if not found
    > function hasAchild(x){
    > isA = false; // global
    > if (x.nodeName == 'A') {
    > isA = x;
    > return isA; // Stop descent on first A element
    > }
    > for (var i=0; i<x.childNodes.length; i++) {
    > // Descend if not found an A yet
    > if (!isA) hasAchild(x.childNodes);
    > }
    > return isA;
    > }


    Had a bit of fun with this, here's a neater version:

    function hasAchild(x){
    isA = ( 'A' == x.nodeName)? x : false;
    for (var i=0, j=x.childNodes.length; !isA && i<j; i++) {
    hasAchild(x.childNodes);
    }
    return isA;
    }


    --
    Rob
    RobG, May 4, 2005
    #5
  6. On 04/05/2005 08:35, RobG wrote:

    [snip]

    > If anything is inserted between the <li> and <a> tags, even a space,
    > this will fail as the <a> element will no longer be the first child
    > of the <li>.
    >
    > Probably better to use a recursive function to go down the tree from
    > the <li> to see if it has an <a> element as a descendant.


    Probably better to use getElementsByTagName to find any A elements
    within a list, directly. An A element would only be valid within a list
    item, so it seems rather pointless to spend time walking through the tree.

    [snip]

    Mike

    --
    Michael Winter
    Replace ".invalid" with ".uk" to reply by e-mail.
    Michael Winter, May 4, 2005
    #6
  7. michael

    michael Guest

    > Probably better to use getElementsByTagName to find any A elements

    There are obvsiously many ways and maybe this one would be the best. I'm a
    bit lost however as how to piece it all together.
    Therefore I shall try and explain a bit more what I'm looking for:

    I plan to generate a drop-down menu with CSS hover effects that would
    simply work on top of bare-bone unordered lists and which will be
    javascript generated by a central.js file for easy cross-site modifications.

    Disregarding style issues for this example sake, the navigation may be
    described simply as a bunch of links, within <LI>'s, within different
    groups of <UL>'s.

    These UL's will be horizontally aligned in CSS navbar style, and only the
    first link of each UL group will be visible until the mouse hovers over it,
    at which point the complete array of links of the UL group appears below it.

    The first and always visible link of each UL would simply lead to an
    overview page containing a summary of contents for its group of links.
    So the top-level links, would function a bit like a subject headings,
    although they may be considered by the javascript as any of the links
    contained within their groups.

    The javascript would define a class property for all LI's in each group, as
    either:
    The active, green class, if the user is on any page linked within its group.
    OR
    Non-active, blue class, for all other UL's and their LI's contained within.

    The purpose of the CSS class is only to indicate in which section the user
    currently is, which should make more sense in the CSS version, as only the
    first link is displayed, and as the mouse hovers over the currently active
    group with its current page on display, or when its over a non-active group.

    An example with only two link groups below, if viewed as a page named
    "lemurs.html" would style all background of the "flora_and_fauna" group of
    links light-green, whilst if viewed as a page named "hiking.html", all
    links in the "activities" group would be light-blue. Or, a page not linked
    from anywhere within the js menu itself, all groups would remain light-blue.

    Note that each link would appear only in one place or the navigation system
    woudl not be clear to the user.

    My so-called javascript below requires all links and groups pre-defined,
    and filenames in the if statements explicity typed out etc.
    This may be OK for a few links only but to be used in a => 50 links
    nav-system that one can easily modified its not a very good solution.
    But anyway, the functionality could be more or less same as below mock-up:

    <style>
    ..green { background-color:lightgreen }
    ..blue { background-color:lightblue; }
    </style>

    var f = window.location.href; /* get file name portion of URL */
    file = f.substring (f.lastIndexOf('/') +1);


    function display_links(group){ /* run function with group argument */
    var state = "green";

    /* explicity type possible combinations for each group */
    if (group == "flora_and_fauna" && file == "flora_and_fauna.html" || group
    == "flora_and_fauna" && file == "lemurs.html" || group == "flora_and_fauna"
    && file == "chameloens.html" || group == "flora_and_fauna" && file ==
    "mangroves.html"){
    return state;
    }

    /* and again ... */
    else if (group == "activities" && file == "activities.html" || group ==
    "activities" && file == "hiking.html" || group == "activities" && file ==
    "diving.html"){
    return state;
    }

    /* if none is matched, eg. a user is on a page not linked within the .js
    navigation system itself, all groups light-blue */
    else {
    return "blue";
    }

    }

    /* write out each ul, li and link, and run function to set class value */
    document.write('<ul>')
    document.write('<li class='+display_links('flora_and_fauna')+'><a
    href="flora_and_fauna.html">Flora & Fauna</a></li>')
    document.write('<li class='+display_links('flora_and_fauna')+'><a
    href="lemurs.html">Lemurs</a></li>')
    document.write('<li class='+display_links('flora_and_fauna')+'><a
    href="chameleons.html">Chameleons</a></li>')
    document.write('<li class='+display_links('flora_and_fauna')+'><a
    href="mangroves.html">Mangroves</a></li>')
    document.write('</ul>')


    document.write('<ul>')
    document.write('<li class='+display_links('activities')+'><a
    href="activities.html">Activities</a></li>')
    document.write('<li class='+display_links('activities')+'><a
    href="hiking.html">Hiking</a></li>')
    document.write('<li class='+display_links('activities')+'><a
    href="diving.html">diving</a></li>')
    document.write('</ul>')

    Any ideas, and especially short code would be greatly appreciated!

    Many thanks,
    Michael
    --

    You know the great thing about TV? If something important happens
    anywhere at all in the world, no matter what time of the day or night,
    you can always change the channel.
    -- Jim Ignatowski
    michael, May 5, 2005
    #7
  8. michael

    RobG Guest

    Michael Winter wrote:
    > On 04/05/2005 08:35, RobG wrote:
    >
    > [snip]
    >
    >> If anything is inserted between the <li> and <a> tags, even a space,
    >> this will fail as the <a> element will no longer be the first child
    >> of the <li>.
    >>
    >> Probably better to use a recursive function to go down the tree from
    >> the <li> to see if it has an <a> element as a descendant.

    >
    >
    > Probably better to use getElementsByTagName to find any A elements
    > within a list, directly. An A element would only be valid within a list
    > item, so it seems rather pointless to spend time walking through the tree.


    Killjoy.


    --
    Rob
    RobG, May 5, 2005
    #8
  9. michael

    RobG Guest

    michael wrote:
    >>Probably better to use getElementsByTagName to find any A elements

    >
    >
    > There are obvsiously many ways and maybe this one would be the best. I'm a
    > bit lost however as how to piece it all together.
    > Therefore I shall try and explain a bit more what I'm looking for:
    >

    [...]

    >')
    >
    > Any ideas, and especially short code would be greatly appreciated!
    >


    Yes, there are a zillon ways to do this, google "DHTML menu".

    Forget 'document.write' to create your menu as the page loads, that
    will guarantee that non-JavaScript browsers can't use your site.

    To get further help:

    1. Create your menus as static HTML.

    2. Add DHTML behaviour as an add-on, that way non-JavaScript browsers
    can still navigate your pages.

    3. As part of the above, you can see if a UL group contains an HREF
    with the same filename as the current page. If so, change its
    parent UL class to 'active'.

    I've posted a bit of code that just does the class thing, I've
    included multiple classes so I can detect the 'head' ULs (I'm not
    interested in descendant ULs, you may be) as an example, but my idea
    of what you are trying to do is probably very different to what you
    are actually doing.

    Note you don't have to define 'convenience' classes like head and sub
    if you don't want to.



    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    <title> Z 0 </title>
    <meta http-equiv="Content-Type"
    content="text/html; charset=ISO-8859-1">
    <style type="text/css">
    ..high {background-color: #99FFCC; color: black;}
    ..low {background-color: #33CC00; color: white;}
    </style>
    <script type="text/javascript">

    function doClass(){
    var As, ff, x;
    var a = RegExp('.*/'); // Needed many times, compile for speed
    var f = document.URL.replace(a,''); // filename of current page
    var d = document.getElementById('menu');
    var uls = d.getElementsByTagName('ul');

    for (var i=0, j=uls.length; i<j; i++){
    x = uls;

    // If the UL className string includes word 'head'
    if ( /\bhead\b/.test(x.className) ){

    // Get its A elements
    As = x.getElementsByTagName('a');

    // Search for matching file names
    for (var k=0, m=As.length; k<m; k++) {
    ff = As[k].href.replace(a,'');

    // If match, modify the className string of the parent UL
    if ( ff == f ){
    x.className = x.className.replace(/\blow\b/,'high');

    // No need to continue once we've found one
    return;
    }
    }
    }
    }
    }
    </script>
    </head>
    <body onload="doClass();">
    <div id="menu">
    <ul class="head low" id="blah">
    <li><a href="z0.html">Flora&nbsp;&amp;&nbsp;funa</a>
    <ul class="sub">
    <li><a href="z1.html">Pretty&nbsp;flowers</a></li>
    <li><a href="z2.html">Deadly&nbsp;vines</a></li>
    </ul>
    </li>
    </ul>
    <ul class="head low">
    <li><a href="z3.html">Aquatic&nbsp;creatures</a>
    <ul class="sub">
    <li><a href="z4.html">Pretty&nbsp;fish</a></li>
    <li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
    </ul>
    </li>
    </ul>
    </div>
    </body>
    </html>


    --
    Rob
    RobG, May 5, 2005
    #9
  10. michael

    RobG Guest

    RobG wrote:
    > michael wrote:
    >

    [...]
    >>
    >> Any ideas, and especially short code would be greatly appreciated!
    >>

    [...]

    > var f = document.URL.replace(a,''); // filename of current page


    Sorry, forgot IE doesn't do document.URI, try this:

    var f = document.location.href.replace(a,'');

    [...]

    --
    Rob
    RobG, May 5, 2005
    #10
  11. michael

    michael Guest

    > interested in descendant ULs, you may be) as an example, but my idea
    > of what you are trying to do is probably very different to what you
    > are actually doing.


    This looks convertable to exactly what I need, perfect!

    And code can't get much shorter. Only, I get a javascript error:

    --
    Error: illegal character
    Source File: file:///tmp/z2.html
    Line: 24, Column: 10
    Source Code:
    if ( \bhead\b.test(x.className) ){

    Error: doClass is not defined
    --

    I don't know how to fix that, I guess second error is due to the first.

    Many thanks,
    Michael
    --
    The first duty of a revolutionary is to get away with it.
    -- Abbie Hoffman
    michael, May 5, 2005
    #11
  12. michael

    RobG Guest

    michael wrote:
    >> interested in descendant ULs, you may be) as an example, but my idea
    >> of what you are trying to do is probably very different to what you
    >> are actually doing.

    >
    >
    > This looks convertable to exactly what I need, perfect!
    >
    > And code can't get much shorter. Only, I get a javascript error:
    >
    > --
    > Error: illegal character
    > Source File: file:///tmp/z2.html
    > Line: 24, Column: 10
    > Source Code:
    > if ( \bhead\b.test(x.className) ){
    >
    > Error: doClass is not defined
    > --
    >
    > I don't know how to fix that, I guess second error is due to the first.
    >
    > Many thanks,
    > Michael
    > --
    > The first duty of a revolutionary is to get away with it.
    > -- Abbie Hoffman
    >


    Don't know why you get the error, I tested in IE and Firefox. Have
    you created files for each link? And included the modified URL/href
    line?

    --
    Rob
    RobG, May 5, 2005
    #12
  13. On 05/05/2005 03:50, RobG wrote:

    [snip]

    > Sorry, forgot IE doesn't do document.URI, try this: [...]


    Not URI, no, but URL, yes. Unless Microsoft are lying in their
    documentation, it's been included in all versions, on all supported
    platforms, since 4.0.

    Have you found a version where it fails to work, or are you just
    assuming it doesn't?

    Mike

    --
    Michael Winter
    Replace ".invalid" with ".uk" to reply by e-mail.
    Michael Winter, May 5, 2005
    #13
  14. On 05/05/2005 06:42, michael wrote:

    [snip]

    > I get a javascript error:


    [snip]

    > if ( \bhead\b.test(x.className) ){


    Where have the forward slashes gone?

    if(/\bhead\b/.test(x.className)) {

    > Error: doClass is not defined
    > --
    >
    > I don't know how to fix that, I guess second error is due to the first.


    Yes. The parsing error within the function causes the parser to halt the
    creation of the function object. When the browser tries to call doClass
    in response to the load event, it fails as the object doesn't exist.

    > --
    > The first duty of a revolutionary is to get away with it.
    > -- Abbie Hoffman


    FYI: Your signature separator seems to be broken. It should be
    dash-dash-space.

    Mike

    --
    Michael Winter
    Replace ".invalid" with ".uk" to reply by e-mail.
    Michael Winter, May 5, 2005
    #14
  15. michael

    michael Guest

    > Where have the forward slashes gone?

    Thanks for mentioning it, I suspect something's wrong with my Linux
    font-config set-up or X-windows, or just the newsreader itself.
    I just viewed source of the posting and indeed found the missing forward
    slashes- I shall try again with "/" and I'm sure it will work much better!

    Michael

    --
    "Don't worry about people stealing your ideas. If your ideas are any
    good, you'll have to ram them down people's throats."
    -- Howard Aiken
    michael, May 5, 2005
    #15
  16. michael

    michael Guest

    > <li><a href="z4.html">Pretty&nbsp;fish</a></li>
    > <li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
    > </ul>
    > </li>
    > </ul>
    > </div>
    > </body>
    > </html>
    >
    >



    This works great!

    But does anyone know how to get it working as a horizontally aligned drop
    menu, only showing 'sub' list items when hovering over the first <li> of
    each <ul class="head low">, so if for example hovering over Flora & Fauna
    or any of its sub-links, show:

    [Flora & funa] [Aquatic creatures[
    [Pretty flowers]
    [Deadly vines]

    And retaining the background scheme for all items, but with a variable, so
    the current page is not actually a link?

    --
    Blore's Razor:
    Given a choice between two theories, take the one which is
    funnier.
    michael, May 9, 2005
    #16
  17. michael

    michael Guest

    I pieced together a hover-drop-menu derived from
    htmldog.com/articles/suckerfish/dropdowns with the colour-by-URL modifier
    script solution as posted by Rob earlier.

    The new styles basically removes the sub-listed items from view, leaving
    only the first LI of the <ul class="head low"> visible until mouse hovers
    over it, to bring its sub-points back into view.

    The background colour works for the LI's on top, which are always visible,
    but not for the sub-points for some reason.
    Although font styles do take effect across a complete lists, for example: ..

    ..high {background-color: #99FFCC; font-size:80%;}

    ... makes a smaller font on all items in the group containing current URL.

    Anyone has any idea why the background colours doesn't take effect behind
    the sub-points?

    See complete page below:

    <html><head><title></title>

    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

    <style type="text/css">

    #menu, #menu ul {
    padding: 0;
    margin: 0;
    list-style:none;
    }

    #menu a {
    display: block:
    width: 10em:
    }

    #menu ul {
    float: left;
    width: 10em;
    }

    #menu li ul {
    position: absolute;
    width: 10em;
    left: -999em;
    }

    #menu li:hover ul {
    left: auto;
    }

    #menu li:hover ul{
    left: auto;
    }


    #menu li.sfhover ul{ /* ie specific, but alignment not yet working */
    left: auto;
    margin-top:1em;margin-left:-1em;
    }


    ..high {background-color: #99FFCC; font-size:80%;}
    ..low {background-color: #33CC00;}

    </style>

    <script type="text/javascript">

    function doClass(){
    var As, ff, x;
    var a = RegExp('.*/'); // Needed many times, compile for speed
    var f = document.URL.replace(a,''); // filename of current page
    var d = document.getElementById('menu');
    var uls = d.getElementsByTagName('ul');

    for (var i=0, j=uls.length; i<j; i++){
    x = uls;

    // If the UL className string includes word 'head'
    if ( /\bhead\b/.test(x.className) ){

    // Get its A elements
    As = x.getElementsByTagName('a');

    // Search for matching file names
    for (var k=0, m=As.length; k<m; k++) {
    ff = As[k].href.replace(a,'');

    // If match, modify the className string of the parent UL
    if ( ff == f ){
    x.className = x.className.replace(/\blow\b/,'high');

    // No need to continue once we've found one
    return;
    }
    }
    }
    }
    }
    </script>


    <script language="javascript">

    /* the suckerfish script to fix IE compatibility in bringing the sub-menu
    items back in view, although not as intended directly under its headings */

    sfHover = function() {
    var sfEls = document.getElementById("menu").getElementsByTagName("LI");
    for (var i=0; i<sfEls.length; i++) {
    sfEls.onmouseover=function() {
    this.className+=" sfhover";
    }
    sfEls.onmouseout=function() {
    this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
    }
    }
    }
    if (window.attachEvent) window.attachEvent("onload", sfHover);

    </script>


    </head>


    <body onload="doClass();">

    <div id="menu">

    <ul class="head low">


    <li><a href="z0.html">Flora&nbsp;&amp;&nbsp;puna</a>

    <ul class="sub">
    <li><a href="z1.html">Pretty&nbsp;flowers</a></li>
    <li><a href="z2.html">Deadly&nbsp;vines</a></li>
    </ul>


    </li>

    </ul>
    <ul class="head low">


    <li><a href="z3.html">Aquatic&nbsp;creatures</a>

    <ul class="sub">
    <li><a href="z4.html">Pretty&nbsp;fish</a></li>
    <li><a href="z5.html">Don&#39t&nbsp;eat</a></li>
    </ul>

    </li>


    </ul>
    </div>

    </body>
    </html>

    --
    One way to make your old car run better is to look up the price of a
    new model.
    michael, May 10, 2005
    #17
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. CRON
    Replies:
    24
    Views:
    200,438
    Adrienne Boswell
    Jun 20, 2006
  2. Soren Vejrum
    Replies:
    4
    Views:
    520
    Lasse Reichstein Nielsen
    Jul 5, 2003
  3. saiho.yuen
    Replies:
    3
    Views:
    406
    kaeli
    Sep 14, 2004
  4. Replies:
    2
    Views:
    441
  5. Vincent van Beveren

    BASE HREF and A HREF="#" onclick="..."

    Vincent van Beveren, Jul 6, 2006, in forum: Javascript
    Replies:
    2
    Views:
    294
    Vincent van Beveren
    Jul 6, 2006
Loading...

Share This Page