/*---------------------------------------------------------------------------- | 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 ? "" : "") + "" + "
" + "" + "" + "
" + "" + itemsHtml.join( "" ) + "
" + "
" + "" + "" + "
" + ""; }; 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; 1000. this._useInsets = true; // should insets be taken into account when showing sub menu 1001. 1002. this.id = menuCache.getId(); 1003. menuCache[ this.id ] = this; 1004.} 1005. 1006.MenuItem.prototype.subMenuDirection = "horizontal"; 1007.MenuItem.prototype.disabled = false; 1008.MenuItem.prototype.mnemonic = null; 1009.MenuItem.prototype.shortcut = null; 1010.MenuItem.prototype.toolTip = ""; 1011.MenuItem.prototype.target = null; 1012.MenuItem.prototype.visible = true; 1013. 1014.MenuItem.prototype.toHtml = function () { 1015. var cssClass = this.getCssClass(); 1016. var toolTip = this.getToolTip(); 1017. 1018. return "" + 1023. this.getIconCellHtml() + 1024. this.getTextCellHtml() + 1025. this.getShortcutCellHtml() + 1026. this.getSubMenuArrowCellHtml() + 1027. ""; 1028.}; 1029. 1030.MenuItem.prototype.getTextHtml = function () { 1031. var s = this.text; 1032. if ( !s || !this.mnemonic ) 1033. return s; 1034. 1035. // replace character with character 1036. // /^(((<([^>]|MNEMONIC)+>)|[^MNEMONIC])*)(MNEMONIC)/i 1037. var re = new RegExp( "^(((<([^>]|" + this.mnemonic + ")+>)|[^<" + 1038. this.mnemonic + "])*)(" + this.mnemonic + ")", "i" ); 1039. re.exec( s ); 1040. if ( RegExp.index != -1 && RegExp.$5 != "" ) 1041. return RegExp.$1 + "" + RegExp.$5 + "" + RegExp.rightContext; 1042. else 1043. return s; 1044.}; 1045. 1046. 1047.MenuItem.prototype.getIconHtml = function () { 1048. return this.icon != "" ? "" : " "; 1049.}; 1050. 1051.MenuItem.prototype.getTextCellHtml = function () { 1052. return "" + 1053. this.makeDisabledContainer( 1054. this.getTextHtml() 1055. ) + 1056. ""; 1057.}; 1058. 1059.MenuItem.prototype.getIconCellHtml = function () { 1060. return "" + 1063. this.makeDisabledContainer( 1064. this.getIconHtml() 1065. ) + 1066. ""; 1067.}; 1068. 1069.MenuItem.prototype.getCssClass = function () { 1070. if ( this.disabled && this._selected ) 1071. return "disabled-hover"; 1072. else if ( this.disabled ) 1073. return "disabled"; 1074. else if ( this._selected ) 1075. return "hover"; 1076. 1077. return ""; 1078.}; 1079. 1080.MenuItem.prototype.getToolTip = function () { 1081. return this.toolTip; 1082.}; 1083. 1084.MenuItem.prototype.getShortcutHtml = function () { 1085. if ( this.shortcut == null ) 1086. return " "; 1087. 1088. return this.shortcut; 1089.}; 1090. 1091.MenuItem.prototype.getShortcutCellHtml = function () { 1092. return "" + 1093. this.makeDisabledContainer( 1094. this.getShortcutHtml() 1095. ) + 1096. ""; 1097.}; 1098. 1099.MenuItem.prototype.getSubMenuArrowHtml = function () { 1100. if ( this.subMenu == null ) 1101. return " "; 1102. 1103. return 4; // right arrow using the marlett (or webdings) font 1104.}; 1105. 1106.MenuItem.prototype.getSubMenuArrowCellHtml = function () { 1107. return "" + 1108. this.makeDisabledContainer( 1109. this.getSubMenuArrowHtml() 1110. ) + 1111. ""; 1112.}; 1113. 1114.MenuItem.prototype.makeDisabledContainer = function ( s ) { 1115. if ( this.disabled ) 1116. return "" + 1117. s + ""; 1118. return s; 1119.}; 1120. 1121.MenuItem.prototype.dispatchAction = function () { 1122. if ( this.disabled ) 1123. return; 1124. 1125. this.setSelected( true ); 1126. 1127. if ( this.subMenu ) { 1128. if ( !this.subMenu.isShown() ) 1129. this.showSubMenu( false ); 1130. return; 1131. } 1132. 1133. if ( typeof this.action == "function" ) { 1134. this.setSelected( false ); 1135. this.parentMenu.closeAllMenus(); 1136. this.action(); 1137. 1138. } 1139. else if ( typeof this.action == "string" ) { // href 1140. this.setSelected( false ); 1141. this.parentMenu.closeAllMenus(); 1142. if ( this.target != null ) 1143. window.open( this.action, this.target ); 1144. else 1145. document.location.href = this.action; 1146. } 1147.}; 1148. 1149.MenuItem.prototype.setSelected = function ( bSelected ) { 1150. if ( this._selected == bSelected ) return; 1151. 1152. this._selected = Boolean( bSelected ); 1153. 1154. var tr = this._htmlElement; 1155. if ( tr ) 1156. tr.className = this.getCssClass(); 1157. 1158. if ( !this._selected ) 1159. this.closeSubMenu( true ); 1160. 1161. var pm = this.parentMenu; 1162. if ( bSelected ) { 1163. 1164. pm.setSelectedIndex( this.itemIndex ); 1165. this.scrollIntoView(); 1166. 1167. // select item in parent menu as well 1168. if ( pm.parentMenuItem ) 1169. pm.parentMenuItem.setSelected( true ); 1170. } 1171. else 1172. pm.setSelectedIndex( -1 ); 1173. 1174. if ( this._selected ) { 1175. // clear timers for parent menu 1176. window.clearTimeout( pm._closeTimer ); 1177. } 1178.}; 1179. 1180. 1181.MenuItem.prototype.getSelected = function () { 1182. return this.itemIndex == this.parentMenu.selectedIndex; 1183.}; 1184. 1185.MenuItem.prototype.showSubMenu = function ( bDelayed ) { 1186. var sm = this.subMenu; 1187. var pm = this.parentMenu; 1188. if ( sm && !this.disabled ) { 1189. 1190. pm._aboutToShowSubMenu = true; 1191. 1192. window.clearTimeout( sm._showTimer ); 1193. window.clearTimeout( sm._closeTimer ); 1194. 1195. var showTimeout = bDelayed ? sm.showTimeout : 0; 1196. 1197. var oThis = this; 1198. sm._showTimer = window.setTimeout( 1199. "eventListeners.menuItem.onshowtimer("" + this.id + "")", 1200. showTimeout ); 1201. } 1202.}; 1203. 1204.MenuItem.prototype.closeSubMenu = function ( bDelay ) { 1205. var sm = this.subMenu; 1206. if ( sm ) { 1207. window.clearTimeout( sm._showTimer ); 1208. window.clearTimeout( sm._closeTimer ); 1209. 1210. if ( sm.popup ) { 1211. if ( !bDelay ) 1212. sm.close(); 1213. else { 1214. var oThis = this; 1215. sm._closeTimer = window.setTimeout( 1216. "eventListeners.menuItem.onclosetimer("" + this.id + "")", 1217. sm.closeTimeout ); 1218. } 1219. } 1220. } 1221.}; 1222. 1223.MenuItem.prototype.scrollIntoView = function () { 1224. if ( this.parentMenu._scrollingMode ) { 1225. var d = this.parentMenu.getDocument(); 1226. var sc = d.getElementById( "scroll-container" ); 1227. var scrollTop = sc.scrollTop; 1228. var clientHeight = sc.clientHeight; 1229. var offsetTop = this._htmlElement.offsetTop; 1230. var offsetHeight = this._htmlElement.offsetHeight; 1231. 1232. if ( offsetTop < scrollTop ) 1233. sc.scrollTop = offsetTop; 1234. else if ( offsetTop + offsetHeight > scrollTop + clientHeight ) 1235. sc.scrollTop = offsetTop + offsetHeight - clientHeight; 1236. } 1237.}; 1238. 1239. 1240. 1241.MenuItem.prototype.positionSubMenu = function () { 1242. var dir = this.subMenuDirection; 1243. var el = this._htmlElement; 1244. var useInsets = this._useInsets; 1245. var sm = this.subMenu; 1246. 1247. var oThis = this; 1248. 1249. if ( !sm._isCssFileLoaded() ) { 1250. window.setTimeout( 1251. "eventListeners.menuItem.onpositionsubmenutimer("" + this.id + "")", 1252. 1 ); 1253. return; 1254. } 1255. 1256. // find parent item rectangle 1257. var rect = { 1258. left: posLib.getScreenLeft( el ), 1259. top: posLib.getScreenTop( el ), 1260. width: el.offsetWidth, 1261. height: el.offsetHeight 1262. }; 1263. 1264. var menuRect = { 1265. left: sm.getLeft(), 1266. top: sm.getTop(), 1267. width: sm.getPreferredWidth(), 1268. height: sm.getPreferredHeight(), 1269. insetLeft: useInsets ? sm.getInsetLeft() : 0, 1270. insetRight: useInsets ? sm.getInsetRight() : 0, 1271. insetTop: useInsets ? sm.getInsetTop() : 0, 1272. insetBottom: useInsets ? sm.getInsetBottom() : 0 1273. }; 1274. 1275. // work around for buggy graphics drivers that screw up the screen.left 1276. var screenWidth = screen.width; 1277. var screenHeight = screen.height; 1278. while ( rect.left > screenWidth ) 1279. screenWidth += screen.width; 1280. while ( rect.top > screenHeight ) 1281. screenHeight += screen.height; 1282. 1283. var left, top, width = menuRect.width, height = menuRect.height; 1284. 1285. if ( dir == "vertical" ) { 1286. if ( rect.left + menuRect.width - menuRect.insetLeft <= screenWidth ) 1287. left = rect.left - menuRect.insetLeft; 1288. else if ( screenWidth >= menuRect.width ) 1289. left = screenWidth - menuRect.width; 1290. else 1291. left = 0; 1292. 1293. if ( rect.top + rect.height + menuRect.height - menuRect.insetTop <= screenHeight ) 1294. top = rect.top + rect.height - menuRect.insetTop; 1295. else if ( rect.top - menuRect.height + menuRect.insetBottom >= 0 ) 1296. top = rect.top - menuRect.height + menuRect.insetBottom; 1297. else { // use largest and resize 1298. var sizeAbove = rect.top + menuRect.insetBottom; 1299. var sizeBelow = screenHeight - rect.top - rect.height + menuRect.insetTop; 1300. if ( sizeBelow >= sizeAbove ) { 1301. top = rect.top + rect.height - menuRect.insetTop; 1302. height = sizeBelow; 1303. } 1304. else { 1305. top = 0; 1306. height = sizeAbove; 1307. } 1308. } 1309. } 1310. else { 1311. if ( rect.top + menuRect.height - menuRect.insetTop <= screenHeight ) 1312. top = rect.top - menuRect.insetTop; 1313. else if ( rect.top + rect.height - menuRect.height + menuRect.insetBottom >= 0) 1314. top = rect.top + rect.height - menuRect.height + menuRect.insetBottom; 1315. else if ( screenHeight >= menuRect.height ) 1316. top = screenHeight - menuRect.height; 1317. else { 1318. top = 0; 1319. height = screenHeight 1320. } 1321. 1322. if ( rect.left + rect.width + menuRect.width - menuRect.insetLeft <= screenWidth ) 1323. left = rect.left + rect.width - menuRect.insetLeft; 1324. else if ( rect.left - menuRect.width + menuRect.insetRight >= 0 ) 1325. left = rect.left - menuRect.width + menuRect.insetRight; 1326. else if ( screenWidth >= menuRect.width ) 1327. left = screenWidth - menuRect.width; 1328. else 1329. left = 0; 1330. } 1331. 1332. var scrollBefore = sm._scrollingMode; 1333. sm.show( left, top, width, height ); 1334. if ( sm._scrollingMode != scrollBefore ) 1335. this.positionSubMenu(); 1336.}; 1337. 1338. 1339.MenuItem.prototype.destroy = function () { 1340. if ( this.subMenu != null ) 1341. this.subMenu.destroy(); 1342. 1343. this.subMenu = null; 1344. this.parentMenu = null; 1345. var el = this._htmlElement 1346. if ( el != null ) 1347. el._menuItem = null; 1348. this._htmlElement = null; 1349. 1350. menuCache.remove( this ); 1351.}; 1352. 1353. 1354./////////////////////////////////////////////////////////////////////////////// 1355.// CheckBoxMenuItem extends MenuItem 1356.// 1357.function CheckBoxMenuItem( sLabelText, bChecked, fAction, oSubMenu ) { 1358. 1359. this.MenuItem = MenuItem; 1360. this.MenuItem( sLabelText, fAction, null, oSubMenu); 1361. 1362. // public 1363. this.checked = bChecked; 1364.} 1365. 1366.CheckBoxMenuItem.prototype = new MenuItem; 1367. 1368.CheckBoxMenuItem.prototype.getIconHtml = function () { 1369. return "" + 1370. (this.checked ? "a" : " ") + 1371. ""; 1372.}; 1373. 1374.CheckBoxMenuItem.prototype.getIconCellHtml = function () { 1375. return "" + 1376. this.makeDisabledContainer( 1377. this.getIconHtml() 1378. ) + 1379. ""; 1380.}; 1381. 1382.CheckBoxMenuItem.prototype.getCssClass = function () { 1383. var s = (this.checked ? " checked" : ""); 1384. if ( this.disabled && this._selected ) 1385. return "disabled-hover" + s; 1386. else if ( this.disabled ) 1387. return "disabled" + s; 1388. else if ( this._selected ) 1389. return "hover" + s; 1390. 1391. return s; 1392.}; 1393. 1394.CheckBoxMenuItem.prototype._menuItem_dispatchAction = 1395. MenuItem.prototype.dispatchAction; 1396.CheckBoxMenuItem.prototype.dispatchAction = function () { 1397. if (!this.disabled) { 1398. this.checked = !this.checked; 1399. this._menuItem_dispatchAction(); 1400. this.parentMenu.invalidate(); 1401. this.parentMenu.closeAllMenus(); 1402. } 1403.}; 1404. 1405. 1406./////////////////////////////////////////////////////////////////////////////// 1407.// RadioButtonMenuItem extends MenuItem 1408.// 1409.function RadioButtonMenuItem( sLabelText, bChecked, sRadioGroupName, fAction, oSubMenu ) { 1410. this.MenuItem = MenuItem; 1411. this.MenuItem( sLabelText, fAction, null, oSubMenu ); 1412. 1413. // public 1414. this.checked = bChecked; 1415. this.radioGroupName = sRadioGroupName; 1416.} 1417. 1418.RadioButtonMenuItem.prototype = new MenuItem; 1419. 1420.RadioButtonMenuItem.prototype.getIconHtml = function () { 1421. return "" + 1422. (this.checked ? "n" : " ") + 1423. ""; 1424.}; 1425. 1426.RadioButtonMenuItem.prototype.getIconCellHtml = function () { 1427. return "" + 1428. this.makeDisabledContainer( 1429. this.getIconHtml() 1430. ) + 1431. ""; 1432.}; 1433. 1434.RadioButtonMenuItem.prototype.getCssClass = function () { 1435. var s = (this.checked ? " checked" : ""); 1436. if ( this.disabled && this._selected ) 1437. return "disabled-hover" + s; 1438. else if ( this.disabled ) 1439. return "disabled" + s; 1440. else if ( this._selected ) 1441. return "hover" + s; 1442. 1443. return s; 1444.}; 1445. 1446.RadioButtonMenuItem.prototype._menuItem_dispatchAction = 1447. MenuItem.prototype.dispatchAction; 1448.RadioButtonMenuItem.prototype.dispatchAction = function () { 1449. if (!this.disabled) { 1450. if ( !this.checked ) { 1451. // loop through items in parent menu 1452. var items = this.parentMenu.items; 1453. var l = items.length; 1454. for ( var i = 0; i < l; i++ ) { 1455. if ( items[i] instanceof RadioButtonMenuItem ) { 1456. if ( items[i].radioGroupName == this.radioGroupName ) { 1457. items[i].checked = items[i] == this; 1458. } 1459. } 1460. } 1461. this.parentMenu.invalidate(); 1462. } 1463. 1464. this._menuItem_dispatchAction(); 1465. this.parentMenu.closeAllMenus(); 1466. } 1467.}; 1468. 1469. 1470./////////////////////////////////////////////////////////////////////////////// 1471.// MenuSeparator extends MenuItem 1472.// 1473.function MenuSeparator() { 1474. this.MenuItem = MenuItem; 1475. this.MenuItem(); 1476.} 1477. 1478.MenuSeparator.prototype = new MenuItem; 1479. 1480.MenuSeparator.prototype.toHtml = function () { 1481. return "" + 1484. "
" + 1485. ""; 1486.}; 1487. 1488.MenuSeparator.prototype.getCssClass = function () { 1489. return "separator"; 1490.}; 1491. 1492. 1493.//////////////////////////////////////////////////////////////////////////////////// 1494.// MenuBar extends Menu 1495.// 1496.function MenuBar() { 1497. this.items = []; 1498. this.parentMenu = null; 1499. this.parentMenuItem = null; 1500. this.shownSubMenu = null; 1501. this._aboutToShowSubMenu = false; 1502. 1503. this.active = false; 1504. this.id = menuCache.getId(); 1505. menuCache[ this.id ] = this; 1506.} 1507.MenuBar.prototype = new Menu; 1508. 1509.MenuBar.prototype._document = null; 1510. 1511.MenuBar.leftMouseButton = 1; 1512. 1513.MenuBar.prototype.toHtml = function () { 1514. var items = this.items; 1515. var l = items.length; 1516. var itemsHtml = new Array( l ); 1517. for (var i = 0; i < l; i++ ) 1518. itemsHtml[i] = items[i].toHtml(); 1519. 1520. return ""; 1523.}; 1524. 1525.MenuBar.prototype.invalidate = function () { 1526. if (this._htmlElement) { 1527. this.detachEvents(); 1528. var oldEl = this._htmlElement; 1529. var newEl = this.create(this._document); 1530. oldEl.parentNode.replaceChild(newEl, oldEl); 1531. } 1532.}; 1533. 1534.MenuBar.prototype.createPopup = function () {}; 1535.MenuBar.prototype.getPopup= function () {}; 1536.MenuBar.prototype.drawMenu = function () {}; 1537. 1538.MenuBar.prototype.getDocument = function () { 1539. return this._document; 1540.}; 1541. 1542.MenuBar.prototype.show = function ( left, top, w, h ) {}; 1543.MenuBar.prototype.isShown = function () { return true; }; 1544.MenuBar.prototype.fixSize = function () {} 1545. 1546.MenuBar.prototype.getWidth = function () { 1547. return this._htmlElement.offsetWidth; 1548.}; 1549. 1550.MenuBar.prototype.getHeight = function () { 1551. return this._htmlElement.offsetHeight; 1552.}; 1553. 1554.MenuBar.prototype.getPreferredWidth = function () { 1555. var el = this._htmlElement; 1556. el.runtimStyle.whiteSpace = "nowrap"; 1557. var sw = el.scrollWidth; 1558. el.runtimStyle.whiteSpace = ""; 1559. return sw + parseInt( el.currentStyle.borderLeftWidth ) + 1560. parseInt( el.currentStyle.borderRightWidth ); 1561.}; 1562. 1563.MenuBar.prototype.getPreferredHeight = function () { 1564. var el = this._htmlElement; 1565. el.runtimStyle.whiteSpace = "nowrap"; 1566. var sw = el.scrollHeight; 1567. el.runtimStyle.whiteSpace = ""; 1568. return sw + parseInt( el.currentStyle.borderTopWidth ) + 1569. parseInt( el.currentStyle.borderBottomWidth ); 1570.}; 1571. 1572.MenuBar.prototype.getLeft = function () { 1573. return posLib.getScreenLeft( this._htmlElement ); 1574.}; 1575.MenuBar.prototype.getTop = function () { 1576. return posLib.getScreenLeft( this._htmlElement ); 1577.}; 1578.MenuBar.prototype.setLeft = function ( l ) {}; 1579.MenuBar.prototype.setTop = function ( t ) {}; 1580.MenuBar.prototype.setLocation = function ( l, t ) {}; 1581.MenuBar.prototype.setRect = function ( l, t, w, h ) {}; 1582.MenuBar.prototype.getInsetLeft = function () { 1583. return parseInt( this._htmlElement.currentStyle.borderLeftWidth ); 1584.}; 1585.MenuBar.prototype.getInsetRight = function () { 1586. return parseInt( this._htmlElement.currentStyle.borderRightWidth ); 1587.}; 1588.MenuBar.prototype.getInsetTop = function () { 1589. return parseInt( this._htmlElement.currentStyle.borderTopWidth ); 1590.}; 1591.MenuBar.prototype.getInsetBottom = function () { 1592. return parseInt( this._htmlElement.currentStyle.borderBottomWidth ); 1593.}; 1594.MenuBar.prototype.fixScrollButtons = function () {}; 1595.MenuBar.prototype.fixScrollEnabledState = function () {}; 1596. 1597.MenuBar.prototype.makeEventListeners = function () { 1598. if ( this.eventListeners != null ) 1599. return; 1600. 1601. this.eventListeners = { 1602. onmouseover: new Function( "eventListeners.menuBar.onmouseover("" + this.id + "")" ), 1603. onmouseout: new Function( "eventListeners.menuBar.onmouseout("" + this.id + "")" ), 1604. onmousedown: new Function( "eventListeners.menuBar.onmousedown("" + this.id + "")" ), 1605. onkeydown: new Function( "eventListeners.menuBar.onkeydown("" + this.id + "")" ), 1606. onunload: new Function( "eventListeners.menuBar.onunload("" + this.id + "")" ) 1607. }; 1608.}; 1609. 1610.MenuBar.prototype.detachEvents = function () { 1611. if ( this.eventListeners == null ) 1612. return; 1613. 1614. this._htmlElement.detachEvent( "onmouseover", this.eventListeners.onmouseover ); 1615. this._htmlElement.detachEvent( "onmouseout", this.eventListeners.onmouseout ); 1616. this._htmlElement.detachEvent( "onmousedown", this.eventListeners.onmousedown ); 1617. this._document.detachEvent( "onkeydown", this.eventListeners.onkeydown ); 1618. window.detachEvent( "onunload", this.eventListeners.onunload ); 1619.} 1620. 1621.MenuBar.prototype.hookupMenu = function ( element ) { 1622. if ( !this._document ) 1623. this._document = element.document; 1624. 1625. this.detachEvents(); 1626. this.makeEventListeners(); 1627. 1628. // create shortcut to html element 1629. this._htmlElement = element; 1630. element.unselectable = "on"; 1631. 1632. // and same for menu buttons 1633. var cs = element.childNodes; 1634. var items = this.items; 1635. var l = cs.length; 1636. for ( var i = 0; i < l; i++ ) { 1637. items[i]._htmlElement = cs[i]; 1638. cs[i]._menuItem = items[i]; 1639. } 1640. 1641. // hook up events 1642. element.attachEvent( "onmouseover", this.eventListeners.onmouseover ); 1643. element.attachEvent( "onmouseout", this.eventListeners.onmouseout ); 1644. element.attachEvent( "onmousedown", this.eventListeners.onmousedown ); 1645. this._document.attachEvent( "onkeydown", this.eventListeners.onkeydown ); 1646. window.attachEvent( "onunload", this.eventListeners.onunload ); 1647.}; 1648. 1649.function getMenuItemElement( el ) { 1650. while ( el != null && el._menuItem == null) 1651. el = el.parentNode; 1652. return el; 1653.} 1654. 1655.function getTrElement( el ) { 1656. while ( el != null && el.tagName != "TR" ) 1657. el = el.parentNode; 1658. return el; 1659.} 1660. 1661.MenuBar.prototype.write = function (oDocument) { 1662. this._document = oDocument || document; 1663. this._document.write( this.toHtml() ); 1664. var el = this._document.getElementById( this.id ); 1665. this.hookupMenu( el ); 1666.}; 1667. 1668.MenuBar.prototype.create = function (oDocument) { 1669. this._document = oDocument || document; 1670. var dummyDiv = this._document.createElement( "DIV" ); 1671. dummyDiv.innerHTML = this.toHtml(); 1672. var el = dummyDiv.removeChild( dummyDiv.firstChild ); 1673. this.hookupMenu( el ); 1674. return el; 1675.}; 1676. 1677.MenuBar.prototype.handleKeyEvent = function ( e ) { 1678. if ( this.getActiveState() == "open" ) 1679. return; 1680. 1681. var nKeyCode = e.keyCode; 1682. 1683. if ( this.active && e[ Menu.keyboardAccelProperty ] ) { 1684. e.returnValue = false; 1685. e.keyCode = 0; 1686. } 1687. 1688. if ( nKeyCode == Menu.keyboardAccelKey || nKeyCode == Menu.keyboardAccelKey2 ) { 1689. if ( !e.repeat ) { 1690. this.toggleActive(); 1691. } 1692. e.returnValue = false; 1693. e.keyCode = 0; 1694. return; 1695. } 1696. 1697. if ( !this.active ) { 1698. // do not set return value to true 1699. return; 1700. } 1701. 1702. switch ( nKeyCode ) { 1703. case 39: // right 1704. this.goToNextMenuItem(); 1705. e.returnValue = false; 1706. break; 1707. 1708. case 37: // left 1709. this.goToPreviousMenuItem(); 1710. e.returnValue = false; 1711. break; 1712. 1713. case 40: // down 1714. case 38: // up 1715. case 13: // enter 1716. var mi = this.items[ this.getSelectedIndex() ]; 1717. if ( mi ) { 1718. mi.dispatchAction(); 1719. if ( mi.subMenu ) 1720. mi.subMenu.setSelectedIndex( 0 ); 1721. } 1722. e.returnValue = false; 1723. break; 1724. 1725. case 27: // esc 1726. // we need to make sure that the menu bar looses its current 1727. // keyboard activation state 1728. 1729. this.setActive( false ); 1730. e.returnValue = false; 1731. break; 1732. 1733. default: 1734. // find any mnemonic that matches 1735. var c = String.fromCharCode( nKeyCode ).toLowerCase(); 1736. var items = this.items; 1737. var l = items.length; 1738. for ( var i = 0; i < l; i++ ) { 1739. if ( items[i].mnemonic == c ) { 1740. items[i].dispatchAction(); 1741. e.returnValue = false; 1742. break; 1743. } 1744. } 1745. } 1746.}; 1747. 1748.MenuBar.prototype.getMenuBar = function () { 1749. return this; 1750.}; 1751. 1752.MenuBar.prototype._menu_goToNextMenuItem = Menu.prototype.goToNextMenuItem; 1753.MenuBar.prototype.goToNextMenuItem = function () { 1754. var expand = this.getActiveState() == "open"; 1755. this._menu_goToNextMenuItem(); 1756. var mi = this.items[ this.getSelectedIndex() ]; 1757. if ( expand && mi != null ) { 1758. window.setTimeout( 1759. "eventListeners.menuBar.ongotonextmenuitem("" + this.id + "")", 1760. 1 ); 1761. } 1762.}; 1763. 1764.MenuBar.prototype._menu_goToPreviousMenuItem = Menu.prototype.goToPreviousMenuItem; 1765.MenuBar.prototype.goToPreviousMenuItem = function () { 1766. var expand = this.getActiveState() == "open"; 1767. this._menu_goToPreviousMenuItem(); 1768. var mi = this.items[ this.getSelectedIndex() ]; 1769. if ( expand && mi != null ) { 1770. window.setTimeout( 1771. "eventListeners.menuBar.ongotopreviousmenuitem("" + this.id + "")", 1772. 1 ); 1773. } 1774.}; 1775. 1776.MenuBar.prototype._menu_setSelectedIndex = Menu.prototype.setSelectedIndex; 1777.MenuBar.prototype.setSelectedIndex = function ( nIndex ) { 1778. this._menu_setSelectedIndex( nIndex ); 1779. this.active = nIndex != -1; 1780.}; 1781. 1782.MenuBar.prototype.setActive = function ( bActive ) { 1783. if ( this.active != bActive ) { 1784. this.active = Boolean( bActive ); 1785. if ( this.active ) { 1786. this.setSelectedIndex( 0 ); 1787. this.backupFocused(); 1788. window.focus(); 1789. } 1790. else { 1791. this.setSelectedIndex( -1 ); 1792. this.restoreFocused(); 1793. } 1794. } 1795.}; 1796. 1797.MenuBar.prototype.toggleActive = function () { 1798. if ( this.getActiveState() == "active" ) 1799. this.setActive( false ); 1800. else if ( this.getActiveState() == "inactive" ) 1801. this.setActive( true ); 1802.}; 1803. 1804.// returns active, inactive or open 1805.MenuBar.prototype.getActiveState = function () { 1806. if ( this.shownSubMenu != null || this._aboutToShowSubMenu) 1807. return "open"; 1808. else if ( this.active ) 1809. return "active"; 1810. else 1811. return "inactive"; 1812.}; 1813. 1814.MenuBar.prototype.backupFocused = function () { 1815. this._activeElement = this._document.activeElement; 1816.}; 1817. 1818.MenuBar.prototype.restoreFocused = function () { 1819. try { 1820. this._activeElement.focus(); 1821. } 1822. catch (ex) {} 1823. delete this._activeElement; 1824. 1825.}; 1826. 1827.MenuBar.prototype.destroy = function () { 1828. var l = this.items.length; 1829. for ( var i = l -1; i >= 0; i-- ) 1830. this.items[i].destroy(); 1831. 1832. this.detachEvents(); 1833. this._activeElement = null; 1834. this._htmlElement = null; 1835. this._document = null; 1836. this.items = []; 1837. this.shownSubMenu = null; 1838. this.eventListeners = null; 1839. 1840. menuCache.remove( this ); 1841.}; 1842. 1843.//////////////////////////////////////////////////////////////////////////////////// 1844.// MenuButton extends MenuItem 1845.// 1846.function MenuButton( sLabelText, oSubMenu ) { 1847. this.MenuItem = MenuItem; 1848. this.MenuItem( sLabelText, null, null, oSubMenu ); 1849. 1850. // private 1851. this._hover = false; 1852. this._useInsets = false; // should insets be taken into account when showing sub menu 1853.} 1854. 1855.MenuButton.prototype = new MenuItem; 1856.MenuButton.prototype.subMenuDirection = "vertical"; 1857. 1858.MenuButton.prototype.scrollIntoView = function () {}; 1859.MenuButton.prototype.toHtml = function () { 1860. var cssClass = this.getCssClass(); 1861. var toolTip = this.getToolTip(); 1862. 1863. if ( this.subMenu && !this.subMenu._onclose ) 1864. this.subMenu._onclose = new Function( "eventListeners.menuButton.onclose("" + this.id + "")" ); 1865. 1866. return "" + 1871. "" + 1872. this.getTextHtml() + 1873. "" + 1874. "" + 1875. ""; 1876.}; 1877. 1878.MenuButton.prototype.getCssClass = function () { 1879. if ( this.disabled && this._selected ) 1880. return "menu-button disabled-hover"; 1881. else if ( this.disabled ) 1882. return "menu-button disabled"; 1883. else if ( this._selected ) { 1884. if ( this.parentMenu.getActiveState() == "open" ) { 1885. return "menu-button active"; 1886. } 1887. else 1888. return "menu-button hover"; 1889. } 1890. else if ( this._hover ) 1891. return "menu-button hover"; 1892. 1893. return "menu-button "; 1894.}; 1895. 1896.MenuButton.prototype.subMenuClosed = function () { 1897. 1898. if ( this.subMenu._closeReason == "escape" ) 1899. this.setSelected( true ); 1900. else 1901. this.setSelected( false ); 1902. 1903. if ( this.parentMenu.getActiveState() == "inactive" ) 1904. this.parentMenu.restoreFocused(); 1905.}; 1906. 1907.MenuButton.prototype.setSelected = function ( bSelected ) { 1908. 1909. var oldSelected = this._selected; 1910. this._selected = Boolean( bSelected ); 1911. 1912. var tr = this._htmlElement; 1913. if ( tr ) 1914. tr.className = this.getCssClass(); 1915. 1916. if ( this._selected == oldSelected ) 1917. return; 1918. 1919. if ( !this._selected ) 1920. this.closeSubMenu( true ); 1921. 1922. if ( bSelected ) { 1923. this.parentMenu.setSelectedIndex( this.itemIndex ); 1924. this.scrollIntoView(); 1925. } 1926. else 1927. this.parentMenu.setSelectedIndex( -1 ); 1928.}; 1929. 1930. 1931. 1932. 1933. 1934.//////////////////////////////////////////////////////////////////////////////////// 1935.// event listener 1936.// 1937. 1938.var eventListeners = { 1939. menu: { 1940. onkeydown: function ( id ) { 1941. var oThis = menuCache[id]; 1942. var w = oThis.getDocument().parentWindow; 1943. oThis.handleKeyEvent( w.event ); 1944. }, 1945. onunload: function ( id ) { 1946. if (id in menuCache) { 1947. menuCache[id].closeAllMenus(); 1948. menuCache[id].destroy(); 1949. } 1950. // else already destroyed 1951. }, 1952. oncontextmenu: function ( id ) { 1953. var oThis = menuCache[id]; 1954. var w = oThis.getDocument().parentWindow; 1955. w.event.returnValue = false; 1956. }, 1957. 1958. onscroll: function ( id ) { 1959. menuCache[id].fixScrollEnabledState(); 1960. }, 1961. 1962. onmouseover: function ( id ) { 1963. var oThis = menuCache[id]; 1964. var w = oThis.getDocument().parentWindow; 1965. 1966. var fromEl = getTrElement( w.event.fromElement ); 1967. var toEl = getTrElement( w.event.toElement ); 1968. 1969. if ( toEl != null && toEl != fromEl ) { 1970. var mi = toEl._menuItem; 1971. if ( mi ) { 1972. if ( !mi.disabled || oThis.mouseHoverDisabled ) { 1973. mi.setSelected( true ); 1974. mi.showSubMenu( true ); 1975. } 1976. } 1977. else { // scroll button 1978. if (toEl.className == "disabled" || toEl.className == "disabled-hover" ) 1979. toEl.className = "disabled-hover"; 1980. else 1981. toEl.className = "hover"; 1982. oThis.selectedIndex = -1; 1983. } 1984. } 1985. }, 1986. 1987. onmouseout: function ( id ) { 1988. var oThis = menuCache[id]; 1989. var w = oThis.getDocument().parentWindow; 1990. 1991. var fromEl = getTrElement( w.event.fromElement ); 1992. var toEl = getTrElement( w.event.toElement ); 1993. 1994. if ( fromEl != null && toEl != fromEl ) { 1995. 1996. var id = fromEl.parentNode.parentNode.id; 1997. var mi = fromEl._menuItem; 1998. 1999. if ( id == "scroll-up-item" || id == "scroll-down-item" ) { 2000. if (fromEl.className == "disabled-hover" || fromEl.className == "disabled" ) 2001. fromEl.className = "disabled"; 2002. else 2003. fromEl.className = ""; 2004. oThis.selectedIndex = -1; 2005. } 2006. 2007. else if ( mi && 2008. ( toEl != null || mi.subMenu == null || mi.disabled ) ) { 2009. 2010. mi.setSelected( false ); 2011. } 2012. } 2013. 2014. }, 2015. 2016. onmouseup: function ( id ) { 2017. var oThis = menuCache[id]; 2018. var w = oThis.getDocument().parentWindow; 2019. 2020. var srcEl = getMenuItemElement( w.event.srcElement ); 2021. 2022. if ( srcEl != null ) { 2023. var id = srcEl.parentNode.parentNode.id; 2024. if ( id == "scroll-up-item" || id == "scroll-down-item" ) { 2025. return; 2026. } 2027. 2028. oThis.selectedIndex = srcEl.rowIndex; 2029. var menuItem = oThis.items[ oThis.selectedIndex ]; 2030. menuItem.dispatchAction(); 2031. } 2032. }, 2033. 2034. onmousewheel: function ( id ) { 2035. var oThis = menuCache[id]; 2036. var d = oThis.getDocument(); 2037. var w = d.parentWindow; 2038. var scrollContainer = d.getElementById("scroll-container"); 2039. scrollContainer.scrollTop -= 3 * w.event.wheelDelta / 120 * ScrollButton.scrollAmount; 2040. }, 2041. 2042. onreadystatechange: function ( id ) { 2043. var oThis = menuCache[id]; 2044. var d = oThis.getDocument(); 2045. var linkEl = d.getElementsByTagName("LINK")[0]; 2046. if ( linkEl.readyState == "complete" ) { 2047. oThis.resetSizeCache(); // reset sizes 2048. oThis.fixSize(); 2049. oThis.fixScrollButtons(); 2050. } 2051. }, 2052. 2053. oncloseinterval: function ( id ) { 2054. menuCache[id]._checkCloseState(); 2055. } 2056. }, 2057. 2058. 2059. menuItem: { 2060. onshowtimer: function ( id ) { 2061. var oThis = menuCache[id]; 2062. var sm = oThis.subMenu; 2063. var pm = oThis.parentMenu; 2064. var selectedIndex = sm.getSelectedIndex(); 2065. 2066. pm.closeAllSubs( sm ); 2067. window.setTimeout( "eventListeners.menuItem.onshowtimer2("" + id + "")", 1); 2068. }, 2069. 2070. onshowtimer2: function ( id ) { 2071. var oThis = menuCache[id]; 2072. var sm = oThis.subMenu; 2073. var selectedIndex = sm.getSelectedIndex(); 2074. oThis.positionSubMenu(); 2075. sm.setSelectedIndex( selectedIndex ); 2076. oThis.setSelected( true ); 2077. }, 2078. 2079. onclosetimer: function ( id ) { 2080. var oThis = menuCache[id]; 2081. var sm = oThis.subMenu; 2082. sm.close(); 2083. }, 2084. 2085. onpositionsubmenutimer: function ( id ) { 2086. var oThis = menuCache[id]; 2087. var sm = oThis.subMenu; 2088. sm.resetSizeCache(); // reset sizes 2089. oThis.positionSubMenu(); 2090. sm.setSelectedIndex( 0 ); 2091. } 2092. }, 2093. 2094. menuBar: { 2095. onmouseover: function ( id ) { 2096. var oThis = menuCache[id]; 2097. 2098. var e = oThis.getDocument().parentWindow.event; 2099. var fromEl = getMenuItemElement( e.fromElement ); 2100. var toEl = getMenuItemElement( e.toElement ); 2101. 2102. if ( toEl != null && toEl != fromEl ) { 2103. 2104. var mb = toEl._menuItem; 2105. var m = mb.parentMenu; 2106. 2107. if ( m.getActiveState() == "open" ) { 2108. window.setTimeout( function () { 2109. mb.dispatchAction(); 2110. }, 1); 2111. } 2112. else if ( m.getActiveState() == "active" ) { 2113. mb.setSelected( true ); 2114. } 2115. else { 2116. mb._hover = true; 2117. toEl.className = mb.getCssClass(); 2118. } 2119. } 2120. }, 2121. 2122. onmouseout: function ( id ) { 2123. var oThis = menuCache[id]; 2124. 2125. var e = oThis.getDocument().parentWindow.event; 2126. var fromEl = getMenuItemElement( e.fromElement ); 2127. var toEl = getMenuItemElement( e.toElement ); 2128. 2129. if ( fromEl != null && toEl != fromEl ) { 2130. var mb = fromEl._menuItem; 2131. mb._hover = false; 2132. fromEl.className = mb.getCssClass(); 2133. } 2134. }, 2135. 2136. onmousedown: function ( id ) { 2137. var oThis = menuCache[id]; 2138. 2139. var e = oThis.getDocument().parentWindow.event; 2140. if ( e.button != MenuBar.leftMouseButton ) 2141. return; 2142. 2143. var el = getMenuItemElement( e.srcElement ); 2144. 2145. if ( el != null ) { 2146. var mb = el._menuItem; 2147. if ( mb.subMenu ) { 2148. mb.subMenu._checkCloseState(); 2149. if ( new Date() - mb.subMenu._closedAt > 100 ) { // longer than the time to 2150. // do the hide 2151. mb.dispatchAction(); 2152. } 2153. else { 2154. mb._hover = true; 2155. mb._htmlElement.className = mb.getCssClass(); 2156. } 2157. } 2158. } 2159. }, 2160. 2161. onkeydown: function ( id ) { 2162. var oThis = menuCache[id]; 2163. var e = oThis.getDocument().parentWindow.event; 2164. oThis.handleKeyEvent( e ); 2165. }, 2166. 2167. onunload: function ( id ) { 2168. menuCache[id].destroy(); 2169. }, 2170. 2171. ongotonextmenuitem: function ( id ) { 2172. var oThis = menuCache[id]; 2173. var mi = oThis.items[ oThis.getSelectedIndex() ]; 2174. mi.dispatchAction(); 2175. if ( mi.subMenu ) 2176. mi.subMenu.setSelectedIndex( 0 ); 2177. }, 2178. 2179. ongotopreviousmenuitem: function ( id ) { 2180. var oThis = menuCache[id]; 2181. var mi = oThis.items[ oThis.getSelectedIndex() ]; 2182. mi.dispatchAction(); 2183. if ( mi.subMenu ) 2184. mi.subMenu.setSelectedIndex( 0 ); 2185. } 2186. }, 2187. 2188. menuButton: { 2189. onclose: function ( id ) { 2190. menuCache[id].subMenuClosed(); 2191. } 2192. } 2193.};