<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Darren Krape &#187; JavaScript</title>
	<atom:link href="http://www.darrenkrape.com/tag/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.darrenkrape.com</link>
	<description>- web design and life stuff</description>
	<lastBuildDate>Tue, 27 Oct 2009 15:45:38 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>CSS drop-down menus: keeping the top level selected when hovering over a sub-menu, now in jQuery</title>
		<link>http://www.darrenkrape.com/categories/design-and-development/css-drop-down-menus-2/</link>
		<comments>http://www.darrenkrape.com/categories/design-and-development/css-drop-down-menus-2/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 15:17:38 +0000</pubDate>
		<dc:creator>Darren</dc:creator>
				<category><![CDATA[Design and Development]]></category>
		<category><![CDATA[Journal]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.darrenkrape.com/?p=233</guid>
		<description><![CDATA[Awhile back I wrote a JavaScript tutorial on how to keep the top level menu item selected when hovering over a drop down menu. Since then I&#8217;ve become a strong user and proponent of the JavaScript library jQuery. Not only is it easy to use, it also can help simplify your code-base very significantly. I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>Awhile back I wrote a <a href="http://www.darrenkrape.com/fun/journal/drop-down-menus-persistent-top-level-menu-styling/">JavaScript tutorial</a> on how to keep the top level menu item selected when hovering over a drop down menu. Since then I&#8217;ve become a strong user and proponent of the JavaScript library <a href="http://www.jquery.com">jQuery</a>. Not only is it easy to use, it also can help simplify your code-base very significantly. I&#8217;ve explained the updated code below. As you can see, it is much simpler.<br />
<span id="more-233"></span></p>
<ul>
<li><a class="code_example" href="/examples/dropdown2/">View this code in action</a></li>
<li><a class="jump" href="#complete_code">View complete code</a></li>
</ul>
<h3>How this works</h3>
<p>There are two main components of the JavaScript, first the code for all browsers to keep the top level selected and a second code block to add the hover state for IE6 (since it only supports <code>:hover</code> pseudo-classes on anchors, not list elements as we use here).</p>
<p>First, you&#8217;ll need to add the jQuery equivalent of &#8220;onLoad&#8221;: <code>$(function() {</code>. Fortunately, the multiple onLoad and caching issues we addressed in the earlier tutorial are now handled in jQuery, so no need to use the &#8220;onEvent&#8221; function from the earlier tutorial. You&#8217;ll also sometimes see this as <code>$(document).ready(function() {</code>. The functionality is the same, so feel free to use either syntax.</p>
<h4>Code for persistent top-level menu formatting</h4>
<p>Next, the general code for maintaining the hover formatting on the top level. Basically, this function iterates through each of the drop-down <code>&lt;ul&gt;</code>s and adds a <code><a href="http://docs.jquery.com/Events/hover">hover</a></code> function to each. So, when a user hovers over a drop down menu, jQuery finds the parent of that drop down, finds all anchor tags, slices out all the anchors but the first and, finally, toggles the &#8220;active&#8221; class.</p>
<pre><code>$("#menu ul").each(function(i){
  $(this).hover(function(){
    $(this).parent().find("a").slice(0,1).addClass("active");
  },function(){
    $(this).parent().find("a").slice(0,1).removeClass("active");
  });
});
</code></pre>
<h4>Internet Explorer 6 functionality</h4>
<p>To make this work in IE6, we need to add some additional code. First, we use jQuery&#8217;s built in <a href="http://docs.jquery.com/Utilities/jQuery.browser">browser sniffer</a> to only target <abbr title="Microsoft Internet Explorer">MSIE</abbr> versions below 7. It then works fundimentally like the code above and the Suckerfish drop downs from the <a href="http://www.darrenkrape.com/fun/journal/drop-down-menus-persistent-top-level-menu-styling/">earlier tutorial</a>. JavaScript cycles through each drop-down <code>&lt;ul&gt;</code> and adds a function that tells the its parent anchor tag to take on a particular class when the browser detects a mouseover on the menu.</p>
<pre><code>if($.browser.msie &amp;&amp; ($.browser.version &lt; 7)) {
  $("#menu").each(function(i){
    $(this).find("li").hover(function(){
      $(this).addClass("sfhover");
    },function(){
      $(this).removeClass("sfhover");
    });
  });
}
</code></pre>
<h4>In closing</h4>
<p>Be sure to add the closing parenthesize and bracket for the jQuery on ready state: <code>});</code>.</p>
<h3 id="complete_code">Complete Code</h3>
<pre class="complete"><code>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;

&lt;head&gt;

  &lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /&gt;
  &lt;title&gt;Menu Example&lt;/title&gt;

  &lt;style type="text/css" media="screen"&gt;

  body {
    margin: 20px;
    background: #fff;
    font-family: Verdana, Helvetica, sans-serif;
    font-size: 9pt;
  }

  * { margin: 0; padding: 0; }
  li { list-style: none; }
  a { text-decoration: none; }

  #menu li {
    float: left;
    display: block;
    font-size: 8pt;
  }

  #menu li a {
    position: relative;
    padding: 6px 10px;
    display: block;
    font-weight: bold;
    color: #333;
  }

  #menu li a:hover, #menu li a.active {
    background: #999;
    color: white;
  }

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

  #menu li ul li { float : none; }

  #menu li ul a {
    width : 136px;
    padding : 8px 10px;
    background : #f4f4f4;
    border-bottom : 1px solid white;
    font-weight : normal;
  } 

  #menu li ul a:hover {
    background: #FFCC99;
    color: #333;
  }

  #menu li:hover ul, #menu li.sfhover ul {
    left: auto;
    border-top: 1px solid #999;
  }

  &lt;/style&gt;

  &lt;script type="text/javascript" src="jquery.js"&gt;  &lt;/script&gt;

  &lt;script type="text/javascript" src="jquery.js"&gt;
  &lt;!--

  $(function() {

    //Preserves the mouse-over on top-level menu elements when hovering over children
    $("#menu ul").each(function(i){
      $(this).hover(function(){
        $(this).parent().find("a").slice(0,1).addClass("active");
      },function(){
        $(this).parent().find("a").slice(0,1).removeClass("active");
      });
    });

    // IE6 Fix: Drop-down fix due to lack of support for :hover on list elements
    if($.browser.msie &amp;&amp; ($.browser.version &lt; 7)) {
      $("#menu").each(function(i){
        $(this).find("li").hover(function(){
          $(this).addClass("sfhover");
        },function(){
          $(this).removeClass("sfhover");
        });
      });
    }

  });

  // --&gt;
  &lt;/script&gt;

&lt;/head&gt;

&lt;body&gt;

  &lt;ul id="menu"&gt;
    &lt;li&gt;&lt;a href="#"&gt;Styles&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Red/White&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Ros?©/Blush&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Sparkling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Dessert&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Fortified&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Fruit&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Ice Wine&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Whites&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Albari?±o&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Chardonnay&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Chenin blanc&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Muscat&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Pinot blanc&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Pinot gris&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Riesling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Sauvignon blanc &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;S?©millon&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Reds&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Cabernet Sauvignon &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Malbec &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Merlot &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Pinot noir &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Syrah/Shiraz &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Zinfandel&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Noted Regionals&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Amarone&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Beaujolais&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Burgundy &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Chianti &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Madeira &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Port &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Sancerre &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Tokaji &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Vinho Verde &lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Key Countries&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;France&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Italy&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Spain&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;United States&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Argentina&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Australia&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;South Africa&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
  &lt;/ul&gt;

&lt;/body&gt;
&lt;/html&gt;
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.darrenkrape.com/categories/design-and-development/css-drop-down-menus-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CSS drop-down menus: how to keep the top level selected when hovering over a sub-menu</title>
		<link>http://www.darrenkrape.com/categories/design-and-development/drop-down-menus-persistent-top-level-menu-styling/</link>
		<comments>http://www.darrenkrape.com/categories/design-and-development/drop-down-menus-persistent-top-level-menu-styling/#comments</comments>
		<pubDate>Thu, 12 Apr 2007 16:31:32 +0000</pubDate>
		<dc:creator>Darren</dc:creator>
				<category><![CDATA[Design and Development]]></category>
		<category><![CDATA[Journal]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.forma3.com/v4/journal/drop-down-menus-persistent-top-level-menu-styling/</guid>
		<description><![CDATA[<p><img src="/i/articles/drop-down.png" alt="CSS drop-down menus: how to keep the top level selected when hovering over a sub-menu" class="article_highlight" />Pure <abbr title="Cascading Style Sheet">CSS</abbr>-based drop-down menus are a great thing, if for no other reason than their sheer simplicity and flexibility. However, they have two main drawbacks.</p>

<p>1. They don't work in Internet Explorer 6 due to the browser's poor support for the <code>:hover</code> pseudo-class.</p>
<p>2. When the mouse cursor is over a drop-down, the top level navigation item does not stay highlighted under most conditions.</p>

<p>Fortunately, both problems can be solved with some simple JavaScript. The first problem is easily corrected with the excellent <a href="http://www.htmldog.com/articles/suckerfish/dropdowns/" class="ext">Son of SuckerFish drop-down code</a>. The second problem can be solved using the equally small amount of code described below.</p>

<p>The best part of this code its use of <abbr title="Document Object Model">DOM</abbr> hooks in your <abbr title="Extensible HyperText Markup Language">XHTML</abbr> document to add the functionality making it self-contained and allowing full separation of content and design.</p>]]></description>
			<content:encoded><![CDATA[<p>Pure <abbr title="Cascading Style Sheet">CSS</abbr>-based drop-down menus are a great thing, if for no other reason than their sheer simplicity and flexibility. However, they have two main drawbacks.</p>
<ol>
<li>They don&#8217;t work in Internet Explorer 6 due to the browser&#8217;s poor support for the <code>:hover</code> pseudo-class.</li>
<li>When the mouse cursor is over a drop-down, the top level navigation item does not stay highlighted under most conditions.</li>
</ol>
<p>Fortunately, both problems can be solved with some simple JavaScript. The first problem is easily corrected with the excellent <a class="ext" href="http://www.htmldog.com/articles/suckerfish/dropdowns/">Son of SuckerFish drop-down code</a>. The second problem can be solved using the equally small amount of code described below.</p>
<p>The best part of this code its use of <abbr title="Document Object Model">DOM</abbr> hooks in your <abbr title="Extensible HyperText Markup Language">XHTML</abbr> document to add the functionality making it self-contained and allowing full separation of content and design.</p>
<p>For the sake of simplicity, and reducing the number of called functions, I&#8217;ve combined the SuckerFish JavaScript with my own.</p>
<ul>
<li><a class="code_example" href="/examples/drop_down_1.html">View this code in action</a></li>
<li><a class="jump" href="#complete_code">View complete code</a></li>
</ul>
<p><span id="more-45"></span></p>
<h3>How this works</h3>
<p>The code is pretty simple, but for novice JavaScriptors (such as myself), here is a set-by-step guide on how the function works.</p>
<h4>Internet Explorer 6 Functionality: The SuckerFish Code</h4>
<p>First, we declare the function and add the SuckerFish code for Internet Explorer 6 compatibility. Since this functionality is already described in their article, I&#8217;ll just note two small changes I&#8217;ve made.</p>
<ul>
<li>The original SuckerFish code had the ID hard-coded into the function. The below version has a variable instead of the hard-coded ID, allowing us to use the function on several different drop-downs.</li>
<li>I&#8217;ve corrected an error in the regular expression which was causing the class name to remain on the list element when the user moves their cursor off the drop-down (this error and the fix used here was <a class="ext" href="http://blogs.thesitedoctor.co.uk/tim/2007/02/23/Firefox+Class+Name+And+Space+Idiosyncrasy.aspx">originally pointed out by Tim Gaunt</a>).</li>
</ul>
<pre><code>menuHover = function(nav) {
  var sfEls = document.getElementById(nav).getElementsByTagName("li");
  for (var i=0; i&lt;sfEls.length; i++) {
    sfEls[i].onmouseover=function() {
      this.className+=" sfhover";
    }
    sfEls[i].onmouseout=function() {
      this.className=this.className.replace(new RegExp("\\s?sfhover\\b"), "");
    }
  }
</code></pre>
<h4>Code for persistent top-level menu formatting</h4>
<p>Now we get into the code that maintains the hover state for top-level navigation elements when the user has moved the cursor over a drop-down list. Fundamentally, this works the same way as the SuckerFish function, but with some adjustments. The system cycles through each drop-down <code>&lt;ul&gt;</code> and adds a function that tells the its parent anchor tag to take on a particular class when the browser detects a mouseover on the menu.</p>
<p>First, we create a variable selecting each sub-navigation list by using the main <code>&lt;ul&gt;</code> ID. This will allow us to add a mouseover function to each of the drop-downs.</p>
<pre><code>var listItem = document.getElementById(nav).getElementsByTagName('ul');</code></pre>
<p>Next, we cycle through each of the <code>&lt;ul&gt;</code> drop-downs so we can add a function on each one.</p>
<pre><code>for(var i=0;i&lt;listItem.length;i++) {</code></pre>
<p>If the browser detects the mouse cursor over the current drop-down it will pull into an array all anchors found in the parentNode (which is, basically, whatever the parent element is in the <abbr title="Document Object Model">DOM</abbr>, in this case the parent node is a <code>&lt;ul&gt;</code>). It then assigns the first anchor, presumably the anchor in the top-level navigation, a new class name. In this case, the class name &#8220;anchor&#8221;.</p>
<pre><code>listItem[i].onmouseover=function() {
  var changeStyle = this.parentNode.getElementsByTagName('a');
  changeStyle[0].className+=" active";
}
</code></pre>
<p>Now, when the user moves the cursor away, we simply remove the class name and the anchor is restored to its original style.</p>
<pre><code>listItem[i].onmouseout=function() {
  var changeStyle = this.parentNode.getElementsByTagName('a');
  changeStyle[0].className=this.className.replace(new RegExp("\\s?active\\b"), "");
}
</code></pre>
<h4>Playing well with others: onLoad Function</h4>
<p>Now we need to call our function on page load so the menus will work from the start. To do this we&#8217;ll use <a class="ext" href="http://ejohn.org/projects/flexible-javascript-events/">John Resig&#8217;s addEvent on load function</a>. This is useful for two reasons:</p>
<ol>
<li>Using this function will allow us to add as many on load events as we like (or what the browser will handle) without worrying that the various functions will interfere with each other.</li>
<li>John&#8217;s function helps avoid the Internet Explorer caching problem that can cause performance problems for end users.</li>
</ol>
<p>Here is the code:</p>
<pre><code>function addEvent( obj, type, fn ) {
  if ( obj.attachEvent ) {
    obj['e'+type+fn] = fn;
    obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
    obj.attachEvent( 'on'+type, obj[type+fn] );
  } else
    obj.addEventListener( type, fn, false );
  }
function removeEvent( obj, type, fn ) {
  if ( obj.detachEvent ) {
  obj.detachEvent( 'on'+type, obj[type+fn] );
  obj[type+fn] = null;
  } else
    obj.removeEventListener( type, fn, false );
  }

addEvent(window, 'load', function () { menuHover('menu'); });
</code></pre>
<p>Take a look at <a class="ext" href="http://ejohn.org/projects/flexible-javascript-events/">John Resig&#8217;s post &#8220;Flexible Javascript Events&#8221;</a> on this function to get a better idea how it works.</p>
<h4>The <abbr title="Cascading Style Sheet">CSS</abbr> and <abbr title="Extensible HyperText Markup Language">XHTML</abbr></h4>
<p>Last but not least, we need our <abbr title="Cascading Style Sheet">CSS</abbr> and <abbr title="Extensible HyperText Markup Language">XHTML</abbr> on which we&#8217;ll apply our JavaScript. The following is almost exactly like the SuckerFish code so I will note the one, very small, different.</p>
<p>In order to apply the highlighted state to the top-level navigation anchor, we need to give it a class name. Fortunately, since we already have a style declaration for the hover state, we&#8217;ll just append another declaration name to the original style, as you can see below.</p>
<pre><code>#menu li.dropdown a:hover, #menu li.dropdown a.active {
  color: white;
  background: #999 url(../i/arrow_down.gif) no-repeat right 50%;
}
</code></pre>
<h3>Areas for improvement</h3>
<ol>
<li>This will only work if your top-level navigation style is on an anchor tag. If your main style is on the &lt;li&gt; then the JavaScript won&#8217;t select it in order to add the custom class. A future improvement might include passing a variable with the tag or class the function should reference.</li>
<li>The class name JavaScript references is hard coded into the function. Fortunately the script will pull the class relative to the element in the <abbr title="Document Object Model">DOM</abbr>, so you can have two classes with the same name with different styles so long as they are declared on different elements higher in the cascade.To illustrate, if using the following code:
<pre><code>&lt;ul id="menu"&gt;
  &lt;li&gt;
    &lt;a href="#" class="active"&gt;Link&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>This function will apply the style <code>#menu ul li .active</code> and not the style <code>#content ul li .active</code>.</p>
<p>Nonetheless, passing a variable with the highlighted class name to the function would help make this function truly flexible.</li>
</ol>
<h3 id="complete_code">Complete Code</h3>
<pre class="complete"><code>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;

&lt;head&gt;

  &lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /&gt;
  &lt;title&gt;Menu Example&lt;/title&gt;

  &lt;style type="text/css" media="screen"&gt;

  body {
    margin: 20px;
    background: #fff;
    font-family: Verdana, Helvetica, sans-serif;
    font-size: 9pt;
  }

  * { margin: 0; padding: 0; }
  li { list-style: none; }
  a { text-decoration: none; }

  #menu li {
    float: left;
    display: block;
    font-size: 8pt;
  }

  #menu li a {
    position: relative;
    padding: 6px 10px;
    display: block;
    font-weight: bold;
    color: #333;
  }

  #menu li a:hover, #menu li a.active {
    background: #999;
    color: white;
  }

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

  #menu li ul li { float : none; }

  #menu li ul a {
    width : 136px;
    padding : 8px 10px;
    background : #f4f4f4;
    border-bottom : 1px solid white;
    font-weight : normal;
  } 

  #menu li ul a:hover {
    background: #FFCC99;
    color: #333;
  }

  #menu li:hover ul, #menu li.sfhover ul {
    left: auto;
    border-top: 1px solid #999;
  }

  &lt;/style&gt;

  &lt;script type="text/javascript"&gt; &lt;!--
  menuHover = function(nav) {
    var sfEls = document.getElementById(nav).getElementsByTagName("li");
    for (var i=0; i&lt;sfEls.length; i++) {
      sfEls[i].onmouseover=function() {
        this.className+=" sfhover";
      }
      sfEls[i].onmouseout=function() {
        this.className=this.className.replace(new RegExp("\\s?sfhover\\b"), "");
      }
    }

    var listItem = document.getElementById(nav).getElementsByTagName('ul');
    for(var i=0;i&lt;listItem.length;i++) {
      listItem[i].onmouseover=function() {
        var changeStyle = this.parentNode.getElementsByTagName('a');
        changeStyle[0].className+=" active";
      }

      listItem[i].onmouseout=function() {
        var changeStyle = this.parentNode.getElementsByTagName('a');
        changeStyle[0].className=this.className.replace(new RegExp("\\s?active\\b"), "");
      }
    }
  }

  function addEvent( obj, type, fn ) {
    if ( obj.attachEvent ) {
      obj['e'+type+fn] = fn;
      obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
      obj.attachEvent( 'on'+type, obj[type+fn] );
    } else
      obj.addEventListener( type, fn, false );
    }
  function removeEvent( obj, type, fn ) {
    if ( obj.detachEvent ) {
    obj.detachEvent( 'on'+type, obj[type+fn] );
    obj[type+fn] = null;
    } else
      obj.removeEventListener( type, fn, false );
    }

  addEvent(window, 'load', function () { menuHover('menu'); });

  // --&gt; &lt;/script&gt;

&lt;/head&gt;

&lt;body&gt;

  &lt;ul id="menu"&gt;
    &lt;li&gt;&lt;a href="#"&gt;Styles&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Red/White&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Ros?©/Blush&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Sparkling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Dessert&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Fortified&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Fruit&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Ice Wine&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Whites&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Albari?±o&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Chardonnay&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Chenin blanc&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Muscat&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Pinot blanc&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Pinot gris&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Riesling&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Sauvignon blanc &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;S?©millon&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Reds&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Cabernet Sauvignon &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Malbec &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Merlot &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Pinot noir &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Syrah/Shiraz &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Zinfandel&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Noted Regionals&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;Amarone&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Beaujolais&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Burgundy &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Chianti &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Madeira &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Port &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Sancerre &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Tokaji &lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Vinho Verde &lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Key Countries&lt;/a&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="#"&gt;France&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Italy&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Spain&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;United States&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Argentina&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;Australia&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="#"&gt;South Africa&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;/li&gt;
  &lt;/ul&gt;

&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<div class="update">
<p><strong>Update: 6 September 2009</strong></p>
<p>I recently got an email from a reader noting how IE6 caused a flicker when mousing over the top level navigation and inquiring if there was a way to fix this. Fortunately, the fix is quite easy. Simply add &#8220;<code>position: relative</code>&#8221; to the CSS declaration &#8220;<code>#menu li a</code>&#8220;.</p>
<p>Basically, what is happening is IE6 hovers don&#8217;t work very well when hovering over padding on an element. So the hover state disappears when moving from the actual text to the padding area and then to the menu below. The &#8220;position: relative&#8221; trick is useful for solving this in many other situations.</p>
<p>I&#8217;ve updated the code above to reflect this change.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.darrenkrape.com/categories/design-and-development/drop-down-menus-persistent-top-level-menu-styling/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Add icons to PDF, XLS, DOC file links, links to new windows and more&#8230;</title>
		<link>http://www.darrenkrape.com/categories/design-and-development/add-icons-to-pdf-xls-doc-file-links-links-to-new-windows-and-more/</link>
		<comments>http://www.darrenkrape.com/categories/design-and-development/add-icons-to-pdf-xls-doc-file-links-links-to-new-windows-and-more/#comments</comments>
		<pubDate>Mon, 09 Apr 2007 00:08:12 +0000</pubDate>
		<dc:creator>Darren</dc:creator>
				<category><![CDATA[Design and Development]]></category>
		<category><![CDATA[Journal]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.forma3.com/v4/journal/add-icons-to-pdf-xls-doc-file-links-links-to-new-windows-and-more/</guid>
		<description><![CDATA[Whenever linking on the web, it is important to let the user know exactly where the link leads, especially if opening a new window or the linked item requires a plug-in or external software. For example, if linking to a PDF a small icon can provide a good hint of where the link leads. Unfortunately, manually adding icons to every link through a site can be quite laborious. This is where JavaScript comes in. With few lines of simple code we can automatically add icons to every link on a page.]]></description>
			<content:encoded><![CDATA[<p>Whenever linking on the web, it is important to let the user know exactly where the link leads, especially if opening a new window or the linked item requires a plug-in or external software. For example, if linking to a PDF a small icon can provide a good hint of where the link leads. Unfortunately, manually adding icons to every link through a site can be quite laborious. This is where JavaScript comes in. With few lines of simple code we can automatically add icons to every link on a page.</p>
<ul>
<li><a class="code_example" href="/examples/icons/">View this code in action</a></li>
<li><a class="code_download" href="/examples/icons/adding_file_links.zip">Download this code</a> (ZIP)</li>
<li><a class="jump" href="#complete_code">View complete code</a></li>
</ul>
<p><span id="more-1"></span></p>
<h3>How this works</h3>
<p>For those familiar with JavaScript, the above code is pretty straightforward. But for novice JavaScript authors &#8211; such as myself &#8211; here is how the function breaks down.</p>
<h4>Collect our links and cycle through them</h4>
<p>We first collect all the links in a document and places them into array. We then cycle through each one using the following for loop:</p>
<pre><code>var links = document.getElementsByTagName("a");
for (i=0; i&amp;lt;links.length; i++) {
</code></pre>
<p>We then create a variable for the current link in the array:</p>
<pre><code>var linkIcons = links[i];</code></pre>
<h4>Check for linked images</h4>
<p>Since we don&#8217;t want to be adding these icons to the ends of images, we&#8217;ll add a line to collect the name of any images in the link the loop is currently on.</p>
<pre><code>var images = currentLink.getElementsByTagName("img");</code></pre>
<p>If an image is found, the variable will be defined and the length will be greater than 0, meaning we can filter out any links on images. We also can use <code>indexOf</code> to find out if a file extension is present in the <code>href</code>. Basically, <code>indexOf</code> returns the position of a specific character or set of characters in a string. If nothing is found, then JavaScript returns &#8220;-1&#8243;. This is useful since we can query the <code>href</code> of our link for a certain character set, in this case file extensions, and if JavaScript does not return &#8220;-1&#8243; then a match was found and we can go ahead and append the image.</p>
<pre><code>if (images.length == 0 &amp;&amp; currentLink.href.indexOf('.pdf') != -1) {</code></pre>
<h4>Adding the file icon</h4>
<p>When JavaScript has a match we need to tell it to create a new element &#8211; in this case a new image &#8211; which we can then append to our link. So, first we create the image, set the source and then add it to the end of the link we are currently parsing.</p>
<pre><code>var newImg=document.createElement('img');
newImg.setAttribute('src','/img/icons/pdf_js.png');
currentLink.appendChild(newImg);
</code></pre>
<p>Adding icons for links that open in new windows is also quite simple, requiring the modification of only one line of code. Instead of using <code>indexOf</code> to check if a particular file extension is used, we use the DOM to check the target. If the target equals &#8220;<code>_blank</code>&#8220;, indicating a new window will open when clicked, then we also append an image.</p>
<pre><code>if (images.length == 0 &amp;&amp; currentLink.target == "_blank") {</code></pre>
<h4>Play well with others: Multiple <code>OnLoad</code> Events</h4>
<p>To ensure that our function plays well with other scripts that may also be use onload events, we add <a href="http://simon.incutio.com/archive/2004/05/26/addLoadEvent" target="_blank">Simon Wilson&#8217;s addLoadEvent function</a> to reduce the chance of conflict.</p>
<pre><code>function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }

addLoadEvent(linkIcons);}</code></pre>
<h3>Areas for Improvement</h3>
<ol>
<li>Since this version of the script adds images to the HTML rather than simply giving the link a new class, it would be slightly more difficult to add additional style declarations than in the earlier example. In this case, since there is no CSS being used, the images all have built-in padding to ensure they aren&#8217;t flush with text on the left and right. Adding this padding using a style would probably be more flexible than my current method but would require a little extra code.</li>
<li>Although adding icons can be very useful for users, I generally go one step further and add additional descriptive text noting the file type and size, for example: Link (954 kb PDF), so they can estimate the download time and ensures there is useable message for users who have JavaScript disabled.</li>
<li>This JavaScript will add icons to every link on your page, possibly in places you&#8217;d prefer stay icon-free. The solution would be to have the script ignore areas with specific <code>id</code> or <code>class</code> tags, such as: <code>class="no-icons"</code>.</li>
</ol>
<h3 id="complete_code">Complete Code</h3>
<pre class="complete"><code>linkIcons = function() {
  var links = document.getElementsByTagName("a");
  for (i=0; i &lt; links.length; i++) {
    var currentLink = links[i];
    var images = currentLink.getElementsByTagName("img");
    if (images.length == 0 &amp;&amp; currentLink.href.indexOf('.pdf') != -1) {
      var newImg=document.createElement('img');
      newImg.setAttribute('src','pdf.png');
      currentLink.appendChild(newImg);
    }
    if (images.length == 0 &amp;&amp; currentLink.href.indexOf('.doc') != -1) {
      var newImg=document.createElement('img');
      newImg.setAttribute('src','doc.png');
      currentLink.appendChild(newImg);
    }
    if (images.length == 0 &amp;&amp; currentLink.target == "_blank") {
      var newImg=document.createElement('img');
      newImg.setAttribute('src','new_window.png');
      currentLink.appendChild(newImg);
    }
  }
}

function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}

addLoadEvent(linkIcons);</code></pre>
<h3>About this script</h3>
<p>As with all things worth doing, this has been done before. <a href="http://www.gqgoat.com/index.php?post=58" target="_blank">gqGoat&#8217;s article, &#8220;Automatically Add Icons After Links to PDF Files with the JavaScript &amp; the DOM&#8221;</a>, lays the foundation for this script, while I&#8217;ve added a few key improvements:</p>
<ol>
<li>Most importantly, in gqGoat&#8217;s method, the icon is added via CSS as a background to the link. For modern browsers this works great, but in Internet Explorer 6 the icon will be aligned poorly for multi-line links and, in many cases, will not even show up.</li>
<li>This method properly uses the <abbr title="Document Object Model">DOM</abbr> instead of relying on <code>innerHTML</code>, which is not standard and not terribly future-proof.</li>
<li>This script includes the onload fix as suggested in gqGoat&#8217;s original post by adding Simon Wilson&#8217;s &#8220;addLoadEvent&#8221; function.</li>
<li>Lastly, this adds several additional icons, including those for Word documents, PowerPoint files, and links that open in a new window using <code>target='_blank'</code>.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.darrenkrape.com/categories/design-and-development/add-icons-to-pdf-xls-doc-file-links-links-to-new-windows-and-more/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
