SitePoint Sponsor

User Tag List

Results 1 to 14 of 14

Hybrid View

  1. #1
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question Script help: remove/add link class when clicked?

    Hi,

    I am on a tight deadline with none of my Javascript books around to reference... Can anyone help me with this script:

    HTML:

    Code:
    <dl class="navList">
    	<dt>Quick Links</dt>
    		<dd class="navFirst currentItem"><a href="javascript:switchid('topJobs');" title="Top Jobs">Jobs</a></dd>
    		<dd><a href="javascript:switchid('topHomes');" title="Top Homes"><strong>Homes</strong></a></dd>
    		<dd><a href="javascript:switchid('topCars');" title="Top Cars">Cars</a></dd>
    </dl>
    
    <div id="topJobs" style="display:block;">
    	<a class="more" href="">See All ⇒</a>
    </div>
    	
    <div id="topHomes" style="display:none;">
    	<a class="more" href="">See All ⇒</a>
    </div>
    	
    <div id="topCars" style="display:none;">
    	<a class="more" href="">See All ⇒</a>
    </div>
    JS:

    PHP Code:
    /*
    **
    **              Ref: http://support.internetconnection.net/CODE_LIBRARY/Javascript_Show_Hide.shtml
    **
    **      Description:
    **                   Specify divs you want to show/hide in below array.
    **                   Use this JS throughout site for showing/hiding of layers.
    **    Example usage:
    **                   <a href="javascript:switchid('a2');">show a2</a>
    **
    */


    /*
    ** Here you place the IDs of every element you want: */
    var ids = new Array('topCars','topJobs','topHomes');

    function 
    switchid(id) { hideallids(); showdiv(id); }

    /*
    ** Loop through the array and hide each element by id: */
    function hideallids(){ for(var i=0i<ids.lengthi++) { hidediv(ids[i]); } }

    /*
    ** Safe function to hide an element with a specified id: */
    function hidediv(id) {
        if(
    document.getElementById) { document.getElementById(id).style.display 'none'; } // DOM3 = IE5, NS6.
        
    else {
            if(
    document.layers) { document.id.display 'none'; } // Netscape 4.
            
    else { document.all.id.style.display 'none'; } // IE 4.
        
    }
    }

    /*
    ** Safe function to show an element with a specified id: */
    function showdiv(id) {
        if(
    document.getElementById) { document.getElementById(id).style.display 'block'; } // DOM3 = IE5, NS6.
        
    else {
            if (
    document.layers) { document.id.display 'block'; } // Netscape 4.
            
    else { document.all.id.style.display 'block'; } // IE 4.
        
    }

    Basically I want to add/append the class "currentItem" to one of the three links in above HTML (dl.navList) if/when clicked... I have tried a few diff things, but I have yet to get this to work. Any thoughts? One prob I have is appending the class to the link that already has the class "navFirst"... this is a static/required class.

    Any help would be great. My goal is to make this JS as simple as possible... Hehe.

    Many TIA's,
    Cheers,
    M

  2. #2
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I did this quickly so be sure to test it well.
    Also be sure to look closely at the changes I made in the html.
    No changes are needed to the Javascript when adding new links.

    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Cross-Browser.com</title>
    <style type='text/css'>
    .currentItem {
      font-weight:bold;
    }
    </style>
    <script type='text/javascript'>
    window.onload = function()
    {
      iterateNavList(function(a){a.onclick = navOnClick;});
    }
    function navOnClick()
    {
      iterateNavList(
        function(a) {
          var id = a.href.substr(a.href.indexOf('#') + 1);
          var e = document.getElementById(id);
          if (e) {
            e.style.display = 'none';
            xRemoveClass(a.parentNode, 'currentItem');
          }
        }
      );
      var id = this.href.substr(this.href.indexOf('#') + 1);
      var e = document.getElementById(id);
      if (e) {
        e.style.display = 'block';
        xAddClass(this.parentNode, 'currentItem');
      }
      return false;
    }
    function iterateNavList(fn)
    {
      var e = document.getElementById('idNavList');
      if (e) {
        var i, a = e.getElementsByTagName('a');
        for (i = 0; i < a.length; ++i) {
          fn(a[i]);
        }
      }
    }
    // Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
    // mf: Modified for this demo so they are no longer 'generic'.
    function xAddClass(e, c)
    {
      var s = '';
      if (e.className.length && e.className.charAt(e.className.length - 1) != ' ') {
        s = ' ';
      }
      e.className += s + c;
    }
    function xRemoveClass(e, c)
    {
      e.className = e.className.replace(new RegExp("(^|\\s)"+c+"(\\s|$)",'g'),
        function(str, p1, p2) { return (p1 == ' ' && p2 == ' ') ? ' ' : ''; }
      );
      return true;
    }
    </script>
    </head>
    <body>
    
    
    <dl id='idNavList' class="navList">
    	<dt>Quick Links</dt>
    		<dd class="navFirst currentItem"><a href="#topJobs" title="Top Jobs">Jobs</a></dd>
    		<dd><a href="#topHomes" title="Top Homes">Homes</a></dd>
    		<dd><a href="#topCars" title="Top Cars">Cars</a></dd>
    </dl>
    
    <div id="topJobs" style="display:block;">
    	<a class="more" href="">See All topJobs</a>
    </div>
    	
    <div id="topHomes" style="display:none;">
    	<a class="more" href="">See All topHomes</a>
    </div>
    	
    <div id="topCars" style="display:none;">
    	<a class="more" href="">See All topCars</a>
    </div>
    
    </body>
    </html>

  3. #3
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike! You rock!!!!

    Many thanks! Looking over your code now... I will test it very well -- thanks so much for your time -- I have been banging my head on the keyboard on this one since posting.

    I will be back with my results and/or questions... this looks like it will work perfectly though... much cleaner! I am totally stoked.

    Thanks again. I owe you one.
    Cheers,
    Micky

  4. #4
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

  5. #5
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Question

    Hi, me again.

    I finally had a chance to really analyze and learn from you code... great work btw! -- I hope you do not mind if I post a few questions over the next day or so...

    My first question:

    Code:
    window.onload = function() {
    	iterateNavList(function(a) { a.onclick = navOnClick; });
    }
    I am not used to passing a function as a function argument...

    How does the var/argument "a" in function(a) get a value?

    What type of function call (or is it a declaration/definition?) is that? (Keyword for google search in order to find other examps would be great!)

    "function(a)" looks kinda like a function call, but then I see a block of code associated with it "{ a.onclick = navOnClick; }", It then kinda looks like a function declaration/definition... Lol, I sure am rusty at ECMAscripting.

    Thanks again, this code is a great learning resource for me.

    Cheers,
    Micky

  6. #6
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Am I heading in right direction if I wanted to use this code on more than one div ID?

    Code:
    var ids = new Array('navList01', 'navList02');
    function iterateNavList(fn) {
    	for(var x=0; x<ids.length; x++) {
    		var e = document.getElementById(ids[x]);
    		if(e) {
    			var i, a = e.getElementsByTagName('a');
    			for(i = 0; i < a.length; ++i) {
    				fn(a[i]);
    			}
    		}
    	}
    }
    It semi-works... but it seems like I am putting the loop in the wrong location... Is it as simple as adding a loop in a particular location?

    It would be great if I could just do this:

    Code:
    function iterateNavList(fn)
    {
      var e = document.getElementByClass('navList');
      if (e) {
        var i, a = e.getElementsByTagName('a');
        for (i = 0; i < a.length; ++i) {
          fn(a[i]);
        }
      }
    }
    I hate to keep asking for help... so, many thanks in advance to those of you who help... And big-ol' thanks to MikeFoster for getting me headed in the right direction.

    Cheers,
    M

  7. #7
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Mickey, I don't mind your questions at all - but I'm pretty tied up right now. I'll try to get to this a little later today. Just wanted to let you know I'm not ignoring you

  8. #8
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Mike!

    No prob at all. I am in no rush. The script you posted above has been working great for one ID on the page.

    No rush on the questions. So far I have been learning a lot looking-over you code -- very advanced! I wish I were as good at JS as you... life would be so much easier!

    Take your time, and thanks for keeping me in mind.

    Many many thanks,
    Cheers,
    Micky

  9. #9
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Micky, I really appreciate it

    You are right - it is passing a function as an argument to iterateNavList. Notice, in iterateNavList, it gets a list of <A> elements that are contained in the 'idNavList' element. It then loops through that list and calls the function (it's argument) and passes it a reference to the current <A> element object in the list. So that becomes the 'a' parameter in the anonymous function.

    The anonymous function is really no different from declaring a function that has a name - except that the anonymous function has no name . It is effectively the same as doing this:
    Code:
    window.onload = function()
    {
      iterateNavList(iterator);
    }
    
    function iterator(a)
    {
      a.onclick = navOnClick;
    }
    I don't know what to suggest to search for except maybe something like javascript "anonymous function".

    To make that code generic let's look at what assumptions the code makes. Here's the original function from my post above.
    Code:
    function iterateNavList(fn)
    {
      var e = document.getElementById('idNavList');
      if (e) {
        var i, a = e.getElementsByTagName('a');
        for (i = 0; i < a.length; ++i) {
          fn(a[i]);
        }
      }
    }
    It has the container ID hard-coded into it. We could pass this as an argument. It also assumes that the caller wants all <A> elements in the container. We could pass that as an arg too. For example:
    Code:
    function iterateNavList(sContainerId, sTagName, fnCallback)
    {
      var e = document.getElementById(sContainerId);
      if (e) {
        var i, a = e.getElementsByTagName(sTagName);
        for (i = 0; i < a.length; ++i) {
          fnCallback(a[i]);
        }
      }
    }
    However, that won't work with navOnClick. But if I had first written iterateNavList as above then when I designed navOnClick I would have made it work with it.

    Have a look at xGetElementsByClassName. Many people have an implementation of this function so just use the one you like best. Note that mine allows a callback function as an argument. So you can use it like this:
    Code:
    var list = xGetElementsByClassName(sClsName, oParentEle, sTagName);
    for (var i = 0; i < list.length; ++i) {
      // do something with list[i]
    }
    or it can be used like this:
    Code:
    xGetElementsByClassName(sClsName, oParentEle, sTagName,
      function(ele) {
        // do something with ele
      }
    );
    Last edited by MikeFoster; Mar 14, 2007 at 17:35. Reason: how did that tab get in there?

  10. #10
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike, you rock!

    Thanks a billion for taking the time to answer my questions. Very helpful -- I have a way better understanding of how your script works now.

    Many many many thanks for you expertise and guidance.

    Have a great day/night!
    Cheers,
    Micky

  11. #11
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You're very welcome, Micky. It's been a pleasure chatting with you.

    All the Best!

  12. #12
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi, me again.

    I just figured-out how to use multiple ID's... Not sure if this is how others would go about it (or how optimal it now might be), but I thought I would post for others to use... also looking for feedback from the pros. See any potential problems? Optimizations?

    I will update my code as I optimize... that is, if I can figure-out ways to optimize.

    Thanks again Mike, I have learned so much!

    Javascript:

    PHP Code:
    <!--//--><![CDATA[//><!--

    /* 
    ** 
    **         @file: show-hide.js
    **       @author: Mike Foster via Sitepoint
    **         @url1: http://www.sitepoint.com/forums/showthread.php?t=464410
    **         @url2: http://cross-browser.com/
    **      @version: 1.0.1
    **      @created: 03/08/07
    **     @modified: 03/18/07
    ** 
    **        @about: Show/hide divs using definition list navigation.
    **        @notes:
    **                On window load, iterate through tabbed navigation and assign function navOnClick to 'a' tags.
    **                When tab link clicked, show related content div, hide others, remove/add "current" class.
    **                Written by Mike Foster via Sitepoint (http://www.sitepoint.com/forums/member.php?u=24565)
    **                <u>Slightly</u> modified by Micky Hulse (pointers/inspiration via Mike) to work with multiple ID's.
    **                BIG PROPS to Mike for the guidance and the script! He is most definitely a JS guru! Check-out his site: http://cross-browser.com/
    ** 
    **        @to-do:
    **                [1] Test for browser/platform (in)compatibilities
    **                [2] Bugs?
    **                [3] Change tabs based on time.
    **                [4] Better comments/descriptions in/for code?
    **                [5] Overall code optimization?
    **                [6] Make more generic? Currently works well with definition list.
    **                [7] Animated transitions?
    **                [8] Set session/cookie for selected tab.
    **                [9] Use absolute positioning to show/hide content: better SEO?
    ** 
    **      @example: http://www.ambiguism.com/sandbox/scripts/tabs-show-hide/tabs.php
    **     @comments: micky@ambiguism.com
    ** 
    **                Don't forget to visit http://cross-browser.com/
    **                Thanks Mike!
    ** 
    */

    // ids array:
    var ids = new Array('navList01''navList02'); // Add more here.

    // Load the script:
    if(document.getElementById || document.all) {
        
    xAddEventListener(window'load'startShowHidefalse); // Start script on window load.
    }

    // startShowHide()
    // Formerly window.onload
    // Updated to use xAddEventListener
    // http://www.sitepoint.com/forums/showpost.php?p=3324072&postcount=13
    function startShowHide() {
        for(var 
    x=0x<ids.lengthx++) {
            
    iterateNavList(ids[x], 'a', function(a) { a.onclick navOnClick; });
        }
    }

    // iterateNavList()
    function iterateNavList(sContainerIdsTagNamefnCallback) {
        var 
    document.getElementById(sContainerId);
        if(
    e) {
            var 
    ie.getElementsByTagName(sTagName);
            for (
    0a.length; ++i) {
                
    fnCallback(a[i]);
            }
        }
    }

    // navOnClick()
    function navOnClick() {
        var 
    pid this.parentNode.parentNode.id// Pointing to parent DL with an ID (<dl id="targID">...</dl>) specified in ids[] array above.
        // Call iterateNavList, pass parent container, tag, and callback function:
        
    iterateNavList(pid'a'
            function(
    a) {
                var 
    id a.href.substr(a.href.indexOf('#') + 1);
                var 
    document.getElementById(id);
                if(
    e) {
                    
    e.style.display 'none'// Hide.
                    
    xRemoveClass(a.parentNode'currentItem');
                }
            }
        );
        var 
    id this.href.substr(this.href.indexOf('#') + 1);
        var 
    document.getElementById(id);
        if(
    e) {
            
    e.style.display 'block'// Show.
            
    xAddClass(this.parentNode'currentItem');
        }
        return 
    false;
    }

    // xAddClass, Copyright 2005-2007 Daniel Frechette - modified by Mike Foster
    // Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
    // mf: Modified for this script so they are no longer 'generic'.
    function xAddClass(ec) {
        var 
    '';
        if(
    e.className.length && e.className.charAt(e.className.length 1) != ' ') { ' '; }
        
    e.className += c;
    }

    // xRemoveClass, Copyright 2005-2007 Daniel Frechette - modified by Mike Foster
    // Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
    // mf: Modified for this script so they are no longer 'generic'.
    function xRemoveClass(ec) {
        
    e.className e.className.replace(new RegExp("(^|\\s)"+c+"(\\s|$)",'g'), function(strp1p2) { return (p1 == ' ' && p2 == ' ') ? ' ' ''; });
        return 
    true;
    }

    // xAddEventListener, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
    // Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
    // Dependencies: xGetElementById
    function xAddEventListener(eeTeLcap) {
        if(!(
    xGetElementById(e))) return;
        
    eT eT.toLowerCase();
        if(
    e.addEventListenere.addEventListener(eTeLcap || false);
        else if(
    e.attachEvente.attachEvent('on' eTeL);
        else {
            var 
    e['on' eT];
            
    e['on' eT] = typeof o == 'function' ? function(v) { o(v); eL(v); } : eL;
        }
    }

    // xGetElementById, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
    // Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
    function xGetElementById(e) {
        if(
    typeof(e) == 'string') {
            if(
    document.getElementByIddocument.getElementById(e);
            else if(
    document.alldocument.all[e];
            else 
    null;
        }
        return 
    e;
    }

    //--><!]]> 
    Last edited by mhulse; Mar 18, 2007 at 23:17. Reason: Updated script. :)

  13. #13
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Mickey,

    That's excellent. Great work! And thank you very much for your kind comments.

    Regarding the questions in your comments:

    // window.onload: How compatible is this with all browsers? Need to test.
    This is what we call a DOM0 event handler - so it is as cross-browser as anything.

    When we have pages that end up using scripts from different places, sometimes each of those scripts will need to run some code onload. Sometimes we end up with this situation:
    Code:
    window.onload = function() {
      // initialize a page enhancement
    };
    // and then in some other js file...
    window.onload = function() {
      // initialize some other page enhancement
    };
    As you can see, the second assignment to 'window.onload' will over-write the first. In these cases it is handy to use something like xAddEventListener.

    var pid = this.parentNode.parentNode.id; // Better way to do this?
    When we develop a page enhancement it can be very hard to not make assumptions about the HTML structure. But some assumptions are ok (if we document them) because the purpose of the enhancement is to work with that particular HTML structure. I think your code above is fine. There are alternatives - but they are not necessarily "better".

  14. #14
    .* draziW tnioPetiS *. bronze trophy
    Join Date
    Jun 2004
    Location
    "Then I figure the most good good guy will win."
    Posts
    1,666
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike! You da man! Thanks for the reply.

    Thanks for tip on DOM0... I will adjust the code to use xAddEventListener -- that looks like a handy function, thanks for sharing it with the world.

    Also, thanks on the parentNote.parentNode.id info... It is really great to hear your feedback. Where do I send the check?

    Cheers!
    Micky


Bookmarks

Posting Permissions

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