//////////////////////////////////////////////////////////////////////////////// // Constants //////////////////////////////////////////////////////////////////////////////// var __CFMENU_APPLY_IE_HACK = (cfBrowserGetName() == CFBROWSER_EXPLORER) && (cfBrowserGetVersion() < 7.0) && (cfBrowserGetOS() != CFBROWSER_OS_MAC); var __CFMENU_ERROR_CONTAINER_ID = "invalid CFMenuContainer id"; var __CFMENU_ERROR_ID = "invalid CFMenu id"; var __CFMENU_ERROR_ITEM_ID = "invalid CFMenuItem id"; var __CFMENU_ERROR_SECTION_ID = "invalid CFMenuSection id"; var __CFMENU_HIDE_TIME = 300; var __CFMENU_SHOW_TIME = 300; var __CFMENU_SECTION_SUBMENU_OFFSET = -2; //////////////////////////////////////////////////////////////////////////////// // Static Variables //////////////////////////////////////////////////////////////////////////////// var __cfMenuContainerMap = {}; var __cfMenuItemMap = {}; var __cfMenuMap = {}; var __cfMenuSectionMap = {}; //////////////////////////////////////////////////////////////////////////////// // Classes //////////////////////////////////////////////////////////////////////////////// // CFMenu function CFMenu(id, sectionIds, itemIds) { CFPopup.call(this, id); var items = new Array(); for (var i = 0; i < itemIds.length; i++) { items.push(cfMenuItemGet(itemIds[i])); } var sections = new Array(); for (var i = 0; i < sectionIds.length; i++) { sections.push(cfMenuSectionGet(sectionIds[i])); } this.__items = items; this.__sections = sections; if (__CFMENU_APPLY_IE_HACK) { this.__hackApplied = false; } __cfMenuMap[id] = this; var element = this.getElement(); var f = cfEventHandlerCreate(this.__handleMouseOutEvent.bind(this)); element.onmouseout = f; f = cfEventHandlerCreate(this.__handleMouseOverEvent.bind(this)); element.onmouseover = f; } CFMenu.extendClasses(CFPopup); CFMenu.prototype.__handleMouseOutEvent = function() { this.__triggerEvent(CFWIDGET_EVENT_MOUSE_OUT); return false; } CFMenu.prototype.__handleMouseOverEvent = function() { this.__triggerEvent(CFWIDGET_EVENT_MOUSE_OVER); return false; } CFMenu.prototype.__showIEHack = function() { var result = CFPopup.prototype.__show.call(this); if (! this.__hackApplied) { var width = 0; var items = this.__items; for (var i = 0; i < items.length; i++) { width = Math.max(width, items[i].getDimensions().width); } var sections = this.__sections; for (var i = 0; i < sections.length; i++) { width = Math.max(width, sections[i].getDimensions().width); } width = width + "px"; for (var i = 0; i < items.length; i++) { var item = items[i]; item.getElement().style.width = width; var linkElement = item.getLinkElement(); if (linkElement) { linkElement.style.width = width; } } for (var i = 0; i < sections.length; i++) { var section = sections[i]; section.getElement().style.width = width; var linkElement = section.getLinkElement(); if (linkElement) { linkElement.style.width = width; } } this.__hackApplied = true; } return result; } CFMenu.prototype.getHideTime = function() { return __CFMENU_HIDE_TIME; } CFMenu.prototype.getItems = function() { return this.__items; } CFMenu.prototype.getSections = function() { return this.__sections; } CFMenu.prototype.getShowTime = function() { return __CFMENU_SHOW_TIME; } CFMenu.prototype.refresh = function() { CFPopup.prototype.refresh.call(this); var items = this.__items; for (var i = 0; i < items.length; i++) { items[i].refresh(); } var sections = this.__sections; for (var i = 0; i < sections.length; i++) { sections[i].refresh(); } } if (__CFMENU_APPLY_IE_HACK) { CFMenu.prototype.__show = CFMenu.prototype.__showIEHack; } // CFMenuContainer function CFMenuContainer(id, rootMenuId) { CFWidget.call(this, id); this.__rootMenu = cfElementGet(rootMenuId); __cfMenuContainerMap[id] = this; } CFMenuContainer.extendClasses(CFWidget); // CFMenuItem function CFMenuItem(id, linkId, hoverClass) { CFWidget.call(this, id); this.__hoverClass = hoverClass; this.__linkElement = linkId.length ? cfElementGet(linkId) : undefined; __cfMenuItemMap[id] = this; var element = this.getElement(); var f = cfEventHandlerCreate(this.__handleMouseOutEvent.bind(this)); element.onmouseout = f; f = cfEventHandlerCreate(this.__handleMouseOverEvent.bind(this)); element.onmouseover = f; } CFMenuItem.extendClasses(CFWidget); CFMenuItem.prototype.__handleMouseOutEvent = function() { cfElementDiscardClass(this.getElement(), this.__hoverClass); this.__triggerEvent(CFWIDGET_EVENT_MOUSE_OUT); return false; } CFMenuItem.prototype.__handleMouseOverEvent = function() { cfElementAddClass(this.getElement(), this.__hoverClass); this.__triggerEvent(CFWIDGET_EVENT_MOUSE_OVER); return false; } CFMenuItem.prototype.getLinkElement = function() { return this.__linkElement; } // CFMenuSection function CFMenuSection(id, subMenuId, linkId, isVertical, hoverClass, showRight) { CFWidget.call(this, id); var subMenu = subMenuId.length ? cfMenuGet(subMenuId) : undefined; this.__hoverClass = hoverClass; this.__isVertical = isVertical; this.__linkElement = linkId.length ? cfElementGet(linkId) : undefined; this.__mouseOverCount = 0; this.__showRight = showRight; this.__subMenu = subMenu; __cfMenuSectionMap[id] = this; var element = this.getElement(); var f = cfEventHandlerCreate(this.__handleMouseOutEvent.bind(this)); element.onmouseout = f; f = cfEventHandlerCreate(this.__handleMouseOverEvent.bind(this)); element.onmouseover = f; if (subMenu) { var f = this.__handleChildSubMenuMouseOutEvent.bind(this); var outFunc = cfEventHandlerCreate(f); f = this.__handleChildSubMenuMouseOverEvent.bind(this); var overFunc = cfEventHandlerCreate(f); this.__addSubMenuEventHandlers(subMenu, overFunc, outFunc); f = cfEventHandlerCreate(this.__handleSubMenuShowEvent.bind(this)); subMenu.addEventHandler(CFWIDGET_EVENT_SHOW, f); } } CFMenuSection.extendClasses(CFWidget); CFMenuSection.prototype.__addSubMenuEventHandlers = function(menu, overFunc, outFunc) { menu.addEventHandler(CFWIDGET_EVENT_MOUSE_OUT, outFunc); menu.addEventHandler(CFWIDGET_EVENT_MOUSE_OVER, overFunc); var sections = menu.getSections(); for (var i = 0; i < sections.length; i++) { var subMenu = sections[i].getSubMenu(); if (subMenu) { this.__addSubMenuEventHandlers(subMenu, overFunc, outFunc); } } } CFMenuSection.prototype.__decrementMouseOverCount = function() { var subMenu = this.__subMenu; if (subMenu) { var count = this.__mouseOverCount; if (count <= 1) { count = 1; subMenu.hide(); } this.__mouseOverCount = count - 1; } } CFMenuSection.prototype.__handleChildSubMenuMouseOutEvent = function() { this.__decrementMouseOverCount(); return true; } CFMenuSection.prototype.__handleChildSubMenuMouseOverEvent = function() { this.__incrementMouseOverCount(); return true; } CFMenuSection.prototype.__handleMouseOutEvent = function() { cfElementDiscardClass(this.getElement(), this.__hoverClass); this.__decrementMouseOverCount(); this.__triggerEvent(CFWIDGET_EVENT_MOUSE_OUT); return false; } CFMenuSection.prototype.__handleMouseOverEvent = function() { cfElementAddClass(this.getElement(), this.__hoverClass); this.__incrementMouseOverCount(); this.__triggerEvent(CFWIDGET_EVENT_MOUSE_OVER); return false; } CFMenuSection.prototype.__handleSubMenuShowEvent = function() { this.__refreshMenuPosition(); } CFMenuSection.prototype.__incrementMouseOverCount = function() { var subMenu = this.__subMenu; if (subMenu) { var count = this.__mouseOverCount; if (! count) { this.__refreshMenuPosition(); subMenu.show(); } this.__mouseOverCount = count + 1; } } CFMenuSection.prototype.__refreshMenuPosition = function() { var dimensions = this.getDimensions(); var position = this.getDocumentPosition(); var left = position.x; var subMenu = this.__subMenu; var top = position.y; if (this.__showRight) { var menuDimensions = subMenu.getDimensions(); if (this.__isVertical) { left = (left - menuDimensions.width) - __CFMENU_SECTION_SUBMENU_OFFSET; } else { left = (left - menuDimensions.width) + dimensions.width; top = dimensions.height + __CFMENU_SECTION_SUBMENU_OFFSET; } } else { if (this.__isVertical) { left += dimensions.width + __CFMENU_SECTION_SUBMENU_OFFSET; } else { top += dimensions.height + __CFMENU_SECTION_SUBMENU_OFFSET; } } subMenu.setTopLeftPosition(top, left); } CFMenuSection.prototype.getLinkElement = function() { return this.__linkElement; } CFMenuSection.prototype.getSubMenu = function() { return this.__subMenu; } //////////////////////////////////////////////////////////////////////////////// // Public API //////////////////////////////////////////////////////////////////////////////// function cfMenuContainerCreate(arg) { return new CFMenuContainer(arg.id, arg.rootMenuId); } function cfMenuContainerGet(id) { var container = __cfMenuContainerMap[id]; if (! container) { return cfErrorTrigger("cfMenuContainerGet: '" + id + "': " + __CFMENU_ERROR_CONTAINER_ID); } return container; } function cfMenuCreate(arg) { return new CFMenu(arg.id, arg.sectionIds, arg.itemIds); } function cfMenuGet(id) { var menu = __cfMenuMap[id]; if (! menu) { return cfErrorTrigger("cfMenuGet: '" + id + "': " + __CFMENU_ERROR_ID); } return menu; } function cfMenuItemCreate(arg) { return new CFMenuItem(arg.id, arg.linkId, arg.hoverClass); } function cfMenuItemGet(id) { var item = __cfMenuItemMap[id]; if (! item) { return cfErrorTrigger("cfMenuItemGet: '" + id + "': " + __CFMENU_ERROR_ITEM_ID); } return item; } function cfMenuSectionCreate(arg) { return new CFMenuSection(arg.id, arg.subMenuId, arg.linkId, arg.isVertical, arg.hoverClass, arg.showRight); } function cfMenuSectionGet(id) { var section = __cfMenuSectionMap[id]; if (! section) { return cfErrorTrigger("cfMenuSectionGet: '" + id + "': " + __CFMENU_ERROR_SECTION_ID); } return section; }