/**
* Cross-browser, dynamic drop-down menu javascript for
* CSS Instant Results
*
* This script requires Dean Edwards' cssQuery JavaScript,
* which can be obtained from 
* http://dean.edwards.name/my/cssQuery
*
* Author: Richard York
* [reference to open source license here]
* (c) Copyright 2005, Wiley Publishing, Inc.
*/

// Set class names here!
var $CSSIR_liClassName  = 'menu';
var $CSSIR_ulClassName  = 'menu';
var $CSSIR_divClassName = 'menu';
var $CSSIR_liHighlight  = 'menu-highlight';
var $CSSIR_aHighlight   = 'menu-link-highlight';

var $CSSIR_menuLast    = null;
var $CSSIR_menuToggle  = false;
var $CSSIR_parent      = new Array();

var $CSSIR_menus;
var $CSSIR_menu;
var $CSSIR_current     = -1;
var $CSSIR_link        = 0;

function CSSIR_menuAttachEvents()
{
    // Grab all the list elements with a menu class name
    // and apply an onclick event.
    $CSSIR_menus = cssQuery('li.' + $CSSIR_liClassName);

    for (var $i in $CSSIR_menus)
    {
        $CSSIR_menus[$i].onclick = CSSIR_menuHandler;

        // The $menuToggle variable tracks whether 
        // or not the user's mouse is over a menu
        $CSSIR_menus[$i].onmouseover = function()
        {
            $CSSIR_menuToggle = true;
        }

        $CSSIR_menus[$i].onmouseout = function()
        {
            $CSSIR_menuToggle = false;
        }
    }
}

function CSSIR_menuHandler()
{
    var $tags;
    var $menu = (!$CSSIR_menu)? this : $CSSIR_menu;
    $CSSIR_menu = null;

    $tags = cssQuery('ul.' + $CSSIR_ulClassName + ' li.' + $CSSIR_aHighlight);

    for (var $i in $tags)
    {
        $tags[$i].className = null;
    }

    if ($CSSIR_parent.length)
    {
        // This bit hides sibling drop down menus, where the 
        // menu is nested more than one deep.
        //
        // Had some trouble with parentNode.childNodes in Safari,
        // so I'm using cssQuery to work around that.
        $tags = cssQuery('#' + $menu.parentNode.parentNode.parentNode.parentNode.id + ' > div li.' + $CSSIR_liClassName);

        if ($tags.length)
        {
            for (var $i in $tags)
            {
                if ($tags[$i].id)
                {
                    // Reattach the menu handler event.
                    $tags[$i].onclick = CSSIR_menuHandler;

                    // Hide the menu
                    cssQuery('#' + $tags[$i].id + ' div.' + $CSSIR_divClassName)[0].style.visibility = 'hidden';
                    $tags[$i].className = $CSSIR_liClassName;
                }
            }
        }
    }

    // Prevent event bubbling
    $menu.onclick = null;
    $menu.className = $CSSIR_liClassName + ' ' + $CSSIR_liHighlight;

    // Detects when a menu is more than one deep
    CSSIR_parent($menu);

    if ($CSSIR_menuLast && !(
            $menu.parentNode && 
            $menu.parentNode.parentNode && 
            $menu.parentNode.parentNode.parentNode && 
            $menu.parentNode.parentNode.parentNode.parentNode &&
            $menu.parentNode.parentNode.parentNode.parentNode.id
        )
    ) {
        cssQuery('#' + $CSSIR_menuLast.id + ' > div')[0].style.visibility = 'hidden';
        $CSSIR_menuLast.onclick   = CSSIR_menuHandler;
        $CSSIR_menuLast.className = $CSSIR_liClassName;

        if ($CSSIR_parent.length)
        {
            for (var $i in $CSSIR_parent)
            {
                $CSSIR_parent[$i].parentNode.onclick   = CSSIR_menuHandler;
                $CSSIR_parent[$i].parentNode.className = $CSSIR_liClassName;
                $CSSIR_parent[$i].style.visibility     = 'hidden';
            }
            $CSSIR_parent = new Array();
        }
    }

    if ($menu.id)
    {
        cssQuery('li#' + $menu.id + ' > div')[0].style.visibility = 'visible';
    }
    $CSSIR_menuLast = $menu;

    // This calls on Dean Edwards' IE7 recalc function
    if (document.recalc)
    {
        document.recalc();
    }
}

function CSSIR_parent($node)
{
    if ($node.parentNode && $node.parentNode.parentNode.parentNode.parentNode.id)
    {
        $CSSIR_parent.push($node.parentNode.parentNode.parentNode);
    }   
}

function CSSIR_hideAll()
{
    // Hide all menus and reset the classname.
    var $nodes = cssQuery('li.' + $CSSIR_liClassName  + ' > div');

    for (var $i in $nodes)
    {
        $nodes[$i].style.visibility     = 'hidden';
        $nodes[$i].parentNode.className = $CSSIR_liClassName;
    }

    // Reset values and put things back to they way they were when the 
    // page loaded up.
    CSSIR_menuAttachEvents();
    $CSSIR_parent   = new Array();
    $CSSIR_menuLast = null;
    $CSSIR_current  = 0;
    $CSSIR_link     = 0;
    $CSSIR_menu     = null;

    // Reset those highlighted links
    $tags = cssQuery('ul.' + $CSSIR_ulClassName + ' li.' + $CSSIR_aHighlight);

    for (var $i in $tags)
    {
        $tags[$i].className = null;   
    }

    if (document.recalc)
    {
        document.recalc();
    }
}

document.onload = CSSIR_menuAttachEvents;

document.onkeydown = function($e)
{
    if (!$e)
    {
        $e = window.event;
    }

    // See if the return key is being pressed
    //
    // Keyboard access should be independant of already built-in
    // browser keyboard shortcuts.  The arrow keys don't appear to 
    // be assigned to anything, by default, so we'll use those for
    // keyboard menu navigation.
    switch ($e.keyCode)
    {
        case 37: // left arrow
        case 39: // right arrow
        {
            // The $CSSIR_current variable is a counter that tracks 
            // which menu is open.
            if ($CSSIR_current == -1)
            {
                // When the user gets to the end of the menu, the menu is 
                // completely closed, this lets the user start over from 
                // the beginning if desired, and provides a way to access
                // top-level links.
                CSSIR_hideAll();

                // The counter is reset, when the user taps the left or right
                // arrow again, the first submenu will be opened.
                $CSSIR_current = 0;
            }
            else
            {
                // Get all menu elements.
                $CSSIR_menus = cssQuery('li.' + $CSSIR_liClassName);

                var $n = 0;

                // Find the menu matching the counter
                for (var $i in $CSSIR_menus)
                {
                    if ($n == $CSSIR_current)
                    {
                        var $menu = $CSSIR_menus[$i];
                        break;
                    }
                    $n++;
                }

                // Set this global so that we can pass the menu to the 
                // menu handler, which will handle the opening and closing bit
                // and keep the menus straight
                $CSSIR_menu = $menu;
                CSSIR_menuHandler();

                // We've reached the last submenu, reset the counter and start over
                if ($CSSIR_current == ($CSSIR_menus.length - 1))
                {
                    $CSSIR_current = -1;
                }
                else
                {
                    // Go on to the next menu
                    $CSSIR_current++;
                }
            }
            break;
        }
        case 38: // top arrow
        case 40: // down arrow
        {
            // See if there is a menu open, if not iterate through the 
            // top level menu.
            var $selector = ($CSSIR_menuLast)?
                '#' + $CSSIR_menuLast.id + ' > div > div > ul > li'
            :
                'ul.' + $CSSIR_ulClassName + ' > li';

            var $tags = cssQuery($selector);

            var $n = 0;

            for (var $i in $tags)
            {
                if ($tags[$i].className.indexOf($CSSIR_aHighlight) != -1)
                {
                    $tags[$i].className = '';
                }

                if ($tags[$i].className.indexOf($CSSIR_liClassName) == -1)
                {
                    if ($n == $CSSIR_link)
                    {
                        $tags[$i].className = $CSSIR_aHighlight;

                        // IE and firefox need the link to receive focus, otherwise
                        // pressing return can have unexpected results
                        cssQuery($selector + '.' + $CSSIR_aHighlight + ' > a')[0].focus();
                    }
                }
                $n++;
            }

            if ($CSSIR_link == ($tags.length - 1))
            {
                $CSSIR_link = 0;
            }
            else
            {
                $CSSIR_link++;
            }
            
            if (document.recalc)
            {
                document.recalc();   
            }
            break;
        }
        case 13: // return key
        {
            // This bit is a fallback for browsers that don't allow a link to receive
            // focus.

            $link = ($CSSIR_menuLast)?
                cssQuery('#' + $CSSIR_menuLast.id + ' > div > div > ul > li.' + $CSSIR_aHighlight + ' > a')[0]
            :
                cssQuery('ul.' + $CSSIR_ulClassName + ' > li.' + $CSSIR_aHighlight + ' > a')[0];

            if ($link)
            {
                // Opera doesn't support a link getting focus
                document.location.href = $link.href;
            }
            break;
        }
    }
}

document.onmousedown = function()
{
    // When the user clicks outside of a menu, the whole menu
    // is hidden and reset
    if (!$CSSIR_menuToggle)
    {
        CSSIR_hideAll();
    }
}