/** * Introducing GuskaBMenu.js * * GuskaBMenu.js is a free, small JavaScript (drop-down) GuskaBMenu for developers. It's * unobtrusive and only requires a HTML unordered list and your own CSS styles. * http: * * Requires Prototype JS version 1.5.0 or greater. * (Also supports version 1.6.0.*, avoiding all deprecated methods) * http: * _____________________________________________________________________________ * * As of version 1.2, released under the MIT License: * * Copyright (c) 2007-2009 Charming Design, Niek Kouwenberg * http: * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE 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. * _____________________________________________________________________________ * * Special thanks to CARE Internet Services B.V. * http: */ GuskaBMenu = { Version: "1.3.1", /* * CONSTANTS */ HORIZONTAL: 1, VERTICAL: 2, /* * GuskaBMenu */ _GuskaBMenuId: null, _GuskaBMenuNode: null, /* * TEMPORARY VARIABLES */ _showTimeout: null, _hideTimeout: null, _activeNodes: new Array(), /* * OPTIONS */ _orientation: 1, _showPause: 0, _hidePause: 150, _opacity: 1, _CloseMenu: false, /* * METHODS */ /** * Sets the time to wait before hiding the sub GuskaBMenu. * * @param int secs * * @deprecated Please use the options argument for GuskaBMenu.init() instead. */ setHidePause: function(secs){ GuskaBMenu._hidePause = secs * 1000; alert("Deprecated method GuskaBMenu.setHidePause() used: Please use the options argument for GuskaBMenu.init().");}, /** * Initializes the dynamic GuskaBMenu. * * @param string GuskaBMenuId * @param object options * * Available options: * - orientation (int; one of: GuskaBMenu.HORIZONTAL, GuskaBMenu.VERTICAL) * - showPause (float; in seconds; default: 0.0) * - hidePause (float; in seconds; default: 1.0) * - opacity (float; 0 = transparent, 1 = opaque; default: 1; transparency of the sub GuskaBMenu) * * Example usage: *<script type="text/javascript">
    *     GuskaBMenu.init("GuskaBMenu", {"hidePause": 0.5});
    * </script>* * This method can be called after document load, but it is preferred to be * called directly from your page (HTML <head>, before document load). This * way the GuskaBMenu loads faster and can be interacted with much sooner. */ init: function(GuskaBMenuId, options){ GuskaBMenu._GuskaBMenuId = (typeof GuskaBMenuId == "string") ? GuskaBMenuId : "GuskaBMenu"; if (options){ if (options.orientation != undefined){ GuskaBMenu._orientation = options.orientation;} if (options.showPause != undefined){ GuskaBMenu._showPause = options.showPause * 1000;} if (options.hidePause != undefined){ GuskaBMenu._hidePause = options.hidePause * 1000;} if (options.opacity != undefined){ GuskaBMenu._opacity = options.opacity;} if (options.move_by_html_id != undefined){ GuskaBMenu._move_by_html_id = options.move_by_html_id;}} /* Check if the document is already loaded. Prototype 1.6.0 introduces * the document.loaded boolean, for 1.5*, check if we can retrieve an * element from the DOM (fails when document is not loaded). */ if (document.loaded === true || $(GuskaBMenu._GuskaBMenuId)){ GuskaBMenu._doInit();} else { /* Do the actual initialization on document load. The "dom:loaded" * event is preffered, but only available since 1.6.0 (with * document.observe construction). Fall back to the window onload * when not available. */ if (document.observe){ document.observe("dom:loaded", GuskaBMenu._doInit);} else { Element.observe(window, "load", GuskaBMenu._doInit);}} }, /** * Initializes the drop down GuskaBMenu. * * Should be called on page load. */ _doInit: function(){ GuskaBMenu._GuskaBMenuNode = $(GuskaBMenu._GuskaBMenuId); /* Add events to each first level GuskaBMenu node (if any with a subGuskaBMenu). The * GuskaBMenu._addEvents() method will add events recursively. */ GuskaBMenu._addEvents(GuskaBMenu._GuskaBMenuNode);}, /** * Recursively attaches events to the GuskaBMenu UL. * * @param HTMLUListElement ulElement * @param int level */ _addEvents: function(ulElement, level){ if (isNaN(level)){ level = 1;} var elements = (Element.select) ? ulElement.select("li") : ulElement.getElementsBySelector("li"); for (var i = 0; i < elements.length; i++){ if (elements[i].parentNode == ulElement){ var subGuskaBMenus = (Element.select) ? elements[i].select("ul") : elements[i].getElementsBySelector("ul"); if (subGuskaBMenus.length > 0){ /* Add collapse listener to the node if it's the first level * (because the LI contains all other subGuskaBMenu's, therefore * any other listeners are over kill). */ if (level == 1){ $('allbodies_menu_div_arrow').observe("mouseout", GuskaBMenu._hideSubGuskaBMenu.bindAsEventListener(elements[i], level)); $('allbodies_menu_div_list').observe("mouseout", GuskaBMenu._hideSubGuskaBMenu.bindAsEventListener(elements[i], level)); $('allbodies_menu_div_arrow').observe("mouseover", GuskaBMenu._showSubGuskaBMenu.bindAsEventListener(elements[i], level)); $('allbodies_menu_div_list').observe("mouseover", GuskaBMenu._showSubGuskaBMenu.bindAsEventListener(elements[i], level));} else { elements[i].observe("mouseover", GuskaBMenu._showSubGuskaBMenu.bindAsEventListener(elements[i], level));} GuskaBMenu._addEvents(subGuskaBMenus[0], (level + 1)); if (level == 1){ var subTables = (Element.select) ? elements[i].select("table") : elements[i].getElementsBySelector("table"); var tr = subTables[0].childNodes[0].childNodes[0]; var tds = tr.childNodes; for (var j = 1; j < tds.length; j++){ var subGuskaBMenus2 = (Element.select) ? tds[j].select("ul") : tds[j].getElementsBySelector("ul"); if (subGuskaBMenus2.length > 0) GuskaBMenu._addEvents(subGuskaBMenus2[0], (level + 1));}} } else { elements[i].observe("mouseover", GuskaBMenu._quickHideSubGuskaBMenu.bindAsEventListener(elements[i], level));}} }}, /** * Shows the sub GuskaBMenu. * * @param Event e * @param int level */ _showSubGuskaBMenu: function(e, level){ GuskaBMenu._CloseMenu = false; showDiv = e; try { showDiv = this.childNodes[1];} catch (err){ } Event.stop(e); var isFirst = (GuskaBMenu._activeNodes.length == 0); GuskaBMenu._quickHideSubGuskaBMenu(e, level); if (isFirst && GuskaBMenu._showPause > 0){ GuskaBMenu._showTimeout = window.setTimeout(function(){ GuskaBMenu._doShowSubGuskaBMenu(showDiv, level);} .bind(this), GuskaBMenu._showPause);} else { GuskaBMenu._doShowSubGuskaBMenu(showDiv, level);}}, /** * Shows the sub GuskaBMenu. * * @param Event e * @param int level */ _doShowSubGuskaBMenu: function(node, level){ if (level > 1){ var _x = '22';} if (GuskaBMenu._showTimeout){ window.clearTimeout(GuskaBMenu._showTimeout);} var a = node; var subGuskaBMenu = node; a.addClassName("GuskaBMenu_open"); subGuskaBMenu.style.visibility = "visible"; subGuskaBMenu.style.position = "absolute"; /* Set correct position. (Note: the horizontal/vertical properties only * apply to the first level nodes. All other levels are fixed vertical. */ var parent = node.parentNode.childNodes[0]; var pos = (Element.positionedOffset) ? parent.positionedOffset() : Position.positionedOffset(parent); var h = parent.getHeight(); var w = parent.getWidth(); if (level == 1 && GuskaBMenu._orientation == GuskaBMenu.HORIZONTAL){ if (GuskaBMenu._move_by_html_id != undefined){ try { move_by_el = $(GuskaBMenu._move_by_html_id); pos = (Element.positionedOffset) ? move_by_el.positionedOffset() : Position.positionedOffset(move_by_el);} catch (er){ }} subGuskaBMenu.style.left = (pos[0] - 5) + "px"; subGuskaBMenu.style.top = (pos[1] + parent.getHeight() + 5) + "px";} else { subGuskaBMenu.style.left = ((pos[0] - 5) + parent.getWidth()) + "px"; subGuskaBMenu.style.top = (pos[1] + 5) + "px";} /* Apply opacity if not fully opaque. (Apply for sub GuskaBMenu of first level * only, because otherwise opacity would be doubled.) */ if (level == 1 && GuskaBMenu._opacity > 0 && GuskaBMenu._opacity < 1){ subGuskaBMenu.setOpacity(GuskaBMenu._opacity);} GuskaBMenu._activeNodes.push({ "level": level, "link": a, "subGuskaBMenu": subGuskaBMenu });}, /** * Immediately hides the active GuskaBMenu. * * @param Event e * @param int level */ _quickHideSubGuskaBMenu: function(e, level){ Event.stop(e); if (GuskaBMenu._hideTimeout){ window.clearTimeout(GuskaBMenu._hideTimeout);} if (level > 1){ GuskaBMenu._doHideSubGuskaBMenusFromLevel(level);}}, /** * Method for hiding all sub GuskaBMenus. * * Triggered onmouseout of first sub GuskaBMenu (level 2). * * @param Event e * @param int level */ _hideSubGuskaBMenu: function(e, level){ Event.stop(e); GuskaBMenu._CloseMenu = true; if (GuskaBMenu._showTimeout){ window.clearTimeout(GuskaBMenu._showTimeout);} if (GuskaBMenu._hidePause <= 0){ GuskaBMenu._doHideSubGuskaBMenusFromLevel(1);} else { GuskaBMenu._hideTimeout = window.setTimeout(function(){ GuskaBMenu._doHideSubGuskaBMenusFromLevel(1);}, GuskaBMenu._hidePause);}}, /** * Hides all active sub GuskaBMenus from the given level. * * @param int level (Default: 1) * * @return boolean */ _doHideSubGuskaBMenusFromLevel: function(level){ if (level == 1 && !GuskaBMenu._CloseMenu) return; if (isNaN(level)){ level = 1;} GuskaBMenu._activeNodes = GuskaBMenu._activeNodes.findAll(function(node){ /* Hide all sub GuskaBMenus with a level equal or higher than the given * level, and return false to remove these from the array. */ if (node.level >= level){ if (node.link){ node.link.removeClassName("GuskaBMenu_open"); node.link.parentNode.removeClassName("GuskaBMenu_open");} if (node.subGuskaBMenu){ node.subGuskaBMenu.style.visibility = "hidden";} return false;} return true;});}};
