a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
462 lines
13 KiB
JavaScript
462 lines
13 KiB
JavaScript
/*
|
|
* Authors:
|
|
* Marek Habersack <grendel@twistedcode.net>
|
|
*
|
|
* (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;
|
|
} |