// Licensed Materials - Property of IBM
//
// IBM Cognos Products: ps
//
// (C) Copyright IBM Corp. 2005, 2014
//
// US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
// Copyright (C) 2008 Cognos ULC, an IBM Company. All rights reserved.
// Cognos and the Cognos logo are trademarks of Cognos ULC, (formerly Cognos Incorporated).
//static property an array that has all the instances of CCPopupMenu
CCPopupMenu.menus = [];
//static property the currently active menu
CCPopupMenu.activeMenu = null;
//Used to temporarily ignore all onclick events - this mechanism
//gives other containers a chance to react to the onclick event.
CCPopupMenu.bIgnoreHideActiveMenu = false;
CCPopupMenu.minSize = 3;
var sPopUpWebRoot = ".."; // default this to a relative location
if (window.g_PS_getWebRoot) {
if (g_PS_getWebRoot() != "") {
sPopUpWebRoot = g_PS_getWebRoot(); // set up the official path to the C8 web root
}
}
CCPopupMenu.imagesRoot = sPopUpWebRoot + "/ps";
CCPopupMenu.psImagesPath = CCPopupMenu.imagesRoot + "/images";
CCPopupMenu.portalImagesPath = CCPopupMenu.imagesRoot + "/portal/images";
//creates an event handler for the given event. Note that events should be assume the w3c names not the
//ie names as this function will create the correct event type name based on the browser
function addEvent(obj, evType, fn) {
if (obj.addEventListener) {
obj.addEventListener(evType, fn, false);
return true;
} else if (obj.attachEvent) {
var r = obj.attachEvent("on" + evType, fn);
return r;
} else {
return false;
}
}
var extensions = {
associate: function (target, obj, methodName) {
return function (e) {
e = e || window.event;
return obj[methodName](e, target);
};
}
};
//removes the function fn from the event listeners for the object and the particular event
function removeEvent(obj, type, fn) {
if (obj.removeEventListener) {
return obj.removeEventListener(type, fn, false);
} else if (obj.detachEvent) {
return obj.detachEvent('on' + type, fn);
} else {
return false;
}
}
//Stops the event at current event handler
function haltEventProcessing(event) {
event.cancelBubble = 'true';
event.returnValue = 'false';
if (event.stopPropagation) {
event.stopPropagation();
event.preventDefault();
}
return false;
}
//returns the width of the browser window
function windowWidth() {
if (window.innerWidth) {
return window.innerWidth;
} else {
return document.body.offsetWidth - 20;
}
}
//returns the height of the drop down based on the style or the offsetHeight
function getDropDownHeight(dropDownElement) {
var indexOfPX;
if (dropDownElement.style.height == "") {
var height = dropDownElement.offsetHeight;
if (window.navigator.userAgent.indexOf("Gecko") != -1) {
var paddingTop = dropDownElement.style.paddingTop;
indexOfPX = paddingTop.indexOf("px");
var v = ((indexOfPX != -1) ? parseInt(paddingTop.substring(0, indexOfPX), 10) : parseInt(paddingTop, 10));
height -= (isNaN(v) ? 0 : v);
var paddingBottom = dropDownElement.style.paddingBottom;
indexOfPX = paddingBottom.indexOf("px");
v = ((indexOfPX != -1) ? parseInt(paddingBottom.substring(0, indexOfPX), 10) : parseInt(paddingBottom, 10));
height -= (isNaN(v) ? 0 : v);
var borderWidth = 1;
height -= (2 * borderWidth);
}
return height;
} else {
//return the style height converted to an integer
var styleHeight = dropDownElement.style.height;
indexOfPX = styleHeight.indexOf("px");
if (indexOfPX != -1) {
styleHeight = styleHeight.substring(0, indexOfPX);
}
return parseInt(styleHeight, 10);
}
}
//returns the width of the drop down based on the style or the offsetWidth
function getDropDownWidth(dropDownElement) {
var indexOfPX;
if (dropDownElement.style.width == "") {
var width = dropDownElement.offsetWidth;
if (window.navigator.userAgent.indexOf("Gecko") != -1) {
var paddingLeft = dropDownElement.style.paddingLeft;
indexOfPX = paddingLeft.indexOf("px");
var v = ((indexOfPX != -1) ? parseInt(paddingLeft.substring(0, indexOfPX), 10) : parseInt(paddingLeft, 10));
width -= (isNaN(v) ? 0 : v);
var paddingRight = dropDownElement.style.paddingRight;
indexOfPX = paddingRight.indexOf("px");
v = ((indexOfPX != -1) ? parseInt(paddingRight.substring(0, indexOfPX), 10) : parseInt(paddingRight, 10));
width -= (isNaN(v) ? 0 : v);
var borderWidth = 1;
width -= (2 * borderWidth);
}
return width;
} else {
//return teh style width converted to an integer
var styleWidth = dropDownElement.style.width;
indexOfPX = styleWidth.indexOf("px");
if (indexOfPX != -1) {
styleWidth = styleWidth.substring(0, indexOfPX);
}
return parseInt(styleWidth, 10);
}
}
//get the offset for the scrolling
function getScrollXY() {
var scrOfX = 0, scrOfY = 0;
if (typeof window.pageYOffset == 'number') {
//Netscape compliant
scrOfY = window.pageYOffset;
scrOfX = window.pageXOffset;
} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
//DOM compliant
scrOfY = document.body.scrollTop;
scrOfX = document.body.scrollLeft;
} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
//IE6 standards compliant mode
scrOfY = document.documentElement.scrollTop;
scrOfX = document.documentElement.scrollLeft;
}
return [scrOfX, scrOfY];
}
//returns the width of the browser window
function windowHeight() {
//have to account for the vertical scroll to get a good idea where we are at
if (window.innerHeight) {
return window.innerHeight + getScrollXY()[1];
} else {
return document.body.offsetHeight + getScrollXY()[1];
}
}
//unfortunately netscape and firefox do not correctly support overflowY. To enable removal of the horizontal
//scrollbar in these browsers you must use a gecko(??some component of these browsers???) specific value for overflow
//called -moz-scrollbars-vertical
function setOverflowStyle(anEl) {
//Gecko is the relevant thing we are looking for here as -moz-scrollbars-vertical is apparently defined in this component
if (window.navigator.userAgent.indexOf("Gecko") != -1) {
anEl.style.overflow = "-moz-scrollbars-vertical";
} else {
anEl.style.overflowY = "auto";
}
}
//sets the focus to the element with the id equal to the controlId of the menu associated with id
//if the element does not exist then do nothing
function CCPopupMenu_setControlFocus() {
var currentMenu = CCPopupMenu.getMenu(CCPopupMenu.activeMenu.id);
var controlElement = document.getElementById(currentMenu.controlId);
if (controlElement != null) {
controlElement.focus();
}
}
function CCPopupMenu_checkBounds(event) {
if (typeof event != "undefined" && event != null && CCPopupMenu.activeMenu.doCheckBounds) {
var tr = event.srcElement;
var table = tr.parentNode;
var id = CCPopupMenu.activeMenu.id;
if (tr.tagName == 'TR') {
if (window.event.keyCode == 27 || window.event.keyCode == 13 || window.event.keyCode == 38 || window.event.keyCode == 40) {
return true;
}
if (tr.rowIndex == 0 && event.shiftKey && event.shiftKey != false) {
CCPopupMenu.hideActiveMenu();
CCPopupMenu.setControlFocus();
return false;
} else if ((tr.rowIndex + 1) == table.rows.length && window.event.shiftKey == false) {
CCPopupMenu.hideActiveMenu();
CCPopupMenu.setControlFocus();
return false;
}
}
}
return true;
}
//static method to close the currextly open drop down menu
function CCPopupMenu_hideActiveMenu() {
if (!CCPopupMenu.bIgnoreHideActiveMenu && CCPopupMenu.activeMenu != null) {
CCPopupMenu.activeMenu.activeMenuItemIndex = -1;
CCPopupMenu.activeMenu.removeDropDown();
}
}
function CCPopupMenu_ignoreHideActiveMenu(ignore) {
CCPopupMenu.bIgnoreHideActiveMenu = (ignore == "ignore") ? true : false;
}
//static method to create an iframe that is positioned under the dropdown so that controls don't show through
function CCPopupMenu_createInsulatingIframe(currentMenu, divEl) {
var iframeEl = document.createElement("iframe");
iframeEl.id = currentMenu.id + "inslIframe";
iframeEl.setAttribute("role","presentation");
iframeEl.title = currentMenu.id;
iframeEl.style.display = "block";
iframeEl.style.border = "0px";
iframeEl.style.padding = "2px";
iframeEl.style.position = "absolute";
iframeEl.style.zIndex = "1";
iframeEl.tabIndex = "-1";
iframeEl.src = CCPopupMenu.psImagesPath + "/space.gif";
var controlEl = document.getElementById(currentMenu.controlId);
controlEl.appendChild(iframeEl);
iframeEl.style.top = divEl.style.top;
iframeEl.style.left = divEl.style.left;
iframeEl.style.right = divEl.style.right;
iframeEl.style.height = divEl.offsetHeight;
iframeEl.style.width = divEl.offsetWidth;
}
function CCPopupMenu_sizeDropDown(dropDownElement, maxHeight, elementHeight) {
//size the height of the drop down if a height was given
//this is to support scrolling of menu items (to ensure the drop down is not humungous)
if (this.mnHeight != -1) {
var elems = dropDownElement.getElementsByTagName('td');
providedHeight = elementHeight * this.mnHeight;
var allowableHeight = Math.min(maxHeight, providedHeight);
allowableHeight = providedHeight;
if (dropDownElement.offsetHeight > allowableHeight) {
dropDownElement.style.height = allowableHeight + "px";
}
} else {
if (getDropDownHeight(dropDownElement) > maxHeight) {
dropDownElement.style.height = maxHeight + "px";
}
}
}
//updates the height of the browser and determines whether to open the browser up or down
function CCPopupMenu_fitHeightToBrowser(x, y) {
var dropDownElement = this.dropDownElement;
getDropDownWidth(dropDownElement);
var winHeight = windowHeight();
var originalMenuHeight = this.mnHeight;
var originalHeight = getDropDownHeight(dropDownElement);
var originalWidth = getDropDownWidth(dropDownElement);
dropDownElement.style.height = originalHeight + "px";
var controlElement = document.getElementById(this.controlId);
var controlElementTop = y;
var controlElementHeight = 0;
if (controlElement != null) {
controlElementTop = controlElement.offsetTop;
controlElementHeight = getDropDownHeight(controlElement);
}
//determine how much space we have above the control element and how much space we have below
var spaceAboveControl = Math.max(0, controlElementTop);
var spaceBelowControl = Math.max(0, winHeight - controlElementTop - controlElementHeight);
//determine the height of a menu item
var elems = dropDownElement.getElementsByTagName('td');
var elementHeight = 20;
if (elems.length > 0) {
elementHeight = getDropDownHeight(elems[1]);
}
//find the minumum number of items to show based on what is smaller the number of menu items available or the
//default minimum items to show
var minimumDropSize = Math.min(CCPopupMenu.minSize, this.menuItems.length) * elementHeight;
//try and size the drop down as if droped below
this.sizeDropDown(dropDownElement, spaceBelowControl, elementHeight);
var downHeight = getDropDownHeight(dropDownElement);
var downWidth = getDropDownWidth(dropDownElement);
//try and size the drop down as if droped above
dropDownElement.style.height = originalHeight + "px";
dropDownElement.style.width = originalWidth + "px";
this.sizeDropDown(dropDownElement, spaceAboveControl, elementHeight);
var upHeight = getDropDownHeight(dropDownElement);
var upWidth = getDropDownWidth(dropDownElement);
dropDownElement.style.height = originalHeight + "px";
dropDownElement.style.width = originalWidth + "px";
//now check what is better to show the menu droped down or dropped up
if (downHeight < upHeight) {
//if the size of the drop down would be less than the min size in the drop down or drop up case
//then force the min size
if (upHeight < minimumDropSize) {
//if we are forcing the height to be the minimum then we may as well just open down
dropDownElement.style.height = minimumDropSize + "px";
dropDownElement.style.top = y + controlElement.offsetHeight + "px";
} else {
//in this case we should show it up
dropDownElement.style.top = (controlElementTop - upHeight) + "px";
dropDownElement.style.width = upWidth + "px";
}
} else {
//droping down is better so restore the size to the drop down scenario
//if the size of the drop down would be less than the min size in the drop down or drop up case
//then force the min size
if (downHeight < minimumDropSize) {
downHeight = minimumDropSize;
}
dropDownElement.style.width = downWidth + "px";
dropDownElement.style.height = downHeight + "px";
dropDownElement.style.top = y + controlElement.offsetHeight + "px";
}
//must check to see if we have shrunk the menu so that we need to show scrollbars
if (getDropDownHeight(dropDownElement) < originalHeight) {
//have to account for the scroll bars....if there are verticle bars then must widen the div a little
//NOTE: because we may change the width of the menu, we have to do the width positioning after this step!!!
dropDownElement.style.width = (getDropDownWidth(dropDownElement) + 20) + "px";
setOverflowStyle(dropDownElement);
}
this.mnHeight = originalMenuHeight;
}
//determines the width of the browser to ensure nothing falls off the edge of the browser
function CCPopupMenu_fitWidthToBrowser(x, y) {
var controlElement = document.getElementById(this.controlId);
if (controlElement == null) {
//if we can't find the control element....give up
return;
}
var dropDownElement = this.dropDownElement;
var rtl=document.body.dir=="rtl";
if(rtl)
CCPopupMenu_fitWidthToBrowserRTL(controlElement, dropDownElement, x, y);
else
CCPopupMenu_fitWidthToBrowserLTR(controlElement, dropDownElement, x, y);
}
//determines the width of the browser to ensure nothing falls off the edge of the browser in LTR case
function CCPopupMenu_fitWidthToBrowserLTR(controlElement, dropDownElement, x, y) {
var controlElementLeft = controlElement.offsetLeft;
//position the drop down based on the size of the browser window
var winWidth = windowWidth();
var dropDownRight = controlElementLeft + dropDownElement.offsetWidth;
//if what was provided would pass off the right of the browser
//move the popup so that is flush with the right (with a small margin) of the of the browser to get it
//close to where you wanted it but not letting anything fall off the edge
if (winWidth < dropDownRight) {
var dropDownLeft = controlElement.offsetWidth - dropDownElement.offsetWidth;
var dropDownAbsoluteLeft = controlElementLeft + dropDownLeft;
if (dropDownAbsoluteLeft < 0) {
//in this case we have very little room to show the menu so we need to position it to
//take up the entire width of the window
dropDownElement.style.left = controlElement.offsetLeft * -1;
} else {
dropDownElement.style.left = (controlElement.offsetWidth - dropDownElement.offsetWidth) + "px";
}
} else {
dropDownElement.style.left = x + "px";
}
}
//determines the width of the browser to ensure nothing falls off the edge of the browser in RTL case
function CCPopupMenu_fitWidthToBrowserRTL(controlElement, dropDownElement, x, y) {
var controlElementRight = controlElement.offsetLeft + controlElement.offsetWidth;
//position the drop down based on the size of the browser window
var winWidth = windowWidth();
var dropDownLeft = controlElementRight - dropDownElement.offsetWidth;
//if what was provided would pass off the left of the browser
//move the popup so that is flush with the left (with a small margin) of the of the browser to get it
//close to where you wanted it but not letting anything fall off the edge
if (dropDownLeft < 0) {
var dropDownRight = controlElement.offsetWidth - dropDownElement.offsetWidth;
var dropDownAbsoluteRight = controlElementRight - dropDownRight;
if (dropDownAbsoluteRight > winWidth) {
//in this case we have very little room to show the menu so we need to position it to
//take up the entire width of the window
dropDownElement.style.right = controlElement.offsetRight * -1;
} else {
//dropDownElement.style.right = (controlElement.scrollWidth - dropDownElement.scrollWidth) + "px";
dropDownElement.style.left = 0 + "px";
}
} else {
dropDownElement.style.right = x + "px";
}
}
//static method to create and show the drop down for the menu with the passed in id
function CCPopupMenu_dropDown(event, x, y, id) {
if (event.type == "keypress" && event.keyCode == 9) {
CCPopupMenu.hideActiveMenu();
return true; //Ignore tabs.
}
var currentMenu = CCPopupMenu.getMenu(id);
if (currentMenu != null) {
//check to make sure the menu was created
if (currentMenu.dropDownElement == null) {
return;
}
//make sure that if there is a menu already open to close it
var isAlreadyOpen = false;
if ((CCPopupMenu.activeMenu != null) && (CCPopupMenu.activeMenu.id == id)) {
isAlreadyOpen = CCPopupMenu.activeMenu.isOpen;
}
CCPopupMenu.hideActiveMenu();
if ((event.type == "keypress" && event.keyCode == 27) && (isAlreadyOpen)) {
return true;
}
//position the drop down based on the passed in x, and y parameters and the size of the browser window
currentMenu.fitHeightToBrowser(x, y);
currentMenu.fitWidthToBrowser(x, y);
//create an iframe so things don't peek through...no peeking allowed!
CCPopupMenu.createInsulatingIframe(currentMenu, currentMenu.dropDownElement);
//show the drop down menu and set the focus to the first menu item
currentMenu.dropDownElement.style.visibility = "visible";
CCPopupMenu.activeMenu = currentMenu;
currentMenu.isOpen = true;
//if the event is a kepress then set the focus to the first menu item so that the tabbing order appears correct
if (event.type == "keypress" || event.type == 'click') {
CCPopupMenu.activeMenu.doCheckBounds = false;
CCPopupMenu.activeMenu.activeMenuItemIndex = -1;
selectedObject = CCPopupMenu.activeMenu.getCurrentSelected();
if (!selectedObject) {
currentMenu.menuItems[0].menuItemEl.focus();
} else {
CCPopupMenu.setActiveMenuItem("current");
}
}
}
CCPopupMenu.ignoreHideActiveMenu("ignore");
setTimeout('CCPopupMenu.ignoreHideActiveMenu("unignore")', 100);
return haltEventProcessing(event);
}
//This function stops the propagation of the onclick event past the dropdown div
function CCPopupMenu_dropDownOnclick(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = 'true';
}
}
function CCPopupMenu_isTapInsideMenu(tapObject) {
var tapX = tapObject.pageX;
var tapY = tapObject.pageY;
var menuRect = this.dropDownElement.getBoundingClientRect();
if (!((tapX >= menuRect.left) && (tapX <= menuRect.right) && (tapY <= menuRect.bottom) && (tapY >= menuRect.top))) {
return true;
}
return false;
}
function CCPopupMenu_createDropDown() {
//create the drop down consisting of the following html structure
var divEl = document.createElement("div");
var tableEl = document.createElement("table");
var tbody = document.createElement("tbody");
var itm;
//can only add table rows to table bodies...can not add them to the table directly
tableEl.appendChild(tbody);
tableEl.style.borderCollapse = "collapse";
tableEl.summary = "";
tableEl.setAttribute("role", "menu");
divEl.id = "flyout_" + this.id;
divEl.className = "flyOutMenu";
divEl.style.display = "block";
divEl.style.position = "absolute";
divEl.style.overflow = "visible";
//ensure that the popup is going to be the highest in the zorder so that things don't peek through
//randomly choose 100 as it seemed like a pretty high number
divEl.style.zIndex = "2";
divEl.style.visibility = "hidden";
divEl.style.padding = "2px";
divEl.setAttribute("role", "presentation");
if (this.label != null) {
tableEl.setAttribute("aria-label", this.label);
}
divEl.tabIndex = -1;
addEvent(divEl, "click", CCPopupMenu_dropDownOnclick);
// Depending on the browser, define the appropriate key event handler for the pop-up menu items
var moz = (window.navigator.userAgent.indexOf("Gecko") != -1);
addEvent(divEl, (moz ? "keypress" : "keydown"), extensions.associate(itm, this, "presskey"));
tableEl.id = "flyoutTab_" + this.id;
//add drop down element as a child of the control element
//this will ensure there are no tabing irregularities
var controlEl = document.getElementById(this.controlId);
if (controlEl != null) {
controlEl.appendChild(divEl);
} else {
//add the drop down to the body if you can't find the control element
document.body.appendChild(divEl);
}
divEl.appendChild(tableEl);
//need to maintain the first menu item as when all is said and done the focus must end up on that element
var maxItmWidth = 0;
for (index = 0; index < this.menuItems.length; index++) {
if (index == 0) {
itm = this.firstMenuItemEl = this.menuItems[index].renderItem(tbody, this.id);
} else {
itm = this.menuItems[index].renderItem(tbody, this.id);
}
if (moz && itm && itm.offsetWidth && maxItmWidth < itm.offsetWidth) {
maxItmWidth = itm.offsetWidth;
}
}
if (moz && maxItmWidth > 0) {
divEl.style.width = maxItmWidth + "px";
}
this.dropDownElement = divEl;
//stick it in the upperleft corner of the browser so as not to make the browser bigger
this.fitHeightToBrowser(0, 0);
this.fitWidthToBrowser(0, 0);
//unfortunately need to do this switch of visibility to ensure that the menu separators get hidden
this.dropDownElement.style.visibility = "visible";
this.dropDownElement.style.visibility = "hidden";
}
//static function to create all the drop down divs so that they can be show later
function CCPopupMenu_createDropDowns() {
for (var index = 0; index < CCPopupMenu.menus.length; index++) {
CCPopupMenu.menus[index].createDropDown();
}
}
//static function returns the menu object associated with the passed in id
function CCPopupMenu_getMenu(id) {
for (var index = 0; index < CCPopupMenu.menus.length; index++) {
if (CCPopupMenu.menus[index].id == id) {
return CCPopupMenu.menus[index];
}
}
}
//constructor to create an new CCPopupMenu object with the passed in id
function CCPopupMenu(sId, controlId, nHeight, hasCheckbox, messagesJSON) {
this.controlId = controlId;
this.id = sId;
this.menuItems = [];
this.isOpen = false;
this.dropDownElement = null;
this.mnHeight = -1;
this.hasCheckbox = ((hasCheckbox != null) && (hasCheckbox == 'true'));
//if a height was passed in use it so that vertical scrolling is enabled...otherwise disable vertical scrolling
//by setting the mnHeight to -1
if (nHeight != "") {
this.mnHeight = parseInt(nHeight, 10);
}
//indicates which index has focus - defaults to -1 so using down key positions correctly on first item in menu list
this.activeMenuItemIndex = -1;
this.firstMenuItemEl = null;
this.doCheckBounds = true;
this.label=null;
this.messages = messagesJSON;
CCPopupMenu.menus.push(this);
}
function CCPopupMenu_setLabel(newLabel){
this.label = newLabel;
}
//instance method to add a menu item with the passed in label and clickFunction
//clickFunction is expected to be a string with valid javascript code
function CCPopupMenu_addMenuItem(id, groupId, label, icon, clickFunction) {
var newMenuItem = new CCPopupMenuItem(id, groupId, label, icon, clickFunction, this.hasCheckbox, this);
this.menuItems.push(newMenuItem);
}
//returns the menu item with the assoicated id
function CCPopupMenu_getMenuItem(id) {
for (var index = 0; index < this.menuItems.length; index++) {
if (this.menuItems[index].id == id) {
return this.menuItems[index];
}
}
}
//sets the selections state of each menu item in the group with the passed in id to "none"
function CCPopupMenu_clearGroup(id) {
for (var index = 0; index < this.menuItems.length; index++) {
if (this.menuItems[index].groupId == id) {
this.menuItems[index].clearSelectionState();
}
}
}
//sets the menu item with the associated id to be checked
function CCPopupMenu_setMenuItemChecked(id) {
//sets the checked attrute of the menuitem
var currentMenuItem = this.getMenuItem(id);
if (currentMenuItem.isInGroup()) {
this.clearGroup(currentMenuItem.groupId);
}
currentMenuItem.check();
}
//returns the menu items with a selection state not set to none
function CCPopupMenu_getCurrentSelected() {
for (var index = 0; index < this.menuItems.length; index++) {
if (this.menuItems[index].type != "item") {
index++;
}
if (this.menuItems[index].itemSelectedState != "none") {
return this.menuItems[index];
}
}
return this.menuItems[index];
}
//returns the menu items with a selection state not set to none
function CCPopupMenu_getCurrentSelectedIndex() {
for (var index = 0;index < this.menuItems.length; index++) {
if (this.menuItems[index].type != "item") {
index++;
}
if (this.menuItems[index].itemSelectedState != "none") {
return index;
}
}
return this.activeMenuItemIndex;
}
// Navigation on the flyout from pressing up and down arrow keys. Also passing current sets first entry that is selected.
// When going 'up' or 'down' check to make sure that the next type is an item, if not then move by 1.
function CCPopupMenu_setActiveMenuItem(direction) {
currentMenu = CCPopupMenu.activeMenu;
var index = direction == 'current' ? currentMenu.getCurrentSelectedIndex() : currentMenu.activeMenuItemIndex;
if (direction == 'up') {
if (index > 0) {
if (currentMenu.menuItems[index - 1].type != "item") {
index--;
}
index--;
}
} else if (direction == 'down') {
if (index < currentMenu.menuItems.length - 1) {
if (currentMenu.menuItems[index + 1].type != "item") {
index++;
}
index++;
}
}
if (index > -1 && index != currentMenu.activeMenuItemIndex) {
currentMenu.activeMenuItemIndex = index;
}
currentMenu.menuItems[index].menuItemEl.focus();
}
//sets the menu item with the associated id to be selected
function CCPopupMenu_setMenuItemSelected(id) {
//sets the checked attrute of the menuitem
currentMenuItem = this.getMenuItem(id);
if (currentMenuItem.isInGroup()) {
this.clearGroup(currentMenuItem.groupId);
}
currentMenuItem.select();
}
//Set the active item index when focus is set.
function CCPopupMenu_setCurrentItemIndex(id) {
currentMenu = CCPopupMenu.activeMenu;
for (var index = 0; index < currentMenu.menuItems.length; index++) {
if (currentMenu.menuItems[index].type != "item") {
continue;
}
if (currentMenu.menuItems[index].menuItemEl.id == id) {
currentMenu.activeMenuItemIndex = index;
currentMenu.menuItems[index].menuItemEl.className = "menuItemOver";
} else {
currentMenu.menuItems[index].menuItemEl.className = "menuItemNormal";
}
}
}
//instance method to add a menu separator
function CCPopupMenu_addMenuSeparator() {
var newMenuItem = new CCPopupMenuSeparator();
this.menuItems.push(newMenuItem);
}
//instance method to hide the current drop down
function CCPopupMenu_removeDropDown() {
if ((this.dropDownElement != null)) {
this.dropDownElement.style.visibility = "hidden";
this.isOpen = false;
var iframeID = this.id + "inslIframe";
var iframeEl = document.getElementById(iframeID);
if (iframeEl != null) {
var controlElement = document.getElementById(this.controlId);
controlElement.removeChild(iframeEl);
}
}
}
// Handle pop-up menu key event to hide the active pop-up menu and reset focus when necessary
function CCPopupMenu_hidePopupForKeyPress() {
var moz = (window.navigator.userAgent.indexOf("Gecko") != -1);
if (moz) {
var currentMenu = CCPopupMenu.getMenu(CCPopupMenu.activeMenu.id);
var controlContainerElement = document.getElementById(currentMenu.controlId);
CCPopupMenu.hideActiveMenu();
if (controlContainerElement != null) {
controlContainerElement.focus();
}
} else {
CCPopupMenu.hideActiveMenu();
}
}
// Handle the pop-up menu key events.
function CCPopupMenu_presskey(evt) {
evt = evt != null ? evt : window.event;
if (evt.keyCode == 13) {
// Enter: Act on the current menu
if (CCPopupMenu.activeMenu.activeMenuItemIndex > -1) {
CCPopupMenu.activeMenu.menuItems[CCPopupMenu.activeMenu.activeMenuItemIndex].keypressFunction();
CCPopupMenu.hidePopupForKeyPress();
}
} else if (evt.keyCode == 27 || evt.keyCode == 9) {
// Esc Key: Close menu and halt
// Tab Key: Close menu and continue
CCPopupMenu.hidePopupForKeyPress();
if (evt.keyCode == 9) {
return true;
}
} else if (evt.keyCode == 38) {
// Up Arrow Key
CCPopupMenu.setActiveMenuItem('up');
} else if (evt.keyCode == 40) {
// Down arrow Key
CCPopupMenu.setActiveMenuItem('down');
}
return haltEventProcessing(evt);
}
//***********************CCPopupMenu specification
CCPopupMenu.prototype.addMenuItem = CCPopupMenu_addMenuItem;
CCPopupMenu.prototype.addMenuSeparator = CCPopupMenu_addMenuSeparator;
CCPopupMenu.prototype.removeDropDown = CCPopupMenu_removeDropDown;
CCPopupMenu.prototype.fitHeightToBrowser = CCPopupMenu_fitHeightToBrowser;
CCPopupMenu.prototype.fitWidthToBrowser = CCPopupMenu_fitWidthToBrowser;
CCPopupMenu.prototype.getMenuItem = CCPopupMenu_getMenuItem;
CCPopupMenu.prototype.clearGroup = CCPopupMenu_clearGroup;
CCPopupMenu.prototype.setMenuItemChecked = CCPopupMenu_setMenuItemChecked;
CCPopupMenu.prototype.setMenuItemSelected = CCPopupMenu_setMenuItemSelected;
CCPopupMenu.prototype.sizeDropDown = CCPopupMenu_sizeDropDown;
CCPopupMenu.prototype.getCurrentSelected = CCPopupMenu_getCurrentSelected;
CCPopupMenu.prototype.createDropDown = CCPopupMenu_createDropDown;
CCPopupMenu.prototype.getCurrentSelectedIndex = CCPopupMenu_getCurrentSelectedIndex;
CCPopupMenu.prototype.presskey = CCPopupMenu_presskey;
CCPopupMenu.prototype.setLabel = CCPopupMenu_setLabel;
CCPopupMenu.prototype.isTapInsideMenu = CCPopupMenu_isTapInsideMenu;
CCPopupMenu.hideActiveMenu = CCPopupMenu_hideActiveMenu;
CCPopupMenu.hidePopupForKeyPress = CCPopupMenu_hidePopupForKeyPress;
CCPopupMenu.ignoreHideActiveMenu = CCPopupMenu_ignoreHideActiveMenu;
CCPopupMenu.getMenu = CCPopupMenu_getMenu;
CCPopupMenu.dropDown = CCPopupMenu_dropDown;
CCPopupMenu.checkBounds = CCPopupMenu_checkBounds;
CCPopupMenu.createInsulatingIframe = CCPopupMenu_createInsulatingIframe;
CCPopupMenu.setControlFocus = CCPopupMenu_setControlFocus;
CCPopupMenu.createDropDowns = CCPopupMenu_createDropDowns;
CCPopupMenu.setActiveMenuItem = CCPopupMenu_setActiveMenuItem;
CCPopupMenu.setCurrentItemIndex = CCPopupMenu_setCurrentItemIndex;
//***********************CCPopupMenu specification
//constructor for CCFlyoutSeparator
//CCFlyoutSeparator has no real state...it just knows how to render itself
function CCPopupMenuSeparator() {
this.type = "separator";
}
function CCPopupMenuSeparator_isInGroup() {
return false;
}
//instance method for rendering a flyout separator
//consisting of the following html: ![]() |
function CCPopupMenuSeparator_renderItem(menuElement, id) {
var menuItemEl = document.createElement("tr");
//menu separators should not be in the tabbing order
menuItemEl.tabIndex = -1;
menuItemEl.setAttribute("role", "separator");
menuElement.appendChild(menuItemEl);
var menuSeparatorContainer = document.createElement("td");
menuSeparatorContainer.colSpan = 3;
var menuSeparator = document.createElement("div");
menuSeparator.className = "flyOutMenuSeparator";
menuSeparatorContainer.appendChild(menuSeparator);
//menuSeparator.className = "flyOutMenuSeparator";
menuItemEl.appendChild(menuSeparatorContainer);
}
//***********************CCFlyoutSeparator specification
CCPopupMenuSeparator.prototype.renderItem = CCPopupMenuSeparator_renderItem;
CCPopupMenuSeparator.prototype.isInGroup = CCPopupMenuSeparator_isInGroup;
//***********************CCFlyoutSeparator specification
//constructor for CCPopupMenuItem
//clickFunction is expected to be a string with valid javascript code
function CCPopupMenuItem(sId, groupId, slabel, icon, clickFunction, hasCheckbox, menu) {
this.id = sId;
this.label = slabel;
this.icon = icon;
this.itemSelectedState = "none";
this.type = "item";
this.groupId = groupId;
this.enabled = true;
this.menuItemEl = null;
this.menuLabelEl = null;
this.iconImageEl = null;
this.selectionStateIcon = null;
this.selectionElement = null;
this.menuIdx = -1;
this.hasCheckbox = hasCheckbox;
this.parentMenu = menu;
//the passed in click action is the action the consumer of the menu item wants to take when clicking on the item
//we must enhance that with some menu caretaking code which will take care of hiding the menu after the click
var clickActionCode = clickFunction + ";CCPopupMenu.hideActiveMenu();";
//keypress actions act similarly to click action but require some additional care taking
// var keypressActionCode = "if (event.keyCode == '13'){" + clickFunction + "} else if (event.keyCode == '27'){CCPopupMenu.hideActiveMenu();}cancelBubble = true;return false;";
this.keypressFunction = new Function("event", clickActionCode);
// this.keyArrowFunction = new Function("event", clickFunction);
// this.keyPressFunction = new Function("event", keypressActionCode);
this.clickFunction = new Function("event", clickActionCode);
}
function CCPopupMenuItem_isInGroup() {
return (this.groupId != "");
}
function CCPopupMenuItem_disable() {
this.enabled = false;
this.updateForEnabled();
}
function CCPopupMenuItem_enable() {
this.enabled = true;
this.updateForEnabled();
}
//sets the selectedState to none
function CCPopupMenuItem_clearSelectionState() {
this.itemSelectedState = "none";
this.updateForSelectionState();
}
//set the selectionState to checked (note selection state and check state are mutually exlusive...an element can not be selected and checked)
function CCPopupMenuItem_check() {
this.itemSelectedState = "checked";
this.updateForSelectionState();
}
//set the selectionState to selected (note selection state and check state are mutually exlusive...an element can not be selected and checked)
function CCPopupMenuItem_select() {
this.itemSelectedState = "selected";
this.updateForSelectionState();
}
//renders the label for the menuitem
function CCPopupMenuItem_renderLabel(menuElement) {
var menuItemLabel = document.createElement("td");
menuItemLabel.style.padding = "2px";
menuItemLabel.className = "menuItemNormal";
this.menuLabelEl = menuItemLabel;
menuElement.appendChild(menuItemLabel);
var nonbreakingSpace = document.createElement("nobr");
menuItemLabel.appendChild(nonbreakingSpace);
var labelLink = document.createElement("span");
labelLink.tabIndex = -1;
nonbreakingSpace.appendChild(labelLink);
labelLink.appendChild(document.createTextNode(this.label));
}
//render the items checked, selected or icon if necessary
function CCPopupMenuItem_renderDecorations(menuElement) {
var decorationTD = document.createElement("td");
decorationTD.className = "text";
decorationTD.style.cursor = "pointer";
decorationTD.style.textDecoration = "underline";
menuElement.appendChild(decorationTD);
this.selectionElement = decorationTD;
if (this.icon != "") {
var imgEl = document.createElement("img");
imgEl.src = this.icon;
imgEl.style.height = "16px";
imgEl.style.width = "16px";
imgEl.alt="";
imgEl.setAttribute("role","presentation");
this.iconImageEl = imgEl;
decorationTD.className = "menuItemIcon";
decorationTD.appendChild(imgEl);
}
}
function CCPopupMenuItem_updateForSelectionState() {
if (this.menuItemEl == null) {
return;
}
if (this.itemSelectedState == "none") {
if (this.selectionStateIcon != null) {
//in this case we remove the selection icon
this.selectionStateIcon.parentNode.removeChild(this.selectionStateIcon);
this.selectionStateIcon = null;
this.menuItemEl.setAttribute("aria-checked","false");
}
} else {
if (this.selectionStateIcon == null) {
var imgEl = document.createElement("img");
if (this.itemSelectedState == "checked") {
imgEl.src = CCPopupMenu.portalImagesPath + "/checkmark.gif";
if (this.parentMenu.messages != null){
imgEl.alt = this.parentMenu.messages.IDS_CCPOPUP_CHECKED;
}
} else {
imgEl.src = CCPopupMenu.portalImagesPath + "/dot.gif";
if (this.parentMenu.messages != null){
imgEl.alt = this.parentMenu.messages.IDS_CCPOPUP_DOT;
}
}
this.selectionElement.appendChild(imgEl);
this.selectionStateIcon = imgEl;
} else {
if (this.itemSelectedState == "checked") {
this.selectionStateIcon.src = CCPopupMenu.portalImagesPath + "/checkmark.gif";
if (this.parentMenu.messages != null){
this.selectionStateIcon.alt = this.parentMenu.messages.IDS_CCPOPUP_CHECKED;
}
} else {
this.selectionStateIcon.src = CCPopupMenu.portalImagesPath + "/dot.gif";
if (this.parentMenu.messages != null){
this.selectionStateIcon.alt = this.parentMenu.messages.IDS_CCPOPUP_DOT;
}
}
this.updateForEnabled();
}
this.menuItemEl.setAttribute("aria-checked","true");
}
}
//updates the rendered menu item based on the enabled state
function CCPopupMenuItem_updateForEnabled() {
if (this.menuItemEl == null) {
return;
}
//only register the click/keypress handlers if the element is enabled
if (this.enabled) {
//enable the click/keypress events
//addEvent(this.menuItemEl, 'keydown', this.presskey);
addEvent(this.menuItemEl, 'click', this.clickFunction);
//update the style
this.menuItemEl.style.MozOpacity = "1.0";
this.menuItemEl.setAttribute("aria-disabled","false");
this.menuItemEl.style.filter = "alpha(opacity=100)";
this.menuLabelEl.className = "text";
if (this.itemSelectedState != "none") {
this.selectionStateIcon.style.MozOpacity = "1.0";
this.selectionStateIcon.style.filter = "alpha(opacity=100)";
}
if (this.iconImageEl != null) {
this.iconImageEl.style.MozOpacity = "1.0";
this.iconImageEl.style.filter = "alpha(opacity=100)";
}
} else {
//disable the click/keypress events
// removeEvent(this.menuItemEl, 'keydown',this.presskey);
removeEvent(this.menuItemEl, 'click', this.clickFunction);
//update the style
this.menuItemEl.style.MozOpacity = "0.5";
this.menuItemEl.setAttribute("aria-disabled","true");
this.menuItemEl.style.filter = "alpha(opacity=50)";
if (this.itemSelectedState != "none") {
this.selectionStateIcon.style.MozOpacity = "0.5";
this.selectionStateIcon.style.filter = "alpha(opacity=50)";
}
if (this.iconImageEl != null) {
this.iconImageEl.style.MozOpacity = "0.5";
this.iconImageEl.style.filter = "alpha(opacity=50)";
}
this.menuLabelEl.className = "inactiveText";
}
}
function menuItemOverEventHandler(id) {
return function ccmenuitemovereventhandler() {
var menuItemEl = document.getElementById(id);
CCPopupMenu.setCurrentItemIndex(menuItemEl.id);
};
}
function menuItemOutEventHandler(id) {
return function ccmenuitemouteventhandler() {
var menuItemEl = document.getElementById(id);
menuItemEl.className = 'menuItemNormal';
};
}
function menuItemBlurEventHandler(id) {
return function ccmenuitemblureventhandler(event) {
var menuItemEl = document.getElementById(id);
menuItemEl.className = 'menuItemNormal';
CCPopupMenu.checkBounds(event);
};
}
function CCPopupMenuItem_createCommonEventHandlers(menuItemEl) {
addEvent(menuItemEl, 'focus', menuItemOverEventHandler(menuItemEl.id));
addEvent(menuItemEl, 'mouseout', menuItemOutEventHandler(menuItemEl.id));
addEvent(menuItemEl, 'mouseover', menuItemOverEventHandler(menuItemEl.id));
addEvent(menuItemEl, 'blur', menuItemBlurEventHandler(menuItemEl.id));
}
//instance method for rendering a flyout menu item
//consisting of the following html: ..label... |
function CCPopupMenuItem_renderItem(menuElement, id) {
var menuItemEl = document.createElement("tr");
var itemRole = "menuitem";
//if this menu has checkable menu items then the role is slightly different to allow for aria-checked attribute
if (this.hasCheckbox){
itemRole = "menuitemcheckbox";
menuItemEl.setAttribute("aria-checked","false");
}
menuItemEl.setAttribute("role", itemRole);
menuItemEl.className = "menuItemNormal";
menuItemEl.id = this.id + "menuItemTR";
menuItemEl.tabIndex = -1;
this.createCommonEventHandlers(menuItemEl);
menuItemEl.style.width = "100%";
menuItemEl.style.overflow = "visible";
menuElement.appendChild(menuItemEl);
this.renderDecorations(menuItemEl);
this.renderLabel(menuItemEl);
var cascadingTD = document.createElement("td");
cascadingTD.className = "text";
cascadingTD.style.cursor = "pointer";
cascadingTD.style.textDecoration = "underline";
menuItemEl.appendChild(cascadingTD);
this.menuItemEl = menuItemEl;
this.updateForSelectionState();
this.updateForEnabled();
return menuItemEl;
}
//***********************CCPopupMenuItem specification
CCPopupMenuItem.prototype.renderItem = CCPopupMenuItem_renderItem;
CCPopupMenuItem.prototype.renderDecorations = CCPopupMenuItem_renderDecorations;
CCPopupMenuItem.prototype.renderLabel = CCPopupMenuItem_renderLabel;
CCPopupMenuItem.prototype.clearSelectionState = CCPopupMenuItem_clearSelectionState;
CCPopupMenuItem.prototype.check = CCPopupMenuItem_check;
CCPopupMenuItem.prototype.select = CCPopupMenuItem_select;
CCPopupMenuItem.prototype.isInGroup = CCPopupMenuItem_isInGroup;
CCPopupMenuItem.prototype.disable = CCPopupMenuItem_disable;
CCPopupMenuItem.prototype.enable = CCPopupMenuItem_enable;
CCPopupMenuItem.prototype.updateForEnabled = CCPopupMenuItem_updateForEnabled;
CCPopupMenuItem.prototype.updateForSelectionState = CCPopupMenuItem_updateForSelectionState;
CCPopupMenuItem.prototype.createCommonEventHandlers = CCPopupMenuItem_createCommonEventHandlers;
//***********************CCPopupMenuItem specification
function respondToTouch(){
if (CCPopupMenu.activeMenu != null){
var event = window.event;
if (CCPopupMenu.activeMenu.isTapInsideMenu(event.targetTouches[0])) {
var controlElement = document.getElementById(CCPopupMenu.activeMenu.controlId);
if (event.taget != controlElement){
CCPopupMenu.hideActiveMenu();
}
}
}
}
//these event handlers will close active menus whenever the browser is resized or one clicks outside of a menu
addEvent(document, 'click', CCPopupMenu.hideActiveMenu);
addEvent(document, 'touchstart', respondToTouch);
addEvent(window, 'resize', CCPopupMenu.hideActiveMenu);
//add this event handler to prebuild the drop downs for the page
addEvent(window, 'load', CCPopupMenu.createDropDowns);