/*----------------------------------------------------------------------------\
| DHTML Menu 4.28 |
|-----------------------------------------------------------------------------|
| Created by Erik Arvidsson |
| (http://webfx.eae.net/contact.html#erik) |
| For WebFX (http://webfx.eae.net/) |
|-----------------------------------------------------------------------------|
| A menu system for Internet Explorer 5.5+ Win32 that allows menus to extend |
| outside the browser window limits. |
|-----------------------------------------------------------------------------|
| Copyright (c) 1999 - 2003 Erik Arvidsson |
|-----------------------------------------------------------------------------|
| This software is provided "as is", without warranty of any kind, express or |
| implied, including but not limited to the warranties of merchantability, |
| fitness for a particular purpose and noninfringement. In no event shall the |
| authors or copyright holders be liable for any claim, damages or other |
| liability, whether in an action of contract, tort or otherwise, arising |
| from, out of or in connection with the software or the use or other |
| dealings in the software. |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| This software is available under the three different licenses mentioned |
| below. To use this software you must chose, and qualify, for one of those. |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| The WebFX Non-Commercial License http://webfx.eae.net/license.html |
| Permits anyone the right to use the software in a non-commercial context |
| free of charge. |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| The WebFX Commercial license http://webfx.eae.net/commercial.html |
| Permits the license holder the right to use the software in a commercial |
| context. Such license must be specifically obtained, however it's valid for |
| any number of implementations of the licensed software. |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| GPL - The GNU General Public License http://www.gnu.org/licenses/gpl.txt |
| Permits anyone the right to use and modify the software without limitations |
| as long as proper credits are given and the original and modified source |
| code are included. Requires that the final product, software derivate from |
| the original source or any software utilizing a GPL component, such as |
| this, is also licensed under the GPL license. |
|-----------------------------------------------------------------------------|
| 2002-05-28 | First version |
| 2002-06-07 | Updated default cssFile value to "skins/winclassic.css" |
| | instead of "winclassic.css" |
| 2002-06-10 | (4.1) Lots of changes. Rewrote measuring and positioning |
| | routines to prevent screen flicker. As well as general code |
| | optimization. |
| 2002-07-03 | getInsetRight and getInsetBottom broke in the last update. |
| | Radio and Check box did not check disabled state correctly. |
| 2002-07-25 | Created a work around for a weird bug that did not show first |
| | menu. Disabled browser keyboard shortcuts when menus are open. |
| | Added workaround for buggy dual monitor drivers. |
| 2002-09-05 | Fixed cases where the caching of the CSS failed and caused the |
| | cached menu size to be incorrect. |
| 2002-09-05 | Insets were ignored for vertical menus. |
| 2002-09-06 | Some properties have been moved to the prototype to make |
| | customizing easier. |
| 2002-09-24 | Minor changes to prevent size errors. |
| 2002-10-22 | Added second argument to Menu add. |
| | Added support for Menu cssText. |
| 2002-10-29 | (4.2) Lots of work to work around IE memory bugs. |
| 2002-11-03 | Typo in MenuBar goToNextMenuItem |
| 2002-11-23 | The height and width were not correctly limited in show. |
| 2002-12-04 | Changed to use onunload instead of onbeforeunload. |
| | Onbeforeunload was causing troubles with certain links. |
| 2003-03-07 | Fixed bug in MenuButton toHtml and added MenuBar invalidate |
| | also created a clone extension (menu4.clone.js) |
| 2003-04-01 | added document arguments to MenuBar create and write. |
| | Better mnemonic handling when HTML is used |
| | onclose, onshow and onbeforeshow |
| 2003-09-12 | Updated mnemonic code and fixed an itemIndex bug when adding |
| | items. |
| 2003-09-23 | The scrollbutton.js still used onbeforeunload |
| 2003-10-15 | Add support for keyboardAccelKey2 (defaults to F10). Also |
| | fixed so that Esc on last menu correctly goes to the menu bar. |
| 2003-11-24 | Changed the MenuButton constructor to not fail if sub menu is |
| | left out. This allows you to set the sub menu later. A sub |
| | menu is still needed! |
|-----------------------------------------------------------------------------|
| Dependencies: poslib.js Used to find positions of elements |
| scrollbutton.js Used for the buttnos that allows the menu |
| to be scrollable |
|-----------------------------------------------------------------------------|
| Created 2002-05-28 | All changes are in the log above. | Updated 2003-11-24 |
\----------------------------------------------------------------------------*/
////////////////////////////////////////////////////////////////////////////////////
// menuCache
//
var menuCache = {
_count: 0,
_idPrefix: "-menu-cache-",
getId: function () {
return this._idPrefix + this._count++;
},
remove: function ( o ) {
delete this[ o.id ];
}
};
////////////////////////////////////////////////////////////////////////////////////
// Menu
//
function Menu() {
this.items = [];
this.parentMenu = null;
this.parentMenuItem = null;
this.popup = null;
this.shownSubMenu = null;
this._aboutToShowSubMenu = false;
this.selectedIndex = -1;
this._drawn = false;
this._scrollingMode = false;
this._showTimer = null;
this._closeTimer = null;
this._onCloseInterval = null;
this._closed = true;
this._closedAt = 0;
this._cachedSizes = {};
this._measureInvalid = true;
this.id = menuCache.getId();
menuCache[ this.id ] = this;
}
Menu.prototype.cssFile = "skins/winclassic.css";
Menu.prototype.cssText = null;
Menu.prototype.mouseHoverDisabled = true;
Menu.prototype.showTimeout = 250;
Menu.prototype.closeTimeout = 250;
Menu.keyboardAccelKey = 27; // the keyCode for the key tp activate
Menu.keyboardAccelKey2 = 121; // the menubar
Menu.keyboardAccelProperty = "ctrlKey"; // when this property is true default
// actions will be canceled on a menu
// Use -1 to disable keyboard invoke of the menubar
// Use "" to allow all normal keyboard commands inside the menus
Menu.prototype.add = function ( mi, beforeMi ) {
if ( beforeMi != null ) {
var items = this.items;
var l = items.length;
var i = 0;
for ( ; i < l; i++ ) {
if ( items[i] == beforeMi )
break;
}
this.items = items.slice( 0, i ).concat( mi ).concat( items.slice( i, l ) );
// update itemIndex
for (var j = i; j < l + 1; j++)
this.items[j].itemIndex = j;
}
else {
this.items.push( mi );
mi.itemIndex = this.items.length - 1;
}
mi.parentMenu = this;
if ( mi.subMenu ) {
mi.subMenu.parentMenu = this;
mi.subMenu.parentMenuItem = mi;
}
return mi;
};
Menu.prototype.remove = function ( mi ) {
var res = [];
var items = this.items;
var l = items.length;
for (var i = 0; i < l; i++) {
if ( items[i] != mi ) {
res.push( items[i] );
items[i].itemIndex = res.length - 1;
}
}
this.items = res;
mi.parentMenu = null;
return mi;
};
Menu.prototype.toHtml = function () {
var items = this.items;
var l = items.length
var itemsHtml = new Array( l );
for (var i = 0; i < l; i++)
itemsHtml[i] = items[i].toHtml();
return "
" +
(this.cssText == null ?
"" :
"") +
"" +
"
" +
"
" +
"
" +
"" +
"5" +
"" + "
" +
"
" +
"
" +
itemsHtml.join( "" ) +
"
" +
"
" +
"
" +
"
" +
"" +
"6" +
"" +
"
" +
"
" +
"";
};
Menu.prototype.createPopup = function () {
var w;
var pm = this.parentMenu;
if ( pm == null )
w = window;
else
w = pm.getDocument().parentWindow;
this.popup = w.createPopup();
};
Menu.prototype.getMeasureDocument = function () {
if ( this.isShown() && this._drawn )
return this.getDocument();
var mf = Menu._measureFrame;
if ( mf == null ) {
// should be top document
mf = Menu._measureFrame = document.createElement("IFRAME");
var mfs = mf.style;
mfs.position = "absolute";
mfs.visibility = "hidden";
mfs.left = "-100px";
mfs.top = "-100px";
mfs.width = "10px";
mfs.height = "10px";
mf.frameBorder = 0;
document.body.appendChild( mf );
}
var d = mf.contentWindow.document
if ( Menu._measureMenu == this && !this._measureInvalid )
return d;
d.open( "text/html", "replace" );
d.write( this.toHtml() );
d.close();
Menu._measureMenu = this;
this._measureInvalid = false;
return d;
};
Menu.prototype.getDocument = function () {
if ( this.popup )
return this.popup.document;
else
return null;
};
Menu.prototype.getPopup = function () {
if ( this.popup == null )
this.createPopup();
return this.popup;
};
Menu.prototype.invalidate = function () {
if ( this._drawn ) {
// do some memory cleanup
if ( this._scrollUpButton )
this._scrollUpButton.destroy();
if ( this._scrollDownButton )
this._scrollDownButton.destroy();
var items = this.items;
var l = items.length;
var mi;
for ( var i = 0; i < l; i++ ) {
mi = items[i];
mi._htmlElement_menuItem = null;
mi._htmlElement = null;
}
this.detachEvents();
}
this._drawn = false;
this.resetSizeCache();
this._measureInvalid = true;
};
Menu.prototype.redrawMenu = function () {
this.invalidate();
this.drawMenu();
};
Menu.prototype.drawMenu = function () {
if ( this._drawn ) return;
this.getPopup();
var d = this.getDocument();
d.open( "text/html", "replace" );
d.write( this.toHtml() );
d.close();
this._drawn = true;
// set up scroll buttons
var up = d.getElementById( "scroll-up-item" );
var down = d.getElementById( "scroll-down-item" );
var scrollContainer = d.getElementById( "scroll-container" );
new ScrollButton( up, scrollContainer, 8 );
new ScrollButton( down, scrollContainer, 2 );
// bind menu items to the table rows
var rows = scrollContainer.firstChild.tBodies[0].rows;
var items = this.items;
var l = rows.length;
var mi;
for ( var i = 0; i < l; i++ ) {
mi = items[i];
rows[i]._menuItem = mi;
mi._htmlElement = rows[i];
}
// hook up mouse
this.hookupMenu( d );
};
Menu.prototype.show = function ( left, top, w, h ) {
var pm = this.parentMenu;
if ( pm )
pm.closeAllSubs( this );
var wasShown = this.isShown();
if ( typeof this.onbeforeshow == "function" && !wasShown )
this.onbeforeshow();
this.drawMenu();
if ( left == null ) left = 0;
if ( top == null ) top = 0;
w = w || Math.min( window.screen.width, this.getPreferredWidth() );
h = h || Math.min( window.screen.height, this.getPreferredHeight() );
this.popup.show( left, top, w, h );
// work around a bug that sometimes occured with large pages when
// opening the first menu
if ( this.getPreferredWidth() == 0 ) {
this.invalidate();
this.show( left, top, w, h );
return;
}
this.fixScrollButtons();
this.fixScrollEnabledState();
// clear selected item
if ( this.selectedIndex != -1 ) {
if ( this.items[ this.selectedIndex ] )
this.items[ this.selectedIndex ].setSelected( false );
}
if ( pm ) {
pm.shownSubMenu = this;
pm._aboutToShowSubMenu = false;
}
window.clearTimeout( this._showTimer );
window.clearTimeout( this._closeTimer );
this._closed = false;
this._startClosePoll();
if ( typeof this.onshow == "function" && !wasShown && this.isShown() )
this.onshow();
};
Menu.prototype.isShown = function () {
this._checkCloseState();
return this.popup != null && this.popup.isOpen;
};
Menu.prototype.fixSize = function () {
var w = Math.min( window.screen.width, this.getPreferredWidth() );
var h = Math.min( window.screen.height, this.getPreferredHeight() );
var l = Math.max( 0, this.getLeft() );
var t = Math.max( 0, this.getTop() );
this.popup.show( l, t, w, h );
};
Menu.prototype.getWidth = function () {
var d = this.getDocument();
if ( d != null )
return d.body.offsetWidth;
else
return 0;
};
Menu.prototype.getHeight = function () {
var d = this.getDocument();
if ( d != null )
return d.body.offsetHeight;
else
return 0;
};
Menu.prototype.getPreferredWidth = function () {
this.updateSizeCache();
return this._cachedSizes.preferredWidth;
};
Menu.prototype.getPreferredHeight = function () {
this.updateSizeCache();
return this._cachedSizes.preferredHeight;
};
Menu.prototype.getLeft = function () {
var d = this.getDocument();
if ( d != null )
return d.parentWindow.screenLeft;
else
return 0;
};
Menu.prototype.getTop = function () {
var d = this.getDocument();
if ( d != null )
return d.parentWindow.screenTop;
else
return 0;
};
// Depreciated. Use show instead
Menu.prototype.setLeft = function ( l ) {
throw new Error("Depreciated. Use show instead");
//var t = this.getTop();
//this.setLocation( l, t );
};
// Depreciated. Use show instead
Menu.prototype.setTop = function ( t ) {
throw new Error("Depreciated. Use show instead");
//var l = this.getLeft();
//this.setLocation( l, t );
};
// Depreciated. Use show instead
Menu.prototype.setLocation = function ( l, t ) {
throw new Error("Depreciated. Use show instead");
//var w = this.getWidth();
//var h = this.getHeight();
//this.popup.show( l, t, w, h );
};
// Depreciated. Use show instead
Menu.prototype.setRect = function ( l, t, w, h ) {
throw new Error("Depreciated. Use show instead");
//this.popup.show( l, t, w, h );
};
Menu.prototype.getInsetLeft = function () {
this.updateSizeCache();
return this._cachedSizes.insetLeft;
};
Menu.prototype.getInsetRight = function () {
this.updateSizeCache();
return this._cachedSizes.insetRight;
};
Menu.prototype.getInsetTop = function () {
this.updateSizeCache();
return this._cachedSizes.insetTop;
};
Menu.prototype.getInsetBottom = function () {
this.updateSizeCache();
return this._cachedSizes.insetBottom;
};
Menu.prototype.areSizesCached = function () {
var cs = this._cachedSizes;
return this._drawn &&
"preferredWidth" in cs &&
"preferredHeight" in cs &&
"insetLeft" in cs &&
"insetRight" in cs &&
"insetTop" in cs &&
"insetBottom" in cs;
};
// depreciated
Menu.prototype.cacheSizes = function ( bForce ) {
return updateSizeCache( bForce );
};
Menu.prototype.resetSizeCache = function () {
this._cachedSizes = {};
};
Menu.prototype.updateSizeCache = function ( bForce ) {
if ( this.areSizesCached() && !bForce )
return;
var d = this.getMeasureDocument();
var body = d.body;
var cs = this._cachedSizes = {}; // reset
var scrollContainer = d.getElementById( "scroll-container" );
// preferred width
cs.preferredWidth = d.body.scrollWidth;
// preferred height
scrollContainer.style.overflow = "visible";
cs.preferredHeight = body.firstChild.offsetHeight; //body.scrollHeight;
scrollContainer.style.overflow = "hidden";
// inset left
cs.insetLeft = posLib.getLeft( scrollContainer );
// inset right
cs.insetRight = body.scrollWidth - posLib.getLeft( scrollContainer ) -
scrollContainer.offsetWidth;
// inset top
var up = d.getElementById( "scroll-up-item" );
if ( up.currentStyle.display == "none" )
cs.insetTop = posLib.getTop( scrollContainer );
else
cs.insetTop = posLib.getTop( up );
// inset bottom
var down = d.getElementById( "scroll-down-item" );
if ( down.currentStyle.display == "none" ) {
cs.insetBottom = body.scrollHeight - posLib.getTop( scrollContainer ) -
scrollContainer.offsetHeight;
}
else {
cs.insetBottom = body.scrollHeight - posLib.getTop( down ) -
down.offsetHeight;
}
};
Menu.prototype.fixScrollButtons = function () {
var d = this.getDocument();
var up = d.getElementById( "scroll-up-item" );
var down = d.getElementById( "scroll-down-item" );
var scrollContainer = d.getElementById( "scroll-container" );
var scs = scrollContainer.style;
if ( scrollContainer.scrollHeight > this.getHeight() ) {
up.style.display = "";
down.style.display = "";
scs.height = "";
scs.overflow = "visible";
scs.height = Math.max( 0, this.getHeight() -
( d.body.scrollHeight - scrollContainer.offsetHeight ) ) + "px";
scs.overflow = "hidden";
this._scrollingMode = true;
}
else {
up.style.display = "none";
down.style.display = "none";
scs.overflow = "visible";
scs.height = "";
this._scrollingMode = false;
}
};
Menu.prototype.fixScrollEnabledState = function () {
var d = this.getDocument();
var up = d.getElementById( "scroll-up-item" );
var down = d.getElementById( "scroll-down-item" );
var scrollContainer = d.getElementById( "scroll-container" );
var tr;
tr = up.rows[0];
if ( scrollContainer.scrollTop == 0 ) {
if ( tr.className == "hover" || tr.className == "disabled-hover" )
tr.className = "disabled-hover";
else
tr.className = "disabled";
}
else {
if ( tr.className == "disabled-hover" || tr.className == "hover" )
tr.className = "hover";
else
tr.className = "";
}
tr = down.rows[0];
if ( scrollContainer.scrollHeight - scrollContainer.clientHeight <=
scrollContainer.scrollTop ) {
if ( tr.className == "hover" || tr.className == "disabled-hover" )
tr.className = "disabled-hover";
else
tr.className = "disabled";
}
else {
if ( tr.className == "disabled-hover" || tr.className == "hover" )
tr.className = "hover";
else
tr.className = "";
}
};
Menu.prototype.closeAllMenus = function () {
if ( this.parentMenu )
this.parentMenu.closeAllMenus();
else
this.close();
};
Menu.prototype.close = function () {
this.closeAllSubs();
window.clearTimeout( this._showTimer );
window.clearTimeout( this._closeTimer );
if ( this.popup )
this.popup.hide();
var pm = this.parentMenu;
if ( pm && pm.shownSubMenu == this )
pm.shownSubMenu = null;
this.setSelectedIndex( -1 );
this._checkCloseState();
};
Menu.prototype.closeAllSubs = function ( oNotThisSub) {
// go through items and check for sub menus
var items = this.items;
var l = items.length;
for (var i = 0; i < l; i++) {
if ( items[i].subMenu != null && items[i].subMenu != oNotThisSub )
items[i].subMenu.close();
}
};
Menu.prototype.getSelectedIndex = function () {
return this.selectedIndex;
};
Menu.prototype.setSelectedIndex = function ( nIndex ) {
if ( this.selectedIndex == nIndex ) return;
if ( nIndex >= this.items.length )
nIndex = -1;
var mi;
// deselect old
if ( this.selectedIndex != -1 ) {
mi = this.items[ this.selectedIndex ];
mi.setSelected( false );
}
this.selectedIndex = nIndex;
mi = this.items[ this.selectedIndex ];
if ( mi != null )
mi.setSelected( true );
};
Menu.prototype.goToNextMenuItem = function () {
var i = 0;
var items = this.items;
var length = items.length;
var index = this.getSelectedIndex();
var tmp;
do {
if ( index == -1 || index >= length )
index = 0;
else
index++;
i++;
tmp = items[index]
} while ( !( tmp != null && tmp instanceof MenuItem &&
!(tmp instanceof MenuSeparator) || i >= length ) )
if ( tmp != null )
this.setSelectedIndex( index );
};
Menu.prototype.goToPreviousMenuItem = function () {
var i = 0;
var items = this.items;
var length = items.length;
var index = this.getSelectedIndex();
var tmp;
do {
if ( index == -1 || index >= length )
index = length - 1;
else
index--;
i++;
tmp = items[index]
} while ( !( tmp != null && tmp instanceof MenuItem &&
!(tmp instanceof MenuSeparator) || i >= length ) )
if ( tmp != null )
this.setSelectedIndex( index );
};
Menu.prototype.goToNextMenu = function () {
var index = this.getSelectedIndex();
var mi = this.items[ index ];
if ( mi && mi.subMenu && !mi.disabled ) {
mi.subMenu.setSelectedIndex( 0 );
mi.showSubMenu( false );
}
else {
// go up to root and select next
var mb = this.getMenuBar();
if ( mb != null )
mb.goToNextMenuItem();
}
};
Menu.prototype.goToPreviousMenu = function () {
if ( this.parentMenuItem && this.parentMenuItem instanceof MenuButton ) {
this.parentMenu.goToPreviousMenuItem();
}
else if ( this.parentMenuItem ) {
this.close();
}
};
Menu.prototype.getMenuBar = function () {
if ( this.parentMenu == null )
return null;
return this.parentMenu.getMenuBar();
};
Menu.prototype.makeEventListeners = function () {
if ( this.eventListeners != null )
return;
this.eventListeners = {
onscroll: new Function( "eventListeners.menu.onscroll(\"" + this.id + "\")" ),
onmouseover: new Function( "eventListeners.menu.onmouseover(\"" + this.id + "\")" ),
onmouseout: new Function( "eventListeners.menu.onmouseout(\"" + this.id + "\")" ),
onmouseup: new Function( "eventListeners.menu.onmouseup(\"" + this.id + "\")" ),
onmousewheel: new Function( "eventListeners.menu.onmousewheel(\"" + this.id + "\")" ),
onreadystatechange: new Function( "eventListeners.menu.onreadystatechange(\"" + this.id + "\")" ),
onkeydown: new Function( "eventListeners.menu.onkeydown(\"" + this.id + "\")" ),
oncontextmenu: new Function( "eventListeners.menu.oncontextmenu(\"" + this.id + "\")" ),
onunload: new Function( "eventListeners.menu.onunload(\"" + this.id + "\")" )
};
};
Menu.prototype.detachEvents = function () {
if ( this.eventListeners == null )
return;
var d = this.getDocument();
var w = d.parentWindow;
var scrollContainer = d.getElementById("scroll-container");
scrollContainer.detachEvent( "onscroll", this.eventListeners.onscroll );
d.detachEvent( "onmouseover", this.eventListeners.onmouseover );
d.detachEvent( "onmouseout", this.eventListeners.onmouseout );
d.detachEvent( "onmouseup", this.eventListeners.onmouseup );
d.detachEvent( "onmousewheel", this.eventListeners.onmousewheel );
if (this.cssText == null) {
var linkEl = d.getElementsByTagName("LINK")[0];
linkEl.detachEvent( "onreadystatechange", this.eventListeners.onreadystatechange );
}
d.detachEvent( "onkeydown", this.eventListeners.onkeydown );
d.detachEvent( "oncontextmenu", this.eventListeners.oncontextmenu );
// prevent IE to keep menu open when navigating away
window.detachEvent( "onunload", this.eventListeners.onunload );
}
Menu.prototype.hookupMenu = function ( d ) {
this.detachEvents();
this.makeEventListeners();
var oThis = this;
var d = this.getDocument();
var w = d.parentWindow;
var scrollContainer = d.getElementById("scroll-container");
// listen to the onscroll
scrollContainer.attachEvent( "onscroll", this.eventListeners.onscroll );
d.attachEvent( "onmouseover", this.eventListeners.onmouseover );
d.attachEvent( "onmouseout", this.eventListeners.onmouseout );
d.attachEvent( "onmouseup", this.eventListeners.onmouseup );
d.attachEvent( "onmousewheel", this.eventListeners.onmousewheel );
// if css file is not loaded we need to wait for it to load.
// Once loaded fix the size
if (this.cssText == null) {
var linkEl = d.getElementsByTagName("LINK")[0];
if ( linkEl.readyState != "complete") {
linkEl.attachEvent( "onreadystatechange", this.eventListeners.onreadystatechange );
}
}
d.attachEvent( "onkeydown", this.eventListeners.onkeydown );
d.attachEvent( "oncontextmenu", this.eventListeners.oncontextmenu );
// prevent IE to keep menu open when navigating away
window.attachEvent( "onunload", this.eventListeners.onunload );
var all = d.all;
var l = all.length;
for ( var i = 0; i < l; i++ )
all[i].unselectable = "on";
};
Menu.prototype.handleKeyEvent = function ( oEvent ) {
if ( this.shownSubMenu )
// sub menu handles key event
return;
var nKeyCode = oEvent.keyCode;
switch ( nKeyCode ) {
case 40: // down
this.goToNextMenuItem();
break;
case 38: // up
this.goToPreviousMenuItem();
break;
case 39: // right
this.goToNextMenu();
break;
case 37: // left
this.goToPreviousMenu();
break;
case 13: // enter
var mi = this.items[ this.getSelectedIndex() ];
if ( mi )
mi.dispatchAction();
break;
case 27: // esc
this.close();
// should close menu and go to parent menu item
break;
case Menu.keyboardAccelKey:
case Menu.keyboardAccelKey2:
this.closeAllMenus();
break;
default:
// find any mnemonic that matches
var c = String.fromCharCode( nKeyCode ).toLowerCase();
var items = this.items;
var l = items.length;
for ( var i = 0; i < l; i++ ) {
if ( items[i].mnemonic == c ) {
items[i].dispatchAction();
break;
}
}
}
// cancel default action
oEvent.returnValue = false;
oEvent.keyCode = 0;
};
// poll close state and when closed call _onclose
Menu.prototype._startClosePoll = function () {
var oThis = this;
window.clearInterval( this._onCloseInterval );
this._onCloseInterval = window.setInterval(
"eventListeners.menu.oncloseinterval(\"" + this.id + "\")", 100 );
};
Menu.prototype._checkCloseState = function () {
var closed = this.popup == null || !this.popup.isOpen;
if ( closed && this._closed != closed ) {
this._closed = closed;
this._closedAt = new Date().valueOf();
window.clearInterval( this._onCloseInterval );
if ( typeof this._onclose == "function" ) {
var e = this.getDocument().parentWindow.event;
if ( e != null && e.keyCode == 27 )
this._closeReason = "escape";
else
this._closeReason = "unknown";
this._onclose();
}
if ( typeof this.onclose == "function" )
this.onclose();
}
};
Menu.prototype._isCssFileLoaded = function () {
if (this.cssText != null)
return true;
var d = this.getMeasureDocument();
var l = d.getElementsByTagName("LINK")[0];
return l.readyState == "complete";
};
Menu.prototype.destroy = function () {
var l = this.items.length;
for ( var i = l -1; i >= 0; i-- )
this.items[i].destroy();
this.detachEvents();
this.items = [];
this.parentMenu = null;
this.parentMenuItem = null;
this.shownSubMenu = null;
this._cachedSizes = null;
this.eventListeners = null;
if ( this.popup != null ) {
var d = this.popup.document;
d.open("text/plain", "replace");
d.write("");
d.close();
this.popup = null;
}
if ( Menu._measureMenu == this ) {
Menu._measureMenu = null;
var d = Menu._measureFrame.contentWindow.document;
d.open("text/plain", "replace");
d.write("");
d.close();
Menu._measureFrame.parentNode.removeChild(Menu._measureFrame);
Menu._measureFrame = null;
}
menuCache.remove( this );
};
////////////////////////////////////////////////////////////////////////////////////
// MenuItem
//
function MenuItem( sLabelText, fAction, sIconSrc, oSubMenu ) {
// public
this.icon = sIconSrc || "";
this.text = sLabelText;
this.action = fAction;
this.subMenu = oSubMenu;
this.parentMenu = null;
// private
this._selected = false;
this._useInsets = true; // should insets be taken into account when showing sub menu
this.id = menuCache.getId();
menuCache[ this.id ] = this;
}
MenuItem.prototype.subMenuDirection = "horizontal";
MenuItem.prototype.disabled = false;
MenuItem.prototype.mnemonic = null;
MenuItem.prototype.shortcut = null;
MenuItem.prototype.toolTip = "";
MenuItem.prototype.target = null;
MenuItem.prototype.visible = true;
MenuItem.prototype.toHtml = function () {
var cssClass = this.getCssClass();
var toolTip = this.getToolTip();
return "
";
};
MenuItem.prototype.getSubMenuArrowHtml = function () {
if ( this.subMenu == null )
return " ";
return 4; // right arrow using the marlett (or webdings) font
};
MenuItem.prototype.getSubMenuArrowCellHtml = function () {
return "