Posts tagged ‘jquery’


Simple expandable menu with jQuery

I recently needed a nested and expandable navigation system (accordion style) for a project I was working on.  I took a look around at the existing jquery plugins and was surprised by the complexity of them. To me, there’s no reason for a simple menu to require 200 lines of JavaScript.  Thankfully jQuery makes it possible to pack a lot of punch into just a few lines of code.  While I recognize the other plugins offer more functionality, I wanted to show that these days it sometimes makes more sense to just roll your own solution. Not only does this solution cut down on the number of bytes that the user has to download, but you’ll also have code that is more concise and easier to maintain.

Click here to check out the demo and download the code

Here’s the jQuery magic that I came up with:

$(document).ready(function() {
    $(".menu").click(function(e) {
        // unhighlight the previous menu selection
        $(".menu .selected").removeClass("selected");
        // highlight the selected item & its parents
        $(e.target).closest("li").addClass("selected").parent().parent().addClass("selected");
    });
});

The HTML is a standard nested list and looks something like this:

<div class='menu'>
    <ul>
        <li><a href='http://www.onlineaspect.com'>My blog</a></li>
        <li><a href='#'>My profiles</a>
            <ul>
                <li><a href='http://www.facebook.com/joshfraser'>Facebook</a></li>
                <li><a href='http://www.linkedin.com/in/joshuafraser'>LinkedIn</a></li>
                <li><a href='http://www.twitter.com/joshfraser'>Twitter</a></li>
            </ul>
        </li>
    </ul>
</div>

And the CSS is easy to customize to match your own look and feel:

.menu {
    width:200px;
}
.menu a {
    color:#666;
    text-decoration:none;
}
.menu ul {
    padding:0;
    border-top:1px solid #CCC;
}
.menu ul li {
    list-style:none;
    border-bottom:1px solid #CCC;
}
.menu ul li a {
    text-indent:6px;
    display:block;
    padding:6px;
}
.menu ul li a:hover, .menu ul li.selected a  {
    color:#FFF;
    background-color:#006363;
}
/* nested items */
.menu ul li ul {
    display:none;
}
.menu ul li.selected ul {
    display:block;
}
.menu ul li.selected ul a {
    color:#666;
    background-color:white;
    border-left:6px solid white;
}
.menu ul li ul li {
    border-bottom:1px solid white;
}
.menu ul li ul li:first-child {
    border-top:1px solid white;
}
.menu ul li.selected ul li.selected a, .menu ul li.selected ul li a:hover {
    color:#FFF;
    background-color:#7EB0B0;
    border-left:6px solid #006363;
}

That’s it. Remember – guard your bytes!

 6 comments

Stop flash from covering HTML content

Browse through a few developer forums and you will find lots of people pulling their hair out over flash content covering up their dropdown menus or modal windows.  The problem is especially bad in IE (surprise, surprise). The fix is actually quite simple as long as you can edit the embed code for your flash. The trick is to change the wmode parameter to either “transparent” or “opaque”.  You should do this for both the <embed> and <object> tags like this:

<object width="200" height="300" data="example.swf" type="application/x-shockwave-flash">
    <param name="quality" value="high" />
    <param name="wmode" value="transparent" />
    <param name="src" value="example.swf" />
</object>

The problem is you don’t always have the option of changing the embed code.  What if you’re developing a JavaScript widget and don’t have any control over how the flash is embedded?  The solution is more complicated than you would expect.  It turns out there are a slew of IE bugs around the <object> tag that escalate what should be a simple task into a real headache.  Basically you need to replace each <embed> and <object> tag with a cloned version that has had its wmode parameter fixed. Here’s how you do it:

<script type="text/javascript">

function fix_flash() {
    // loop through every embed tag on the site
    var embeds = document.getElementsByTagName('embed');
    for(i=0; i<embeds.length; i++)  {
        embed = embeds[i];
        var new_embed;
        // everything but Firefox & Konqueror
        if(embed.outerHTML) {
            var html = embed.outerHTML;
            // replace an existing wmode parameter
            if(html.match(/wmode\s*=\s*('|")[a-zA-Z]+('|")/i))
                new_embed = html.replace(/wmode\s*=\s*('|")window('|")/i,"wmode='transparent'");
            // add a new wmode parameter
            else
                new_embed = html.replace(/<embed\s/i,"<embed wmode='transparent' ");
            // replace the old embed object with the fixed version
            embed.insertAdjacentHTML('beforeBegin',new_embed);
            embed.parentNode.removeChild(embed);
        } else {
            // cloneNode is buggy in some versions of Safari & Opera, but works fine in FF
            new_embed = embed.cloneNode(true);
            if(!new_embed.getAttribute('wmode') || new_embed.getAttribute('wmode').toLowerCase()=='window')
                new_embed.setAttribute('wmode','transparent');
            embed.parentNode.replaceChild(new_embed,embed);
        }
    }
    // loop through every object tag on the site
    var objects = document.getElementsByTagName('object');
    for(i=0; i<objects.length; i++) {
        object = objects[i];
        var new_object;
        // object is an IE specific tag so we can use outerHTML here
        if(object.outerHTML) {
            var html = object.outerHTML;
            // replace an existing wmode parameter
            if(html.match(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")[a-zA-Z]+('|")\s*\/?\>/i))
                new_object = html.replace(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")window('|")\s*\/?\>/i,"<param name='wmode' value='transparent' />");
            // add a new wmode parameter
            else
                new_object = html.replace(/<\/object\>/i,"<param name='wmode' value='transparent' />\n</object>");
            // loop through each of the param tags
            var children = object.childNodes;
            for(j=0; j<children.length; j++) {
                if(children[j].getAttribute('name').match(/flashvars/i)) {
                    new_object = new_object.replace(/<param\s+name\s*=\s*('|")flashvars('|")\s+value\s*=\s*('|")[^'"]*('|")\s*\/?\>/i,"<param name='flashvars' value='"+children[j].getAttribute('value')+"' />");
                }
            }
            // replace the old embed object with the fixed versiony
            object.insertAdjacentHTML('beforeBegin',new_object);
            object.parentNode.removeChild(object);
        }
    }
}

</script>

This solution is adapted from code I found on QIndex. Hopefully this version is a little cleaner and easier for people to find.

Note: There is also a jquery version of this code, complements of José Nobile.
 51 comments