/* * Authors: * Marek Habersack * * (C) 2010 Novell, Inc (http: *novell.com) * * 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. * * This code serves only the List rendering mode of the Menu control in Mono * */ if (!window.Sys) { window.Sys = {}; } if (!Sys.WebForms) { Sys.WebForms = {}; } Sys.WebForms.Menu = function (options) { if (options == null) throw "Sys.WebForms.Menu constructor requires options to be not null."; if (options.element == null) throw "options.element is required."; if (options.orientation == null) throw "options.orientation is required."; if (typeof (options.element) == "string") this.menuID = options.element; else this.mainElement = options.element; this.disappearAfter = options.disappearAfter || 500; this.orientation = options.orientation; this.tabIndex = options.tabIndex || 0; this.disabled = options.disabled || false; this.level = options.level || 0; this.menuItemIndex = 0; if (this.level != 0) { if (options.parentMenu == null) throw "options.parentMenu is required for all submenus."; this.parentMenu = options.parentMenu; } if (this.mainElement == null) { this.mainElement = document.getElementById (this.menuID); if (this.mainElement == null) throw "Unable to find menu element with id '" + this.menuID + "'."; if (this.mainElement.tagName != "DIV") throw "This script must be used only when the menu containing element is DIV."; } /* Due to the way we generate the menu in the list mode, every submenu other than the root one is dynamic */ if (this.level > 1) { this.menuType = "dynamic"; if (options.parentMenu == null) throw "options.parent is required for all submenus."; var subMenuId = Sys.WebForms.Menu.Helpers.getNextSubMenuId (); this.parentMenu = options.parentMenu; this.orientation = this.parentMenu.orientation; this.path = this.parentMenu.path + subMenuId; this.menuID = this.parentMenu.menuID; if (this.mainElement.id == null || this.mainElement.id == "") this.mainElement.id = this.menuID + ":submenu:" + subMenuId; } else { this.menuType = "static"; if (this.level == 1) { this.menuID = this.parentMenu.menuID; this.orientation = this.parentMenu.orientation; } this.parentMenu = null; this.path = "0"; this.mainElement.setAttribute ("tabindex", this.tabIndex); this.mainElement.setAttribute ("role", this.orientation == "vertical" ? "menu" : "menubar"); with (this.mainElement.style) { width = "auto"; position = "relative"; } } if (this.level > 0) { Sys.WebForms.Menu.Helpers.appendCssClass (this.mainElement, this.menuType); } if (this.level <= 1) Sys.WebForms.Menu.Helpers.setFloat (this.mainElement, "left"); this.loadItems (); } Sys.WebForms.Menu.Helpers = { __subMenuCounter: 0, __menuItems: [], __popupToClose: null, setPopupToClose: function (element) { this.__popupToClose = element; }, getPopupToClose: function () { return this.__popupToClose; }, setFloat: function (element, side) { /* For standards-compliant browsers */ element.style.cssFloat = "left"; /* For IE */ element.style.styleFloat = "left"; }, appendCssClass: function (element, className) { if (element == null || className == null) return; var cname = element.className; if (cname == null || cname == "") cname = className; else cname += " " + className; element.className = cname; }, highlight: function (element) { if (element == null) return; if (element.classList.contains ("highlighted")) return; element.classList.add ("highlighted"); }, unhighlight: function (element) { if (element == null) return; if (!element.classList.contains ("highlighted")) return; element.classList.remove ("highlighted"); }, getNextSubMenuId: function () { return ++this.__subMenuCounter; }, addMenuItem: function (item) { if (item == null) return; if (!(item instanceof Sys.WebForms.MenuItem)) throw "item must be an instance of Sys.WebForms.MenuItem"; if (this.__menuItems [item.path] != null) throw "item already exists (path " + item.path + ")"; this.__menuItems [item.path] = item; }, getMenuItem: function (element) { if (element == null) return null; var itemPath = element ["__MonoMenuItemPath"]; if (itemPath == null) return null; return this.__menuItems [itemPath]; }, addEventHandler: function (element, eventType, handler, capture) { /* There's also element.attachEvent, but it changes handler semantics on IE, so we don't * even take it into consideration. */ if (element.addEventListener) element.addEventListener(eventType, handler, !!capture); else element ["on" + eventType] = handler; } }; Sys.WebForms.Menu.prototype.loadItems = function () { var children = this.mainElement.childNodes; var count = children.length; var child; for (var i = 0; i < count; i++) { child = children [i]; if (child.nodeType != 1) continue; if (child.tagName == "UL") { var submenu = new Sys.WebForms.Menu ({ element: child, disappearAfter: this.disappearAfter, orientation: this.orientation, disabled: this.disabled, level: this.level + 1, tabIndex: this.tabIndex, parentMenu: this}); } else if (child.tagName == "LI") { var menuItem = new Sys.WebForms.MenuItem ({ element: child, menuType: this.menuType, disappearAfter: this.disappearAfter, orientation: this.orientation, disabled: this.disabled, level: this.level + 1, tabIndex: this.tabIndex, parentMenu: this}); } } } Sys.WebForms.Menu.prototype.getNextMenuItemId = function () { return ++this.menuItemIndex; } Sys.WebForms.MenuItem = function (options) { if (options == null) throw "Sys.WebForms.MenuItem constructor requires options to be not null."; if (options.element == null) throw "options.element must be set."; if (options.menuType == null) throw "options.menuType must be set."; if (options.parentMenu == null) throw "options.parentMenu is required."; this.element = options.element; this.menuType = options.menuType; this.parentMenu = options.parentMenu; this.path = this.parentMenu.path + this.parentMenu.getNextMenuItemId (); var children = this.element.childNodes; var child; var subMenu = null; for (var i = 0; i < children.length; i++) { child = children [i]; if (child.nodeType != 1) continue; switch (child.tagName) { case "A": Sys.WebForms.Menu.Helpers.appendCssClass (child, this.menuType); Sys.WebForms.Menu.Helpers.addEventHandler (child, "mouseover", this.mouseOverHandler); Sys.WebForms.Menu.Helpers.addEventHandler (child, "mouseout", this.mouseOutHandler); child.setAttribute ("tabindex", "-1"); break; case "UL": this.subMenu = new Sys.WebForms.Menu ({ element: child, disappearAfter: options.disappearAfter, orientation: options.orientation, disabled: options.disabled, level: options.level, tabIndex: options.tabIndex, parentMenu: options.parentMenu}); if (this.subMenu.menuType == "dynamic") { var topValue; var leftValue; if (this.subMenu.orientation == "horizontal" && this.subMenu.parentMenu != null && this.subMenu.parentMenu.menuType == "static") { topValue = "100%"; leftValue = "0px"; } else { topValue = "0px"; leftValue = "100%"; } with (this.subMenu.mainElement.style) { display = "none"; position = "absolute"; top = topValue; left = leftValue; } } Sys.WebForms.Menu.Helpers.appendCssClass (this.element, "has-popup"); this.element.setAttribute ("aria-haspopup", this.subMenu.mainElement.id); Sys.WebForms.Menu.Helpers.addEventHandler (this.element, "mouseover", this.mouseOverHandler); Sys.WebForms.Menu.Helpers.addEventHandler (this.element, "mouseout", this.mouseOutHandler); break; } } Sys.WebForms.Menu.Helpers.appendCssClass (this.element, this.menuType); this.element.style.position = "relative"; this.element.setAttribute ("role", "menuitem"); this.element ["__MonoMenuItemPath"] = this.path; if (this.parentMenu.orientation == "horizontal" && this.parentMenu.menuType == "static") Sys.WebForms.Menu.Helpers.setFloat (this.element, "left"); Sys.WebForms.Menu.Helpers.addMenuItem (this); } Sys.WebForms.MenuItem.prototype.log = function (msg) { if (console && console.log) console.log (msg); } Sys.WebForms.MenuItem.prototype.hide = function (popup, leaveParentOpen) { if (popup == null || popup.mainElement == null || popup.menuType == "static") return; var current = popup; while (current != null) { if (current.menuType == "static" || (leaveParentOpen && current == this.parentMenu)) break; if (current.mainElement != null) { current.mainElement.style.display = "none"; Sys.WebForms.Menu.Helpers.unhighlight (current.mainElement.parentNode.children [0]); } if (current.hideTimerId != null) { window.clearTimeout (current.hideTimerId); current.hideTimerId = null; } current = current.parentMenu; } } Sys.WebForms.MenuItem.prototype.isPopupChildOf = function (popup, element) { if (popup == null || element == null) return false; var cur = popup.parentNode; while (cur != null) { if (cur == element) return true; cur = cur.parentNode; } return false; } Sys.WebForms.MenuItem.prototype.onMouseOver = function (popupId) { var popup; var noPopup = popupId == null || popupId == ""; if (noPopup) popup = null; else popup = document.getElementById (popupId); var cur = Sys.WebForms.Menu.Helpers.getPopupToClose (); if (cur != null) { if (cur.hideTimerId != null) { window.clearTimeout (cur.hideTimerId); cur.hideTimerId = null; } if (popup == null || (popup != cur.mainElement && !this.isPopupChildOf (popup, cur.mainElement))) this.hide (cur, true); Sys.WebForms.Menu.Helpers.setPopupToClose (null); } if (noPopup) return; if (popup == null) throw "Popup with id '" + popupId + "' could not be found."; if (cur != null && popup != cur.mainElement) this.hide (cur, true); if (popup.style.display != "block") popup.style.display = "block"; Sys.WebForms.Menu.Helpers.highlight (popup.parentNode.children [0]); } Sys.WebForms.MenuItem.prototype.onMouseOut = function (popupId) { if (popupId == null || popupId == "") return; var popup = document.getElementById (popupId); if (popup == null) throw "Popup with id '" + popupId + "' could not be found."; var cur = this.subMenu; if (cur != null) { var myself = this; cur.hideTimerId = window.setTimeout (function () { myself.hide (cur, false); }, this.subMenu.disappearAfter); } Sys.WebForms.Menu.Helpers.setPopupToClose (cur); } Sys.WebForms.MenuItem.prototype.mouseOverHandler = function (e) { if (this.nodeName == "A") { if (this.parentNode.getAttribute ("role") != "menuitem" || this.parentNode.getAttribute ("aria-haspopup") != null) return; Sys.WebForms.Menu.Helpers.highlight (this); return; } var menuItem = Sys.WebForms.Menu.Helpers.getMenuItem (this); if (menuItem == null || !(menuItem instanceof Sys.WebForms.MenuItem)) { e.returnResult = false; e.cancelBuble = false; throw "MenuItem could not be found in mouseover handler."; } menuItem.onMouseOver (this.getAttribute ("aria-haspopup")); menuItem.finalizeEvent (e); } Sys.WebForms.MenuItem.prototype.mouseOutHandler = function (e) { if (this.nodeName == "A") { if (this.parentNode.getAttribute ("role") != "menuitem" || this.parentNode.getAttribute ("aria-haspopup") != null) return; Sys.WebForms.Menu.Helpers.unhighlight (this); return; } var menuItem = Sys.WebForms.Menu.Helpers.getMenuItem (this); if (menuItem == null || !(menuItem instanceof Sys.WebForms.MenuItem)) { e.returnResult = false; e.cancelBuble = false; throw "MenuItem could not be found in mouseout handler."; } menuItem.onMouseOut (this.getAttribute ("aria-haspopup")); menuItem.finalizeEvent (e); } Sys.WebForms.MenuItem.prototype.finalizeEvent = function (e) { /* For standards-compliant browsers */ if (e != null) { if (e.preventDefault) e.preventDefault(); else e.returnResult = false; if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; } /* For IE */ if (window.event != null) window.event.cancelBubble = true; }