<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
<head>
<title>[DOM Menu] :: Example 1 :: Horizontal Menu</title>
<style>
body {
margin: 0;
padding: 10px;
}
a:link, a:visited, a:active {
font-family: Verdana, sans-serif;
font-size: 12px;
text-decoration: underline;
color: #000066;
font-weight: bold;
}
a:hover {
text-decoration: none;
}
div.p {
font-family: Verdana, sans-serif;
font-size: 12px;
margin: 0;
padding: 10px;
}
div.small {
font-family: Verdana, sans-serif;
font-size: 10px;
}
div.title {
color: #000066;
padding-left: 1px;
font-family: monospace;
letter-spacing: 2px;
font-size: 12px;
line-height: 9px;
height: 9px;
margin-bottom: 1px;
}
div.main {
border: 1px solid #000066;
}
/* Default Style (Opera inspired) */
div.domMenu_menuBar {
border: solid #7E7E7E;
border-width: 1px 0 0 1px;
}
div.domMenu_menuElement {
font-family: Arial, sans-serif;
font-size: 12px;
border: solid #7E7E7E;
border-width: 0 1px 1px 0;
background: url(gradient.png) repeat-x;
color: #0F0F0F;
text-align: center;
height: 28px;
line-height: 28px;
vertical-align: middle;
}
div.domMenu_menuElementHover {
background: url(gradient_hover.png) repeat-x;
}
div.domMenu_subMenuBar {
border: solid #7E7E7E 1px;
background-color: #FFFFFF;
padding-bottom: 1px;
opacity: .9;
filter: alpha(opacity=90);
}
div.domMenu_subMenuElement {
font-family: Arial, sans-serif;
font-size: 12px;
border: solid #CCCCCC 1px;
margin: 1px 1px 0 1px;
color: #0F0F0F;
padding: 2px 7px;
}
div.domMenu_subMenuElementHover {
background-color: #EFEFEF;
}
/* Keramik Style */
div.keramik_menuBar {
padding: 2px 4px 0 4px;
}
div.keramik_subMenuBar {
background: url(keramik_gradient_h.gif) repeat-y;
border: 1px solid;
border-color: #FFFFFF #535352 #535352 #FFFFFF;
}
div.keramik_menuElement, div.keramik_subMenuElement {
border: 0;
color: #535352;
font-family: serif;
font-size: 12px;
line-height: 14px;
text-align: left;
padding: 3px 5px;
}
div.keramik_subMenuElement {
padding: 3px 3px 3px 13px;
}
div.keramik_menuElementHover {
padding: 2px 4px;
border: 1px solid;
border-color: #535352 #FFFFFF #FFFFFF #535352;
background-color: #FFFFFF;
}
div.keramik_subMenuElementHover {
padding: 2px 2px 2px 12px;
border: 1px solid;
border-color: #82A0C2;
background: url(keramik_bubble.gif) repeat-x;
}
div.domMenu_subMenuElementHeading {
font-weight: bold;
}
/* BrainJar Style */
div.BJ_menuBar, div.BJ_menuElement,
div.BJ_subMenuBar, div.BJ_subMenuElement {
font-family: 'MS Sans Serif', Arial, sans-serif;
font-size: 10px;
color: #000000;
text-align: left;
}
div.BJ_menuBar,
div.BJ_subMenuBar {
background-color: #c09070;
border: 2px solid;
border-color: #e0b090 #906040 #906040 #e0b090;
}
div.BJ_menuBar {
padding: 1px 4px;
}
div.BJ_menuElement {
border: 1px solid #c09070;
padding: 2px 6px 2px 6px;
font-weight: bold;
}
div.BJ_subMenuElement {
padding: 2px 6px 2px 6px;
margin: 0 1px 1px 0;
}
div.BJ_subMenuElementHover {
background-color: #906040;
color: #FFFFFF;
}
div.BJ_subMenuElementHeading {
font-weight: bold;
}
div.BJ_menuElementHover {
border-color: #e0b090 #906040 #906040 #e0b090;
}
div.BJ_menuElementActive {
background-color: #906040;
color: #FFFFFF;
border-color: #906040 #e0b090 #e0b090 #906040;
}
div.hr {
border-top: 1px solid #906040;
border-bottom: 1px solid #e0b090;
}
/* NBLSA styles */
.domMenuNBLSA_subMenuElement {
background-color: #000000;
font-family: Verdana;
color: #EBCC72;
font-weight: bold;
font-size: 10px;
text-align: left;
vertical-align: top;
padding: 6px 10px;
white-space: nowrap;
}
.domMenuNBLSA_subMenuElementHover {
background-color: #EBCC72;
color: #000000;
}
</style>
<!-- domLib.js -->
<script language="javascript">
/** $Id: domLib.js 1891 2005-05-25 05:01:19Z dallen $ */
// {{{ docs <-- this is a VIM (text editor) text fold
/**
* Title: DOM Library Core
* Version: 0.65
*
* Summary:
* A set of commonly used functions that make it easier to create javascript
* applications that rely on the DOM.
*
* Updated: 2005/05/17
*
* Maintainer: Dan Allen <dan.allen@mojavelinux.com>
* Maintainer: Jason Rust <jrust@rustyparts.com>
*
* License: LGPL
*/
// }}}
// {{{ global constants (DO NOT EDIT)
/**
* Global constants (DO NOT EDIT)
*/
// -- Browser Detection --
var domLib_userAgent = navigator.userAgent.toLowerCase();
var domLib_isMac = navigator.appVersion.indexOf('Mac') != -1;
var domLib_isWin = domLib_userAgent.indexOf('windows') != -1;
var domLib_isOpera = domLib_userAgent.indexOf('opera') != -1;
var domLib_isOpera7up = domLib_userAgent.match(/opera.(7|8)/i);
var domLib_isSafari = domLib_userAgent.indexOf('safari') != -1;
var domLib_isKonq = domLib_userAgent.indexOf('konqueror') != -1;
// Both konqueror and safari use the khtml rendering engine
var domLib_isKHTML = (domLib_isKonq || domLib_isSafari || domLib_userAgent.indexOf('khtml') != -1);
var domLib_isIE = (!domLib_isKHTML && !domLib_isOpera && (domLib_userAgent.indexOf('msie 5') != -1 || domLib_userAgent.indexOf('msie 6') != -1));
var domLib_isIE5up = domLib_isIE;
var domLib_isIE50 = (domLib_isIE && domLib_userAgent.indexOf('msie 5.0') != -1);
var domLib_isIE55 = (domLib_isIE && domLib_userAgent.indexOf('msie 5.5') != -1);
var domLib_isIE5 = (domLib_isIE50 || domLib_isIE55);
// safari and konq may use string "khtml, like gecko", so check for destinctive /
var domLib_isGecko = domLib_userAgent.indexOf('gecko/') != -1;
var domLib_isMacIE = (domLib_isIE && domLib_isMac);
var domLib_isIE55up = domLib_isIE5up && !domLib_isIE50 && !domLib_isMacIE;
var domLib_isIE6up = domLib_isIE55up && !domLib_isIE55;
// -- Browser Abilities --
var domLib_standardsMode = (document.compatMode && document.compatMode == 'CSS1Compat');
var domLib_useLibrary = (domLib_isOpera7up || domLib_isKHTML || domLib_isIE5up || domLib_isGecko || domLib_isMacIE || document.defaultView);
var domLib_hasBrokenTimeout = (domLib_isMacIE || (domLib_isKonq && domLib_userAgent.match(/konqueror\/3.([2-9])/) == null));
var domLib_canFade = (domLib_isGecko || domLib_isIE || domLib_isSafari || domLib_isOpera);
var domLib_canDrawOverSelect = (domLib_isMac || domLib_isOpera || domLib_isGecko);
var domLib_canDrawOverFlash = (domLib_isMac || domLib_isWin);
// -- Event Variables --
var domLib_eventTarget = domLib_isIE ? 'srcElement' : 'currentTarget';
var domLib_eventButton = domLib_isIE ? 'button' : 'which';
var domLib_eventTo = domLib_isIE ? 'toElement' : 'relatedTarget';
var domLib_stylePointer = domLib_isIE ? 'hand' : 'pointer';
// NOTE: a bug exists in Opera that prevents maxWidth from being set to 'none', so we make it huge
var domLib_styleNoMaxWidth = domLib_isOpera ? '10000px' : 'none';
var domLib_hidePosition = '-1000px';
var domLib_scrollbarWidth = 14;
var domLib_autoId = 1;
var domLib_zIndex = 100;
// -- Detection --
var domLib_collisionElements;
var domLib_collisionsCached = false;
var domLib_timeoutStateId = 0;
var domLib_timeoutStates = new Hash();
// }}}
// {{{ DOM enhancements
if (!document.ELEMENT_NODE)
{
document.ELEMENT_NODE = 1;
document.ATTRIBUTE_NODE = 2;
document.TEXT_NODE = 3;
document.DOCUMENT_NODE = 9;
document.DOCUMENT_FRAGMENT_NODE = 11;
}
Object.prototype.clone = function()
{
var copy = {};
for (var i in this)
{
var value = this[i];
try
{
if (value != null && typeof(value) == 'object' && value != window && !value.nodeType)
{
// for IE5 which doesn't inherit prototype
value.clone = Object.clone;
copy[i] = value.clone();
}
else
{
copy[i] = value;
}
}
catch(e)
{
copy[i] = value;
}
}
return copy;
}
// }}}
// {{{ class Hash()
function Hash()
{
this.length = 0;
this.numericLength = 0;
this.elementData = [];
for (var i = 0; i < arguments.length; i += 2)
{
if (typeof(arguments[i + 1]) != 'undefined')
{
this.elementData[arguments[i]] = arguments[i + 1];
this.length++;
if (arguments[i] == parseInt(arguments[i]))
{
this.numericLength++;
}
}
}
}
// using prototype as opposed to inner functions saves on memory
Hash.prototype.get = function(in_key)
{
return this.elementData[in_key];
}
Hash.prototype.set = function(in_key, in_value)
{
if (typeof(in_value) != 'undefined')
{
if (typeof(this.elementData[in_key]) == 'undefined')
{
this.length++;
if (in_key == parseInt(in_key))
{
this.numericLength++;
}
}
return this.elementData[in_key] = in_value;
}
return false;
}
Hash.prototype.remove = function(in_key)
{
var tmp_value;
if (typeof(this.elementData[in_key]) != 'undefined')
{
this.length--;
if (in_key == parseInt(in_key))
{
this.numericLength--;
}
tmp_value = this.elementData[in_key];
delete this.elementData[in_key];
}
return tmp_value;
}
Hash.prototype.size = function()
{
return this.length;
}
Hash.prototype.has = function(in_key)
{
return typeof(this.elementData[in_key]) != 'undefined';
}
Hash.prototype.find = function(in_obj)
{
for (var tmp_key in this.elementData)
{
if (this.elementData[tmp_key] == in_obj)
{
return tmp_key;
}
}
}
Hash.prototype.merge = function(in_hash)
{
for (var tmp_key in in_hash.elementData)
{
if (typeof(this.elementData[tmp_key]) == 'undefined')
{
this.length++;
if (tmp_key == parseInt(tmp_key))
{
this.numericLength++;
}
}
this.elementData[tmp_key] = in_hash.elementData[tmp_key];
}
}
Hash.prototype.compare = function(in_hash)
{
if (this.length != in_hash.length)
{
return false;
}
for (var tmp_key in this.elementData)
{
if (this.elementData[tmp_key] != in_hash.elementData[tmp_key])
{
return false;
}
}
return true;
}
// }}}
// {{{ domLib_isDescendantOf()
function domLib_isDescendantOf(in_object, in_ancestor)
{
if (in_object == in_ancestor)
{
return true;
}
while (in_object != document.documentElement)
{
try
{
if ((tmp_object = in_object.offsetParent) && tmp_object == in_ancestor)
{
return true;
}
else if ((tmp_object = in_object.parentNode) == in_ancestor)
{
return true;
}
else
{
in_object = tmp_object;
}
}
// in case we get some wierd error, just assume we haven't gone out yet
catch(e)
{
return true;
}
}
return false;
}
// }}}
// {{{ domLib_detectCollisions()
/**
* For any given target element, determine if elements on the page
* are colliding with it that do not obey the rules of z-index.
*/
function domLib_detectCollisions(in_object, in_recover, in_useCache)
{
// the reason for the cache is that if the root menu is built before
// the page is done loading, then it might not find all the elements.
// so really the only time you don't use cache is when building the
// menu as part of the page load
if (!domLib_collisionsCached)
{
var tags = [];
if (!domLib_canDrawOverFlash)
{
tags[tags.length] = 'object';
}
if (!domLib_canDrawOverSelect)
{
tags[tags.length] = 'select';
}
domLib_collisionElements = domLib_getElementsByTagNames(tags);
domLib_collisionsCached = in_useCache;
}
// if we don't have a tip, then unhide selects
if (in_recover)
{
for (var cnt = 0; cnt < domLib_collisionElements.length; cnt++)
{
var thisElement = domLib_collisionElements[cnt];
if (!thisElement.hideList)
{
thisElement.hideList = new Hash();
}
thisElement.hideList.remove(in_object.id);
if (!thisElement.hideList.length)
{
domLib_collisionElements[cnt].style.visibility = 'visible';
if (domLib_isKonq)
{
domLib_collisionElements[cnt].style.display = '';
}
}
}
return;
}
else if (domLib_collisionElements.length == 0)
{
return;
}
// okay, we have a tip, so hunt and destroy
var objectOffsets = domLib_getOffsets(in_object);
for (var cnt = 0; cnt < domLib_collisionElements.length; cnt++)
{
var thisElement = domLib_collisionElements[cnt];
// if collision element is in active element, move on
// WARNING: is this too costly?
if (domLib_isDescendantOf(thisElement, in_object))
{
continue;
}
// konqueror only has trouble with multirow selects
if (domLib_isKonq &&
thisElement.tagName == 'SELECT' &&
(thisElement.size <= 1 && !thisElement.multiple))
{
continue;
}
if (!thisElement.hideList)
{
thisElement.hideList = new Hash();
}
var selectOffsets = domLib_getOffsets(thisElement);
var center2centerDistance = Math.sqrt(Math.pow(selectOffsets.get('leftCenter') - objectOffsets.get('leftCenter'), 2) + Math.pow(selectOffsets.get('topCenter') - objectOffsets.get('topCenter'), 2));
var radiusSum = selectOffsets.get('radius') + objectOffsets.get('radius');
// the encompassing circles are overlapping, get in for a closer look
if (center2centerDistance < radiusSum)
{
// tip is left of select
if ((objectOffsets.get('leftCenter') <= selectOffsets.get('leftCenter') && objectOffsets.get('right') < selectOffsets.get('left')) ||
// tip is right of select
(objectOffsets.get('leftCenter') > selectOffsets.get('leftCenter') && objectOffsets.get('left') > selectOffsets.get('right')) ||
// tip is above select
(objectOffsets.get('topCenter') <= selectOffsets.get('topCenter') && objectOffsets.get('bottom') < selectOffsets.get('top')) ||
// tip is below select
(objectOffsets.get('topCenter') > selectOffsets.get('topCenter') && objectOffsets.get('top') > selectOffsets.get('bottom')))
{
thisElement.hideList.remove(in_object.id);
if (!thisElement.hideList.length)
{
thisElement.style.visibility = 'visible';
if (domLib_isKonq)
{
thisElement.style.display = '';
}
}
}
else
{
thisElement.hideList.set(in_object.id, true);
thisElement.style.visibility = 'hidden';
if (domLib_isKonq)
{
thisElement.style.display = 'none';
}
}
}
}
}
// }}}
// {{{ domLib_getOffsets()
function domLib_getOffsets(in_object)
{
var originalObject = in_object;
var originalWidth = in_object.offsetWidth;
var originalHeight = in_object.offsetHeight;
var offsetLeft = 0;
var offsetTop = 0;
while (in_object)
{
offsetLeft += in_object.offsetLeft;
offsetTop += in_object.offsetTop;
in_object = in_object.offsetParent;
}
// MacIE misreports the offsets (even with margin: 0 in body{}), still not perfect
if (domLib_isMacIE) {
offsetLeft += 10;
offsetTop += 10;
}
return new Hash(
'left', offsetLeft,
'top', offsetTop,
'right', offsetLeft + originalWidth,
'bottom', offsetTop + originalHeight,
'leftCenter', offsetLeft + originalWidth/2,
'topCenter', offsetTop + originalHeight/2,
'radius', Math.max(originalWidth, originalHeight)
);
}
// }}}
// {{{ domLib_setTimeout()
function domLib_setTimeout(in_function, in_timeout, in_args)
{
if (typeof(in_args) == 'undefined')
{
in_args = [];
}
if (in_timeout == -1)
{
// timeout event is disabled
return;
}
else if (in_timeout == 0)
{
in_function(in_args);
return 0;
}
// must make a copy of the arguments so that we release the reference
if (typeof(in_args.clone) != 'function')
{
in_args.clone = Object.clone;
}
var args = in_args.clone();
if (!domLib_hasBrokenTimeout)
{
return setTimeout(function() { in_function(args); }, in_timeout);
}
else
{
var id = domLib_timeoutStateId++;
var data = new Hash();
data.set('function', in_function);
data.set('args', args);
domLib_timeoutStates.set(id, data);
data.set('timeoutId', setTimeout('domLib_timeoutStates.get(' + id + ').get(\'function\')(domLib_timeoutStates.get(' + id + ').get(\'args\')); domLib_timeoutStates.remove(' + id + ');', in_timeout));
return id;
}
}
// }}}
// {{{ domLib_clearTimeout()
function domLib_clearTimeout(in_id)
{
if (!domLib_hasBrokenTimeout)
{
clearTimeout(in_id);
}
else
{
if (domLib_timeoutStates.has(in_id))
{
clearTimeout(domLib_timeoutStates.get(in_id).get('timeoutId'))
domLib_timeoutStates.remove(in_id);
}
}
}
// }}}
// {{{ domLib_getEventPosition()
function domLib_getEventPosition(in_eventObj)
{
var eventPosition = new Hash('x', 0, 'y', 0, 'scrollX', 0, 'scrollY', 0);
// IE varies depending on standard compliance mode
if (domLib_isIE)
{
var doc = (domLib_standardsMode ? document.documentElement : document.body);
// NOTE: events may fire before the body has been loaded
if (doc)
{
eventPosition.set('x', in_eventObj.clientX + doc.scrollLeft);
eventPosition.set('y', in_eventObj.clientY + doc.scrollTop);
eventPosition.set('scrollX', doc.scrollLeft);
eventPosition.set('scrollY', doc.scrollTop);
}
}
else
{
eventPosition.set('x', in_eventObj.pageX);
eventPosition.set('y', in_eventObj.pageY);
eventPosition.set('scrollX', in_eventObj.pageX - in_eventObj.clientX);
eventPosition.set('scrollY', in_eventObj.pageY - in_eventObj.clientY);
}
return eventPosition;
}
// }}}
// {{{ domLib_cancelBubble()
function domLib_cancelBubble(in_event)
{
var eventObj = in_event ? in_event : window.event;
eventObj.cancelBubble = true;
}
// }}}
// {{{ domLib_getIFrameReference()
function domLib_getIFrameReference(in_frame)
{
if (domLib_isGecko || domLib_isIE)
{
return in_frame.frameElement;
}
else
{
// we could either do it this way or require an id on the frame
// equivalent to the name
var name = in_frame.name;
if (!name || !in_frame.parent)
{
return;
}
var candidates = in_frame.parent.document.getElementsByTagName('iframe');
for (var i = 0; i < candidates.length; i++)
{
if (candidates[i].name == name)
{
return candidates[i];
}
}
}
}
// }}}
// {{{ domLib_getElementsByClass()
function domLib_getElementsByClass(in_class)
{
var elements = domLib_isIE5 ? document.all : document.getElementsByTagName('*');
var matches = [];
var cnt = 0;
for (var i = 0; i < elements.length; i++)
{
if ((" " + elements[i].className + " ").indexOf(" " + in_class + " ") != -1)
{
matches[cnt++] = elements[i];
}
}
return matches;
}
// }}}
// {{{
function domLib_getElementsByTagNames(in_list)
{
var elements = [];
for (var i = 0; i < in_list.length; i++)
{
var matches = document.getElementsByTagName(in_list[i]);
for (var j = 0; j < matches.length; j++)
{
elements[elements.length] = matches[j];
}
}
return elements;
}
// }}}
// {{{ makeTrue()
function makeTrue()
{
return true;
}
// }}}
// {{{ makeFalse()
function makeFalse()
{
return false;
}
// }}}
</script>
<!-- domMenu.js -->
<script language="javascript">
/** $Id: domMenu.js 1884 2005-05-24 05:08:38Z dallen $ */
// {{{ docs <-- this is a VIM (text editor) text fold
/**
* DOM Menu 0.3.4
*
* Summary: Allows developers to add dynamic drop down menus on webpages. The
* menu can either be horizontal or vertical, and can open in either
* direction. It has both edge detection and <select> tag detection
* (for browsers that cannot hide these form elements). The styles
* for the menu items are controlled almost entirely through CSS and
* the menus are created and destroyed using the DOM. Menu configuration
* is done using a custom Hash() class and is very portable from a PHP
* type array structure.
*
* Dependency: domLib.js version 0.67
*
* Maintainer (lead): Dan Allen <dan@mojavelinux.com>
* Maintainer: Jason Rust <jrust@rustyparts.com>
*
* License: LGPL - however, if you use this library, please post to my forum where you
* use it so that I get a chance to see my baby in action. If you are doing
* this for commercial work perhaps you could send me a few Starbucks Coffee
* gift dollars to encourage future developement (NOT REQUIRED). E-mail me
* for and address.
*
* Homepage: http://www.mojavelinux.com/forum/viewtopic.php
*
* Freshmeat Project: http://freshmeat.net/projects/dommenu/?topic_id=92
*
* Updated: $Id: domMenu.js 1884 2005-05-24 05:08:38Z dallen $
*
* Supported Browsers: Mozilla (Gecko), IE 5.0+, IE on Mac, Safari, Konqueror, Opera 7+
*
* Usage:
*
* Menu Options: Each option is followed by the value for that option. The options avaiable are:
* 'contents'
* 'rolloverContents',
* 'uri' (may be javascript)
* 'statusText'
* 'target'
* [0-9] an index to create a submenu item
*
* API:
*
* menuElementObject {
* ** properties **
* data
* contents
* uri
* target
* statusText
* parentElement
* subMenu
* childElements
* level
* index (index within this level)
* id
* className
* style
* cellSpacing (Konq only)
*
* ** events **
* mouseover/click -> domMenu_openEvent
* mouseout -> domMenu_closeEvent
* click -> domMenu_resolveLink
* }
*
* If there is a non-negative click open delay, then any uri of the element will be ignored
*
* The alternate contents for a hover element are treated by creating to <span> wrapper elements
* and then alternating the display of them. This avoids the need for innerHTML, which can
* do nasty things to the browsers. If <span> turns out to be a bad choice for tags, then a
* non-HTML element can be used instead.
*
* Dev Notes:
* - added cellSpacing = 0 for domLib_isMacIE (two places)
* - seems that Safari and Firefox share an offset problem of menu under parent (pmp example)
* - must use createTextNode() to add the "\n" that is required for Mac to
* render the appendChild element (two places); this might be the solution for
* the sub menus as well
* - Safari seems to have a problem with offsetTop if a descendent of body has a margin; solution
* is to use padding on the body
*/
// }}}
// {{{ settings (editable)
var domMenu_data = new Hash();
var domMenu_settings = new Hash();
domMenu_settings.set('global', new Hash(
'menuBarClass', 'domMenu_menuBar',
'menuElementClass', 'domMenu_menuElement',
'menuElementHoverClass', 'domMenu_menuElementHover',
'menuElementActiveClass', 'domMenu_menuElementHover',
'subMenuBarClass', 'domMenu_subMenuBar',
'subMenuElementClass', 'domMenu_subMenuElement',
'subMenuElementHoverClass', 'domMenu_subMenuElementHover',
'subMenuElementActiveClass', 'domMenu_subMenuElementHover',
'subMenuElementHeadingClass', 'domMenu_subMenuElementHeading',
'menuBarWidth', '100%',
'subMenuMinWidth', 'inherit',
'distributeSpace', true,
'axis', 'horizontal',
'verticalExpand', 'south',
'horizontalExpand', 'east',
'expandMenuArrowUrl', 'arrow.gif',
'subMenuWidthCorrection', 0,
'verticalSubMenuOffsetY', 0,
'verticalSubMenuOffsetX', 0,
'horizontalSubMenuOffsetX', 0,
'horizontalSubMenuOffsetY', 0,
'screenPadding', 0,
'openMouseoverMenuDelay', 300,
'openMousedownMenuDelay', -1,
'closeMouseoutMenuDelay', 800,
'closeClickMenuDelay', -1,
'openMouseoverSubMenuDelay', 300,
'openClickSubMenuDelay', -1,
'closeMouseoutSubMenuDelay', 300,
'closeClickSubMenuDelay', -1,
'baseZIndex', 100,
'baseUri', ''
));
// }}}
// {{{ global variables
/**
* The data for the menu is stored here, loaded from an external file
* @hash domMenu_data
*/
var domMenu_data;
var domMenu_selectElements;
var domMenu_scrollbarWidth = 14;
var domMenu_eventTo = domLib_isIE ? 'toElement' : 'relatedTarget';
var domMenu_eventFrom = domLib_isIE ? 'fromElement' : 'relatedTarget';
var domMenu_activeElement = new Hash();
/**
* Array of hashes listing the timouts currently running for opening/closing menus
* @array domMenu_timeouts
*/
var domMenu_timeouts = new Array();
domMenu_timeouts['open'] = new Hash();
domMenu_timeouts['close'] = new Hash();
/**
* Style to use for a link pointer, which is different between Gecko and IE
* @var domMenu_pointerStyle
*/
var domMenu_pointerStyle = domLib_isIE ? 'hand' : 'pointer';
// }}}
// {{{ domMenu_activate()
function domMenu_activate(in_containerId, in_disableWarning)
{
var container;
var data;
// make sure we can use the menu system
if (!domLib_useLibrary)
{
if (!in_disableWarning)
{
alert('domMenu: Browser not supported. Menu will be disabled.');
}
return;
}
// make sure that this is a valid menu,
// and that the menu actually has data
if (!(container = document.getElementById(in_containerId)) ||
!(data = domMenu_data.get(in_containerId)) ||
data.numericLength == 0) {
if (!in_disableWarning) {
alert('domMenu: Menu failed to load.');
}
return;
}
if (window.attachEvent) {
window.attachEvent('onunload', domMenu_fixCircleRefs);
}
// start with the global settings and merge in the local changes
if (!domMenu_settings.has(in_containerId)) {
domMenu_settings.set(in_containerId, new Hash());
}
var settings = domMenu_settings.get(in_containerId);
for (var i in domMenu_settings.get('global').elementData) {
if (!settings.has(i)) {
settings.set(i, domMenu_settings.get('global').get(i));
}
}
// populate the zero level element
container.data = new Hash(
'parentElement', false,
'numChildren', data.numericLength,
'childElements', new Hash(),
'level', 0,
'index', 1
);
// if we choose to distribute either height or width, determine ratio of each cell
var distributeRatio = Math.round(100/container.data.get('numChildren')) + '%';
// the first menu is the rootMenu, which is a child of the zero level element
var rootMenu = document.createElement('div');
rootMenu.id = in_containerId + '-0';
rootMenu.className = settings.get('menuBarClass');
container.data.set('subMenu', rootMenu);
var rootMenuTable = rootMenu.appendChild(document.createElement('table'));
if (domLib_isKonq || domLib_isMacIE) {
rootMenuTable.cellSpacing = 0;
}
rootMenuTable.style.border = 0;
rootMenuTable.style.borderCollapse = 'collapse';
rootMenuTable.style.width = settings.get('menuBarWidth');
var rootMenuTableBody = rootMenuTable.appendChild(document.createElement('tbody'));
var numSiblings = container.data.get('numChildren');
for (var index = 1; index <= numSiblings; index++) {
// create a row the first time if horizontal or each time if vertical
if (index == 1 || settings.get('axis') == 'vertical') {
var rootMenuTableRow = rootMenuTableBody.appendChild(document.createElement('tr'));
}
// create an instance of the root level menu element
var rootMenuTableCell = rootMenuTableRow.appendChild(document.createElement('td'));
rootMenuTableCell.style.padding = 0;
rootMenuTableCell.id = in_containerId + '-' + index;
// add element to list of parent children
container.data.get('childElements').set(rootMenuTableCell.id, rootMenuTableCell);
// assign the settings to the root level element
// NOTE: this is a problem if two menus are using the same data
rootMenuTableCell.data = data.get(index);
rootMenuTableCell.data.merge(new Hash(
'basename', in_containerId,
'parentElement', container,
'numChildren', rootMenuTableCell.data.numericLength,
'childElements', new Hash(),
'offsets', new Hash(),
'level', container.data.get('level') + 1,
'index', index
));
// assign the styles
rootMenuTableCell.style.cursor = 'default';
if (settings.get('axis') == 'horizontal') {
if (settings.get('distributeSpace')) {
rootMenuTableCell.style.width = distributeRatio;
}
}
// Needed for when the text wraps
rootMenuTableCell.style.verticalAlign = 'top';
var rootElement = rootMenuTableCell.appendChild(document.createElement('div'));
rootElement.className = settings.get('menuElementClass');
// fill in the menu element contents
var spanElement = rootElement.appendChild(document.createElement('span'));
// can't use createTextNode() because there might be img tags in the contents
spanElement.innerHTML = rootMenuTableCell.data.get('contents').replace(/\/\/\//, settings.get('baseUri'));
// add hover contents if needed
if (rootMenuTableCell.data.has('contentsHover')) {
spanElement = rootElement.appendChild(document.createElement('span'));
spanElement.style.display = 'none';
spanElement.innerHTML = rootMenuTableCell.data.get('contentsHover').replace(/\/\/\//, settings.get('baseUri'));
}
// MacIE has to have a newline at the end or else it barfs
// additionally, it MUST be added using createTextNode() or IE will crash!
if (domLib_isMacIE) {
rootMenuTableCell.appendChild(document.createTextNode("\n"));
}
// attach the events
rootMenuTableCell.onmouseover = domMenu_runMouseoverOpenEvent;
rootMenuTableCell.onmouseout = domMenu_runCloseEvent;
if (settings.get('openMousedownMenuDelay') >= 0 && rootMenuTableCell.data.get('numChildren')) {
rootMenuTableCell.onmousedown = domMenu_runMousedownOpenEvent;
// cancel mouseup so that it doesn't propogate to global mouseup event
rootMenuTableCell.onmouseup = domLib_cancelBubble;
if (domLib_isIE) {
rootMenuTableCell.ondblclick = domMenu_runMousedownOpenEvent;
}
}
else if (rootMenuTableCell.data.get('uri')) {
rootMenuTableCell.style.cursor = domMenu_pointerStyle;
rootMenuTableCell.onclick = domMenu_runResolveLink;
}
// prevent highlighting of text
if (domLib_isIE) {
rootMenuTableCell.onselectstart = makeFalse;
}
rootMenuTableCell.oncontextmenu = makeFalse;
}
// add the menu rootMenu to the zero level element
rootMenu = container.appendChild(rootMenu);
// even though most cases the top level menu does not go away, it could
// if this menu system is used by another process
domLib_detectCollisions(rootMenu, false, false);
}
// }}}
// {{{ domMenu_activateSubMenu()
function domMenu_activateSubMenu(in_parentElement)
{
// NOTE: submenus not supported in MacIE because of problems using
// appendChild on document.body
if (domLib_isMacIE) {
return;
}
// see if submenu already exists
if (in_parentElement.data.has('subMenu')) {
domMenu_toggleSubMenu(in_parentElement, 'visible');
return;
}
var settings = domMenu_settings.get(in_parentElement.data.get('basename'));
// build the submenu
var menu = document.createElement('div');
menu.id = in_parentElement.id + '-0';
menu.className = settings.get('subMenuBarClass');
menu.style.zIndex = settings.get('baseZIndex');
menu.style.position = 'absolute';
// position the menu in the upper left corner hidden so that we can work on it
menu.style.visibility = 'hidden';
menu.style.top = 0;
menu.style.left = 0;
in_parentElement.data.set('subMenu', menu);
var menuTable = menu.appendChild(document.createElement('table'));
// ** opera wants to make absolute tables width 100% **
if (domLib_isOpera) {
menuTable.style.width = '1px';
menuTable.style.whiteSpace = 'nowrap';
}
if (domLib_isKonq || domLib_isMacIE) {
menuTable.cellSpacing = 0;
}
menuTable.style.border = 0;
menuTable.style.borderCollapse = 'collapse';
var menuTableBody = menuTable.appendChild(document.createElement('tbody'));
var numSiblings = in_parentElement.data.get('numChildren');
for (var index = 1; index <= numSiblings; index++) {
var dataIndex = in_parentElement.data.get('level') == 1 && settings.get('verticalExpand') == 'north' && settings.get('axis') == 'horizontal' ? numSiblings + 1 - index : index;
var menuTableCell = menuTableBody.appendChild(document.createElement('tr')).appendChild(document.createElement('td'));
menuTableCell.style.padding = 0;
menuTableCell.id = in_parentElement.id + '-' + dataIndex;
// add element to list of parent children
in_parentElement.data.get('childElements').set(menuTableCell.id, menuTableCell);
// assign the settings to nth level element
menuTableCell.data = in_parentElement.data.get(dataIndex);
menuTableCell.data.merge(new Hash(
'basename', in_parentElement.data.get('basename'),
'parentElement', in_parentElement,
'numChildren', menuTableCell.data.numericLength,
'childElements', new Hash(),
'offsets', new Hash(),
'level', in_parentElement.data.get('level') + 1,
'index', index
));
// assign the styles
menuTableCell.style.cursor = 'default';
var element = menuTableCell.appendChild(document.createElement('div'));
var outerElement = element;
outerElement.className = settings.get('subMenuElementClass');
if (menuTableCell.data.get('numChildren')) {
element = outerElement.appendChild(document.createElement('div'));
// FIXME: this should depend on which way we are opening the menu!
element.style.backgroundImage = 'url(' + settings.get('expandMenuArrowUrl') + ')';
element.style.backgroundRepeat = 'no-repeat';
element.style.backgroundPosition = 'right center';
// add appropriate padding to fit the arrow
element.style.paddingRight = '12px';
}
// fill in the menu item contents
if (domLib_isMacIE) {
// we don't support images in sub-menu elements in MacIE because in order for
// the menu to work consistently the data has to be added with createTextNode()
element.appendChild(document.createTextNode(menuTableCell.data.get('contents')));
// MacIE has to have a newline and it has to be added with createTextNode!
menuTableCell.appendChild(document.createTextNode("\n"));
}
else {
element.innerHTML = menuTableCell.data.get('contents');
}
// attach the events
menuTableCell.onmouseover = domMenu_runMouseoverSubOpenEvent;
menuTableCell.onmouseout = domMenu_runCloseEvent;
if (settings.get('openClickSubMenuDelay') >= 0 && menuTableCell.data.get('numChildren')) {
menuTableCell.onmousedown = domMenu_runClickSubOpenEvent;
menuTableCell.onmouseup = domLib_cancelBubble;
if (domLib_isIE) {
menuTableCell.ondblclick = domMenu_runClickSubOpenEvent;
}
}
else if (menuTableCell.data.get('uri')) {
menuTableCell.style.cursor = domMenu_pointerStyle;
menuTableCell.onclick = domMenu_runResolveLink;
}
else if (!menuTableCell.data.get('numChildren')) {
outerElement.className += ' ' + settings.get('subMenuElementHeadingClass');
}
// prevent highlighting of text
if (domLib_isIE) {
menuTableCell.onselectstart = makeFalse;
}
menuTableCell.oncontextmenu = makeFalse;
}
menu = document.body.appendChild(menu);
domMenu_toggleSubMenu(in_parentElement, 'visible');
}
// }}}
// {{{ domMenu_changeActivePath()
/**
* Close the old active path up to the new active element
* and return the value of the new active element (or the same if unchanged)
* NOTE: If the new active element is not set (false), the top level is assumed
*
* @return mixed new active element or false if not set
*/
function domMenu_changeActivePath(in_newActiveElement, in_oldActiveElement, in_closeDelay)
{
// protect against crap
if (!in_oldActiveElement && !in_newActiveElement) {
return false;
}
// cancel open timeouts since we know we are opening something different now
for (var i in domMenu_timeouts['open'].elementData) {
domLib_clearTimeout(domMenu_timeouts['open'].get(i));
}
// grab some info about this menu system...will this ever be null?
var basename = in_oldActiveElement ? in_oldActiveElement.data.get('basename') : in_newActiveElement.data.get('basename');
var settings = domMenu_settings.get(basename);
// build the old active path and unhighlight previously selected element, if appropriate
var oldActivePath = new Hash();
if (in_oldActiveElement) {
var tmp_newActiveLevel = in_newActiveElement ? in_newActiveElement.data.get('level') : -1;
var tmp_oldActivePathElement = in_oldActiveElement;
do {
// NOTE: using set() causes IE to lag and leaves behind highlighted artifacts!
oldActivePath.elementData[tmp_oldActivePathElement.id] = tmp_oldActivePathElement;
// unhighlight if sibling of new element, even if it has open submenus
if (tmp_newActiveLevel >= 0 && tmp_oldActivePathElement.data.get('level') == tmp_newActiveLevel) {
domMenu_toggleHighlight(tmp_oldActivePathElement, false);
}
} while ((tmp_oldActivePathElement = tmp_oldActivePathElement.data.get('parentElement')) && tmp_oldActivePathElement.id != basename);
// unhighlight element immediately if no submenu (or submenu is closed)
if (!in_oldActiveElement.data.get('subMenu') || in_oldActiveElement.data.get('subMenu').style.visibility == 'hidden') {
domMenu_toggleHighlight(in_oldActiveElement, false);
}
}
// build the new path and...(explain me!)
var newActivePath = new Hash();
var intersectPoint;
if (in_newActiveElement) {
var actualActiveElement = in_newActiveElement;
window.status = in_newActiveElement.data.get('statusText') + ' ';
// in the event we have no old active element, just highlight new one and return
// without setting the new active element (handled later)
if (!in_oldActiveElement) {
domLib_clearTimeout(domMenu_timeouts['close'].get(in_newActiveElement.id));
domMenu_toggleHighlight(in_newActiveElement, true);
return false;
}
// if the new element is in the path of the old element, then pretend event is
// on the old active element
else if (oldActivePath.has(in_newActiveElement.id)) {
in_newActiveElement = in_oldActiveElement;
}
var tmp_newActivePathElement = in_newActiveElement;
do {
// if we have met up with the old active path, then record merge point
if (!intersectPoint && oldActivePath.has(tmp_newActivePathElement.id)) {
intersectPoint = tmp_newActivePathElement;
}
newActivePath.set(tmp_newActivePathElement.id, tmp_newActivePathElement);
domLib_clearTimeout(domMenu_timeouts['close'].get(tmp_newActivePathElement.id));
// FIXME: this is ugly!
if (tmp_newActivePathElement != in_oldActiveElement || actualActiveElement == in_oldActiveElement) {
domMenu_toggleHighlight(tmp_newActivePathElement, true);
}
} while ((tmp_newActivePathElement = tmp_newActivePathElement.data.get('parentElement')) && tmp_newActivePathElement.id != basename);
// if we move to the child of the old active element
if (in_newActiveElement.data.get('parentElement') == in_oldActiveElement) {
return in_newActiveElement;
}
// if the new active element is in the old active path
else if (in_newActiveElement == in_oldActiveElement) {
return in_newActiveElement;
}
// find the sibling element
var intersectSibling;
if (intersectPoint && oldActivePath.length > 0) {
for (var i in oldActivePath.elementData) {
if (oldActivePath.get(i).data.get('parentElement') == intersectPoint) {
intersectSibling = oldActivePath.get(i);
break;
}
}
}
var isRootLevel = in_newActiveElement.data.get('level') == 1 ? true : false;
var closeDelay = isRootLevel ? settings.get('closeMouseoutMenuDelay') : settings.get('closeMouseoutSubMenuDelay');
}
else {
var isRootLevel = false;
var closeDelay = settings.get('closeMouseoutMenuDelay');
window.status = window.defaultStatus;
}
// override the close delay with that passed in
if (typeof(in_closeDelay) != 'undefined') {
closeDelay = in_closeDelay;
}
// if there is an intersect sibling, then we need to work from there up to
// preserve the active path
if (intersectSibling) {
// only if this is not the root level to we allow the scheduled close
// events to persist...otherwise we close immediately
if (!isRootLevel) {
// toggle the sibling highlight (only one sibling highlighted at a time)
domMenu_toggleHighlight(intersectSibling, false);
}
// we are moving to another top level menu
// FIXME: clean this up
else {
// add lingering menus outside of old active path to active path
for (var i in domMenu_timeouts['close'].elementData) {
if (!oldActivePath.has(i)) {
var tmp_element = document.getElementById(i);
if (tmp_element.data.get('basename') == basename) {
oldActivePath.set(i, tmp_element);
}
}
}
}
}
// schedule the old active path to be closed
for (var i in oldActivePath.elementData) {
if (newActivePath.has(i)) {
continue;
}
// make sure we don't double schedule here
domLib_clearTimeout(domMenu_timeouts['close'].get(i));
if (isRootLevel) {
domMenu_toggleHighlight(oldActivePath.get(i), false);
domMenu_toggleSubMenu(oldActivePath.get(i), 'hidden');
}
else {
domMenu_timeouts['close'].set(i, domLib_setTimeout(domMenu_runCloseMenu, closeDelay, [oldActivePath.get(i), basename]));
}
}
return in_newActiveElement;
}
// }}}
// {{{ domMenu_deactivate()
function domMenu_deactivate(in_basename, in_delay)
{
if (!in_delay) {
in_delay = 0;
}
domMenu_changeActivePath(false, domMenu_activeElement.get(in_basename), in_delay);
}
// }}}
// {{{ domMenu_openEvent()
/**
* Handle the mouse event to open a menu
*
* When an event is received to open the menu, this function is
* called, handles reinitialization of the menu state and sets
* a timeout interval for opening the submenu (if one exists)
*/
function domMenu_openEvent(in_this, in_event, in_delayType)
{
if (domLib_isGecko) {
window.getSelection().removeAllRanges();
}
// setup the cross-browser event object and target
var eventObj = domLib_isIE ? event : in_event;
var currentTarget = domLib_isIE ? in_this : eventObj.currentTarget;
var basename = currentTarget.data.get('basename');
var settings = domMenu_settings.get(basename);
// if we are moving amoungst DOM children of the same element, just ignore event
if (eventObj.type != 'mousedown' && domMenu_getElement(eventObj[domMenu_eventFrom], basename) == currentTarget) {
return;
}
// if we click on an open menu, close it
if (eventObj.type == 'mousedown' && domMenu_activeElement.get(basename)) {
domMenu_changeActivePath(false, domMenu_activeElement.get(basename), currentTarget.data.get('level') == 1 ? settings.get('closeClickMenuDelay') : settings.get('closeClickSubMenuDelay'));
return;
}
// if this element has children, popup the child menu
if (currentTarget.data.get('numChildren')) {
// the top level menus have no delay when moving between them
// so activate submenu immediately
if (currentTarget.data.get('level') == 1 && domMenu_activeElement.get(basename)) {
// ** I place changeActivePath() call here so the hiding of selects does not flicker **
// THOUGHT: instead I could tell changeActivePath to clear select ownership but not
// toggle visibility....hmmm....
domMenu_activateSubMenu(currentTarget);
// clear the active path and initialize the new one
domMenu_activeElement.set(basename, domMenu_changeActivePath(currentTarget, domMenu_activeElement.get(basename)));
}
else {
// clear the active path and initialize the new one
domMenu_activeElement.set(basename, domMenu_changeActivePath(currentTarget, domMenu_activeElement.get(basename)));
domMenu_timeouts['open'].set(currentTarget.id, domLib_setTimeout(domMenu_runOpenMenu, settings.get(in_delayType), [currentTarget, basename]));
}
}
else {
// clear the active path and initialize the new one
domMenu_activeElement.set(basename, domMenu_changeActivePath(currentTarget, domMenu_activeElement.get(basename)));
}
}
// }}}
// {{{ domMenu_closeEvent()
/**
* Handle the mouse event to close a menu
*
* When an mouseout event is received to close the menu, this function is
* called, sets a timeout interval for closing the menu.
*/
function domMenu_closeEvent(in_this, in_event)
{
// setup the cross-browser event object and target
var eventObj = domLib_isIE ? event : in_event;
var currentTarget = domLib_isIE ? in_this : eventObj.currentTarget;
var basename = currentTarget.data.get('basename');
var relatedTarget = domMenu_getElement(eventObj[domMenu_eventTo], basename);
// if the related target is not a menu element then we left the menu system
// at this point (or cannot discern where we are in the menu)
if (domMenu_activeElement.get(basename)) {
if (!relatedTarget) {
domMenu_changeActivePath(false, domMenu_activeElement.get(basename));
}
}
// we are highlighting the top level, but menu is not yet 'active'
else {
if (currentTarget != relatedTarget) {
domLib_clearTimeout(domMenu_timeouts['open'].get(currentTarget.id));
domMenu_toggleHighlight(currentTarget, false);
}
}
}
// }}}
// {{{ domMenu_getElement()
function domMenu_getElement(in_object, in_basename)
{
while (in_object) {
try {
if (in_object.id && in_object.id.search(new RegExp('^' + in_basename + '(\\[[0-9]\\])*\\[[1-9]\\]$')) == 0) {
return in_object;
}
else {
in_object = in_object.parentNode;
}
}
catch(e) {
return false;
}
}
return false;
}
// }}}
// {{{ domMenu_correctEdgeBleed()
function domMenu_correctEdgeBleed(in_width, in_height, in_x, in_y, in_padding, in_axis)
{
if (domLib_isIE && !domLib_isIE5 && !domLib_isMacIE) {
var pageHeight = document.documentElement.clientHeight;
}
else if (!domLib_isKonq) {
var pageHeight = document.body.clientHeight;
}
else {
var pageHeight = window.innerHeight;
}
var pageYOffset = domLib_isIE ? document.body.scrollTop : window.pageYOffset;
var pageXOffset = domLib_isIE ? document.body.scrollLeft : window.pageXOffset;
if (in_axis == 'horizontal') {
var bleedRight = (in_x - pageXOffset) + in_width - (document.body.clientWidth - in_padding);
var bleedLeft = (in_x - pageXOffset) - in_padding;
// we are bleeding off the right, move menu to stay on page
if (bleedRight > 0) {
in_x -= bleedRight;
}
// we are bleeding to the left, move menu over to stay on page
// we don't want an 'else if' here, because if it doesn't fit we will bleed off the right
if (bleedLeft < 0) {
in_x += bleedLeft;
}
}
else {
var bleedTop = (in_y - pageYOffset) - in_padding;
var bleedBottom = (in_y - pageYOffset) + in_height - (pageHeight - in_padding);
// if we are bleeding off the bottom, move menu to stay on page
if (bleedBottom > 0) {
in_y -= bleedBottom;
}
// if we are bleeding off the top, move menu down
// we don't want an 'else if' here, because if we just can't fit it, bleed off the bottom
if (bleedTop < 0) {
in_y += bleedTop;
}
}
return new Array(in_x, in_y);
}
// }}}
// {{{ domMenu_toggleSubMenu()
function domMenu_toggleSubMenu(in_parentElement, in_style)
{
var subMenu = in_parentElement.data.get('subMenu');
if (subMenu && subMenu.style.visibility != in_style) {
var settings = domMenu_settings.get(in_parentElement.data.get('basename'));
var prefix = in_parentElement.data.get('level') == 1 ? 'menu' : 'subMenu';
var className = settings.get(prefix + 'ElementClass');
// :BUG: this is a problem if submenus click to open, then it won't
// have the right class when you click to close
if (in_style == 'visible') {
className += ' ' + settings.get(prefix + 'Element' + (in_style == 'visible' ? 'Active' : 'Hover') + 'Class');
}
in_parentElement.firstChild.className = className;
// position our submenu
if (in_style == 'visible') {
var tmp_offsets = domLib_getOffsets(in_parentElement);
if (in_parentElement.data.get('level') == 1) {
tmp_offsets.set('top', tmp_offsets.get('top') + settings.get('verticalSubMenuOffsetY'));
tmp_offsets.set('bottom', tmp_offsets.get('bottom') + settings.get('verticalSubMenuOffsetY'));
tmp_offsets.set('left', tmp_offsets.get('left') + settings.get('verticalSubMenuOffsetX'));
tmp_offsets.set('right', tmp_offsets.get('right') + settings.get('verticalSubMenuOffsetX'));
}
// reposition if there was a change in the parent position/size
if (!in_parentElement.data.get('offsets').compare(tmp_offsets)) {
in_parentElement.data.set('offsets', tmp_offsets);
if (settings.get('axis') == 'horizontal' && in_parentElement.data.get('level') == 1) {
var xCoor = tmp_offsets.get('left');
if (settings.get('verticalExpand') == 'north') {
var yCoor = tmp_offsets.get('top') - subMenu.offsetHeight - settings.get('verticalSubMenuOffsetY');
}
else {
var yCoor = tmp_offsets.get('bottom');
}
}
else {
var xCoor = tmp_offsets.get('right') + settings.get('horizontalSubMenuOffsetX');
var yCoor = tmp_offsets.get('top') + settings.get('horizontalSubMenuOffsetY');
if (domLib_isOpera || domLib_isSafari) {
var marginLeft = parseInt(document.defaultView.getComputedStyle(document.body, '').getPropertyValue('margin-left'));
var marginTop = parseInt(document.defaultView.getComputedStyle(document.body, '').getPropertyValue('margin-top'));
xCoor -= marginLeft;
yCoor -= marginTop;
}
}
var minWidth = settings.get('subMenuMinWidth');
var renderedWidth = subMenu.offsetWidth;
if (minWidth == 'inherit') {
minWidth = in_parentElement.offsetWidth + settings.get('subMenuWidthCorrection');
}
else if (minWidth == 'auto') {
minWidth = renderedWidth;
}
if (domLib_isKonq) {
// change with width of the first cell
subMenu.firstChild.firstChild.firstChild.firstChild.style.width = Math.max(minWidth, renderedWidth) + 'px';
}
else {
// change the width of the table
subMenu.firstChild.style.width = Math.max(minWidth, renderedWidth) + 'px';
}
var coordinates = domMenu_correctEdgeBleed(subMenu.offsetWidth, subMenu.offsetHeight, xCoor, yCoor, settings.get('screenPadding'), settings.get('axis'));
subMenu.style.left = coordinates[0] + 'px';
subMenu.style.top = coordinates[1] + 'px';
// ** if we inherit, it is necessary to check the parent element width again **
if (settings.get('axis') == 'horizontal' && settings.get('subMenuMinWidth') == 'inherit') {
subMenu.firstChild.style.width = Math.max(in_parentElement.offsetWidth + settings.get('subMenuWidthCorrection'), renderedWidth) + 'px';
}
}
}
// force konqueror to change the styles
if (domLib_isKonq) {
in_parentElement.firstChild.style.display = 'none';
in_parentElement.firstChild.style.display = '';
}
subMenu.style.visibility = in_style;
domLib_detectCollisions(subMenu, (in_style == 'hidden'), true);
}
}
// }}}
// {{{ domMenu_toggleHighlight()
function domMenu_toggleHighlight(in_element, in_status)
{
// if this is a heading, don't change the style
if (!in_element.data.get('numChildren') && !in_element.data.get('uri')) {
return;
}
var settings = domMenu_settings.get(in_element.data.get('basename'));
var prefix = in_element.data.get('level') == 1 ? 'menu' : 'subMenu';
var className = settings.get(prefix + 'ElementClass');
var highlightElement = in_element.firstChild;
var pseudoClass;
if (in_status) {
if (in_element.data.has('subMenu') && in_element.data.get('subMenu').style.visibility == 'visible') {
pseudoClass = 'Active';
}
else if (in_element.data.get('numChildren') || in_element.data.get('uri')) {
pseudoClass = 'Hover';
}
}
if (pseudoClass) {
className += ' ' + settings.get(prefix + 'Element' + pseudoClass + 'Class');
// if we are changing to hover, change the alt contents (only change if needs it)
if (highlightElement.childNodes.length == 2) {
//alert(highlightElement.lastChild);
}
if (highlightElement.childNodes.length == 2 && highlightElement.lastChild.style.display == 'none') {
highlightElement.firstChild.style.display = 'none';
highlightElement.lastChild.style.display = '';
}
}
else {
// if we are changing to non-hover, change the alt contents (only change if needs it)
if (highlightElement.childNodes.length == 2 && highlightElement.firstChild.style.display == 'none') {
highlightElement.lastChild.style.display = 'none';
highlightElement.firstChild.style.display = '';
}
}
highlightElement.className = className;
// force konqueror to change the styles
if (domLib_isKonq) {
highlightElement.style.display = 'none';
highlightElement.style.display = '';
}
}
// }}}
// {{{ domMenu_resolveLink()
function domMenu_resolveLink(in_this, in_event)
{
var eventObj = domLib_isIE ? event : in_event;
var currentTarget = domLib_isIE ? in_this : eventObj.currentTarget;
var basename = currentTarget.data.get('basename');
// close the menu system immediately when we resolve the uri
domMenu_changeActivePath(false, domMenu_activeElement.get(basename), 0);
var uri = currentTarget.data.get('uri');
if (uri) {
window.status = 'Resolving Link...';
uri = uri.replace(/\/\/\//, domMenu_settings.get(basename).get('baseUri'));
// open in current window
if (!currentTarget.data.get('target') || currentTarget.data.get('target') == '_self') {
window.location = uri;
}
// open in new window
else {
window.open(uri, currentTarget.data.get('target'));
}
}
}
// }}}
// {{{ domMenu_fixCircleRefs()
// We try and get rid of all circular references by using the domMenu_runXXX()
// methods, but some are still left, so we run this function for IE
// @see http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=bcslfd%24ahl%241%248300dec7%40news.demon.co.uk
function domMenu_fixCircleRefs()
{
var clearElementProps = ['data', 'onmouseover', 'onmouseout', 'onmousedown',
'onmouseup', 'ondblclick', 'onclick', 'onselectstart', 'oncontextmenu'];
var el;
for (var d = document.all.length; d--;) {
el = document.all[d];
for (var c = clearElementProps.length; c--;) {
el[clearElementProps[c]] = null;
}
}
}
// }}}
// {{{ domMenu_runXXX()
// All of these domMenu_runXXX() methods are used by the event handling sections to
// avoid the circular memory leaks caused by inner functions
function domMenu_runMouseoverOpenEvent(in_event) { domMenu_openEvent(this, in_event, 'openMouseoverMenuDelay'); }
function domMenu_runMousedownOpenEvent(in_event) { domMenu_openEvent(this, in_event, 'openMousedownMenuDelay'); }
function domMenu_runMouseoverSubOpenEvent(in_event) { domMenu_openEvent(this, in_event, 'openMouseoverSubMenuDelay'); }
function domMenu_runClickSubOpenEvent(in_event) { domMenu_openEvent(this, in_event, 'openClickSubMenuDelay'); }
function domMenu_runCloseEvent(in_event) { domMenu_closeEvent(this, in_event); }
function domMenu_runResolveLink(in_event) { domMenu_resolveLink(this, in_event); };
function domMenu_runCloseMenu(argv)
{
domMenu_toggleHighlight(argv[0], false);
domMenu_toggleSubMenu(argv[0], 'hidden');
// if this is the top level, then the menu is being deactivated
if (argv[0].data.get('level') == 1) {
domMenu_activeElement.set(argv[1], false);
}
}
function domMenu_runOpenMenu(argv)
{
if (!domMenu_activeElement.get(argv[1])) {
domMenu_activeElement.set(argv[1], argv[0]);
}
domMenu_activateSubMenu(argv[0]);
}
// }}}
</script>
<script language="javascript">
// {{{ domMenu_main: data
domMenu_data.set('domMenu_main', new Hash(
1, new Hash(
'contents', 'Home',
'contentsHover', 'Home',
'uri', 'http://mojavelinux.com',
'target', '_self',
'statusText', 'Mojavelinux.com homepages',
1, new Hash(
'contents', 'News',
'uri', 'http://mojavelinux.com',
'target', '_blank',
'statusText', 'Latest mojavelinux.com news'
),
2, new Hash(
'contents', 'Cooker',
'uri', 'http://www.java2java.com',
'statusText', 'Released open source programs',
1, new Hash(
'contents', 'Demos',
'uri', 'http://www.java2java.com',
'statusText', 'Program demos'
),
2, new Hash(
'contents', 'Beta',
'uri', 'http://www.java2java.com',
'statusText', 'Program betas'
)
),
3, new Hash(
'contents', 'Pictures',
'uri', 'http://www.java2java.com',
'statusText', 'Pictureview picture catalog'
),
4, new Hash(
'contents', 'Tutorials',
'uri', 'http://www.java2java.com',
'statusText', 'Various tutorials I have put together'
),
5, new Hash(
'contents', 'Stats',
'uri', 'http://www.java2java.com',
'statusText', 'website statistics')),
2, new Hash(
'contents', 'Forums',
'contentsHover', 'Forums',
'uri', '',
'statusText', 'Mojave forums',
1, new Hash(
'contents', 'Cooker',
'uri', 'http://www.java2java.com',
'statusText', 'Released programs'
),
2, new Hash(
'contents', 'phpBB Mods',
'uri', 'http://www.java2java.com',
'statusText', 'phpBB Forum Modifications'
),
3, new Hash(
'contents', 'MyCalendar Mod',
'uri', 'http://www.java2java.com',
'statusText', 'MyCalendar add-on for phpBB')),
3, new Hash(
'contents', 'Demos',
'contentsHover', 'Demos',
'uri', '',
'statusText', 'Demo Sites',
1, new Hash(
'contents', 'DOM Menu',
'uri', 'http://www.java2java.com',
'statusText', 'Dynamic hierarchial menu using the DOM'
),
2, new Hash(
'contents', 'DOM Tooltip',
'uri', 'http://www.java2java.com',
'statusText', 'Dynamic tooltips using the DOM'
),
3, new Hash(
'contents', 'Popup Calendar',
'uri', 'http://www.java2java.com',
'statusText', 'Date selector popup calendar')),
4, new Hash(
'contents', 'Tutorials',
'contentsHover', 'Tutorials',
'uri', '',
'statusText', 'Various tutorials',
1, new Hash(
'contents', 'Hash Tables',
'uri', 'http://www.java2java.com',
'statusText', 'Creating hash tables in javascript'
),
2, new Hash(
'contents', 'Understanding Events',
'uri', 'http://www.java2java.com',
'statusText', 'Understanding Events in javascript'
),
3, new Hash(
'contents', 'Using setTimeout',
'uri', 'http://www.java2java.com',
'statusText', 'Using the setTimeout method in javascript'
),
4, new Hash(
'contents', 'Tips & Tricks',
'uri', 'http://www.java2java.com',
'statusText', 'Random tips and tricks')),
5, new Hash(
'contents', 'Pictures',
'contentsHover', 'Pictures',
'uri', 'http://www.java2java.com',
'statusText', 'Picture sites',
1, new Hash(
'contents', 'Pictureview',
'uri', 'http://www.java2java.com',
'statusText', 'Mojavelinux.com picture catalog'
),
2, new Hash(
'contents', 'Chintoons',
'uri', 'http://www.java2java.com',
'statusText', 'Chinchilla cartoons')),
6, new Hash(
'contents', 'Stats',
'contentsHover', 'Stats',
'uri', 'http://www.java2java.com',
'statusText', 'Mojavelinux.com site statistics',
1, new Hash(
'contents', 'Overall Site Statistics for mojavelinux.com',
'uri', 'http://www.java2java.com',
'statusText', 'Overall statistics for mojavelinux.com'))
));
// }}}
// {{{ domMenu_main: settings
domMenu_settings.set('domMenu_main', new Hash(
'subMenuWidthCorrection', -1,
'verticalSubMenuOffsetX', -1,
'verticalSubMenuOffsetY', -1,
'horizontalSubMenuOffsetX', 1,
'openMouseoverMenuDelay', 300,
'closeMouseoutMenuDelay', 500,
'expandMenuArrowUrl', 'arrow.gif'
));
// }}}
// {{{ domMenu_keramik: data
domMenu_data.set('domMenu_keramik', new Hash(
1, new Hash(
'contents', 'Home',
'uri', '',
'statusText', 'Home',
1, new Hash(
'contents', 'Main Page',
'uri', 'http://www.java2java.com',
'statusText', 'Mojave Page'
),
2, new Hash(
'contents', 'Contact mojavelinux.com',
'uri', '',
'statusText', 'Contact mojavelinux.com',
1, new Hash(
'contents', 'Dan',
'uri', 'http://www.java2java.com',
'statusText', 'Dan'
),
2, new Hash(
'contents', 'Sarah',
'uri', 'http://www.java2java.com',
'statusText', 'Sarah'
)
),
3, new Hash(
'contents', 'Terms of Use',
'uri', 'http://www.java2java.com',
'statusText', 'Terms of Use'
),
4, new Hash(
'contents', 'Search this site',
'uri', 'http://www.java2java.com',
'statusText', 'Search this site'
),
5, new Hash(
'contents', 'Customize',
'uri', '',
'statusText', 'Customize',
1, new Hash(
'contents', 'Style Schemas',
'uri', '',
'statusText', 'Style Schemas'
),
2, new Hash(
'contents', 'Blue',
'uri', 'http://java2s.com',
'statusText', 'Blue'
),
3, new Hash(
'contents', 'Green',
'uri', 'http://java2s.com',
'statusText', 'Green',
1, new Hash(
'contents', 'Green',
'uri', 'http://java2s.com',
'statusText', 'Green'
)
)
)
),
2, new Hash(
'contents', 'CSS',
'uri', '',
'statusText', 'CSS',
1, new Hash(
'contents', 'Tutorials',
'uri', '',
'statusText', 'Tutorial Links'
),
2, new Hash(
'contents', 'Using Stylesheets',
'uri', 'http://www.java2java.com',
'statusText', ''
),
3, new Hash(
'contents', 'CSS Positioning',
'uri', 'http://www.java2java.com',
'statusText', 'Learning how to position elements with CSS'
)
),
3, new Hash(
'contents', 'JavaScript',
'uri', '',
'statusText', 'JavaScript Section',
1, new Hash(
'contents', 'Tutorials',
'uri', '',
'statusText', 'JavaScript Tutorials'
),
2, new Hash(
'contents', 'Custom Hash() Class',
'uri', 'http://www.java2java.com',
'statusText', 'Making your own associative arrays in javascript'
)
),
4, new Hash(
'contents', 'DHTML',
'uri', '',
'statusText', 'Dynamic HTML',
1, new Hash(
'contents', 'Tutorials',
'uri', '',
'statusText', 'Dynamic HTML Tutorials'
),
2, new Hash(
'contents', 'DOM Tooltip',
'uri', 'http://www.java2java.com',
'statusText', 'Making custom tooltips using the DOM'
)
),
5, new Hash(
'contents', 'PHP',
'uri', '',
'statusText', 'PHP Section',
1, new Hash(
'contents', 'Tutorials',
'uri', '',
'statusText', 'PHP Tutorials'
),
2, new Hash(
'contents', 'Handling actions',
'uri', 'http://www.java2java.com',
'statusText', 'Form actions in PHP'
)
)
));
// }}}
// {{{ domMenu_keramik: settings
domMenu_settings.set('domMenu_keramik', new Hash(
'menuBarWidth', '0%',
'menuBarClass', 'keramik_menuBar',
'menuElementClass', 'keramik_menuElement',
'menuElementHoverClass', 'keramik_menuElementHover',
'menuElementActiveClass', 'keramik_menuElementHover',
'subMenuBarClass', 'keramik_subMenuBar',
'subMenuElementClass', 'keramik_subMenuElement',
'subMenuElementHoverClass', 'keramik_subMenuElementHover',
'subMenuElementActiveClass', 'keramik_subMenuElementHover',
'subMenuMinWidth', 'auto',
'horizontalSubMenuOffsetX', -5,
'horizontalSubMenuOffsetY', 3,
'distributeSpace', false,
'openMouseoverMenuDelay', -1,
'openMousedownMenuDelay', 0,
'closeClickMenuDelay', 0,
'closeMouseoutMenuDelay', -1,
'expandMenuArrowUrl', 'arrow.gif'
));
// }}}
// {{{ domMenu_BJ: data
domMenu_data.set('domMenu_BJ', domMenu_data.elementData['domMenu_keramik']);
// }}}
// {{{ domMenu_BJ: settings
domMenu_settings.set('domMenu_BJ', new Hash(
'menuBarWidth', '0%',
'menuBarClass', 'BJ_menuBar',
'menuElementClass', 'BJ_menuElement',
'menuElementHoverClass', 'BJ_menuElementHover',
'menuElementActiveClass', 'BJ_menuElementActive',
'subMenuBarClass', 'BJ_subMenuBar',
'subMenuElementClass', 'BJ_subMenuElement',
'subMenuElementHoverClass', 'BJ_subMenuElementHover',
'subMenuElementActiveClass', 'BJ_subMenuElementHover',
'subMenuMinWidth', 'auto',
'distributeSpace', false,
'openMouseoverMenuDelay', -1,
'openMousedownMenuDelay', 0,
'closeClickMenuDelay', 0,
'closeMouseoutMenuDelay', -1,
'expandMenuArrowUrl', 'arrow.gif'
));
// }}}
// {{{ domMenu_vertical: data
domMenu_data.set('domMenu_vertical', new Hash(
1, new Hash(
'contents', 'Home',
'uri', 'http://mojavelinux.com',
'target', '_self',
'statusText', 'Mojavelinux.com homepages',
1, new Hash(
'contents', 'News',
'uri', 'http://mojavelinux.com',
'target', '_blank',
'statusText', 'Latest mojavelinux.com news'
),
2, new Hash(
'contents', 'Cooker',
'uri', 'http://www.java2java.com',
'statusText', 'Released open source programs'
),
3, new Hash(
'contents', 'Demos',
'uri', 'http://www.java2java.com',
'statusText', 'Program demos'
),
4, new Hash(
'contents', 'Pictures',
'uri', 'http://www.java2java.com',
'statusText', 'Pictureview picture catalog'
),
5, new Hash(
'contents', 'Tutorials',
'uri', 'http://www.java2java.com',
'statusText', 'Various tutorials I have put together'
),
6, new Hash(
'contents', 'Stats',
'uri', 'http://www.java2java.com',
'statusText', 'website statistics'
)
),
2, new Hash(
'contents', 'Forums',
'uri', '',
'statusText', 'Mojave forums',
1, new Hash(
'contents', 'Cooker',
'uri', 'http://www.java2java.com',
'statusText', 'Released programs'
),
2, new Hash(
'contents', 'phpBB Mods',
'uri', 'http://www.java2java.com',
'statusText', 'phpBB Forum Modifications'
),
3, new Hash(
'contents', 'MyCalendar Mod',
'uri', 'http://www.java2java.com',
'statusText', 'MyCalendar add-on for phpBB'
)
),
3, new Hash(
'contents', 'Demos',
'uri', '',
'statusText', 'Demo Sites',
1, new Hash(
'contents', 'DOM Menu',
'uri', 'http://www.java2java.com',
'statusText', 'Dynamic hierarchial menu using the DOM'
),
2, new Hash(
'contents', 'DOM Tooltip',
'uri', 'http://www.java2java.com',
'statusText', 'Dynamic tooltips using the DOM'
),
3, new Hash(
'contents', 'Popup Calendar',
'uri', 'http://www.java2java.com',
'statusText', 'Date selector popup calendar'
)
),
4, new Hash(
'contents', 'Tutorials',
'uri', '',
'statusText', 'Various tutorials',
1, new Hash(
'contents', 'Hash Tables',
'uri', 'http://www.java2java.com',
'statusText', 'Creating hash tables in javascript'
),
2, new Hash(
'contents', 'Understanding Events',
'uri', 'http://www.java2java.com',
'statusText', 'Understanding Events in javascript'
),
3, new Hash(
'contents', 'Using setTimeout',
'uri', 'http://www.java2java.com',
'statusText', 'Using the setTimeout method in javascript'
),
4, new Hash(
'contents', 'Tips & Tricks',
'uri', 'http://www.java2java.com',
'statusText', 'Random tips and tricks'
)
),
5, new Hash(
'contents', 'Pictures',
'uri', 'http://',
'statusText', 'Picture sites',
1, new Hash(
'contents', 'Pictureview',
'uri', 'http://',
'statusText', 'status text'
),
2, new Hash(
'contents', 'Chintoons',
'uri', 'http://',
'statusText', 'status text'
)
),
6, new Hash(
'contents', 'Stats',
'uri', 'http://',
'statusText', 'status text',
1, new Hash(
'contents', 'Overall Site Statistics',
'uri', 'http://',
'statusText', 'Overall statistics for'
)
)
));
// }}}
// {{{ domMenu_vertical: settings
domMenu_settings.set('domMenu_vertical', new Hash(
'axis', 'vertical',
'subMenuWidthCorrection', -1,
'verticalSubMenuOffsetX', -1,
'verticalSubMenuOffsetY', -1,
'horizontalSubMenuOffsetX', 0,
'horizontalSubMenuOffsetY', 0,
'expandMenuArrowUrl', 'arrow.gif'
));
// }}}
</script>
</head>
<body>
<div class="title">Example 1: Horizontal Menu</div>
<div class="main">
<div class="p">
<div id="domMenu_main"></div>
<script language="javascript">
domMenu_activate('domMenu_main');
</script>
</div>
</div>
</body>
</html>
|