/** * @author Marcel Werk * @copyright 2001-2007 WoltLab GmbH * @license GNU Lesser General Public License */ function PopupMenuList() { this.menus = new Array(); this.menuBarOpen = false; this.hiddenSelects = new Array(); // set event listeners window.onresize = function() { popupMenuList.closeAllMenus() } document.onclick = function(e) { return popupMenuList.handleClickEvents(e); } /** * Registers a new popup menu. */ this.register = function(id) { for (var i = 0; i < this.menus.length; i++) { if (this.menus[i] == id) { return false; } } this.menus.push(id); return true; } /** * Closes all popup menus. */ this.closeAllMenus = function() { for (var i = 0; i < this.menus.length; i++) { var popupMenu = document.getElementById(this.menus[i] + "Menu"); if (!popupMenu) { this.menus.slice(i, 1); continue; } popupMenu.className = "hidden"; } this.menuBarOpen = false; } /** * Listens to all mouse click events. */ this.handleClickEvents = function(event) { if (!event) event = window.event; var target; if (event.target) target = event.target; else if (event.srcElement) target = event.srcElement; if (target.nodeType == 3) {// defeat Safari bug target = target.parentNode; } var id = target.getAttribute("id"); if ((id == null || !id) && target.parentNode && target.parentNode.getAttribute) { id = target.parentNode.getAttribute("id"); } this.enable(id); } /** * Returns the offset of an element. */ this.getOffset = function(element) { var offsetLeft = element.offsetLeft; var offsetTop = element.offsetTop; while ((element = element.offsetParent) != null) { offsetLeft += element.offsetLeft; offsetTop += element.offsetTop; } return {'left' : offsetLeft, 'top' : offsetTop}; } /** * Enables a popup menu. */ this.enable = function(id, mouseOver) { this.showSelects(); this.menuBarOpen = false; for (var i = 0; i < this.menus.length; i++) { var popupMenu = document.getElementById(this.menus[i] + "Menu"); if (!popupMenu) { this.menus.slice(i, 1); continue; } if (this.menus[i] == id) { if (popupMenu.className != 'popupMenu pageMenu') { // get parent height var parentHeight = popupMenu.parentNode ? popupMenu.parentNode.offsetHeight : 0; // get inner window height var windowInnerHeight = window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight); // get inner window width var windowInnerWidth = window.innerWidth ? window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth); // init sliding // no sliding in opera because of bad performance :( var slidingDirection = 'down'; if (!mouseOver && !IS_OPERA) { popupMenu.style.clip = 'rect(auto, auto, 0, auto)'; } else { popupMenu.style.clip = 'rect(auto, auto, auto, auto)'; } // make popup visible popupMenu.className = "popupMenu pageMenu"; // add some IE specials ;) if (IS_IE) { popupMenu.style.filter = "progid:DXImageTransform.Microsoft.alpha(enabled=1,opacity=90)"; popupMenu.style.filter += "progid:DXImageTransform.Microsoft.shadow(direction=135,color=#8e8e8e,strength=3)"; } // set menu bar status if (id.indexOf('menuBar') != -1) this.menuBarOpen = true; // check top offset popupMenu.style.marginTop = ''; var scrollBottom = (window.pageYOffset ? window.pageYOffset : (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop)) + windowInnerHeight; var offset = this.getOffset(popupMenu); if ((offset['top'] - popupMenu.offsetHeight - parentHeight) >= 0 && (offset['top'] + popupMenu.offsetHeight >= scrollBottom || (IS_IE && parentHeight > 0 && id.indexOf('menuBar') == -1 && offset['top'] - popupMenu.offsetHeight > 0))) { //if (offset['top'] + popupMenu.offsetHeight >= scrollBottom) { popupMenu.style.marginTop = (-popupMenu.offsetHeight - parentHeight)+'px'; // change sliding direction slidingDirection = 'up'; if (!mouseOver && !IS_OPERA) { popupMenu.style.clip = 'rect('+popupMenu.offsetHeight+'px, auto, auto, auto)'; } } // hide overlaped selects in IE this.hideSelects(popupMenu); // check left offset if (offset['left'] + popupMenu.offsetWidth >= windowInnerWidth) { popupMenu.style.right = '0'; } // start sliding if (!mouseOver && !IS_OPERA) { var interval = parseInt(popupMenu.offsetHeight / 8); this.slide(this.menus[i] + "Menu", 0, interval, slidingDirection); } continue; } else if (mouseOver) { if (id.indexOf('menuBar') != -1) this.menuBarOpen = true; continue; } } // close popup if (popupMenu.className != "hidden") popupMenu.className = "hidden"; } } /** * Slides a popup menu. */ this.slide = function(id, size, interval, direction) { var popupMenu = document.getElementById(id); if (size > popupMenu.offsetHeight) { size = popupMenu.offsetHeight; } if (direction == 'down') { popupMenu.style.clip = 'rect(auto, auto, '+size+'px, auto)'; } else { popupMenu.style.clip = 'rect('+(popupMenu.offsetHeight - size)+'px, auto, auto, auto)'; } if (size >= popupMenu.offsetHeight) { return; } size += interval; setTimeout("popupMenuList.slide('"+id+"', "+size+", "+interval+", '"+direction+"')", 10); } /** * Returns true, if the menu element overlaps the select element. */ this.overlaps = function(menuPosition, selectPosition) { if ( selectPosition['left'] > menuPosition['right'] || selectPosition['right'] < menuPosition['left'] || selectPosition['top'] > menuPosition['bottom'] || selectPosition['bottom'] < menuPosition['top']) { return false; } return true; } /** * Returns the position of an element. */ this.getPositionArray = function(element) { var offset = this.getOffset(element); offset['right'] = offset['left'] + element.offsetWidth; offset['bottom'] = offset['top'] + element.offsetHeight; return offset; } /** * Hides by a popup menu overlaped selects in IE. */ this.hideSelects = function(popupMenu) { if (!IS_IE6) { return; } var selects = document.getElementsByTagName('select'); if (selects.length > 0) { var menuPosition = this.getPositionArray(popupMenu); for (var i = 0; i < selects.length; i++) { var selectPosition = this.getPositionArray(selects[i]); if (this.overlaps(menuPosition, selectPosition)) { selects[i].style.visibility = 'hidden'; this.hiddenSelects.push(selects[i]); } } } } /** * Shows hidden selects. */ this.showSelects = function() { if (!IS_IE) { return; } while (this.hiddenSelects.length > 0) { var select = this.hiddenSelects.shift(); if (select) { select.style.visibility = 'visible'; } } } } var popupMenuList = new PopupMenuList();