Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > Web Programming > CSS > BOOK: CSS Instant Results
Password Reminder
Register
Register | FAQ | Members List | Calendar | 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 tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old November 14th, 2006, 09: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 5 Times in 5 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
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

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 12: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 07:10 PM



All times are GMT -4. The time now is 08:35 PM.


Powered by vBulletin®
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.