/******************************************************************************************
* Developed by Shawn Lawsure - shawnl@maine.rr.com - http://www.linkedin.com/in/shawnlawsure
NOTE: see ZenithControlBase.ts for documentation on the public members that are inherited
by this control.
* Example of use for top menu:
var cMenu = new Zenith.Menu('baseElement')
cMenu.addZenithEventListener(Zenith.ZenithEvent.EventType.Selected, function (id, text, contextElement)
{
var span = document.getElementById('output1');
if (span)
span.textContent = id + ' : ' + text;
if (contextElement)
span.textContent += ' : ' + contextElement.tagName;
//alert(span.textContent);
//alert(id + ' : ' + text);
//var span2 = document.getElementById('output2');
//span2.textContent = '';
});
var editMenu = cMenu.AddMenuItem(1, "Edit");
editMenu.AddMenuItem(2, "Edit 1");
editMenu.AddMenuItem(3, "Edit 2");
var copyMenu = cMenu.AddMenuItem(4, "Copy");
copyMenu.AddMenuItem(5, "Copy Func 1");
copyMenu.AddMenuItem(6, "Copy Func 2", "Copy.png");
copyMenu.AddMenuItem(7, "Copy Func 3");
var copyMenu2 = copyMenu.AddMenuItem(8, "Copy Func 4");
copyMenu.AddMenuItem(9, "Copy Func 5");
copyMenu2.AddMenuItem(10, "Copy Func 1");
copyMenu2.AddMenuItem(11, "Copy Func 2");
var pasteMenu = cMenu.AddMenuItem(12, "Paste");
pasteMenu.AddMenuItem(13, "Paste 1");
pasteMenu.AddMenuItem(14, "Paste 2");
var deleteMenu = cMenu.AddMenuItem(15, "Delete");
deleteMenu.AddMenuItem(16, "Delete 1");
deleteMenu.AddMenuItem(17, "Delete 2");
cMenu.Build();
* Example of use for context menu:
var cMenu = new Zenith.Menu('baseElement', true)
cMenu.contextElementType = Zenith.Menu.ContextElementType.Button;
//var btn = document.getElementById('testPopup');
//cMenu.AddContextElement(btn)
//cMenu.AddContextElement(testGrid.ParentElement)
cMenu.addZenithEventListener(Zenith.ZenithEvent.EventType.Selected, function (id, text, contextElement)
{
var span = document.getElementById('output1');
if (span)
span.textContent = id + ' : ' + text;
if (contextElement)
span.textContent += ' : ' + contextElement.tagName;
//alert(id + ' : ' + text);
//var span2 = document.getElementById('output2');
//span2.textContent = '';
});
cMenu.AddMenuItem(1, "Edit");
var copyMenu = cMenu.AddMenuItem(2, "Copy...", "Copy.png"); // 3rd parameter is URL of image to display with menu item.
cMenu.AddMenuItem(3, "Paste");
cMenu.AddMenuItem(4, "Delete");
copyMenu.AddMenuItem(5, "Copy Func 1");
copyMenu.AddMenuItem(6, "Copy Func 2");
copyMenu.AddMenuItem(7, "Copy Func 3");
var copyMenu2 = copyMenu.AddMenuItem(8, "Copy Func 4...");
copyMenu.AddMenuItem(9, "Copy Func 5");
copyMenu2.AddMenuItem(10, "Copy Func 1");
copyMenu2.AddMenuItem(11, "Copy Func 2");
cMenu.Build();
* CSS Class Names (hard-coded) - set these in your own CSS file:
> ZenithContextMenuTable
> ZenithMenuRow
> ZenithMenuItemLabel_Unselected
> ZenithMenuItem_SubMenuIndicator
******************************************************************************************/
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
///<reference path='ZenithControlBase.ts'/>
///<reference path='ZenithList.ts'/>
var Zenith;
(function (Zenith) {
var zenithTopLevelMenu = null;
var Menu = (function (_super) {
__extends(Menu, _super);
// =============== Constructor ====================================================
// The id of a 'div' HTML element must be passed in when creating this object type.
function Menu(baseDivElementId, isContextMenu, isTopLevel) {
if (typeof isContextMenu === "undefined") { isContextMenu = false; }
if (typeof isTopLevel === "undefined") { isTopLevel = true; }
_super.call(this, baseDivElementId);
this.hoverBackgroundColor = 'white';
// =============== Private Attributes =================================================
this.items = new Array();
this.IsContextMenu = false;
this.isTopLevel = false;
this.menuPosition = Zenith.Menu.MenuPosition.Top;
this.contextElementType = Zenith.Menu.ContextElementType.None;
this.contextElements = new Array();
this.IsMouseCaptured = false;
this.IsContextMenu = isContextMenu;
this.isTopLevel = isTopLevel;
if (this.isTopLevel)
this.popupClickType = this.IsContextMenu ? Zenith.ControlBase.ClickTypePopup.Right : Zenith.ControlBase.ClickTypePopup.Left;
if (isTopLevel)
zenithTopLevelMenu = this;
}
// =============== Public Methods ====================================================
Menu.prototype.AddContextElement = function (contextElement) {
if (!(contextElement instanceof HTMLElement))
throw Error('An HTML element must be passed into the AddContextElement method on a ContextMenu.');
this.contextElements.push(contextElement);
};
Menu.prototype.AddMenuItem = function (id, text, imageURL) {
var menuItem = new MenuItem(id, text, imageURL);
this.items.push(menuItem);
return menuItem;
};
Menu.prototype.AddZenithEventListener = function (eventType, listener) {
this.events.push(new Zenith.ZenithEvent(eventType, listener));
};
Menu.prototype.IsVisible = function () {
return (this.BaseElement.style.visibility == 'visible');
};
Menu.prototype.Build = function (firstLevelSubMenu) {
var _this = this;
if (typeof firstLevelSubMenu === "undefined") { firstLevelSubMenu = false; }
this.Clear();
this.popupOffset = 0;
this.mouseOverEventHandler();
var table = document.createElement('table');
this.BaseElement.appendChild(table);
this.ParentElement = table;
table.cellPadding = '0px';
table.cellSpacing = '0px';
table.className = 'ZenithContextMenuTable';
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var trow, tcell;
for (var index = 0; index < this.items.length; index++) {
if (this.IsContextMenu || index == 0 || !this.isTopLevel) {
trow = document.createElement('tr');
tbody.appendChild(trow);
trow.setAttribute('value', this.items[index].Id);
var css = document.createElement("style");
css.type = "text/css";
if (!this.IsContextMenu && this.isTopLevel)
css.innerHTML = "td:hover { border-style: none !important; background-color: " + this.hoverBackgroundColor + "; }";
else {
trow.className = "ZenithMenuRow";
css.innerHTML = ".ZenithMenuRow:hover { border-style: none !important; background-color: " + this.hoverBackgroundColor + "; }";
}
trow.appendChild(css);
this.addEventListener(trow, 'click', function (event) {
_this.selectedEventHandler(event);
});
}
if (this.IsContextMenu || !this.isTopLevel) {
tcell = document.createElement('td');
trow.appendChild(tcell);
tcell.setAttribute('ZenithMenuElement', 'true');
tcell.setAttribute('value', this.items[index].Id);
tcell.height = 25;
if (this.UseDefaultStyles) {
tcell.style.paddingLeft = '5px';
tcell.style.paddingRight = '5px';
tcell.style.paddingTop = '2px';
tcell.style.paddingBottom = '2px';
}
if (this.items[index].ImageUrl && this.items[index].ImageUrl.length > 0) {
var icon = document.createElement('img');
tcell.appendChild(icon);
icon.setAttribute('ZenithMenuElement', 'true');
icon.setAttribute('value', this.items[index].Id);
icon.width = 20;
icon.height = 20;
icon.src = this.items[index].ImageUrl;
}
}
tcell = document.createElement('td');
trow.appendChild(tcell);
tcell.setAttribute('ZenithMenuElement', 'true');
tcell.setAttribute('value', this.items[index].Id);
if (this.items[index].subMenu) {
if (this.IsContextMenu || !this.isTopLevel)
this.items[index].subMenu.popupElement = trow;
else
this.items[index].subMenu.popupElement = tcell;
}
var label = document.createElement('label');
tcell.appendChild(label);
label.setAttribute('ZenithMenuElement', 'true');
if (this.UseDefaultStyles) {
label.style.marginLeft = '10px';
label.style.marginRight = '10px';
}
label.setAttribute('value', this.items[index].Id);
label.textContent = this.items[index].Text;
label.innerHTML = this.items[index].Text;
label.className = 'ZenithMenuItemLabel_Unselected';
if (!this.isTopLevel) {
tcell = document.createElement('td');
trow.appendChild(tcell);
// Right arrow for submenu.
if (this.items[index].subMenu) {
var arrowDiv = document.createElement('div');
tcell.appendChild(arrowDiv);
tcell.setAttribute('ZenithMenuElement', 'true');
tcell.setAttribute('value', this.items[index].Id);
arrowDiv.className = 'ZenithMenuItem_SubMenuIndicator';
arrowDiv.style.borderTopStyle = 'solid';
arrowDiv.style.borderTopWidth = '5px';
arrowDiv.style.borderTopColor = 'transparent';
arrowDiv.style.borderBottomStyle = 'solid';
arrowDiv.style.borderBottomWidth = '5px';
arrowDiv.style.borderBottomColor = 'transparent';
arrowDiv.style.borderLeftStyle = 'solid';
arrowDiv.style.borderLeftWidth = '5px';
arrowDiv.style.borderLeftColor = 'black';
arrowDiv.setAttribute('ZenithMenuElement', 'true');
arrowDiv.setAttribute('value', this.items[index].Id);
}
}
}
if (this.isTopLevel) {
if (!_super.prototype.IsPopup.call(this) && this.IsContextMenu)
this.popupElement = document.documentElement;
this.mouseDownEventHandler();
this.keyDownHandler();
// Disable default context menu.
if (this.IsContextMenu)
this.addEventListener(document, 'contextmenu', function (event) {
event.preventDefault();
});
}
if (!this.IsContextMenu && firstLevelSubMenu && this.menuPosition == Zenith.Menu.MenuPosition.Top) {
this.PopUpPosition = 'belowright';
this.PopUpDirection = 'down';
}
// We need to let all of the sub menus build before hiding them so we pass in false
// to the base class Build method and then below, after building all of them, we
// hide all of them.
_super.prototype.Build.call(this, false, false);
if (this.isTopLevel)
_super.prototype.SetPopupEventHandlers.call(this, false, false, false);
for (var index = 0; index < this.items.length; index++) {
for (var eventIndex = 0; eventIndex < this.events.length; eventIndex++)
if (this.events[eventIndex].listener)
this.items[index].AddZenithEventListener(this.events[eventIndex].eventType, this.events[eventIndex].listener);
if (this.items[index].subMenu)
this.items[index].Build(this.isTopLevel);
}
if (this.popupElement)
this.BaseElement.style.visibility = 'collapse';
for (var index = 0; index < this.items.length; index++)
if (this.items[index].subMenu)
this.items[index].Hide();
};
Menu.prototype.Close = function (closeTopLevel) {
if (typeof closeTopLevel === "undefined") { closeTopLevel = true; }
if (closeTopLevel)
_super.prototype.Close.call(this);
for (var index = 0; index < this.items.length; index++)
if (this.items[index].subMenu)
this.items[index].subMenu.Close();
this.IsMouseCaptured = false;
};
// =============== Event Handlers ====================================================
Menu.prototype.keyDownHandler = function () {
var _this = this;
// Escape key listener.
this.addEventListener(document, 'keydown', function (event) {
var keyEvent = event;
if ((event && keyEvent.keyCode) && keyEvent.keyCode == 27 || (window.event && window.event.keyCode && window.event.keyCode == 27))
if (_this.BaseElement.style.visibility == 'visible' || _this.BaseElement.style.visibility == '')
_this.Close(_this.IsContextMenu);
});
};
Menu.prototype.mouseDownEventHandler = function () {
var _this = this;
this.addEventListener(document, 'mousedown', function (event) {
var mouseEvent = event;
var targetElement = mouseEvent.target;
var menuItemId;
if (targetElement.getAttribute('ZenithMenuElement'))
menuItemId = targetElement.getAttribute('value');
_this.recurseMenuItem = null;
for (var index = 0; index < _this.items.length; index++)
_this.recurseMenu(_this.items[index], menuItemId);
var selectedMenu;
if (_this.recurseMenuItem && _this.recurseMenuItem.subMenu)
selectedMenu = _this.recurseMenuItem.subMenu;
else
selectedMenu = _this;
var selectedTarget = targetElement;
while (targetElement && targetElement != selectedMenu.BaseElement && targetElement != selectedMenu.popupElement && targetElement != document.documentElement)
targetElement = targetElement.parentElement;
if (targetElement && selectedMenu && selectedMenu.popupElement == targetElement && ((selectedMenu.popupClickType == Zenith.ControlBase.ClickTypePopup.Left && mouseEvent.button == Zenith.ControlBase.ClickTypePopup.Left) || (selectedMenu.popupClickType == Zenith.ControlBase.ClickTypePopup.Right && mouseEvent.button == Zenith.ControlBase.ClickTypePopup.Right))) {
if (!_this.IsContextMenu)
_this.IsMouseCaptured = true;
if (_this.IsContextMenu && _this.contextElementCheck(selectedTarget) && !_this.recurseMenuItem) {
selectedMenu.BaseElement.style.posLeft = mouseEvent.x;
selectedMenu.BaseElement.style.posTop = mouseEvent.y;
if (!selectedMenu.IsVisible()) {
_this.SetPopup(true);
_this.OnPopupElement();
}
}
//else if (!this.IsContextMenu)
// this.Close(false);
} else if (!_this.recurseMenuItem)
_this.Close(_this.IsContextMenu);
});
};
Menu.prototype.mouseOverEventHandler = function () {
var _this = this;
this.addEventListener(this.BaseElement, 'mouseover', function (event) {
var mouseEvent = event;
var targetElement = mouseEvent.srcElement;
if (!targetElement)
targetElement = mouseEvent.target;
//targetElement = <HTMLElement>document.elementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
var menuItemId;
if (targetElement.getAttribute('ZenithMenuElement'))
menuItemId = targetElement.getAttribute('value');
for (var index = 0; index < _this.items.length; index++) {
if (_this.items[index].Id == menuItemId && _this.items[index].subMenu && !_this.items[index].subMenu.IsVisible() && (!_this.isTopLevel || _this.IsMouseCaptured || _this.IsContextMenu)) {
_this.items[index].subMenu.SetPopup();
_this.items[index].subMenu.OnPopupElement();
} else if (_this.items[index].Id != menuItemId && _this.items[index].subMenu && _this.items[index].subMenu.IsVisible() && (_this.IsContextMenu || _this.IsMouseCaptured))
_this.items[index].subMenu.Close();
}
if (!menuItemId)
_this.IsMouseCaptured = false;
});
};
Menu.prototype.selectedEventHandler = function (event) {
var targetElement = event.target;
if (targetElement) {
var menuItemId = targetElement.getAttribute('value');
// Get the corresponding menu item.
this.recurseMenuItem = null;
for (var index = 0; index < this.items.length; index++)
this.recurseMenu(this.items[index], menuItemId);
// Get text value of the menu item.
var menuText;
if (this.recurseMenuItem)
menuText = this.recurseMenuItem.Text;
else {
var labels = targetElement.getElementsByTagName('label');
if (labels.length > 0) {
var label = labels[0];
if (label)
menuText = label.textContent;
}
}
if (!this.recurseMenuItem.subMenu)
_super.prototype.ExecuteEvent.call(this, Zenith.ZenithEvent.EventType.Selected, [menuItemId, menuText, this.currentContextElement]);
if (this.recurseMenuItem && this.recurseMenuItem.subMenu) {
if (!this.recurseMenuItem.subMenu.IsVisible()) {
if (this.isTopLevel)
for (var index = 0; index < this.items.length; index++)
if (this.items[index].subMenu && this.items[index].subMenu != this.recurseMenuItem.subMenu)
this.items[index].subMenu.Close();
this.recurseMenuItem.subMenu.SetPopup();
this.recurseMenuItem.subMenu.OnPopupElement();
}
} else if (zenithTopLevelMenu)
zenithTopLevelMenu.Close(this.IsContextMenu);
}
};
// =============== Private Methods ===================================================
Menu.prototype.recurseMenu = function (menuItem, menuItemId) {
if (menuItem.Id == menuItemId)
this.recurseMenuItem = menuItem;
else if (menuItem.subMenu)
for (var index = 0; index < menuItem.subMenu.items.length; index++)
this.recurseMenu(menuItem.subMenu.items[index], menuItemId);
};
Menu.prototype.contextElementCheck = function (element) {
this.currentContextElement = element;
// If the ContextElementType is not 'None' then try to match it with the element type passed in.
if (this.contextElementType == Menu.ContextElementType.Any)
return true;
if (this.contextElementType == Menu.ContextElementType.Document && element == document.documentElement)
return true;
if (this.contextElementType == Menu.ContextElementType.Image && element instanceof HTMLImageElement)
return true;
if (this.contextElementType == Menu.ContextElementType.TextInput && element instanceof HTMLInputElement && element.type == 'text')
return true;
if (this.contextElementType == Menu.ContextElementType.Button && element instanceof HTMLInputElement && element.type == 'button')
return true;
if (this.contextElementType == Menu.ContextElementType.TableRow) {
var targetElement = element;
while (targetElement && !(targetElement instanceof HTMLTableRowElement))
targetElement = targetElement.parentElement;
this.currentContextElement = targetElement;
if (targetElement)
return true;
}
// If we didn't match on ContextElementType then check whether the passed in element is in the list of context elements.
if (this.contextElements) {
var targetElement = element;
while (targetElement) {
for (var index = 0; index < this.contextElements.length; index++) {
if (this.contextElements[index] === targetElement) {
this.currentContextElement = this.contextElements[index];
return true;
}
}
targetElement = targetElement.parentElement;
}
}
return false;
};
Menu.MenuPosition = { Top: 1, Left: 2 };
Menu.ContextElementType = { None: 0, Any: 1, Document: 2, TextInput: 3, Image: 4, Button: 5, TableRow: 6 };
return Menu;
})(Zenith.ControlBase);
Zenith.Menu = Menu;
var MenuItem = (function () {
// =============== Constructor ==================================================
function MenuItem(id, text, imageURL) {
if (typeof imageURL === "undefined") { imageURL = ''; }
this.subMenu = null;
this.Id = id;
this.Text = text;
this.ImageUrl = imageURL;
}
// =============== Public Methods ====================================================
MenuItem.prototype.AddMenuItem = function (id, text, imageURL) {
if (!this.subMenu)
this.CreateSubMenu();
return this.subMenu.AddMenuItem(id, text, imageURL);
};
MenuItem.prototype.Build = function (firstLevelSubMenu) {
if (typeof firstLevelSubMenu === "undefined") { firstLevelSubMenu = false; }
if (this.subMenu)
this.subMenu.Build(firstLevelSubMenu);
};
MenuItem.prototype.AddZenithEventListener = function (eventType, listener) {
if (this.subMenu)
this.subMenu.AddZenithEventListener(eventType, listener);
};
MenuItem.prototype.Hide = function () {
if (this.subMenu && this.subMenu.BaseElement)
this.subMenu.BaseElement.style.visibility = 'collapse';
};
MenuItem.prototype.CreateSubMenu = function () {
var baseElement = document.createElement('div');
document.documentElement.appendChild(baseElement);
baseElement.id = 'ZenithSubMenu_' + this.Id;
this.subMenu = new Menu(baseElement.id, zenithTopLevelMenu && zenithTopLevelMenu.IsContextMenu, false);
};
return MenuItem;
})();
Zenith.MenuItem = MenuItem;
})(Zenith || (Zenith = {}));