Wrox Programmer Forums
Go Back   Wrox Programmer Forums > Web Programming > CSS > BOOK: CSS Instant Results
| Search | Today's Posts | Mark Forums Read
BOOK: CSS Instant Results
This is the forum to discuss the Wrox book CSS Instant Results by Richard York; ISBN: 9780471751267
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: CSS Instant Results section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
  #1 (permalink)  
Old November 14th, 2006, 10:57 AM
richard.york's Avatar
Wrox Author
Points: 5,506, Level: 31
Points: 5,506, Level: 31 Points: 5,506, Level: 31 Points: 5,506, Level: 31
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jun 2003
Location: Camby, IN, USA.
Posts: 1,706
Thanks: 0
Thanked 6 Times in 6 Posts
Default Code Announcement: Ch3, Dynamic Drop Down Menus

I have prepared a drop in replacement for the drop_down_menus.js script used in the Implementing JavaScript-enabled Drop-Down Menus project in Chapter 3.

The code that I have prepared as a replacement ought to be able to survive with the same structural markup as presented in the book.

The script that appears here has a few fundamental differences with the code supplied with the book.

 * It uses a mouseover to open and close menus
 * It does not have any keyboard-based navigation

mouseover vs. click
In the book I discussed the pitfalls of a mouseover based menu system. After some further consideration I came to the conclusion that mouseover is the best way to go, but only if you also implement a "sticky" menu system. That is to say, menus that don't immediately close when the mouse leaves the menu. This script includes this "sticky" menu feature, a brief timeout is set (almost a second) so that menus don't close immediately, making this menu more accessible.

Keyboard Navigation
I'm still searching for the best way to implement keyboard-based navigation. The approach I used in the book fails when a page is large enough to scroll and the user wants to use the arrow keys to scroll the page. I believe the best approach is to use tabs for keyboard-based navigation. I will try to revisit this functionality soon.

The Code
Just replace the contents of drop_down_menus.js with the following:

Code:
/*
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//\\\       \\\\\\\\|
//\\\ @@    @@\\\\\\| Menu Script
//\\ @@@@  @@@@\\\\\| (c) Copyright 2006 Richard York, All rights Reserved
//\\\@@@@| @@@@\\\\\|
//\\\ @@ |\\@@\\\\\\|
//\\\\  ||   \\\\\\\|
//\\\\  \\_   \\\\\\|
//\\\\\        \\\\\|
//\\\\\  ----  \@@@@|
//@@@@@\       \@@@@|
//@@@@@@\     \@@@@@|
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
*/

// addEvent functions
//
// written by Dean Edwards, 2005
// with input from Tino Zijdel
//
// http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler)
{
    if (typeof(element) == 'string')
    {
        element = document.getElementById(element);
    }

    if (typeof(element) == 'object' && element && handler)
    {
        // assign each event handler a unique ID
        if (!handler.$$guid)
        {
            handler.$$guid = addEvent.guid++;
        }

        // create a hash table of event types for the element
        if (!element.events)
        {
            element.events = {};
        }

        // create a hash table of event handlers for each element/event pair
        var handlers = element.events[type];

        if (!handlers)
        {
            handlers = element.events[type] = {};

            // store the existing event handler (if there is one)
            if (element['on' + type])
            {
                handlers[0] = element['on' + type];
            }
        }

        // store the event handler in the hash table
        handlers[handler.$$guid] = handler;

        // assign a global event handler to do all the work
        element['on' + type] = handleEvent;
    }
};

// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler)
{
    // delete the event handler from the hash table
    if (element.events && element.events[type] && handler)
    {
        delete element.events[type][handler.$$guid];
    }
};

function handleEvent(event)
{
    var returnValue = true;

    // grab the event object (IE uses a global event object)
    event = event || fixEvent(window.event);

    // get a reference to the hash table of event handlers
    var handlers = this.events[event.type];

    // execute each event handler
    for (var i in handlers)
    {
        this.$$handleEvent = handlers[i];

        if (this.$$handleEvent(event) === false)
        {
            returnValue = false;
        }
    }

    return returnValue;
};

function fixEvent(event)
{
    // add W3C standard event methods
    event.preventDefault  = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
};

fixEvent.preventDefault = function()
{
    this.returnValue = false;
};

fixEvent.stopPropagation = function()
{
    this.cancelBubble = true;
};

var hMenu = {

    active : false,
    timer  : false,
    last   : '',

    attachEvents : function()
    {
        // Grab all the list elements with a menu class name
        // and apply a mouseover event.
        var $menus = cssQuery('ul#menu li.menu');

        for (var $i = 0, $l = $menus.length; $i < $l; $i++)
        {
            addEvent(
                $menus[$i],
                'mouseover',
                function($e)
                {
                    $e.stopPropagation();
                    hMenu.stopTimer();

                    var $childMenu = cssQuery('#' + this.id + ' > ul');

                    if ($childMenu && $childMenu.length)
                    {
                        // This bit hides sibling drop down menus, where the
                        // menu is nested more than one deep.
                        $nodes = (this.parentNode.id == 'menu')?
                            cssQuery('ul#menu ul')
                        :
                            cssQuery('li#' + this.parentNode.parentNode.id + ' ul ul');

                        if ($nodes && $nodes.length)
                        {
                            for (var $i = 0, $l = $nodes.length; $i < $l; $i++)
                            {
                                if ($nodes[$i] && $nodes[$i].style)
                                {
                                    $nodes[$i].style.visibility = 'hidden';
                                }
                            }
                        }

                        $childMenu[0].style.visibility = 'visible';
                    }
                }
            );
        }

        addEvent(
            'menu',
            'mouseover',
            function()
            {
                hMenu.active = true;
            }
        );

        addEvent(
            'menu',
            'mouseout',
            function()
            {
                hMenu.active = false;

                if (!hMenu.timer)
                {
                    hMenu.timer = setInterval('hMenu.isActive();', 800);
                }
            }
        );
    },

    isActive : function()
    {
        if (!hMenu.active)
        {
            hMenu.close();
        }
    },

    stopTimer : function()
    {
        if (hMenu.timer)
        {
            clearInterval(hMenu.timer);
            hMenu.timer = '';
        }
    },

    close : function()
    {
        var $nodes = cssQuery('ul#menu ul');

        if ($nodes.length)
        {
            for (var $i = 0, $l = $nodes.length; $i < $l; $i++)
            {
                if ($nodes[$i] && $nodes[$i].style)
                {
                    $nodes[$i].style.visibility = 'hidden';
                }
            }
        }

        clearInterval(hMenu.timer);
        hMenu.timer = '';
    }
};

addEvent(window, 'load', hMenu.attachEvents);

Regards,
Rich

--
Author,
Beginning CSS: Cascading Style Sheets For Web Design
CSS Instant Results

http://www.catb.org/~esr/faqs/smart-questions.html


Similar Threads
Thread Thread Starter Forum Replies Last Post
Code Announcement: Emulating min/max width in IE richard.york BOOK: CSS Instant Results 0 November 27th, 2006 01:58 PM
Drop Down Menus in Tables danludlow Javascript How-To 0 April 8th, 2006 05:22 PM
JS validation on the drop-down menus crmpicco Javascript How-To 0 July 1st, 2005 05:30 AM
change the value of two drop-down menus crmpicco Classic ASP Basics 3 March 28th, 2005 08:10 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.