menu.js
9823 lines
| 233.2 KiB
| application/javascript
|
JavascriptLexer
r547 | /* | |||
Copyright (c) 2009, Yahoo! Inc. All rights reserved. | ||||
Code licensed under the BSD License: | ||||
http://developer.yahoo.net/yui/license.txt | ||||
version: 2.8.0r4 | ||||
*/ | ||||
/** | ||||
* @module menu | ||||
* @description <p>The Menu family of components features a collection of | ||||
* controls that make it easy to add menus to your website or web application. | ||||
* With the Menu Controls you can create website fly-out menus, customized | ||||
* context menus, or application-style menu bars with just a small amount of | ||||
* scripting.</p><p>The Menu family of controls features:</p> | ||||
* <ul> | ||||
* <li>Keyboard and mouse navigation.</li> | ||||
* <li>A rich event model that provides access to all of a menu's | ||||
* interesting moments.</li> | ||||
* <li>Support for | ||||
* <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive | ||||
* Enhancement</a>; Menus can be created from simple, | ||||
* semantic markup on the page or purely through JavaScript.</li> | ||||
* </ul> | ||||
* @title Menu | ||||
* @namespace YAHOO.widget | ||||
* @requires Event, Dom, Container | ||||
*/ | ||||
(function () { | ||||
var UA = YAHOO.env.ua, | ||||
Dom = YAHOO.util.Dom, | ||||
Event = YAHOO.util.Event, | ||||
Lang = YAHOO.lang, | ||||
_DIV = "DIV", | ||||
_HD = "hd", | ||||
_BD = "bd", | ||||
_FT = "ft", | ||||
_LI = "LI", | ||||
_DISABLED = "disabled", | ||||
_MOUSEOVER = "mouseover", | ||||
_MOUSEOUT = "mouseout", | ||||
_MOUSEDOWN = "mousedown", | ||||
_MOUSEUP = "mouseup", | ||||
_CLICK = "click", | ||||
_KEYDOWN = "keydown", | ||||
_KEYUP = "keyup", | ||||
_KEYPRESS = "keypress", | ||||
_CLICK_TO_HIDE = "clicktohide", | ||||
_POSITION = "position", | ||||
_DYNAMIC = "dynamic", | ||||
_SHOW_DELAY = "showdelay", | ||||
_SELECTED = "selected", | ||||
_VISIBLE = "visible", | ||||
_UL = "UL", | ||||
_MENUMANAGER = "MenuManager"; | ||||
/** | ||||
* Singleton that manages a collection of all menus and menu items. Listens | ||||
* for DOM events at the document level and dispatches the events to the | ||||
* corresponding menu or menu item. | ||||
* | ||||
* @namespace YAHOO.widget | ||||
* @class MenuManager | ||||
* @static | ||||
*/ | ||||
YAHOO.widget.MenuManager = function () { | ||||
// Private member variables | ||||
// Flag indicating if the DOM event handlers have been attached | ||||
var m_bInitializedEventHandlers = false, | ||||
// Collection of menus | ||||
m_oMenus = {}, | ||||
// Collection of visible menus | ||||
m_oVisibleMenus = {}, | ||||
// Collection of menu items | ||||
m_oItems = {}, | ||||
// Map of DOM event types to their equivalent CustomEvent types | ||||
m_oEventTypes = { | ||||
"click": "clickEvent", | ||||
"mousedown": "mouseDownEvent", | ||||
"mouseup": "mouseUpEvent", | ||||
"mouseover": "mouseOverEvent", | ||||
"mouseout": "mouseOutEvent", | ||||
"keydown": "keyDownEvent", | ||||
"keyup": "keyUpEvent", | ||||
"keypress": "keyPressEvent", | ||||
"focus": "focusEvent", | ||||
"focusin": "focusEvent", | ||||
"blur": "blurEvent", | ||||
"focusout": "blurEvent" | ||||
}, | ||||
m_oFocusedMenuItem = null; | ||||
// Private methods | ||||
/** | ||||
* @method getMenuRootElement | ||||
* @description Finds the root DIV node of a menu or the root LI node of | ||||
* a menu item. | ||||
* @private | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object | ||||
* specifying an HTML element. | ||||
*/ | ||||
function getMenuRootElement(p_oElement) { | ||||
var oParentNode, | ||||
returnVal; | ||||
if (p_oElement && p_oElement.tagName) { | ||||
switch (p_oElement.tagName.toUpperCase()) { | ||||
case _DIV: | ||||
oParentNode = p_oElement.parentNode; | ||||
// Check if the DIV is the inner "body" node of a menu | ||||
if (( | ||||
Dom.hasClass(p_oElement, _HD) || | ||||
Dom.hasClass(p_oElement, _BD) || | ||||
Dom.hasClass(p_oElement, _FT) | ||||
) && | ||||
oParentNode && | ||||
oParentNode.tagName && | ||||
oParentNode.tagName.toUpperCase() == _DIV) { | ||||
returnVal = oParentNode; | ||||
} | ||||
else { | ||||
returnVal = p_oElement; | ||||
} | ||||
break; | ||||
case _LI: | ||||
returnVal = p_oElement; | ||||
break; | ||||
default: | ||||
oParentNode = p_oElement.parentNode; | ||||
if (oParentNode) { | ||||
returnVal = getMenuRootElement(oParentNode); | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return returnVal; | ||||
} | ||||
// Private event handlers | ||||
/** | ||||
* @method onDOMEvent | ||||
* @description Generic, global event handler for all of a menu's | ||||
* DOM-based events. This listens for events against the document | ||||
* object. If the target of a given event is a member of a menu or | ||||
* menu item's DOM, the instance's corresponding Custom Event is fired. | ||||
* @private | ||||
* @param {Event} p_oEvent Object representing the DOM event object | ||||
* passed back by the event utility (YAHOO.util.Event). | ||||
*/ | ||||
function onDOMEvent(p_oEvent) { | ||||
// Get the target node of the DOM event | ||||
var oTarget = Event.getTarget(p_oEvent), | ||||
// See if the target of the event was a menu, or a menu item | ||||
oElement = getMenuRootElement(oTarget), | ||||
bFireEvent = true, | ||||
sEventType = p_oEvent.type, | ||||
sCustomEventType, | ||||
sTagName, | ||||
sId, | ||||
oMenuItem, | ||||
oMenu; | ||||
if (oElement) { | ||||
sTagName = oElement.tagName.toUpperCase(); | ||||
if (sTagName == _LI) { | ||||
sId = oElement.id; | ||||
if (sId && m_oItems[sId]) { | ||||
oMenuItem = m_oItems[sId]; | ||||
oMenu = oMenuItem.parent; | ||||
} | ||||
} | ||||
else if (sTagName == _DIV) { | ||||
if (oElement.id) { | ||||
oMenu = m_oMenus[oElement.id]; | ||||
} | ||||
} | ||||
} | ||||
if (oMenu) { | ||||
sCustomEventType = m_oEventTypes[sEventType]; | ||||
/* | ||||
There is an inconsistency between Firefox for Mac OS X and | ||||
Firefox Windows & Linux regarding the triggering of the | ||||
display of the browser's context menu and the subsequent | ||||
firing of the "click" event. In Firefox for Windows & Linux, | ||||
when the user triggers the display of the browser's context | ||||
menu the "click" event also fires for the document object, | ||||
even though the "click" event did not fire for the element | ||||
that was the original target of the "contextmenu" event. | ||||
This is unique to Firefox on Windows & Linux. For all | ||||
other A-Grade browsers, including Firefox for Mac OS X, the | ||||
"click" event doesn't fire for the document object. | ||||
This bug in Firefox for Windows affects Menu, as Menu | ||||
instances listen for events at the document level and | ||||
dispatches Custom Events of the same name. Therefore users | ||||
of Menu will get an unwanted firing of the "click" | ||||
custom event. The following line fixes this bug. | ||||
*/ | ||||
if (sEventType == "click" && | ||||
(UA.gecko && oMenu.platform != "mac") && | ||||
p_oEvent.button > 0) { | ||||
bFireEvent = false; | ||||
} | ||||
// Fire the Custom Event that corresponds the current DOM event | ||||
if (bFireEvent && oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) { | ||||
oMenuItem[sCustomEventType].fire(p_oEvent); | ||||
} | ||||
if (bFireEvent) { | ||||
oMenu[sCustomEventType].fire(p_oEvent, oMenuItem); | ||||
} | ||||
} | ||||
else if (sEventType == _MOUSEDOWN) { | ||||
/* | ||||
If the target of the event wasn't a menu, hide all | ||||
dynamically positioned menus | ||||
*/ | ||||
for (var i in m_oVisibleMenus) { | ||||
if (Lang.hasOwnProperty(m_oVisibleMenus, i)) { | ||||
oMenu = m_oVisibleMenus[i]; | ||||
if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) && | ||||
!(oMenu instanceof YAHOO.widget.MenuBar) && | ||||
oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
oMenu.hide(); | ||||
// In IE when the user mouses down on a focusable | ||||
// element that element will be focused and become | ||||
// the "activeElement". | ||||
// (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx) | ||||
// However, there is a bug in IE where if there is | ||||
// a positioned element with a focused descendant | ||||
// that is hidden in response to the mousedown | ||||
// event, the target of the mousedown event will | ||||
// appear to have focus, but will not be set as | ||||
// the activeElement. This will result in the | ||||
// element not firing key events, even though it | ||||
// appears to have focus. The following call to | ||||
// "setActive" fixes this bug. | ||||
if (UA.ie && oTarget.focus) { | ||||
oTarget.setActive(); | ||||
} | ||||
} | ||||
else { | ||||
if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) { | ||||
oMenu._cancelShowDelay(); | ||||
} | ||||
if (oMenu.activeItem) { | ||||
oMenu.activeItem.blur(); | ||||
oMenu.activeItem.cfg.setProperty(_SELECTED, false); | ||||
oMenu.activeItem = null; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
/** | ||||
* @method onMenuDestroy | ||||
* @description "destroy" event handler for a menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event | ||||
* was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event. | ||||
*/ | ||||
function onMenuDestroy(p_sType, p_aArgs, p_oMenu) { | ||||
if (m_oMenus[p_oMenu.id]) { | ||||
this.removeMenu(p_oMenu); | ||||
} | ||||
} | ||||
/** | ||||
* @method onMenuFocus | ||||
* @description "focus" event handler for a MenuItem instance. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
function onMenuFocus(p_sType, p_aArgs) { | ||||
var oItem = p_aArgs[1]; | ||||
if (oItem) { | ||||
m_oFocusedMenuItem = oItem; | ||||
} | ||||
} | ||||
/** | ||||
* @method onMenuBlur | ||||
* @description "blur" event handler for a MenuItem instance. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
function onMenuBlur(p_sType, p_aArgs) { | ||||
m_oFocusedMenuItem = null; | ||||
} | ||||
/** | ||||
* @method onMenuVisibleConfigChange | ||||
* @description Event handler for when the "visible" configuration | ||||
* property of a Menu instance changes. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
function onMenuVisibleConfigChange(p_sType, p_aArgs) { | ||||
var bVisible = p_aArgs[0], | ||||
sId = this.id; | ||||
if (bVisible) { | ||||
m_oVisibleMenus[sId] = this; | ||||
} | ||||
else if (m_oVisibleMenus[sId]) { | ||||
delete m_oVisibleMenus[sId]; | ||||
} | ||||
} | ||||
/** | ||||
* @method onItemDestroy | ||||
* @description "destroy" event handler for a MenuItem instance. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
function onItemDestroy(p_sType, p_aArgs) { | ||||
removeItem(this); | ||||
} | ||||
/** | ||||
* @method removeItem | ||||
* @description Removes a MenuItem instance from the MenuManager's collection of MenuItems. | ||||
* @private | ||||
* @param {MenuItem} p_oMenuItem The MenuItem instance to be removed. | ||||
*/ | ||||
function removeItem(p_oMenuItem) { | ||||
var sId = p_oMenuItem.id; | ||||
if (sId && m_oItems[sId]) { | ||||
if (m_oFocusedMenuItem == p_oMenuItem) { | ||||
m_oFocusedMenuItem = null; | ||||
} | ||||
delete m_oItems[sId]; | ||||
p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy); | ||||
} | ||||
} | ||||
/** | ||||
* @method onItemAdded | ||||
* @description "itemadded" event handler for a Menu instance. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
function onItemAdded(p_sType, p_aArgs) { | ||||
var oItem = p_aArgs[0], | ||||
sId; | ||||
if (oItem instanceof YAHOO.widget.MenuItem) { | ||||
sId = oItem.id; | ||||
if (!m_oItems[sId]) { | ||||
m_oItems[sId] = oItem; | ||||
oItem.destroyEvent.subscribe(onItemDestroy); | ||||
} | ||||
} | ||||
} | ||||
return { | ||||
// Privileged methods | ||||
/** | ||||
* @method addMenu | ||||
* @description Adds a menu to the collection of known menus. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu | ||||
* instance to be added. | ||||
*/ | ||||
addMenu: function (p_oMenu) { | ||||
var oDoc; | ||||
if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id && | ||||
!m_oMenus[p_oMenu.id]) { | ||||
m_oMenus[p_oMenu.id] = p_oMenu; | ||||
if (!m_bInitializedEventHandlers) { | ||||
oDoc = document; | ||||
Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true); | ||||
Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true); | ||||
Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true); | ||||
Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true); | ||||
Event.on(oDoc, _CLICK, onDOMEvent, this, true); | ||||
Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true); | ||||
Event.on(oDoc, _KEYUP, onDOMEvent, this, true); | ||||
Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true); | ||||
Event.onFocus(oDoc, onDOMEvent, this, true); | ||||
Event.onBlur(oDoc, onDOMEvent, this, true); | ||||
m_bInitializedEventHandlers = true; | ||||
} | ||||
p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange); | ||||
p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this); | ||||
p_oMenu.itemAddedEvent.subscribe(onItemAdded); | ||||
p_oMenu.focusEvent.subscribe(onMenuFocus); | ||||
p_oMenu.blurEvent.subscribe(onMenuBlur); | ||||
} | ||||
}, | ||||
/** | ||||
* @method removeMenu | ||||
* @description Removes a menu from the collection of known menus. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu | ||||
* instance to be removed. | ||||
*/ | ||||
removeMenu: function (p_oMenu) { | ||||
var sId, | ||||
aItems, | ||||
i; | ||||
if (p_oMenu) { | ||||
sId = p_oMenu.id; | ||||
if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) { | ||||
// Unregister each menu item | ||||
aItems = p_oMenu.getItems(); | ||||
if (aItems && aItems.length > 0) { | ||||
i = aItems.length - 1; | ||||
do { | ||||
removeItem(aItems[i]); | ||||
} | ||||
while (i--); | ||||
} | ||||
// Unregister the menu | ||||
delete m_oMenus[sId]; | ||||
/* | ||||
Unregister the menu from the collection of | ||||
visible menus | ||||
*/ | ||||
if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) { | ||||
delete m_oVisibleMenus[sId]; | ||||
} | ||||
// Unsubscribe event listeners | ||||
if (p_oMenu.cfg) { | ||||
p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE, | ||||
onMenuVisibleConfigChange); | ||||
} | ||||
p_oMenu.destroyEvent.unsubscribe(onMenuDestroy, | ||||
p_oMenu); | ||||
p_oMenu.itemAddedEvent.unsubscribe(onItemAdded); | ||||
p_oMenu.focusEvent.unsubscribe(onMenuFocus); | ||||
p_oMenu.blurEvent.unsubscribe(onMenuBlur); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method hideVisible | ||||
* @description Hides all visible, dynamically positioned menus | ||||
* (excluding instances of YAHOO.widget.MenuBar). | ||||
*/ | ||||
hideVisible: function () { | ||||
var oMenu; | ||||
for (var i in m_oVisibleMenus) { | ||||
if (Lang.hasOwnProperty(m_oVisibleMenus, i)) { | ||||
oMenu = m_oVisibleMenus[i]; | ||||
if (!(oMenu instanceof YAHOO.widget.MenuBar) && | ||||
oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
oMenu.hide(); | ||||
} | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method getVisible | ||||
* @description Returns a collection of all visible menus registered | ||||
* with the menu manger. | ||||
* @return {Object} | ||||
*/ | ||||
getVisible: function () { | ||||
return m_oVisibleMenus; | ||||
}, | ||||
/** | ||||
* @method getMenus | ||||
* @description Returns a collection of all menus registered with the | ||||
* menu manger. | ||||
* @return {Object} | ||||
*/ | ||||
getMenus: function () { | ||||
return m_oMenus; | ||||
}, | ||||
/** | ||||
* @method getMenu | ||||
* @description Returns a menu with the specified id. | ||||
* @param {String} p_sId String specifying the id of the | ||||
* <code><div></code> element representing the menu to | ||||
* be retrieved. | ||||
* @return {YAHOO.widget.Menu} | ||||
*/ | ||||
getMenu: function (p_sId) { | ||||
var returnVal; | ||||
if (p_sId in m_oMenus) { | ||||
returnVal = m_oMenus[p_sId]; | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method getMenuItem | ||||
* @description Returns a menu item with the specified id. | ||||
* @param {String} p_sId String specifying the id of the | ||||
* <code><li></code> element representing the menu item to | ||||
* be retrieved. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
getMenuItem: function (p_sId) { | ||||
var returnVal; | ||||
if (p_sId in m_oItems) { | ||||
returnVal = m_oItems[p_sId]; | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method getMenuItemGroup | ||||
* @description Returns an array of menu item instances whose | ||||
* corresponding <code><li></code> elements are child | ||||
* nodes of the <code><ul></code> element with the | ||||
* specified id. | ||||
* @param {String} p_sId String specifying the id of the | ||||
* <code><ul></code> element representing the group of | ||||
* menu items to be retrieved. | ||||
* @return {Array} | ||||
*/ | ||||
getMenuItemGroup: function (p_sId) { | ||||
var oUL = Dom.get(p_sId), | ||||
aItems, | ||||
oNode, | ||||
oItem, | ||||
sId, | ||||
returnVal; | ||||
if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) { | ||||
oNode = oUL.firstChild; | ||||
if (oNode) { | ||||
aItems = []; | ||||
do { | ||||
sId = oNode.id; | ||||
if (sId) { | ||||
oItem = this.getMenuItem(sId); | ||||
if (oItem) { | ||||
aItems[aItems.length] = oItem; | ||||
} | ||||
} | ||||
} | ||||
while ((oNode = oNode.nextSibling)); | ||||
if (aItems.length > 0) { | ||||
returnVal = aItems; | ||||
} | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method getFocusedMenuItem | ||||
* @description Returns a reference to the menu item that currently | ||||
* has focus. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
getFocusedMenuItem: function () { | ||||
return m_oFocusedMenuItem; | ||||
}, | ||||
/** | ||||
* @method getFocusedMenu | ||||
* @description Returns a reference to the menu that currently | ||||
* has focus. | ||||
* @return {YAHOO.widget.Menu} | ||||
*/ | ||||
getFocusedMenu: function () { | ||||
var returnVal; | ||||
if (m_oFocusedMenuItem) { | ||||
returnVal = m_oFocusedMenuItem.parent.getRoot(); | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method toString | ||||
* @description Returns a string representing the menu manager. | ||||
* @return {String} | ||||
*/ | ||||
toString: function () { | ||||
return _MENUMANAGER; | ||||
} | ||||
}; | ||||
}(); | ||||
})(); | ||||
(function () { | ||||
var Lang = YAHOO.lang, | ||||
// String constants | ||||
_MENU = "Menu", | ||||
_DIV_UPPERCASE = "DIV", | ||||
_DIV_LOWERCASE = "div", | ||||
_ID = "id", | ||||
_SELECT = "SELECT", | ||||
_XY = "xy", | ||||
_Y = "y", | ||||
_UL_UPPERCASE = "UL", | ||||
_UL_LOWERCASE = "ul", | ||||
_FIRST_OF_TYPE = "first-of-type", | ||||
_LI = "LI", | ||||
_OPTGROUP = "OPTGROUP", | ||||
_OPTION = "OPTION", | ||||
_DISABLED = "disabled", | ||||
_NONE = "none", | ||||
_SELECTED = "selected", | ||||
_GROUP_INDEX = "groupindex", | ||||
_INDEX = "index", | ||||
_SUBMENU = "submenu", | ||||
_VISIBLE = "visible", | ||||
_HIDE_DELAY = "hidedelay", | ||||
_POSITION = "position", | ||||
_DYNAMIC = "dynamic", | ||||
_STATIC = "static", | ||||
_DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC, | ||||
_URL = "url", | ||||
_HASH = "#", | ||||
_TARGET = "target", | ||||
_MAX_HEIGHT = "maxheight", | ||||
_TOP_SCROLLBAR = "topscrollbar", | ||||
_BOTTOM_SCROLLBAR = "bottomscrollbar", | ||||
_UNDERSCORE = "_", | ||||
_TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED, | ||||
_BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED, | ||||
_MOUSEMOVE = "mousemove", | ||||
_SHOW_DELAY = "showdelay", | ||||
_SUBMENU_HIDE_DELAY = "submenuhidedelay", | ||||
_IFRAME = "iframe", | ||||
_CONSTRAIN_TO_VIEWPORT = "constraintoviewport", | ||||
_PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap", | ||||
_SUBMENU_ALIGNMENT = "submenualignment", | ||||
_AUTO_SUBMENU_DISPLAY = "autosubmenudisplay", | ||||
_CLICK_TO_HIDE = "clicktohide", | ||||
_CONTAINER = "container", | ||||
_SCROLL_INCREMENT = "scrollincrement", | ||||
_MIN_SCROLL_HEIGHT = "minscrollheight", | ||||
_CLASSNAME = "classname", | ||||
_SHADOW = "shadow", | ||||
_KEEP_OPEN = "keepopen", | ||||
_HD = "hd", | ||||
_HAS_TITLE = "hastitle", | ||||
_CONTEXT = "context", | ||||
_EMPTY_STRING = "", | ||||
_MOUSEDOWN = "mousedown", | ||||
_KEYDOWN = "keydown", | ||||
_HEIGHT = "height", | ||||
_WIDTH = "width", | ||||
_PX = "px", | ||||
_EFFECT = "effect", | ||||
_MONITOR_RESIZE = "monitorresize", | ||||
_DISPLAY = "display", | ||||
_BLOCK = "block", | ||||
_VISIBILITY = "visibility", | ||||
_ABSOLUTE = "absolute", | ||||
_ZINDEX = "zindex", | ||||
_YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled", | ||||
_NON_BREAKING_SPACE = " ", | ||||
_SPACE = " ", | ||||
_MOUSEOVER = "mouseover", | ||||
_MOUSEOUT = "mouseout", | ||||
_ITEM_ADDED = "itemAdded", | ||||
_ITEM_REMOVED = "itemRemoved", | ||||
_HIDDEN = "hidden", | ||||
_YUI_MENU_SHADOW = "yui-menu-shadow", | ||||
_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible", | ||||
_YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE; | ||||
/** | ||||
* The Menu class creates a container that holds a vertical list representing | ||||
* a set of options or commands. Menu is the base class for all | ||||
* menu containers. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><div></code> element of the menu. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><select></code> element to be used as the data source | ||||
* for the menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object | ||||
* specifying the <code><div></code> element of the menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement | ||||
* Object specifying the <code><select></code> element to be used as | ||||
* the data source for the menu. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu. See configuration class documentation for | ||||
* more details. | ||||
* @namespace YAHOO.widget | ||||
* @class Menu | ||||
* @constructor | ||||
* @extends YAHOO.widget.Overlay | ||||
*/ | ||||
YAHOO.widget.Menu = function (p_oElement, p_oConfig) { | ||||
if (p_oConfig) { | ||||
this.parent = p_oConfig.parent; | ||||
this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload; | ||||
this.itemData = p_oConfig.itemData || p_oConfig.itemdata; | ||||
} | ||||
YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig); | ||||
}; | ||||
/** | ||||
* @method checkPosition | ||||
* @description Checks to make sure that the value of the "position" property | ||||
* is one of the supported strings. Returns true if the position is supported. | ||||
* @private | ||||
* @param {Object} p_sPosition String specifying the position of the menu. | ||||
* @return {Boolean} | ||||
*/ | ||||
function checkPosition(p_sPosition) { | ||||
var returnVal = false; | ||||
if (Lang.isString(p_sPosition)) { | ||||
returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1); | ||||
} | ||||
return returnVal; | ||||
} | ||||
var Dom = YAHOO.util.Dom, | ||||
Event = YAHOO.util.Event, | ||||
Module = YAHOO.widget.Module, | ||||
Overlay = YAHOO.widget.Overlay, | ||||
Menu = YAHOO.widget.Menu, | ||||
MenuManager = YAHOO.widget.MenuManager, | ||||
CustomEvent = YAHOO.util.CustomEvent, | ||||
UA = YAHOO.env.ua, | ||||
m_oShadowTemplate, | ||||
bFocusListenerInitialized = false, | ||||
oFocusedElement, | ||||
EVENT_TYPES = [ | ||||
["mouseOverEvent", _MOUSEOVER], | ||||
["mouseOutEvent", _MOUSEOUT], | ||||
["mouseDownEvent", _MOUSEDOWN], | ||||
["mouseUpEvent", "mouseup"], | ||||
["clickEvent", "click"], | ||||
["keyPressEvent", "keypress"], | ||||
["keyDownEvent", _KEYDOWN], | ||||
["keyUpEvent", "keyup"], | ||||
["focusEvent", "focus"], | ||||
["blurEvent", "blur"], | ||||
["itemAddedEvent", _ITEM_ADDED], | ||||
["itemRemovedEvent", _ITEM_REMOVED] | ||||
], | ||||
VISIBLE_CONFIG = { | ||||
key: _VISIBLE, | ||||
value: false, | ||||
validator: Lang.isBoolean | ||||
}, | ||||
CONSTRAIN_TO_VIEWPORT_CONFIG = { | ||||
key: _CONSTRAIN_TO_VIEWPORT, | ||||
value: true, | ||||
validator: Lang.isBoolean, | ||||
supercedes: [_IFRAME,"x",_Y,_XY] | ||||
}, | ||||
PREVENT_CONTEXT_OVERLAP_CONFIG = { | ||||
key: _PREVENT_CONTEXT_OVERLAP, | ||||
value: true, | ||||
validator: Lang.isBoolean, | ||||
supercedes: [_CONSTRAIN_TO_VIEWPORT] | ||||
}, | ||||
POSITION_CONFIG = { | ||||
key: _POSITION, | ||||
value: _DYNAMIC, | ||||
validator: checkPosition, | ||||
supercedes: [_VISIBLE, _IFRAME] | ||||
}, | ||||
SUBMENU_ALIGNMENT_CONFIG = { | ||||
key: _SUBMENU_ALIGNMENT, | ||||
value: ["tl","tr"] | ||||
}, | ||||
AUTO_SUBMENU_DISPLAY_CONFIG = { | ||||
key: _AUTO_SUBMENU_DISPLAY, | ||||
value: true, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true | ||||
}, | ||||
SHOW_DELAY_CONFIG = { | ||||
key: _SHOW_DELAY, | ||||
value: 250, | ||||
validator: Lang.isNumber, | ||||
suppressEvent: true | ||||
}, | ||||
HIDE_DELAY_CONFIG = { | ||||
key: _HIDE_DELAY, | ||||
value: 0, | ||||
validator: Lang.isNumber, | ||||
suppressEvent: true | ||||
}, | ||||
SUBMENU_HIDE_DELAY_CONFIG = { | ||||
key: _SUBMENU_HIDE_DELAY, | ||||
value: 250, | ||||
validator: Lang.isNumber, | ||||
suppressEvent: true | ||||
}, | ||||
CLICK_TO_HIDE_CONFIG = { | ||||
key: _CLICK_TO_HIDE, | ||||
value: true, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true | ||||
}, | ||||
CONTAINER_CONFIG = { | ||||
key: _CONTAINER, | ||||
suppressEvent: true | ||||
}, | ||||
SCROLL_INCREMENT_CONFIG = { | ||||
key: _SCROLL_INCREMENT, | ||||
value: 1, | ||||
validator: Lang.isNumber, | ||||
supercedes: [_MAX_HEIGHT], | ||||
suppressEvent: true | ||||
}, | ||||
MIN_SCROLL_HEIGHT_CONFIG = { | ||||
key: _MIN_SCROLL_HEIGHT, | ||||
value: 90, | ||||
validator: Lang.isNumber, | ||||
supercedes: [_MAX_HEIGHT], | ||||
suppressEvent: true | ||||
}, | ||||
MAX_HEIGHT_CONFIG = { | ||||
key: _MAX_HEIGHT, | ||||
value: 0, | ||||
validator: Lang.isNumber, | ||||
supercedes: [_IFRAME], | ||||
suppressEvent: true | ||||
}, | ||||
CLASS_NAME_CONFIG = { | ||||
key: _CLASSNAME, | ||||
value: null, | ||||
validator: Lang.isString, | ||||
suppressEvent: true | ||||
}, | ||||
DISABLED_CONFIG = { | ||||
key: _DISABLED, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true | ||||
}, | ||||
SHADOW_CONFIG = { | ||||
key: _SHADOW, | ||||
value: true, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true, | ||||
supercedes: [_VISIBLE] | ||||
}, | ||||
KEEP_OPEN_CONFIG = { | ||||
key: _KEEP_OPEN, | ||||
value: false, | ||||
validator: Lang.isBoolean | ||||
}; | ||||
function onDocFocus(event) { | ||||
oFocusedElement = Event.getTarget(event); | ||||
} | ||||
YAHOO.lang.extend(Menu, Overlay, { | ||||
// Constants | ||||
/** | ||||
* @property CSS_CLASS_NAME | ||||
* @description String representing the CSS class(es) to be applied to the | ||||
* menu's <code><div></code> element. | ||||
* @default "yuimenu" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
CSS_CLASS_NAME: "yuimenu", | ||||
/** | ||||
* @property ITEM_TYPE | ||||
* @description Object representing the type of menu item to instantiate and | ||||
* add when parsing the child nodes (either <code><li></code> element, | ||||
* <code><optgroup></code> element or <code><option></code>) | ||||
* of the menu's source HTML element. | ||||
* @default YAHOO.widget.MenuItem | ||||
* @final | ||||
* @type YAHOO.widget.MenuItem | ||||
*/ | ||||
ITEM_TYPE: null, | ||||
/** | ||||
* @property GROUP_TITLE_TAG_NAME | ||||
* @description String representing the tagname of the HTML element used to | ||||
* title the menu's item groups. | ||||
* @default H6 | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
GROUP_TITLE_TAG_NAME: "h6", | ||||
/** | ||||
* @property OFF_SCREEN_POSITION | ||||
* @description Array representing the default x and y position that a menu | ||||
* should have when it is positioned outside the viewport by the | ||||
* "poistionOffScreen" method. | ||||
* @default "-999em" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
OFF_SCREEN_POSITION: "-999em", | ||||
// Private properties | ||||
/** | ||||
* @property _useHideDelay | ||||
* @description Boolean indicating if the "mouseover" and "mouseout" event | ||||
* handlers used for hiding the menu via a call to "YAHOO.lang.later" have | ||||
* already been assigned. | ||||
* @default false | ||||
* @private | ||||
* @type Boolean | ||||
*/ | ||||
_useHideDelay: false, | ||||
/** | ||||
* @property _bHandledMouseOverEvent | ||||
* @description Boolean indicating the current state of the menu's | ||||
* "mouseover" event. | ||||
* @default false | ||||
* @private | ||||
* @type Boolean | ||||
*/ | ||||
_bHandledMouseOverEvent: false, | ||||
/** | ||||
* @property _bHandledMouseOutEvent | ||||
* @description Boolean indicating the current state of the menu's | ||||
* "mouseout" event. | ||||
* @default false | ||||
* @private | ||||
* @type Boolean | ||||
*/ | ||||
_bHandledMouseOutEvent: false, | ||||
/** | ||||
* @property _aGroupTitleElements | ||||
* @description Array of HTML element used to title groups of menu items. | ||||
* @default [] | ||||
* @private | ||||
* @type Array | ||||
*/ | ||||
_aGroupTitleElements: null, | ||||
/** | ||||
* @property _aItemGroups | ||||
* @description Multi-dimensional Array representing the menu items as they | ||||
* are grouped in the menu. | ||||
* @default [] | ||||
* @private | ||||
* @type Array | ||||
*/ | ||||
_aItemGroups: null, | ||||
/** | ||||
* @property _aListElements | ||||
* @description Array of <code><ul></code> elements, each of which is | ||||
* the parent node for each item's <code><li></code> element. | ||||
* @default [] | ||||
* @private | ||||
* @type Array | ||||
*/ | ||||
_aListElements: null, | ||||
/** | ||||
* @property _nCurrentMouseX | ||||
* @description The current x coordinate of the mouse inside the area of | ||||
* the menu. | ||||
* @default 0 | ||||
* @private | ||||
* @type Number | ||||
*/ | ||||
_nCurrentMouseX: 0, | ||||
/** | ||||
* @property _bStopMouseEventHandlers | ||||
* @description Stops "mouseover," "mouseout," and "mousemove" event handlers | ||||
* from executing. | ||||
* @default false | ||||
* @private | ||||
* @type Boolean | ||||
*/ | ||||
_bStopMouseEventHandlers: false, | ||||
/** | ||||
* @property _sClassName | ||||
* @description The current value of the "classname" configuration attribute. | ||||
* @default null | ||||
* @private | ||||
* @type String | ||||
*/ | ||||
_sClassName: null, | ||||
// Public properties | ||||
/** | ||||
* @property lazyLoad | ||||
* @description Boolean indicating if the menu's "lazy load" feature is | ||||
* enabled. If set to "true," initialization and rendering of the menu's | ||||
* items will be deferred until the first time it is made visible. This | ||||
* property should be set via the constructor using the configuration | ||||
* object literal. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
lazyLoad: false, | ||||
/** | ||||
* @property itemData | ||||
* @description Array of items to be added to the menu. The array can contain | ||||
* strings representing the text for each item to be created, object literals | ||||
* representing the menu item configuration properties, or MenuItem instances. | ||||
* This property should be set via the constructor using the configuration | ||||
* object literal. | ||||
* @default null | ||||
* @type Array | ||||
*/ | ||||
itemData: null, | ||||
/** | ||||
* @property activeItem | ||||
* @description Object reference to the item in the menu that has is selected. | ||||
* @default null | ||||
* @type YAHOO.widget.MenuItem | ||||
*/ | ||||
activeItem: null, | ||||
/** | ||||
* @property parent | ||||
* @description Object reference to the menu's parent menu or menu item. | ||||
* This property can be set via the constructor using the configuration | ||||
* object literal. | ||||
* @default null | ||||
* @type YAHOO.widget.MenuItem | ||||
*/ | ||||
parent: null, | ||||
/** | ||||
* @property srcElement | ||||
* @description Object reference to the HTML element (either | ||||
* <code><select></code> or <code><div></code>) used to | ||||
* create the menu. | ||||
* @default null | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a | ||||
* href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html. | ||||
* html#ID-22445964">HTMLDivElement</a> | ||||
*/ | ||||
srcElement: null, | ||||
// Events | ||||
/** | ||||
* @event mouseOverEvent | ||||
* @description Fires when the mouse has entered the menu. Passes back | ||||
* the DOM Event object as an argument. | ||||
*/ | ||||
/** | ||||
* @event mouseOutEvent | ||||
* @description Fires when the mouse has left the menu. Passes back the DOM | ||||
* Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event mouseDownEvent | ||||
* @description Fires when the user mouses down on the menu. Passes back the | ||||
* DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event mouseUpEvent | ||||
* @description Fires when the user releases a mouse button while the mouse is | ||||
* over the menu. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event clickEvent | ||||
* @description Fires when the user clicks the on the menu. Passes back the | ||||
* DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event keyPressEvent | ||||
* @description Fires when the user presses an alphanumeric key when one of the | ||||
* menu's items has focus. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event keyDownEvent | ||||
* @description Fires when the user presses a key when one of the menu's items | ||||
* has focus. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event keyUpEvent | ||||
* @description Fires when the user releases a key when one of the menu's items | ||||
* has focus. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event itemAddedEvent | ||||
* @description Fires when an item is added to the menu. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event itemRemovedEvent | ||||
* @description Fires when an item is removed to the menu. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @method init | ||||
* @description The Menu class's initialization method. This method is | ||||
* automatically called by the constructor, and sets up all DOM references | ||||
* for pre-existing markup, and creates required markup if it is not | ||||
* already present. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><div></code> element of the menu. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><select></code> element to be used as the data source | ||||
* for the menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object | ||||
* specifying the <code><div></code> element of the menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement | ||||
* Object specifying the <code><select></code> element to be used as | ||||
* the data source for the menu. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu. See configuration class documentation for | ||||
* more details. | ||||
*/ | ||||
init: function (p_oElement, p_oConfig) { | ||||
this._aItemGroups = []; | ||||
this._aListElements = []; | ||||
this._aGroupTitleElements = []; | ||||
if (!this.ITEM_TYPE) { | ||||
this.ITEM_TYPE = YAHOO.widget.MenuItem; | ||||
} | ||||
var oElement; | ||||
if (Lang.isString(p_oElement)) { | ||||
oElement = Dom.get(p_oElement); | ||||
} | ||||
else if (p_oElement.tagName) { | ||||
oElement = p_oElement; | ||||
} | ||||
if (oElement && oElement.tagName) { | ||||
switch(oElement.tagName.toUpperCase()) { | ||||
case _DIV_UPPERCASE: | ||||
this.srcElement = oElement; | ||||
if (!oElement.id) { | ||||
oElement.setAttribute(_ID, Dom.generateId()); | ||||
} | ||||
/* | ||||
Note: we don't pass the user config in here yet | ||||
because we only want it executed once, at the lowest | ||||
subclass level. | ||||
*/ | ||||
Menu.superclass.init.call(this, oElement); | ||||
this.beforeInitEvent.fire(Menu); | ||||
break; | ||||
case _SELECT: | ||||
this.srcElement = oElement; | ||||
/* | ||||
The source element is not something that we can use | ||||
outright, so we need to create a new Overlay | ||||
Note: we don't pass the user config in here yet | ||||
because we only want it executed once, at the lowest | ||||
subclass level. | ||||
*/ | ||||
Menu.superclass.init.call(this, Dom.generateId()); | ||||
this.beforeInitEvent.fire(Menu); | ||||
break; | ||||
} | ||||
} | ||||
else { | ||||
/* | ||||
Note: we don't pass the user config in here yet | ||||
because we only want it executed once, at the lowest | ||||
subclass level. | ||||
*/ | ||||
Menu.superclass.init.call(this, p_oElement); | ||||
this.beforeInitEvent.fire(Menu); | ||||
} | ||||
if (this.element) { | ||||
Dom.addClass(this.element, this.CSS_CLASS_NAME); | ||||
// Subscribe to Custom Events | ||||
this.initEvent.subscribe(this._onInit); | ||||
this.beforeRenderEvent.subscribe(this._onBeforeRender); | ||||
this.renderEvent.subscribe(this._onRender); | ||||
this.beforeShowEvent.subscribe(this._onBeforeShow); | ||||
this.hideEvent.subscribe(this._onHide); | ||||
this.showEvent.subscribe(this._onShow); | ||||
this.beforeHideEvent.subscribe(this._onBeforeHide); | ||||
this.mouseOverEvent.subscribe(this._onMouseOver); | ||||
this.mouseOutEvent.subscribe(this._onMouseOut); | ||||
this.clickEvent.subscribe(this._onClick); | ||||
this.keyDownEvent.subscribe(this._onKeyDown); | ||||
this.keyPressEvent.subscribe(this._onKeyPress); | ||||
this.blurEvent.subscribe(this._onBlur); | ||||
if (!bFocusListenerInitialized) { | ||||
Event.onFocus(document, onDocFocus); | ||||
bFocusListenerInitialized = true; | ||||
} | ||||
// Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY" | ||||
// methods return values that don't take scrollTop into consideration | ||||
if ((UA.gecko && UA.gecko < 1.9) || UA.webkit) { | ||||
this.cfg.subscribeToConfigEvent(_Y, this._onYChange); | ||||
} | ||||
if (p_oConfig) { | ||||
this.cfg.applyConfig(p_oConfig, true); | ||||
} | ||||
// Register the Menu instance with the MenuManager | ||||
MenuManager.addMenu(this); | ||||
this.initEvent.fire(Menu); | ||||
} | ||||
}, | ||||
// Private methods | ||||
/** | ||||
* @method _initSubTree | ||||
* @description Iterates the childNodes of the source element to find nodes | ||||
* used to instantiate menu and menu items. | ||||
* @private | ||||
*/ | ||||
_initSubTree: function () { | ||||
var oSrcElement = this.srcElement, | ||||
sSrcElementTagName, | ||||
nGroup, | ||||
sGroupTitleTagName, | ||||
oNode, | ||||
aListElements, | ||||
nListElements, | ||||
i; | ||||
if (oSrcElement) { | ||||
sSrcElementTagName = | ||||
(oSrcElement.tagName && oSrcElement.tagName.toUpperCase()); | ||||
if (sSrcElementTagName == _DIV_UPPERCASE) { | ||||
// Populate the collection of item groups and item group titles | ||||
oNode = this.body.firstChild; | ||||
if (oNode) { | ||||
nGroup = 0; | ||||
sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase(); | ||||
do { | ||||
if (oNode && oNode.tagName) { | ||||
switch (oNode.tagName.toUpperCase()) { | ||||
case sGroupTitleTagName: | ||||
this._aGroupTitleElements[nGroup] = oNode; | ||||
break; | ||||
case _UL_UPPERCASE: | ||||
this._aListElements[nGroup] = oNode; | ||||
this._aItemGroups[nGroup] = []; | ||||
nGroup++; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
while ((oNode = oNode.nextSibling)); | ||||
/* | ||||
Apply the "first-of-type" class to the first UL to mimic | ||||
the ":first-of-type" CSS3 psuedo class. | ||||
*/ | ||||
if (this._aListElements[0]) { | ||||
Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE); | ||||
} | ||||
} | ||||
} | ||||
oNode = null; | ||||
if (sSrcElementTagName) { | ||||
switch (sSrcElementTagName) { | ||||
case _DIV_UPPERCASE: | ||||
aListElements = this._aListElements; | ||||
nListElements = aListElements.length; | ||||
if (nListElements > 0) { | ||||
i = nListElements - 1; | ||||
do { | ||||
oNode = aListElements[i].firstChild; | ||||
if (oNode) { | ||||
do { | ||||
if (oNode && oNode.tagName && | ||||
oNode.tagName.toUpperCase() == _LI) { | ||||
this.addItem(new this.ITEM_TYPE(oNode, | ||||
{ parent: this }), i); | ||||
} | ||||
} | ||||
while ((oNode = oNode.nextSibling)); | ||||
} | ||||
} | ||||
while (i--); | ||||
} | ||||
break; | ||||
case _SELECT: | ||||
oNode = oSrcElement.firstChild; | ||||
do { | ||||
if (oNode && oNode.tagName) { | ||||
switch (oNode.tagName.toUpperCase()) { | ||||
case _OPTGROUP: | ||||
case _OPTION: | ||||
this.addItem( | ||||
new this.ITEM_TYPE( | ||||
oNode, | ||||
{ parent: this } | ||||
) | ||||
); | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
while ((oNode = oNode.nextSibling)); | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _getFirstEnabledItem | ||||
* @description Returns the first enabled item in the menu. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
* @private | ||||
*/ | ||||
_getFirstEnabledItem: function () { | ||||
var aItems = this.getItems(), | ||||
nItems = aItems.length, | ||||
oItem, | ||||
returnVal; | ||||
for(var i=0; i<nItems; i++) { | ||||
oItem = aItems[i]; | ||||
if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) { | ||||
returnVal = oItem; | ||||
break; | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method _addItemToGroup | ||||
* @description Adds a menu item to a group. | ||||
* @private | ||||
* @param {Number} p_nGroupIndex Number indicating the group to which the | ||||
* item belongs. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem | ||||
* instance to be added to the menu. | ||||
* @param {String} p_oItem String specifying the text of the item to be added | ||||
* to the menu. | ||||
* @param {Object} p_oItem Object literal containing a set of menu item | ||||
* configuration properties. | ||||
* @param {Number} p_nItemIndex Optional. Number indicating the index at | ||||
* which the menu item should be added. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
_addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) { | ||||
var oItem, | ||||
nGroupIndex, | ||||
aGroup, | ||||
oGroupItem, | ||||
bAppend, | ||||
oNextItemSibling, | ||||
nItemIndex, | ||||
returnVal; | ||||
function getNextItemSibling(p_aArray, p_nStartIndex) { | ||||
return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1))); | ||||
} | ||||
if (p_oItem instanceof this.ITEM_TYPE) { | ||||
oItem = p_oItem; | ||||
oItem.parent = this; | ||||
} | ||||
else if (Lang.isString(p_oItem)) { | ||||
oItem = new this.ITEM_TYPE(p_oItem, { parent: this }); | ||||
} | ||||
else if (Lang.isObject(p_oItem)) { | ||||
p_oItem.parent = this; | ||||
oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem); | ||||
} | ||||
if (oItem) { | ||||
if (oItem.cfg.getProperty(_SELECTED)) { | ||||
this.activeItem = oItem; | ||||
} | ||||
nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0; | ||||
aGroup = this._getItemGroup(nGroupIndex); | ||||
if (!aGroup) { | ||||
aGroup = this._createItemGroup(nGroupIndex); | ||||
} | ||||
if (Lang.isNumber(p_nItemIndex)) { | ||||
bAppend = (p_nItemIndex >= aGroup.length); | ||||
if (aGroup[p_nItemIndex]) { | ||||
aGroup.splice(p_nItemIndex, 0, oItem); | ||||
} | ||||
else { | ||||
aGroup[p_nItemIndex] = oItem; | ||||
} | ||||
oGroupItem = aGroup[p_nItemIndex]; | ||||
if (oGroupItem) { | ||||
if (bAppend && (!oGroupItem.element.parentNode || | ||||
oGroupItem.element.parentNode.nodeType == 11)) { | ||||
this._aListElements[nGroupIndex].appendChild(oGroupItem.element); | ||||
} | ||||
else { | ||||
oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1)); | ||||
if (oNextItemSibling && (!oGroupItem.element.parentNode || | ||||
oGroupItem.element.parentNode.nodeType == 11)) { | ||||
this._aListElements[nGroupIndex].insertBefore( | ||||
oGroupItem.element, oNextItemSibling.element); | ||||
} | ||||
} | ||||
oGroupItem.parent = this; | ||||
this._subscribeToItemEvents(oGroupItem); | ||||
this._configureSubmenu(oGroupItem); | ||||
this._updateItemProperties(nGroupIndex); | ||||
this.itemAddedEvent.fire(oGroupItem); | ||||
this.changeContentEvent.fire(); | ||||
returnVal = oGroupItem; | ||||
} | ||||
} | ||||
else { | ||||
nItemIndex = aGroup.length; | ||||
aGroup[nItemIndex] = oItem; | ||||
oGroupItem = aGroup[nItemIndex]; | ||||
if (oGroupItem) { | ||||
if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) { | ||||
this._aListElements[nGroupIndex].appendChild(oGroupItem.element); | ||||
} | ||||
oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex); | ||||
oGroupItem.element.setAttribute(_INDEX, nItemIndex); | ||||
oGroupItem.parent = this; | ||||
oGroupItem.index = nItemIndex; | ||||
oGroupItem.groupIndex = nGroupIndex; | ||||
this._subscribeToItemEvents(oGroupItem); | ||||
this._configureSubmenu(oGroupItem); | ||||
if (nItemIndex === 0) { | ||||
Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE); | ||||
} | ||||
this.itemAddedEvent.fire(oGroupItem); | ||||
this.changeContentEvent.fire(); | ||||
returnVal = oGroupItem; | ||||
} | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method _removeItemFromGroupByIndex | ||||
* @description Removes a menu item from a group by index. Returns the menu | ||||
* item that was removed. | ||||
* @private | ||||
* @param {Number} p_nGroupIndex Number indicating the group to which the menu | ||||
* item belongs. | ||||
* @param {Number} p_nItemIndex Number indicating the index of the menu item | ||||
* to be removed. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
_removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) { | ||||
var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0, | ||||
aGroup = this._getItemGroup(nGroupIndex), | ||||
aArray, | ||||
oItem, | ||||
oUL; | ||||
if (aGroup) { | ||||
aArray = aGroup.splice(p_nItemIndex, 1); | ||||
oItem = aArray[0]; | ||||
if (oItem) { | ||||
// Update the index and className properties of each member | ||||
this._updateItemProperties(nGroupIndex); | ||||
if (aGroup.length === 0) { | ||||
// Remove the UL | ||||
oUL = this._aListElements[nGroupIndex]; | ||||
if (this.body && oUL) { | ||||
this.body.removeChild(oUL); | ||||
} | ||||
// Remove the group from the array of items | ||||
this._aItemGroups.splice(nGroupIndex, 1); | ||||
// Remove the UL from the array of ULs | ||||
this._aListElements.splice(nGroupIndex, 1); | ||||
/* | ||||
Assign the "first-of-type" class to the new first UL | ||||
in the collection | ||||
*/ | ||||
oUL = this._aListElements[0]; | ||||
if (oUL) { | ||||
Dom.addClass(oUL, _FIRST_OF_TYPE); | ||||
} | ||||
} | ||||
this.itemRemovedEvent.fire(oItem); | ||||
this.changeContentEvent.fire(); | ||||
} | ||||
} | ||||
// Return a reference to the item that was removed | ||||
return oItem; | ||||
}, | ||||
/** | ||||
* @method _removeItemFromGroupByValue | ||||
* @description Removes a menu item from a group by reference. Returns the | ||||
* menu item that was removed. | ||||
* @private | ||||
* @param {Number} p_nGroupIndex Number indicating the group to which the | ||||
* menu item belongs. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem | ||||
* instance to be removed. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
_removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) { | ||||
var aGroup = this._getItemGroup(p_nGroupIndex), | ||||
nItems, | ||||
nItemIndex, | ||||
returnVal, | ||||
i; | ||||
if (aGroup) { | ||||
nItems = aGroup.length; | ||||
nItemIndex = -1; | ||||
if (nItems > 0) { | ||||
i = nItems-1; | ||||
do { | ||||
if (aGroup[i] == p_oItem) { | ||||
nItemIndex = i; | ||||
break; | ||||
} | ||||
} | ||||
while (i--); | ||||
if (nItemIndex > -1) { | ||||
returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex); | ||||
} | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method _updateItemProperties | ||||
* @description Updates the "index," "groupindex," and "className" properties | ||||
* of the menu items in the specified group. | ||||
* @private | ||||
* @param {Number} p_nGroupIndex Number indicating the group of items to update. | ||||
*/ | ||||
_updateItemProperties: function (p_nGroupIndex) { | ||||
var aGroup = this._getItemGroup(p_nGroupIndex), | ||||
nItems = aGroup.length, | ||||
oItem, | ||||
oLI, | ||||
i; | ||||
if (nItems > 0) { | ||||
i = nItems - 1; | ||||
// Update the index and className properties of each member | ||||
do { | ||||
oItem = aGroup[i]; | ||||
if (oItem) { | ||||
oLI = oItem.element; | ||||
oItem.index = i; | ||||
oItem.groupIndex = p_nGroupIndex; | ||||
oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex); | ||||
oLI.setAttribute(_INDEX, i); | ||||
Dom.removeClass(oLI, _FIRST_OF_TYPE); | ||||
} | ||||
} | ||||
while (i--); | ||||
if (oLI) { | ||||
Dom.addClass(oLI, _FIRST_OF_TYPE); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _createItemGroup | ||||
* @description Creates a new menu item group (array) and its associated | ||||
* <code><ul></code> element. Returns an aray of menu item groups. | ||||
* @private | ||||
* @param {Number} p_nIndex Number indicating the group to create. | ||||
* @return {Array} | ||||
*/ | ||||
_createItemGroup: function (p_nIndex) { | ||||
var oUL, | ||||
returnVal; | ||||
if (!this._aItemGroups[p_nIndex]) { | ||||
this._aItemGroups[p_nIndex] = []; | ||||
oUL = document.createElement(_UL_LOWERCASE); | ||||
this._aListElements[p_nIndex] = oUL; | ||||
returnVal = this._aItemGroups[p_nIndex]; | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method _getItemGroup | ||||
* @description Returns the menu item group at the specified index. | ||||
* @private | ||||
* @param {Number} p_nIndex Number indicating the index of the menu item group | ||||
* to be retrieved. | ||||
* @return {Array} | ||||
*/ | ||||
_getItemGroup: function (p_nIndex) { | ||||
var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0, | ||||
aGroups = this._aItemGroups, | ||||
returnVal; | ||||
if (nIndex in aGroups) { | ||||
returnVal = aGroups[nIndex]; | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method _configureSubmenu | ||||
* @description Subscribes the menu item's submenu to its parent menu's events. | ||||
* @private | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem | ||||
* instance with the submenu to be configured. | ||||
*/ | ||||
_configureSubmenu: function (p_oItem) { | ||||
var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
/* | ||||
Listen for configuration changes to the parent menu | ||||
so they they can be applied to the submenu. | ||||
*/ | ||||
this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true); | ||||
this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _subscribeToItemEvents | ||||
* @description Subscribes a menu to a menu item's event. | ||||
* @private | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem | ||||
* instance whose events should be subscribed to. | ||||
*/ | ||||
_subscribeToItemEvents: function (p_oItem) { | ||||
p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this); | ||||
p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this); | ||||
}, | ||||
/** | ||||
* @method _onVisibleChange | ||||
* @description Change event handler for the the menu's "visible" configuration | ||||
* property. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onVisibleChange: function (p_sType, p_aArgs) { | ||||
var bVisible = p_aArgs[0]; | ||||
if (bVisible) { | ||||
Dom.addClass(this.element, _VISIBLE); | ||||
} | ||||
else { | ||||
Dom.removeClass(this.element, _VISIBLE); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _cancelHideDelay | ||||
* @description Cancels the call to "hideMenu." | ||||
* @private | ||||
*/ | ||||
_cancelHideDelay: function () { | ||||
var oTimer = this.getRoot()._hideDelayTimer; | ||||
if (oTimer) { | ||||
oTimer.cancel(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _execHideDelay | ||||
* @description Hides the menu after the number of milliseconds specified by | ||||
* the "hidedelay" configuration property. | ||||
* @private | ||||
*/ | ||||
_execHideDelay: function () { | ||||
this._cancelHideDelay(); | ||||
var oRoot = this.getRoot(); | ||||
oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () { | ||||
if (oRoot.activeItem) { | ||||
if (oRoot.hasFocus()) { | ||||
oRoot.activeItem.focus(); | ||||
} | ||||
oRoot.clearActiveItem(); | ||||
} | ||||
if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) && | ||||
this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
this.hide(); | ||||
} | ||||
}); | ||||
}, | ||||
/** | ||||
* @method _cancelShowDelay | ||||
* @description Cancels the call to the "showMenu." | ||||
* @private | ||||
*/ | ||||
_cancelShowDelay: function () { | ||||
var oTimer = this.getRoot()._showDelayTimer; | ||||
if (oTimer) { | ||||
oTimer.cancel(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _execSubmenuHideDelay | ||||
* @description Hides a submenu after the number of milliseconds specified by | ||||
* the "submenuhidedelay" configuration property have ellapsed. | ||||
* @private | ||||
* @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that | ||||
* should be hidden. | ||||
* @param {Number} p_nMouseX The x coordinate of the mouse when it left | ||||
* the specified submenu's parent menu item. | ||||
* @param {Number} p_nHideDelay The number of milliseconds that should ellapse | ||||
* before the submenu is hidden. | ||||
*/ | ||||
_execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) { | ||||
p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () { | ||||
if (this._nCurrentMouseX > (p_nMouseX + 10)) { | ||||
p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () { | ||||
this.hide(); | ||||
}); | ||||
} | ||||
else { | ||||
p_oSubmenu.hide(); | ||||
} | ||||
}); | ||||
}, | ||||
// Protected methods | ||||
/** | ||||
* @method _disableScrollHeader | ||||
* @description Disables the header used for scrolling the body of the menu. | ||||
* @protected | ||||
*/ | ||||
_disableScrollHeader: function () { | ||||
if (!this._bHeaderDisabled) { | ||||
Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED); | ||||
this._bHeaderDisabled = true; | ||||
} | ||||
}, | ||||
/** | ||||
* @method _disableScrollFooter | ||||
* @description Disables the footer used for scrolling the body of the menu. | ||||
* @protected | ||||
*/ | ||||
_disableScrollFooter: function () { | ||||
if (!this._bFooterDisabled) { | ||||
Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED); | ||||
this._bFooterDisabled = true; | ||||
} | ||||
}, | ||||
/** | ||||
* @method _enableScrollHeader | ||||
* @description Enables the header used for scrolling the body of the menu. | ||||
* @protected | ||||
*/ | ||||
_enableScrollHeader: function () { | ||||
if (this._bHeaderDisabled) { | ||||
Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED); | ||||
this._bHeaderDisabled = false; | ||||
} | ||||
}, | ||||
/** | ||||
* @method _enableScrollFooter | ||||
* @description Enables the footer used for scrolling the body of the menu. | ||||
* @protected | ||||
*/ | ||||
_enableScrollFooter: function () { | ||||
if (this._bFooterDisabled) { | ||||
Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED); | ||||
this._bFooterDisabled = false; | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onMouseOver | ||||
* @description "mouseover" event handler for the menu. | ||||
* @protected | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onMouseOver: function (p_sType, p_aArgs) { | ||||
var oEvent = p_aArgs[0], | ||||
oItem = p_aArgs[1], | ||||
oTarget = Event.getTarget(oEvent), | ||||
oRoot = this.getRoot(), | ||||
oSubmenuHideDelayTimer = this._submenuHideDelayTimer, | ||||
oParentMenu, | ||||
nShowDelay, | ||||
bShowDelay, | ||||
oActiveItem, | ||||
oItemCfg, | ||||
oSubmenu; | ||||
var showSubmenu = function () { | ||||
if (this.parent.cfg.getProperty(_SELECTED)) { | ||||
this.show(); | ||||
} | ||||
}; | ||||
if (!this._bStopMouseEventHandlers) { | ||||
if (!this._bHandledMouseOverEvent && (oTarget == this.element || | ||||
Dom.isAncestor(this.element, oTarget))) { | ||||
// Menu mouseover logic | ||||
if (this._useHideDelay) { | ||||
this._cancelHideDelay(); | ||||
} | ||||
this._nCurrentMouseX = 0; | ||||
Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true); | ||||
/* | ||||
If the mouse is moving from the submenu back to its corresponding menu item, | ||||
don't hide the submenu or clear the active MenuItem. | ||||
*/ | ||||
if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) { | ||||
this.clearActiveItem(); | ||||
} | ||||
if (this.parent && oSubmenuHideDelayTimer) { | ||||
oSubmenuHideDelayTimer.cancel(); | ||||
this.parent.cfg.setProperty(_SELECTED, true); | ||||
oParentMenu = this.parent.parent; | ||||
oParentMenu._bHandledMouseOutEvent = true; | ||||
oParentMenu._bHandledMouseOverEvent = false; | ||||
} | ||||
this._bHandledMouseOverEvent = true; | ||||
this._bHandledMouseOutEvent = false; | ||||
} | ||||
if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) && | ||||
(oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) { | ||||
// Menu Item mouseover logic | ||||
nShowDelay = this.cfg.getProperty(_SHOW_DELAY); | ||||
bShowDelay = (nShowDelay > 0); | ||||
if (bShowDelay) { | ||||
this._cancelShowDelay(); | ||||
} | ||||
oActiveItem = this.activeItem; | ||||
if (oActiveItem) { | ||||
oActiveItem.cfg.setProperty(_SELECTED, false); | ||||
} | ||||
oItemCfg = oItem.cfg; | ||||
// Select and focus the current menu item | ||||
oItemCfg.setProperty(_SELECTED, true); | ||||
if (this.hasFocus() || oRoot._hasFocus) { | ||||
oItem.focus(); | ||||
oRoot._hasFocus = false; | ||||
} | ||||
if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) { | ||||
// Show the submenu this menu item | ||||
oSubmenu = oItemCfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
if (bShowDelay) { | ||||
oRoot._showDelayTimer = | ||||
Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu); | ||||
} | ||||
else { | ||||
oSubmenu.show(); | ||||
} | ||||
} | ||||
} | ||||
oItem.handledMouseOverEvent = true; | ||||
oItem.handledMouseOutEvent = false; | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onMouseOut | ||||
* @description "mouseout" event handler for the menu. | ||||
* @protected | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onMouseOut: function (p_sType, p_aArgs) { | ||||
var oEvent = p_aArgs[0], | ||||
oItem = p_aArgs[1], | ||||
oRelatedTarget = Event.getRelatedTarget(oEvent), | ||||
bMovingToSubmenu = false, | ||||
oItemCfg, | ||||
oSubmenu, | ||||
nSubmenuHideDelay, | ||||
nShowDelay; | ||||
if (!this._bStopMouseEventHandlers) { | ||||
if (oItem && !oItem.cfg.getProperty(_DISABLED)) { | ||||
oItemCfg = oItem.cfg; | ||||
oSubmenu = oItemCfg.getProperty(_SUBMENU); | ||||
if (oSubmenu && (oRelatedTarget == oSubmenu.element || | ||||
Dom.isAncestor(oSubmenu.element, oRelatedTarget))) { | ||||
bMovingToSubmenu = true; | ||||
} | ||||
if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element && | ||||
!Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) { | ||||
// Menu Item mouseout logic | ||||
if (!bMovingToSubmenu) { | ||||
oItem.cfg.setProperty(_SELECTED, false); | ||||
if (oSubmenu) { | ||||
nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY); | ||||
nShowDelay = this.cfg.getProperty(_SHOW_DELAY); | ||||
if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 && | ||||
nShowDelay >= nSubmenuHideDelay) { | ||||
this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent), | ||||
nSubmenuHideDelay); | ||||
} | ||||
else { | ||||
oSubmenu.hide(); | ||||
} | ||||
} | ||||
} | ||||
oItem.handledMouseOutEvent = true; | ||||
oItem.handledMouseOverEvent = false; | ||||
} | ||||
} | ||||
if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element && | ||||
!Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) { | ||||
// Menu mouseout logic | ||||
if (this._useHideDelay) { | ||||
this._execHideDelay(); | ||||
} | ||||
Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove); | ||||
this._nCurrentMouseX = Event.getPageX(oEvent); | ||||
this._bHandledMouseOutEvent = true; | ||||
this._bHandledMouseOverEvent = false; | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onMouseMove | ||||
* @description "click" event handler for the menu. | ||||
* @protected | ||||
* @param {Event} p_oEvent Object representing the DOM event object passed | ||||
* back by the event utility (YAHOO.util.Event). | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
_onMouseMove: function (p_oEvent, p_oMenu) { | ||||
if (!this._bStopMouseEventHandlers) { | ||||
this._nCurrentMouseX = Event.getPageX(p_oEvent); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onClick | ||||
* @description "click" event handler for the menu. | ||||
* @protected | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onClick: function (p_sType, p_aArgs) { | ||||
var oEvent = p_aArgs[0], | ||||
oItem = p_aArgs[1], | ||||
bInMenuAnchor = false, | ||||
oSubmenu, | ||||
oMenu, | ||||
oRoot, | ||||
sId, | ||||
sURL, | ||||
nHashPos, | ||||
nLen; | ||||
var hide = function () { | ||||
oRoot = this.getRoot(); | ||||
if (oRoot instanceof YAHOO.widget.MenuBar || | ||||
oRoot.cfg.getProperty(_POSITION) == _STATIC) { | ||||
oRoot.clearActiveItem(); | ||||
} | ||||
else { | ||||
oRoot.hide(); | ||||
} | ||||
}; | ||||
if (oItem) { | ||||
if (oItem.cfg.getProperty(_DISABLED)) { | ||||
Event.preventDefault(oEvent); | ||||
hide.call(this); | ||||
} | ||||
else { | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
/* | ||||
Check if the URL of the anchor is pointing to an element that is | ||||
a child of the menu. | ||||
*/ | ||||
sURL = oItem.cfg.getProperty(_URL); | ||||
if (sURL) { | ||||
nHashPos = sURL.indexOf(_HASH); | ||||
nLen = sURL.length; | ||||
if (nHashPos != -1) { | ||||
sURL = sURL.substr(nHashPos, nLen); | ||||
nLen = sURL.length; | ||||
if (nLen > 1) { | ||||
sId = sURL.substr(1, nLen); | ||||
oMenu = YAHOO.widget.MenuManager.getMenu(sId); | ||||
if (oMenu) { | ||||
bInMenuAnchor = | ||||
(this.getRoot() === oMenu.getRoot()); | ||||
} | ||||
} | ||||
else if (nLen === 1) { | ||||
bInMenuAnchor = true; | ||||
} | ||||
} | ||||
} | ||||
if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) { | ||||
Event.preventDefault(oEvent); | ||||
if (UA.webkit) { | ||||
oItem.focus(); | ||||
} | ||||
else { | ||||
oItem.focusEvent.fire(); | ||||
} | ||||
} | ||||
if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) { | ||||
hide.call(this); | ||||
} | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onKeyDown | ||||
* @description "keydown" event handler for the menu. | ||||
* @protected | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onKeyDown: function (p_sType, p_aArgs) { | ||||
var oEvent = p_aArgs[0], | ||||
oItem = p_aArgs[1], | ||||
oSubmenu, | ||||
oItemCfg, | ||||
oParentItem, | ||||
oRoot, | ||||
oNextItem, | ||||
oBody, | ||||
nBodyScrollTop, | ||||
nBodyOffsetHeight, | ||||
aItems, | ||||
nItems, | ||||
nNextItemOffsetTop, | ||||
nScrollTarget, | ||||
oParentMenu, | ||||
oFocusedEl; | ||||
if (this._useHideDelay) { | ||||
this._cancelHideDelay(); | ||||
} | ||||
/* | ||||
This function is called to prevent a bug in Firefox. In Firefox, | ||||
moving a DOM element into a stationary mouse pointer will cause the | ||||
browser to fire mouse events. This can result in the menu mouse | ||||
event handlers being called uncessarily, especially when menus are | ||||
moved into a stationary mouse pointer as a result of a | ||||
key event handler. | ||||
*/ | ||||
function stopMouseEventHandlers() { | ||||
this._bStopMouseEventHandlers = true; | ||||
Lang.later(10, this, function () { | ||||
this._bStopMouseEventHandlers = false; | ||||
}); | ||||
} | ||||
if (oItem && !oItem.cfg.getProperty(_DISABLED)) { | ||||
oItemCfg = oItem.cfg; | ||||
oParentItem = this.parent; | ||||
switch(oEvent.keyCode) { | ||||
case 38: // Up arrow | ||||
case 40: // Down arrow | ||||
oNextItem = (oEvent.keyCode == 38) ? | ||||
oItem.getPreviousEnabledSibling() : | ||||
oItem.getNextEnabledSibling(); | ||||
if (oNextItem) { | ||||
this.clearActiveItem(); | ||||
oNextItem.cfg.setProperty(_SELECTED, true); | ||||
oNextItem.focus(); | ||||
if (this.cfg.getProperty(_MAX_HEIGHT) > 0) { | ||||
oBody = this.body; | ||||
nBodyScrollTop = oBody.scrollTop; | ||||
nBodyOffsetHeight = oBody.offsetHeight; | ||||
aItems = this.getItems(); | ||||
nItems = aItems.length - 1; | ||||
nNextItemOffsetTop = oNextItem.element.offsetTop; | ||||
if (oEvent.keyCode == 40 ) { // Down | ||||
if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) { | ||||
oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight; | ||||
} | ||||
else if (nNextItemOffsetTop <= nBodyScrollTop) { | ||||
oBody.scrollTop = 0; | ||||
} | ||||
if (oNextItem == aItems[nItems]) { | ||||
oBody.scrollTop = oNextItem.element.offsetTop; | ||||
} | ||||
} | ||||
else { // Up | ||||
if (nNextItemOffsetTop <= nBodyScrollTop) { | ||||
oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight; | ||||
} | ||||
else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) { | ||||
oBody.scrollTop = nNextItemOffsetTop; | ||||
} | ||||
if (oNextItem == aItems[0]) { | ||||
oBody.scrollTop = 0; | ||||
} | ||||
} | ||||
nBodyScrollTop = oBody.scrollTop; | ||||
nScrollTarget = oBody.scrollHeight - oBody.offsetHeight; | ||||
if (nBodyScrollTop === 0) { | ||||
this._disableScrollHeader(); | ||||
this._enableScrollFooter(); | ||||
} | ||||
else if (nBodyScrollTop == nScrollTarget) { | ||||
this._enableScrollHeader(); | ||||
this._disableScrollFooter(); | ||||
} | ||||
else { | ||||
this._enableScrollHeader(); | ||||
this._enableScrollFooter(); | ||||
} | ||||
} | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
stopMouseEventHandlers(); | ||||
break; | ||||
case 39: // Right arrow | ||||
oSubmenu = oItemCfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
if (!oItemCfg.getProperty(_SELECTED)) { | ||||
oItemCfg.setProperty(_SELECTED, true); | ||||
} | ||||
oSubmenu.show(); | ||||
oSubmenu.setInitialFocus(); | ||||
oSubmenu.setInitialSelection(); | ||||
} | ||||
else { | ||||
oRoot = this.getRoot(); | ||||
if (oRoot instanceof YAHOO.widget.MenuBar) { | ||||
oNextItem = oRoot.activeItem.getNextEnabledSibling(); | ||||
if (oNextItem) { | ||||
oRoot.clearActiveItem(); | ||||
oNextItem.cfg.setProperty(_SELECTED, true); | ||||
oSubmenu = oNextItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.show(); | ||||
oSubmenu.setInitialFocus(); | ||||
} | ||||
else { | ||||
oNextItem.focus(); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
stopMouseEventHandlers(); | ||||
break; | ||||
case 37: // Left arrow | ||||
if (oParentItem) { | ||||
oParentMenu = oParentItem.parent; | ||||
if (oParentMenu instanceof YAHOO.widget.MenuBar) { | ||||
oNextItem = | ||||
oParentMenu.activeItem.getPreviousEnabledSibling(); | ||||
if (oNextItem) { | ||||
oParentMenu.clearActiveItem(); | ||||
oNextItem.cfg.setProperty(_SELECTED, true); | ||||
oSubmenu = oNextItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.show(); | ||||
oSubmenu.setInitialFocus(); | ||||
} | ||||
else { | ||||
oNextItem.focus(); | ||||
} | ||||
} | ||||
} | ||||
else { | ||||
this.hide(); | ||||
oParentItem.focus(); | ||||
} | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
stopMouseEventHandlers(); | ||||
break; | ||||
} | ||||
} | ||||
if (oEvent.keyCode == 27) { // Esc key | ||||
if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
this.hide(); | ||||
if (this.parent) { | ||||
this.parent.focus(); | ||||
} | ||||
else { | ||||
// Focus the element that previously had focus | ||||
oFocusedEl = this._focusedElement; | ||||
if (oFocusedEl && oFocusedEl.focus) { | ||||
try { | ||||
oFocusedEl.focus(); | ||||
} | ||||
catch(ex) { | ||||
} | ||||
} | ||||
} | ||||
} | ||||
else if (this.activeItem) { | ||||
oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) { | ||||
oSubmenu.hide(); | ||||
this.activeItem.focus(); | ||||
} | ||||
else { | ||||
this.activeItem.blur(); | ||||
this.activeItem.cfg.setProperty(_SELECTED, false); | ||||
} | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onKeyPress | ||||
* @description "keypress" event handler for a Menu instance. | ||||
* @protected | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
_onKeyPress: function (p_sType, p_aArgs) { | ||||
var oEvent = p_aArgs[0]; | ||||
if (oEvent.keyCode == 40 || oEvent.keyCode == 38) { | ||||
Event.preventDefault(oEvent); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onBlur | ||||
* @description "blur" event handler for a Menu instance. | ||||
* @protected | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
_onBlur: function (p_sType, p_aArgs) { | ||||
if (this._hasFocus) { | ||||
this._hasFocus = false; | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onYChange | ||||
* @description "y" event handler for a Menu instance. | ||||
* @protected | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
_onYChange: function (p_sType, p_aArgs) { | ||||
var oParent = this.parent, | ||||
nScrollTop, | ||||
oIFrame, | ||||
nY; | ||||
if (oParent) { | ||||
nScrollTop = oParent.parent.body.scrollTop; | ||||
if (nScrollTop > 0) { | ||||
nY = (this.cfg.getProperty(_Y) - nScrollTop); | ||||
Dom.setY(this.element, nY); | ||||
oIFrame = this.iframe; | ||||
if (oIFrame) { | ||||
Dom.setY(oIFrame, nY); | ||||
} | ||||
this.cfg.setProperty(_Y, nY, true); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onScrollTargetMouseOver | ||||
* @description "mouseover" event handler for the menu's "header" and "footer" | ||||
* elements. Used to scroll the body of the menu up and down when the | ||||
* menu's "maxheight" configuration property is set to a value greater than 0. | ||||
* @protected | ||||
* @param {Event} p_oEvent Object representing the DOM event object passed | ||||
* back by the event utility (YAHOO.util.Event). | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
_onScrollTargetMouseOver: function (p_oEvent, p_oMenu) { | ||||
var oBodyScrollTimer = this._bodyScrollTimer; | ||||
if (oBodyScrollTimer) { | ||||
oBodyScrollTimer.cancel(); | ||||
} | ||||
this._cancelHideDelay(); | ||||
var oTarget = Event.getTarget(p_oEvent), | ||||
oBody = this.body, | ||||
nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT), | ||||
nScrollTarget, | ||||
fnScrollFunction; | ||||
function scrollBodyDown() { | ||||
var nScrollTop = oBody.scrollTop; | ||||
if (nScrollTop < nScrollTarget) { | ||||
oBody.scrollTop = (nScrollTop + nScrollIncrement); | ||||
this._enableScrollHeader(); | ||||
} | ||||
else { | ||||
oBody.scrollTop = nScrollTarget; | ||||
this._bodyScrollTimer.cancel(); | ||||
this._disableScrollFooter(); | ||||
} | ||||
} | ||||
function scrollBodyUp() { | ||||
var nScrollTop = oBody.scrollTop; | ||||
if (nScrollTop > 0) { | ||||
oBody.scrollTop = (nScrollTop - nScrollIncrement); | ||||
this._enableScrollFooter(); | ||||
} | ||||
else { | ||||
oBody.scrollTop = 0; | ||||
this._bodyScrollTimer.cancel(); | ||||
this._disableScrollHeader(); | ||||
} | ||||
} | ||||
if (Dom.hasClass(oTarget, _HD)) { | ||||
fnScrollFunction = scrollBodyUp; | ||||
} | ||||
else { | ||||
nScrollTarget = oBody.scrollHeight - oBody.offsetHeight; | ||||
fnScrollFunction = scrollBodyDown; | ||||
} | ||||
this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true); | ||||
}, | ||||
/** | ||||
* @method _onScrollTargetMouseOut | ||||
* @description "mouseout" event handler for the menu's "header" and "footer" | ||||
* elements. Used to stop scrolling the body of the menu up and down when the | ||||
* menu's "maxheight" configuration property is set to a value greater than 0. | ||||
* @protected | ||||
* @param {Event} p_oEvent Object representing the DOM event object passed | ||||
* back by the event utility (YAHOO.util.Event). | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
_onScrollTargetMouseOut: function (p_oEvent, p_oMenu) { | ||||
var oBodyScrollTimer = this._bodyScrollTimer; | ||||
if (oBodyScrollTimer) { | ||||
oBodyScrollTimer.cancel(); | ||||
} | ||||
this._cancelHideDelay(); | ||||
}, | ||||
// Private methods | ||||
/** | ||||
* @method _onInit | ||||
* @description "init" event handler for the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onInit: function (p_sType, p_aArgs) { | ||||
this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange); | ||||
var bRootMenu = !this.parent, | ||||
bLazyLoad = this.lazyLoad; | ||||
/* | ||||
Automatically initialize a menu's subtree if: | ||||
1) This is the root menu and lazyload is off | ||||
2) This is the root menu, lazyload is on, but the menu is | ||||
already visible | ||||
3) This menu is a submenu and lazyload is off | ||||
*/ | ||||
if (((bRootMenu && !bLazyLoad) || | ||||
(bRootMenu && (this.cfg.getProperty(_VISIBLE) || | ||||
this.cfg.getProperty(_POSITION) == _STATIC)) || | ||||
(!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) { | ||||
if (this.srcElement) { | ||||
this._initSubTree(); | ||||
} | ||||
if (this.itemData) { | ||||
this.addItems(this.itemData); | ||||
} | ||||
} | ||||
else if (bLazyLoad) { | ||||
this.cfg.fireQueue(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onBeforeRender | ||||
* @description "beforerender" event handler for the menu. Appends all of the | ||||
* <code><ul></code>, <code><li></code> and their accompanying | ||||
* title elements to the body element of the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onBeforeRender: function (p_sType, p_aArgs) { | ||||
var oEl = this.element, | ||||
nListElements = this._aListElements.length, | ||||
bFirstList = true, | ||||
i = 0, | ||||
oUL, | ||||
oGroupTitle; | ||||
if (nListElements > 0) { | ||||
do { | ||||
oUL = this._aListElements[i]; | ||||
if (oUL) { | ||||
if (bFirstList) { | ||||
Dom.addClass(oUL, _FIRST_OF_TYPE); | ||||
bFirstList = false; | ||||
} | ||||
if (!Dom.isAncestor(oEl, oUL)) { | ||||
this.appendToBody(oUL); | ||||
} | ||||
oGroupTitle = this._aGroupTitleElements[i]; | ||||
if (oGroupTitle) { | ||||
if (!Dom.isAncestor(oEl, oGroupTitle)) { | ||||
oUL.parentNode.insertBefore(oGroupTitle, oUL); | ||||
} | ||||
Dom.addClass(oUL, _HAS_TITLE); | ||||
} | ||||
} | ||||
i++; | ||||
} | ||||
while (i < nListElements); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onRender | ||||
* @description "render" event handler for the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onRender: function (p_sType, p_aArgs) { | ||||
if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
if (!this.cfg.getProperty(_VISIBLE)) { | ||||
this.positionOffScreen(); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onBeforeShow | ||||
* @description "beforeshow" event handler for the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onBeforeShow: function (p_sType, p_aArgs) { | ||||
var nOptions, | ||||
n, | ||||
oSrcElement, | ||||
oContainer = this.cfg.getProperty(_CONTAINER); | ||||
if (this.lazyLoad && this.getItemGroups().length === 0) { | ||||
if (this.srcElement) { | ||||
this._initSubTree(); | ||||
} | ||||
if (this.itemData) { | ||||
if (this.parent && this.parent.parent && | ||||
this.parent.parent.srcElement && | ||||
this.parent.parent.srcElement.tagName.toUpperCase() == | ||||
_SELECT) { | ||||
nOptions = this.itemData.length; | ||||
for(n=0; n<nOptions; n++) { | ||||
if (this.itemData[n].tagName) { | ||||
this.addItem((new this.ITEM_TYPE(this.itemData[n]))); | ||||
} | ||||
} | ||||
} | ||||
else { | ||||
this.addItems(this.itemData); | ||||
} | ||||
} | ||||
oSrcElement = this.srcElement; | ||||
if (oSrcElement) { | ||||
if (oSrcElement.tagName.toUpperCase() == _SELECT) { | ||||
if (Dom.inDocument(oSrcElement)) { | ||||
this.render(oSrcElement.parentNode); | ||||
} | ||||
else { | ||||
this.render(oContainer); | ||||
} | ||||
} | ||||
else { | ||||
this.render(); | ||||
} | ||||
} | ||||
else { | ||||
if (this.parent) { | ||||
this.render(this.parent.element); | ||||
} | ||||
else { | ||||
this.render(oContainer); | ||||
} | ||||
} | ||||
} | ||||
var oParent = this.parent, | ||||
aAlignment; | ||||
if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
this.cfg.refireEvent(_XY); | ||||
} | ||||
if (oParent) { | ||||
aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT); | ||||
this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]); | ||||
this.align(); | ||||
} | ||||
}, | ||||
getConstrainedY: function (y) { | ||||
var oMenu = this, | ||||
aContext = oMenu.cfg.getProperty(_CONTEXT), | ||||
nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT), | ||||
nMaxHeight, | ||||
oOverlapPositions = { | ||||
"trbr": true, | ||||
"tlbl": true, | ||||
"bltl": true, | ||||
"brtr": true | ||||
}, | ||||
bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]), | ||||
oMenuEl = oMenu.element, | ||||
nMenuOffsetHeight = oMenuEl.offsetHeight, | ||||
nViewportOffset = Overlay.VIEWPORT_OFFSET, | ||||
viewPortHeight = Dom.getViewportHeight(), | ||||
scrollY = Dom.getDocumentScrollTop(), | ||||
bCanConstrain = | ||||
(oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight), | ||||
nAvailableHeight, | ||||
oContextEl, | ||||
nContextElY, | ||||
nContextElHeight, | ||||
bFlipped = false, | ||||
nTopRegionHeight, | ||||
nBottomRegionHeight, | ||||
topConstraint = scrollY + nViewportOffset, | ||||
bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset, | ||||
yNew = y; | ||||
var flipVertical = function () { | ||||
var nNewY; | ||||
// The Menu is below the context element, flip it above | ||||
if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { | ||||
nNewY = (nContextElY - nMenuOffsetHeight); | ||||
} | ||||
else { // The Menu is above the context element, flip it below | ||||
nNewY = (nContextElY + nContextElHeight); | ||||
} | ||||
oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true); | ||||
return nNewY; | ||||
}; | ||||
/* | ||||
Uses the context element's position to calculate the availble height | ||||
above and below it to display its corresponding Menu. | ||||
*/ | ||||
var getDisplayRegionHeight = function () { | ||||
// The Menu is below the context element | ||||
if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { | ||||
return (nBottomRegionHeight - nViewportOffset); | ||||
} | ||||
else { // The Menu is above the context element | ||||
return (nTopRegionHeight - nViewportOffset); | ||||
} | ||||
}; | ||||
/* | ||||
Sets the Menu's "y" configuration property to the correct value based on its | ||||
current orientation. | ||||
*/ | ||||
var alignY = function () { | ||||
var nNewY; | ||||
if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { | ||||
nNewY = (nContextElY + nContextElHeight); | ||||
} | ||||
else { | ||||
nNewY = (nContextElY - oMenuEl.offsetHeight); | ||||
} | ||||
oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true); | ||||
}; | ||||
// Resets the maxheight of the Menu to the value set by the user | ||||
var resetMaxHeight = function () { | ||||
oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT)); | ||||
oMenu.hideEvent.unsubscribe(resetMaxHeight); | ||||
}; | ||||
/* | ||||
Trys to place the Menu in the best possible position (either above or | ||||
below its corresponding context element). | ||||
*/ | ||||
var setVerticalPosition = function () { | ||||
var nDisplayRegionHeight = getDisplayRegionHeight(), | ||||
bMenuHasItems = (oMenu.getItems().length > 0), | ||||
nMenuMinScrollHeight, | ||||
fnReturnVal; | ||||
if (nMenuOffsetHeight > nDisplayRegionHeight) { | ||||
nMenuMinScrollHeight = | ||||
bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight; | ||||
if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) { | ||||
nMaxHeight = nDisplayRegionHeight; | ||||
} | ||||
else { | ||||
nMaxHeight = nInitialMaxHeight; | ||||
} | ||||
oMenu._setScrollHeight(nMaxHeight); | ||||
oMenu.hideEvent.subscribe(resetMaxHeight); | ||||
// Re-align the Menu since its height has just changed | ||||
// as a result of the setting of the maxheight property. | ||||
alignY(); | ||||
if (nDisplayRegionHeight < nMenuMinScrollHeight) { | ||||
if (bFlipped) { | ||||
/* | ||||
All possible positions and values for the "maxheight" | ||||
configuration property have been tried, but none were | ||||
successful, so fall back to the original size and position. | ||||
*/ | ||||
flipVertical(); | ||||
} | ||||
else { | ||||
flipVertical(); | ||||
bFlipped = true; | ||||
fnReturnVal = setVerticalPosition(); | ||||
} | ||||
} | ||||
} | ||||
else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) { | ||||
oMenu._setScrollHeight(nInitialMaxHeight); | ||||
oMenu.hideEvent.subscribe(resetMaxHeight); | ||||
// Re-align the Menu since its height has just changed | ||||
// as a result of the setting of the maxheight property. | ||||
alignY(); | ||||
} | ||||
return fnReturnVal; | ||||
}; | ||||
// Determine if the current value for the Menu's "y" configuration property will | ||||
// result in the Menu being positioned outside the boundaries of the viewport | ||||
if (y < topConstraint || y > bottomConstraint) { | ||||
// The current value for the Menu's "y" configuration property WILL | ||||
// result in the Menu being positioned outside the boundaries of the viewport | ||||
if (bCanConstrain) { | ||||
if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) { | ||||
// SOLUTION #1: | ||||
// If the "preventcontextoverlap" configuration property is set to "true", | ||||
// try to flip and/or scroll the Menu to both keep it inside the boundaries of the | ||||
// viewport AND from overlaping its context element (MenuItem or MenuBarItem). | ||||
oContextEl = aContext[0]; | ||||
nContextElHeight = oContextEl.offsetHeight; | ||||
nContextElY = (Dom.getY(oContextEl) - scrollY); | ||||
nTopRegionHeight = nContextElY; | ||||
nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight)); | ||||
setVerticalPosition(); | ||||
yNew = oMenu.cfg.getProperty(_Y); | ||||
} | ||||
else if (!(oMenu instanceof YAHOO.widget.MenuBar) && | ||||
nMenuOffsetHeight >= viewPortHeight) { | ||||
// SOLUTION #2: | ||||
// If the Menu exceeds the height of the viewport, introduce scroll bars | ||||
// to keep the Menu inside the boundaries of the viewport | ||||
nAvailableHeight = (viewPortHeight - (nViewportOffset * 2)); | ||||
if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) { | ||||
oMenu._setScrollHeight(nAvailableHeight); | ||||
oMenu.hideEvent.subscribe(resetMaxHeight); | ||||
alignY(); | ||||
yNew = oMenu.cfg.getProperty(_Y); | ||||
} | ||||
} | ||||
else { | ||||
// SOLUTION #3: | ||||
if (y < topConstraint) { | ||||
yNew = topConstraint; | ||||
} else if (y > bottomConstraint) { | ||||
yNew = bottomConstraint; | ||||
} | ||||
} | ||||
} | ||||
else { | ||||
// The "y" configuration property cannot be set to a value that will keep | ||||
// entire Menu inside the boundary of the viewport. Therefore, set | ||||
// the "y" configuration property to scrollY to keep as much of the | ||||
// Menu inside the viewport as possible. | ||||
yNew = nViewportOffset + scrollY; | ||||
} | ||||
} | ||||
return yNew; | ||||
}, | ||||
/** | ||||
* @method _onHide | ||||
* @description "hide" event handler for the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onHide: function (p_sType, p_aArgs) { | ||||
if (this.cfg.getProperty(_POSITION) === _DYNAMIC) { | ||||
this.positionOffScreen(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onShow | ||||
* @description "show" event handler for the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onShow: function (p_sType, p_aArgs) { | ||||
var oParent = this.parent, | ||||
oParentMenu, | ||||
oElement, | ||||
nOffsetWidth, | ||||
sWidth; | ||||
function disableAutoSubmenuDisplay(p_oEvent) { | ||||
var oTarget; | ||||
if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) { | ||||
/* | ||||
Set the "autosubmenudisplay" to "false" if the user | ||||
clicks outside the menu bar. | ||||
*/ | ||||
oTarget = Event.getTarget(p_oEvent); | ||||
if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) { | ||||
oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false); | ||||
Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay); | ||||
Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay); | ||||
} | ||||
} | ||||
} | ||||
function onSubmenuHide(p_sType, p_aArgs, p_sWidth) { | ||||
this.cfg.setProperty(_WIDTH, _EMPTY_STRING); | ||||
this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth); | ||||
} | ||||
if (oParent) { | ||||
oParentMenu = oParent.parent; | ||||
if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) && | ||||
(oParentMenu instanceof YAHOO.widget.MenuBar || | ||||
oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) { | ||||
oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true); | ||||
Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay); | ||||
Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay); | ||||
} | ||||
// The following fixes an issue with the selected state of a MenuItem | ||||
// not rendering correctly when a submenu is aligned to the left of | ||||
// its parent Menu instance. | ||||
if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) && | ||||
(UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) { | ||||
oElement = this.element; | ||||
nOffsetWidth = oElement.offsetWidth; | ||||
/* | ||||
Measuring the difference of the offsetWidth before and after | ||||
setting the "width" style attribute allows us to compute the | ||||
about of padding and borders applied to the element, which in | ||||
turn allows us to set the "width" property correctly. | ||||
*/ | ||||
oElement.style.width = nOffsetWidth + _PX; | ||||
sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX; | ||||
this.cfg.setProperty(_WIDTH, sWidth); | ||||
this.hideEvent.subscribe(onSubmenuHide, sWidth); | ||||
} | ||||
} | ||||
/* | ||||
Dynamically positioned, root Menus focus themselves when visible, and | ||||
will then, when hidden, restore focus to the UI control that had focus | ||||
before the Menu was made visible. | ||||
*/ | ||||
if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) { | ||||
this._focusedElement = oFocusedElement; | ||||
this.focus(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onBeforeHide | ||||
* @description "beforehide" event handler for the menu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onBeforeHide: function (p_sType, p_aArgs) { | ||||
var oActiveItem = this.activeItem, | ||||
oRoot = this.getRoot(), | ||||
oConfig, | ||||
oSubmenu; | ||||
if (oActiveItem) { | ||||
oConfig = oActiveItem.cfg; | ||||
oConfig.setProperty(_SELECTED, false); | ||||
oSubmenu = oConfig.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.hide(); | ||||
} | ||||
} | ||||
/* | ||||
Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu. | ||||
For this reason, it is necessary to maintain the focused state in a private property | ||||
so that the _onMouseOver event handler is able to determined whether or not to set focus | ||||
to MenuItems as the user is moving the mouse. | ||||
*/ | ||||
if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) { | ||||
oRoot._hasFocus = this.hasFocus(); | ||||
} | ||||
if (oRoot == this) { | ||||
oRoot.blur(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onParentMenuConfigChange | ||||
* @description "configchange" event handler for a submenu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that | ||||
* subscribed to the event. | ||||
*/ | ||||
_onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) { | ||||
var sPropertyName = p_aArgs[0][0], | ||||
oPropertyValue = p_aArgs[0][1]; | ||||
switch(sPropertyName) { | ||||
case _IFRAME: | ||||
case _CONSTRAIN_TO_VIEWPORT: | ||||
case _HIDE_DELAY: | ||||
case _SHOW_DELAY: | ||||
case _SUBMENU_HIDE_DELAY: | ||||
case _CLICK_TO_HIDE: | ||||
case _EFFECT: | ||||
case _CLASSNAME: | ||||
case _SCROLL_INCREMENT: | ||||
case _MAX_HEIGHT: | ||||
case _MIN_SCROLL_HEIGHT: | ||||
case _MONITOR_RESIZE: | ||||
case _SHADOW: | ||||
case _PREVENT_CONTEXT_OVERLAP: | ||||
case _KEEP_OPEN: | ||||
p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue); | ||||
break; | ||||
case _SUBMENU_ALIGNMENT: | ||||
if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) { | ||||
p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue); | ||||
} | ||||
break; | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onParentMenuRender | ||||
* @description "render" event handler for a submenu. Renders a | ||||
* submenu in response to the firing of its parent's "render" event. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that | ||||
* subscribed to the event. | ||||
*/ | ||||
_onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) { | ||||
var oParentMenu = p_oSubmenu.parent.parent, | ||||
oParentCfg = oParentMenu.cfg, | ||||
oConfig = { | ||||
constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT), | ||||
xy: [0,0], | ||||
clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE), | ||||
effect: oParentCfg.getProperty(_EFFECT), | ||||
showdelay: oParentCfg.getProperty(_SHOW_DELAY), | ||||
hidedelay: oParentCfg.getProperty(_HIDE_DELAY), | ||||
submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY), | ||||
classname: oParentCfg.getProperty(_CLASSNAME), | ||||
scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT), | ||||
maxheight: oParentCfg.getProperty(_MAX_HEIGHT), | ||||
minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT), | ||||
iframe: oParentCfg.getProperty(_IFRAME), | ||||
shadow: oParentCfg.getProperty(_SHADOW), | ||||
preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP), | ||||
monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE), | ||||
keepopen: oParentCfg.getProperty(_KEEP_OPEN) | ||||
}, | ||||
oLI; | ||||
if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) { | ||||
oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT); | ||||
} | ||||
p_oSubmenu.cfg.applyConfig(oConfig); | ||||
if (!this.lazyLoad) { | ||||
oLI = this.parent.element; | ||||
if (this.element.parentNode == oLI) { | ||||
this.render(); | ||||
} | ||||
else { | ||||
this.render(oLI); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onMenuItemDestroy | ||||
* @description "destroy" event handler for the menu's items. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event | ||||
* that was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
_onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) { | ||||
this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem); | ||||
}, | ||||
/** | ||||
* @method _onMenuItemConfigChange | ||||
* @description "configchange" event handler for the menu's items. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
_onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) { | ||||
var sPropertyName = p_aArgs[0][0], | ||||
oPropertyValue = p_aArgs[0][1], | ||||
oSubmenu; | ||||
switch(sPropertyName) { | ||||
case _SELECTED: | ||||
if (oPropertyValue === true) { | ||||
this.activeItem = p_oItem; | ||||
} | ||||
break; | ||||
case _SUBMENU: | ||||
oSubmenu = p_aArgs[0][1]; | ||||
if (oSubmenu) { | ||||
this._configureSubmenu(p_oItem); | ||||
} | ||||
break; | ||||
} | ||||
}, | ||||
// Public event handlers for configuration properties | ||||
/** | ||||
* @method configVisible | ||||
* @description Event handler for when the "visible" configuration property | ||||
* the menu changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
configVisible: function (p_sType, p_aArgs, p_oMenu) { | ||||
var bVisible, | ||||
sDisplay; | ||||
if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu); | ||||
} | ||||
else { | ||||
bVisible = p_aArgs[0]; | ||||
sDisplay = Dom.getStyle(this.element, _DISPLAY); | ||||
Dom.setStyle(this.element, _VISIBILITY, _VISIBLE); | ||||
if (bVisible) { | ||||
if (sDisplay != _BLOCK) { | ||||
this.beforeShowEvent.fire(); | ||||
Dom.setStyle(this.element, _DISPLAY, _BLOCK); | ||||
this.showEvent.fire(); | ||||
} | ||||
} | ||||
else { | ||||
if (sDisplay == _BLOCK) { | ||||
this.beforeHideEvent.fire(); | ||||
Dom.setStyle(this.element, _DISPLAY, _NONE); | ||||
this.hideEvent.fire(); | ||||
} | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method configPosition | ||||
* @description Event handler for when the "position" configuration property | ||||
* of the menu changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
configPosition: function (p_sType, p_aArgs, p_oMenu) { | ||||
var oElement = this.element, | ||||
sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE, | ||||
oCfg = this.cfg, | ||||
nZIndex; | ||||
Dom.setStyle(oElement, _POSITION, sCSSPosition); | ||||
if (sCSSPosition == _STATIC) { | ||||
// Statically positioned menus are visible by default | ||||
Dom.setStyle(oElement, _DISPLAY, _BLOCK); | ||||
oCfg.setProperty(_VISIBLE, true); | ||||
} | ||||
else { | ||||
/* | ||||
Even though the "visible" property is queued to | ||||
"false" by default, we need to set the "visibility" property to | ||||
"hidden" since Overlay's "configVisible" implementation checks the | ||||
element's "visibility" style property before deciding whether | ||||
or not to show an Overlay instance. | ||||
*/ | ||||
Dom.setStyle(oElement, _VISIBILITY, _HIDDEN); | ||||
} | ||||
if (sCSSPosition == _ABSOLUTE) { | ||||
nZIndex = oCfg.getProperty(_ZINDEX); | ||||
if (!nZIndex || nZIndex === 0) { | ||||
oCfg.setProperty(_ZINDEX, 1); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method configIframe | ||||
* @description Event handler for when the "iframe" configuration property of | ||||
* the menu changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
configIframe: function (p_sType, p_aArgs, p_oMenu) { | ||||
if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configHideDelay | ||||
* @description Event handler for when the "hidedelay" configuration property | ||||
* of the menu changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
configHideDelay: function (p_sType, p_aArgs, p_oMenu) { | ||||
var nHideDelay = p_aArgs[0]; | ||||
this._useHideDelay = (nHideDelay > 0); | ||||
}, | ||||
/** | ||||
* @method configContainer | ||||
* @description Event handler for when the "container" configuration property | ||||
* of the menu changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that | ||||
* fired the event. | ||||
*/ | ||||
configContainer: function (p_sType, p_aArgs, p_oMenu) { | ||||
var oElement = p_aArgs[0]; | ||||
if (Lang.isString(oElement)) { | ||||
this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _clearSetWidthFlag | ||||
* @description Change event listener for the "width" configuration property. This listener is | ||||
* added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and | ||||
* is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property | ||||
* is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll" | ||||
* property is set to "false", and the "_setScrollHeight" method is in the process of tearing down | ||||
* scrolling functionality, it will maintain the Menu's new width rather than reseting it. | ||||
* @private | ||||
*/ | ||||
_clearSetWidthFlag: function () { | ||||
this._widthSetForScroll = false; | ||||
this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag); | ||||
}, | ||||
/** | ||||
* @method _setScrollHeight | ||||
* @description | ||||
* @param {String} p_nScrollHeight Number representing the scrolling height of the Menu. | ||||
* @private | ||||
*/ | ||||
_setScrollHeight: function (p_nScrollHeight) { | ||||
var nScrollHeight = p_nScrollHeight, | ||||
bRefireIFrameAndShadow = false, | ||||
bSetWidth = false, | ||||
oElement, | ||||
oBody, | ||||
oHeader, | ||||
oFooter, | ||||
fnMouseOver, | ||||
fnMouseOut, | ||||
nMinScrollHeight, | ||||
nHeight, | ||||
nOffsetWidth, | ||||
sWidth; | ||||
if (this.getItems().length > 0) { | ||||
oElement = this.element; | ||||
oBody = this.body; | ||||
oHeader = this.header; | ||||
oFooter = this.footer; | ||||
fnMouseOver = this._onScrollTargetMouseOver; | ||||
fnMouseOut = this._onScrollTargetMouseOut; | ||||
nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT); | ||||
if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) { | ||||
nScrollHeight = nMinScrollHeight; | ||||
} | ||||
Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING); | ||||
Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED); | ||||
oBody.scrollTop = 0; | ||||
// Need to set a width for the Menu to fix the following problems in | ||||
// Firefox 2 and IE: | ||||
// #1) Scrolled Menus will render at 1px wide in Firefox 2 | ||||
// #2) There is a bug in gecko-based browsers where an element whose | ||||
// "position" property is set to "absolute" and "overflow" property is | ||||
// set to "hidden" will not render at the correct width when its | ||||
// offsetParent's "position" property is also set to "absolute." It is | ||||
// possible to work around this bug by specifying a value for the width | ||||
// property in addition to overflow. | ||||
// #3) In IE it is necessary to give the Menu a width before the | ||||
// scrollbars are rendered to prevent the Menu from rendering with a | ||||
// width that is 100% of the browser viewport. | ||||
bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie); | ||||
if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) { | ||||
nOffsetWidth = oElement.offsetWidth; | ||||
/* | ||||
Measuring the difference of the offsetWidth before and after | ||||
setting the "width" style attribute allows us to compute the | ||||
about of padding and borders applied to the element, which in | ||||
turn allows us to set the "width" property correctly. | ||||
*/ | ||||
oElement.style.width = nOffsetWidth + _PX; | ||||
sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX; | ||||
this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag); | ||||
this.cfg.setProperty(_WIDTH, sWidth); | ||||
/* | ||||
Set a flag (_widthSetForScroll) to maintain some history regarding how the | ||||
"width" configuration property was set. If the "width" configuration property | ||||
is set by something other than the "_setScrollHeight" method, it will be | ||||
necessary to maintain that new value and not clear the width if scrolling | ||||
is turned off. | ||||
*/ | ||||
this._widthSetForScroll = true; | ||||
this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag); | ||||
} | ||||
if (nScrollHeight > 0 && (!oHeader && !oFooter)) { | ||||
this.setHeader(_NON_BREAKING_SPACE); | ||||
this.setFooter(_NON_BREAKING_SPACE); | ||||
oHeader = this.header; | ||||
oFooter = this.footer; | ||||
Dom.addClass(oHeader, _TOP_SCROLLBAR); | ||||
Dom.addClass(oFooter, _BOTTOM_SCROLLBAR); | ||||
oElement.insertBefore(oHeader, oBody); | ||||
oElement.appendChild(oFooter); | ||||
} | ||||
nHeight = nScrollHeight; | ||||
if (oHeader && oFooter) { | ||||
nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight)); | ||||
} | ||||
if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) { | ||||
Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED); | ||||
Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX)); | ||||
if (!this._hasScrollEventHandlers) { | ||||
Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true); | ||||
Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true); | ||||
Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true); | ||||
Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true); | ||||
this._hasScrollEventHandlers = true; | ||||
} | ||||
this._disableScrollHeader(); | ||||
this._enableScrollFooter(); | ||||
bRefireIFrameAndShadow = true; | ||||
} | ||||
else if (oHeader && oFooter) { | ||||
/* | ||||
Only clear the the "width" configuration property if it was set the | ||||
"_setScrollHeight" method and wasn't changed by some other means after it was set. | ||||
*/ | ||||
if (this._widthSetForScroll) { | ||||
this._widthSetForScroll = false; | ||||
this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag); | ||||
this.cfg.setProperty(_WIDTH, _EMPTY_STRING); | ||||
} | ||||
this._enableScrollHeader(); | ||||
this._enableScrollFooter(); | ||||
if (this._hasScrollEventHandlers) { | ||||
Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver); | ||||
Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut); | ||||
Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver); | ||||
Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut); | ||||
this._hasScrollEventHandlers = false; | ||||
} | ||||
oElement.removeChild(oHeader); | ||||
oElement.removeChild(oFooter); | ||||
this.header = null; | ||||
this.footer = null; | ||||
bRefireIFrameAndShadow = true; | ||||
} | ||||
if (bRefireIFrameAndShadow) { | ||||
this.cfg.refireEvent(_IFRAME); | ||||
this.cfg.refireEvent(_SHADOW); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _setMaxHeight | ||||
* @description "renderEvent" handler used to defer the setting of the | ||||
* "maxheight" configuration property until the menu is rendered in lazy | ||||
* load scenarios. | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event | ||||
* was fired. | ||||
* @param {Number} p_nMaxHeight Number representing the value to set for the | ||||
* "maxheight" configuration property. | ||||
* @private | ||||
*/ | ||||
_setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) { | ||||
this._setScrollHeight(p_nMaxHeight); | ||||
this.renderEvent.unsubscribe(this._setMaxHeight); | ||||
}, | ||||
/** | ||||
* @method configMaxHeight | ||||
* @description Event handler for when the "maxheight" configuration property of | ||||
* a Menu changes. | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event | ||||
* was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired | ||||
* the event. | ||||
*/ | ||||
configMaxHeight: function (p_sType, p_aArgs, p_oMenu) { | ||||
var nMaxHeight = p_aArgs[0]; | ||||
if (this.lazyLoad && !this.body && nMaxHeight > 0) { | ||||
this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this); | ||||
} | ||||
else { | ||||
this._setScrollHeight(nMaxHeight); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configClassName | ||||
* @description Event handler for when the "classname" configuration property of | ||||
* a menu changes. | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event. | ||||
*/ | ||||
configClassName: function (p_sType, p_aArgs, p_oMenu) { | ||||
var sClassName = p_aArgs[0]; | ||||
if (this._sClassName) { | ||||
Dom.removeClass(this.element, this._sClassName); | ||||
} | ||||
Dom.addClass(this.element, sClassName); | ||||
this._sClassName = sClassName; | ||||
}, | ||||
/** | ||||
* @method _onItemAdded | ||||
* @description "itemadded" event handler for a Menu instance. | ||||
* @private | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event | ||||
* was fired. | ||||
*/ | ||||
_onItemAdded: function (p_sType, p_aArgs) { | ||||
var oItem = p_aArgs[0]; | ||||
if (oItem) { | ||||
oItem.cfg.setProperty(_DISABLED, true); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configDisabled | ||||
* @description Event handler for when the "disabled" configuration property of | ||||
* a menu changes. | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event. | ||||
*/ | ||||
configDisabled: function (p_sType, p_aArgs, p_oMenu) { | ||||
var bDisabled = p_aArgs[0], | ||||
aItems = this.getItems(), | ||||
nItems, | ||||
i; | ||||
if (Lang.isArray(aItems)) { | ||||
nItems = aItems.length; | ||||
if (nItems > 0) { | ||||
i = nItems - 1; | ||||
do { | ||||
aItems[i].cfg.setProperty(_DISABLED, bDisabled); | ||||
} | ||||
while (i--); | ||||
} | ||||
if (bDisabled) { | ||||
this.clearActiveItem(true); | ||||
Dom.addClass(this.element, _DISABLED); | ||||
this.itemAddedEvent.subscribe(this._onItemAdded); | ||||
} | ||||
else { | ||||
Dom.removeClass(this.element, _DISABLED); | ||||
this.itemAddedEvent.unsubscribe(this._onItemAdded); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method configShadow | ||||
* @description Event handler for when the "shadow" configuration property of | ||||
* a menu changes. | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event. | ||||
*/ | ||||
configShadow: function (p_sType, p_aArgs, p_oMenu) { | ||||
var sizeShadow = function () { | ||||
var oElement = this.element, | ||||
oShadow = this._shadow; | ||||
if (oShadow && oElement) { | ||||
// Clear the previous width | ||||
if (oShadow.style.width && oShadow.style.height) { | ||||
oShadow.style.width = _EMPTY_STRING; | ||||
oShadow.style.height = _EMPTY_STRING; | ||||
} | ||||
oShadow.style.width = (oElement.offsetWidth + 6) + _PX; | ||||
oShadow.style.height = (oElement.offsetHeight + 1) + _PX; | ||||
} | ||||
}; | ||||
var replaceShadow = function () { | ||||
this.element.appendChild(this._shadow); | ||||
}; | ||||
var addShadowVisibleClass = function () { | ||||
Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE); | ||||
}; | ||||
var removeShadowVisibleClass = function () { | ||||
Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE); | ||||
}; | ||||
var createShadow = function () { | ||||
var oShadow = this._shadow, | ||||
oElement; | ||||
if (!oShadow) { | ||||
oElement = this.element; | ||||
if (!m_oShadowTemplate) { | ||||
m_oShadowTemplate = document.createElement(_DIV_LOWERCASE); | ||||
m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE; | ||||
} | ||||
oShadow = m_oShadowTemplate.cloneNode(false); | ||||
oElement.appendChild(oShadow); | ||||
this._shadow = oShadow; | ||||
this.beforeShowEvent.subscribe(addShadowVisibleClass); | ||||
this.beforeHideEvent.subscribe(removeShadowVisibleClass); | ||||
if (UA.ie) { | ||||
/* | ||||
Need to call sizeShadow & syncIframe via setTimeout for | ||||
IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode | ||||
or the shadow and iframe shim will not be sized and | ||||
positioned properly. | ||||
*/ | ||||
Lang.later(0, this, function () { | ||||
sizeShadow.call(this); | ||||
this.syncIframe(); | ||||
}); | ||||
this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow); | ||||
this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow); | ||||
this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow); | ||||
this.changeContentEvent.subscribe(sizeShadow); | ||||
Module.textResizeEvent.subscribe(sizeShadow, this, true); | ||||
this.destroyEvent.subscribe(function () { | ||||
Module.textResizeEvent.unsubscribe(sizeShadow, this); | ||||
}); | ||||
} | ||||
this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow); | ||||
} | ||||
}; | ||||
var onBeforeShow = function () { | ||||
if (this._shadow) { | ||||
// If called because the "shadow" event was refired - just append again and resize | ||||
replaceShadow.call(this); | ||||
if (UA.ie) { | ||||
sizeShadow.call(this); | ||||
} | ||||
} | ||||
else { | ||||
createShadow.call(this); | ||||
} | ||||
this.beforeShowEvent.unsubscribe(onBeforeShow); | ||||
}; | ||||
var bShadow = p_aArgs[0]; | ||||
if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) { | ||||
if (this.cfg.getProperty(_VISIBLE)) { | ||||
if (this._shadow) { | ||||
// If the "shadow" event was refired - just append again and resize | ||||
replaceShadow.call(this); | ||||
if (UA.ie) { | ||||
sizeShadow.call(this); | ||||
} | ||||
} | ||||
else { | ||||
createShadow.call(this); | ||||
} | ||||
} | ||||
else { | ||||
this.beforeShowEvent.subscribe(onBeforeShow); | ||||
} | ||||
} | ||||
}, | ||||
// Public methods | ||||
/** | ||||
* @method initEvents | ||||
* @description Initializes the custom events for the menu. | ||||
*/ | ||||
initEvents: function () { | ||||
Menu.superclass.initEvents.call(this); | ||||
// Create custom events | ||||
var i = EVENT_TYPES.length - 1, | ||||
aEventData, | ||||
oCustomEvent; | ||||
do { | ||||
aEventData = EVENT_TYPES[i]; | ||||
oCustomEvent = this.createEvent(aEventData[1]); | ||||
oCustomEvent.signature = CustomEvent.LIST; | ||||
this[aEventData[0]] = oCustomEvent; | ||||
} | ||||
while (i--); | ||||
}, | ||||
/** | ||||
* @method positionOffScreen | ||||
* @description Positions the menu outside of the boundaries of the browser's | ||||
* viewport. Called automatically when a menu is hidden to ensure that | ||||
* it doesn't force the browser to render uncessary scrollbars. | ||||
*/ | ||||
positionOffScreen: function () { | ||||
var oIFrame = this.iframe, | ||||
oElement = this.element, | ||||
sPos = this.OFF_SCREEN_POSITION; | ||||
oElement.style.top = _EMPTY_STRING; | ||||
oElement.style.left = _EMPTY_STRING; | ||||
if (oIFrame) { | ||||
oIFrame.style.top = sPos; | ||||
oIFrame.style.left = sPos; | ||||
} | ||||
}, | ||||
/** | ||||
* @method getRoot | ||||
* @description Finds the menu's root menu. | ||||
*/ | ||||
getRoot: function () { | ||||
var oItem = this.parent, | ||||
oParentMenu, | ||||
returnVal; | ||||
if (oItem) { | ||||
oParentMenu = oItem.parent; | ||||
returnVal = oParentMenu ? oParentMenu.getRoot() : this; | ||||
} | ||||
else { | ||||
returnVal = this; | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method toString | ||||
* @description Returns a string representing the menu. | ||||
* @return {String} | ||||
*/ | ||||
toString: function () { | ||||
var sReturnVal = _MENU, | ||||
sId = this.id; | ||||
if (sId) { | ||||
sReturnVal += (_SPACE + sId); | ||||
} | ||||
return sReturnVal; | ||||
}, | ||||
/** | ||||
* @method setItemGroupTitle | ||||
* @description Sets the title of a group of menu items. | ||||
* @param {String} p_sGroupTitle String specifying the title of the group. | ||||
* @param {Number} p_nGroupIndex Optional. Number specifying the group to which | ||||
* the title belongs. | ||||
*/ | ||||
setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) { | ||||
var nGroupIndex, | ||||
oTitle, | ||||
i, | ||||
nFirstIndex; | ||||
if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) { | ||||
nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0; | ||||
oTitle = this._aGroupTitleElements[nGroupIndex]; | ||||
if (oTitle) { | ||||
oTitle.innerHTML = p_sGroupTitle; | ||||
} | ||||
else { | ||||
oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME); | ||||
oTitle.innerHTML = p_sGroupTitle; | ||||
this._aGroupTitleElements[nGroupIndex] = oTitle; | ||||
} | ||||
i = this._aGroupTitleElements.length - 1; | ||||
do { | ||||
if (this._aGroupTitleElements[i]) { | ||||
Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE); | ||||
nFirstIndex = i; | ||||
} | ||||
} | ||||
while (i--); | ||||
if (nFirstIndex !== null) { | ||||
Dom.addClass(this._aGroupTitleElements[nFirstIndex], | ||||
_FIRST_OF_TYPE); | ||||
} | ||||
this.changeContentEvent.fire(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method addItem | ||||
* @description Appends an item to the menu. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem | ||||
* instance to be added to the menu. | ||||
* @param {String} p_oItem String specifying the text of the item to be added | ||||
* to the menu. | ||||
* @param {Object} p_oItem Object literal containing a set of menu item | ||||
* configuration properties. | ||||
* @param {Number} p_nGroupIndex Optional. Number indicating the group to | ||||
* which the item belongs. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
addItem: function (p_oItem, p_nGroupIndex) { | ||||
return this._addItemToGroup(p_nGroupIndex, p_oItem); | ||||
}, | ||||
/** | ||||
* @method addItems | ||||
* @description Adds an array of items to the menu. | ||||
* @param {Array} p_aItems Array of items to be added to the menu. The array | ||||
* can contain strings specifying the text for each item to be created, object | ||||
* literals specifying each of the menu item configuration properties, | ||||
* or MenuItem instances. | ||||
* @param {Number} p_nGroupIndex Optional. Number specifying the group to | ||||
* which the items belongs. | ||||
* @return {Array} | ||||
*/ | ||||
addItems: function (p_aItems, p_nGroupIndex) { | ||||
var nItems, | ||||
aItems, | ||||
oItem, | ||||
i, | ||||
returnVal; | ||||
if (Lang.isArray(p_aItems)) { | ||||
nItems = p_aItems.length; | ||||
aItems = []; | ||||
for(i=0; i<nItems; i++) { | ||||
oItem = p_aItems[i]; | ||||
if (oItem) { | ||||
if (Lang.isArray(oItem)) { | ||||
aItems[aItems.length] = this.addItems(oItem, i); | ||||
} | ||||
else { | ||||
aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem); | ||||
} | ||||
} | ||||
} | ||||
if (aItems.length) { | ||||
returnVal = aItems; | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method insertItem | ||||
* @description Inserts an item into the menu at the specified index. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem | ||||
* instance to be added to the menu. | ||||
* @param {String} p_oItem String specifying the text of the item to be added | ||||
* to the menu. | ||||
* @param {Object} p_oItem Object literal containing a set of menu item | ||||
* configuration properties. | ||||
* @param {Number} p_nItemIndex Number indicating the ordinal position at which | ||||
* the item should be added. | ||||
* @param {Number} p_nGroupIndex Optional. Number indicating the group to which | ||||
* the item belongs. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) { | ||||
return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex); | ||||
}, | ||||
/** | ||||
* @method removeItem | ||||
* @description Removes the specified item from the menu. | ||||
* @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem | ||||
* instance to be removed from the menu. | ||||
* @param {Number} p_oObject Number specifying the index of the item | ||||
* to be removed. | ||||
* @param {Number} p_nGroupIndex Optional. Number specifying the group to | ||||
* which the item belongs. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
removeItem: function (p_oObject, p_nGroupIndex) { | ||||
var oItem, | ||||
returnVal; | ||||
if (!Lang.isUndefined(p_oObject)) { | ||||
if (p_oObject instanceof YAHOO.widget.MenuItem) { | ||||
oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject); | ||||
} | ||||
else if (Lang.isNumber(p_oObject)) { | ||||
oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject); | ||||
} | ||||
if (oItem) { | ||||
oItem.destroy(); | ||||
returnVal = oItem; | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method getItems | ||||
* @description Returns an array of all of the items in the menu. | ||||
* @return {Array} | ||||
*/ | ||||
getItems: function () { | ||||
var aGroups = this._aItemGroups, | ||||
nGroups, | ||||
returnVal, | ||||
aItems = []; | ||||
if (Lang.isArray(aGroups)) { | ||||
nGroups = aGroups.length; | ||||
returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups))); | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method getItemGroups | ||||
* @description Multi-dimensional Array representing the menu items as they | ||||
* are grouped in the menu. | ||||
* @return {Array} | ||||
*/ | ||||
getItemGroups: function () { | ||||
return this._aItemGroups; | ||||
}, | ||||
/** | ||||
* @method getItem | ||||
* @description Returns the item at the specified index. | ||||
* @param {Number} p_nItemIndex Number indicating the ordinal position of the | ||||
* item to be retrieved. | ||||
* @param {Number} p_nGroupIndex Optional. Number indicating the group to which | ||||
* the item belongs. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
getItem: function (p_nItemIndex, p_nGroupIndex) { | ||||
var aGroup, | ||||
returnVal; | ||||
if (Lang.isNumber(p_nItemIndex)) { | ||||
aGroup = this._getItemGroup(p_nGroupIndex); | ||||
if (aGroup) { | ||||
returnVal = aGroup[p_nItemIndex]; | ||||
} | ||||
} | ||||
return returnVal; | ||||
}, | ||||
/** | ||||
* @method getSubmenus | ||||
* @description Returns an array of all of the submenus that are immediate | ||||
* children of the menu. | ||||
* @return {Array} | ||||
*/ | ||||
getSubmenus: function () { | ||||
var aItems = this.getItems(), | ||||
nItems = aItems.length, | ||||
aSubmenus, | ||||
oSubmenu, | ||||
oItem, | ||||
i; | ||||
if (nItems > 0) { | ||||
aSubmenus = []; | ||||
for(i=0; i<nItems; i++) { | ||||
oItem = aItems[i]; | ||||
if (oItem) { | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
aSubmenus[aSubmenus.length] = oSubmenu; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return aSubmenus; | ||||
}, | ||||
/** | ||||
* @method clearContent | ||||
* @description Removes all of the content from the menu, including the menu | ||||
* items, group titles, header and footer. | ||||
*/ | ||||
clearContent: function () { | ||||
var aItems = this.getItems(), | ||||
nItems = aItems.length, | ||||
oElement = this.element, | ||||
oBody = this.body, | ||||
oHeader = this.header, | ||||
oFooter = this.footer, | ||||
oItem, | ||||
oSubmenu, | ||||
i; | ||||
if (nItems > 0) { | ||||
i = nItems - 1; | ||||
do { | ||||
oItem = aItems[i]; | ||||
if (oItem) { | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
this.cfg.configChangedEvent.unsubscribe( | ||||
this._onParentMenuConfigChange, oSubmenu); | ||||
this.renderEvent.unsubscribe(this._onParentMenuRender, | ||||
oSubmenu); | ||||
} | ||||
this.removeItem(oItem, oItem.groupIndex); | ||||
} | ||||
} | ||||
while (i--); | ||||
} | ||||
if (oHeader) { | ||||
Event.purgeElement(oHeader); | ||||
oElement.removeChild(oHeader); | ||||
} | ||||
if (oFooter) { | ||||
Event.purgeElement(oFooter); | ||||
oElement.removeChild(oFooter); | ||||
} | ||||
if (oBody) { | ||||
Event.purgeElement(oBody); | ||||
oBody.innerHTML = _EMPTY_STRING; | ||||
} | ||||
this.activeItem = null; | ||||
this._aItemGroups = []; | ||||
this._aListElements = []; | ||||
this._aGroupTitleElements = []; | ||||
this.cfg.setProperty(_WIDTH, null); | ||||
}, | ||||
/** | ||||
* @method destroy | ||||
* @description Removes the menu's <code><div></code> element | ||||
* (and accompanying child nodes) from the document. | ||||
*/ | ||||
destroy: function () { | ||||
// Remove all items | ||||
this.clearContent(); | ||||
this._aItemGroups = null; | ||||
this._aListElements = null; | ||||
this._aGroupTitleElements = null; | ||||
// Continue with the superclass implementation of this method | ||||
Menu.superclass.destroy.call(this); | ||||
}, | ||||
/** | ||||
* @method setInitialFocus | ||||
* @description Sets focus to the menu's first enabled item. | ||||
*/ | ||||
setInitialFocus: function () { | ||||
var oItem = this._getFirstEnabledItem(); | ||||
if (oItem) { | ||||
oItem.focus(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method setInitialSelection | ||||
* @description Sets the "selected" configuration property of the menu's first | ||||
* enabled item to "true." | ||||
*/ | ||||
setInitialSelection: function () { | ||||
var oItem = this._getFirstEnabledItem(); | ||||
if (oItem) { | ||||
oItem.cfg.setProperty(_SELECTED, true); | ||||
} | ||||
}, | ||||
/** | ||||
* @method clearActiveItem | ||||
* @description Sets the "selected" configuration property of the menu's active | ||||
* item to "false" and hides the item's submenu. | ||||
* @param {Boolean} p_bBlur Boolean indicating if the menu's active item | ||||
* should be blurred. | ||||
*/ | ||||
clearActiveItem: function (p_bBlur) { | ||||
if (this.cfg.getProperty(_SHOW_DELAY) > 0) { | ||||
this._cancelShowDelay(); | ||||
} | ||||
var oActiveItem = this.activeItem, | ||||
oConfig, | ||||
oSubmenu; | ||||
if (oActiveItem) { | ||||
oConfig = oActiveItem.cfg; | ||||
if (p_bBlur) { | ||||
oActiveItem.blur(); | ||||
this.getRoot()._hasFocus = true; | ||||
} | ||||
oConfig.setProperty(_SELECTED, false); | ||||
oSubmenu = oConfig.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.hide(); | ||||
} | ||||
this.activeItem = null; | ||||
} | ||||
}, | ||||
/** | ||||
* @method focus | ||||
* @description Causes the menu to receive focus and fires the "focus" event. | ||||
*/ | ||||
focus: function () { | ||||
if (!this.hasFocus()) { | ||||
this.setInitialFocus(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method blur | ||||
* @description Causes the menu to lose focus and fires the "blur" event. | ||||
*/ | ||||
blur: function () { | ||||
var oItem; | ||||
if (this.hasFocus()) { | ||||
oItem = MenuManager.getFocusedMenuItem(); | ||||
if (oItem) { | ||||
oItem.blur(); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method hasFocus | ||||
* @description Returns a boolean indicating whether or not the menu has focus. | ||||
* @return {Boolean} | ||||
*/ | ||||
hasFocus: function () { | ||||
return (MenuManager.getFocusedMenu() == this.getRoot()); | ||||
}, | ||||
_doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) { | ||||
var oItem = p_aArgs[0], | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.subscribe.apply(oSubmenu, p_oObject); | ||||
} | ||||
}, | ||||
_doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) { | ||||
var oSubmenu = this.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.subscribe.apply(oSubmenu, p_oObject); | ||||
} | ||||
}, | ||||
/** | ||||
* Adds the specified CustomEvent subscriber to the menu and each of | ||||
* its submenus. | ||||
* @method subscribe | ||||
* @param p_type {string} the type, or name of the event | ||||
* @param p_fn {function} the function to exectute when the event fires | ||||
* @param p_obj {Object} An object to be passed along when the event | ||||
* fires | ||||
* @param p_override {boolean} If true, the obj passed in becomes the | ||||
* execution scope of the listener | ||||
*/ | ||||
subscribe: function () { | ||||
// Subscribe to the event for this Menu instance | ||||
Menu.superclass.subscribe.apply(this, arguments); | ||||
// Subscribe to the "itemAdded" event so that all future submenus | ||||
// also subscribe to this event | ||||
Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments); | ||||
var aItems = this.getItems(), | ||||
nItems, | ||||
oItem, | ||||
oSubmenu, | ||||
i; | ||||
if (aItems) { | ||||
nItems = aItems.length; | ||||
if (nItems > 0) { | ||||
i = nItems - 1; | ||||
do { | ||||
oItem = aItems[i]; | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.subscribe.apply(oSubmenu, arguments); | ||||
} | ||||
else { | ||||
oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments); | ||||
} | ||||
} | ||||
while (i--); | ||||
} | ||||
} | ||||
}, | ||||
unsubscribe: function () { | ||||
// Remove the event for this Menu instance | ||||
Menu.superclass.unsubscribe.apply(this, arguments); | ||||
// Remove the "itemAdded" event so that all future submenus don't have | ||||
// the event handler | ||||
Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments); | ||||
var aItems = this.getItems(), | ||||
nItems, | ||||
oItem, | ||||
oSubmenu, | ||||
i; | ||||
if (aItems) { | ||||
nItems = aItems.length; | ||||
if (nItems > 0) { | ||||
i = nItems - 1; | ||||
do { | ||||
oItem = aItems[i]; | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.unsubscribe.apply(oSubmenu, arguments); | ||||
} | ||||
else { | ||||
oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments); | ||||
} | ||||
} | ||||
while (i--); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @description Initializes the class's configurable properties which can be | ||||
* changed using the menu's Config object ("cfg"). | ||||
* @method initDefaultConfig | ||||
*/ | ||||
initDefaultConfig: function () { | ||||
Menu.superclass.initDefaultConfig.call(this); | ||||
var oConfig = this.cfg; | ||||
// Module documentation overrides | ||||
/** | ||||
* @config effect | ||||
* @description Object or array of objects representing the ContainerEffect | ||||
* classes that are active for animating the container. When set this | ||||
* property is automatically applied to all submenus. | ||||
* @type Object | ||||
* @default null | ||||
*/ | ||||
// Overlay documentation overrides | ||||
/** | ||||
* @config x | ||||
* @description Number representing the absolute x-coordinate position of | ||||
* the Menu. This property is only applied when the "position" | ||||
* configuration property is set to dynamic. | ||||
* @type Number | ||||
* @default null | ||||
*/ | ||||
/** | ||||
* @config y | ||||
* @description Number representing the absolute y-coordinate position of | ||||
* the Menu. This property is only applied when the "position" | ||||
* configuration property is set to dynamic. | ||||
* @type Number | ||||
* @default null | ||||
*/ | ||||
/** | ||||
* @description Array of the absolute x and y positions of the Menu. This | ||||
* property is only applied when the "position" configuration property is | ||||
* set to dynamic. | ||||
* @config xy | ||||
* @type Number[] | ||||
* @default null | ||||
*/ | ||||
/** | ||||
* @config context | ||||
* @description Array of context arguments for context-sensitive positioning. | ||||
* The format is: [id or element, element corner, context corner]. | ||||
* For example, setting this property to ["img1", "tl", "bl"] would | ||||
* align the Menu's top left corner to the context element's | ||||
* bottom left corner. This property is only applied when the "position" | ||||
* configuration property is set to dynamic. | ||||
* @type Array | ||||
* @default null | ||||
*/ | ||||
/** | ||||
* @config fixedcenter | ||||
* @description Boolean indicating if the Menu should be anchored to the | ||||
* center of the viewport. This property is only applied when the | ||||
* "position" configuration property is set to dynamic. | ||||
* @type Boolean | ||||
* @default false | ||||
*/ | ||||
/** | ||||
* @config iframe | ||||
* @description Boolean indicating whether or not the Menu should | ||||
* have an IFRAME shim; used to prevent SELECT elements from | ||||
* poking through an Overlay instance in IE6. When set to "true", | ||||
* the iframe shim is created when the Menu instance is intially | ||||
* made visible. This property is only applied when the "position" | ||||
* configuration property is set to dynamic and is automatically applied | ||||
* to all submenus. | ||||
* @type Boolean | ||||
* @default true for IE6 and below, false for all other browsers. | ||||
*/ | ||||
// Add configuration attributes | ||||
/* | ||||
Change the default value for the "visible" configuration | ||||
property to "false" by re-adding the property. | ||||
*/ | ||||
/** | ||||
* @config visible | ||||
* @description Boolean indicating whether or not the menu is visible. If | ||||
* the menu's "position" configuration property is set to "dynamic" (the | ||||
* default), this property toggles the menu's <code><div></code> | ||||
* element's "visibility" style property between "visible" (true) or | ||||
* "hidden" (false). If the menu's "position" configuration property is | ||||
* set to "static" this property toggles the menu's | ||||
* <code><div></code> element's "display" style property | ||||
* between "block" (true) or "none" (false). | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
VISIBLE_CONFIG.key, | ||||
{ | ||||
handler: this.configVisible, | ||||
value: VISIBLE_CONFIG.value, | ||||
validator: VISIBLE_CONFIG.validator | ||||
} | ||||
); | ||||
/* | ||||
Change the default value for the "constraintoviewport" configuration | ||||
property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property. | ||||
*/ | ||||
/** | ||||
* @config constraintoviewport | ||||
* @description Boolean indicating if the menu will try to remain inside | ||||
* the boundaries of the size of viewport. This property is only applied | ||||
* when the "position" configuration property is set to dynamic and is | ||||
* automatically applied to all submenus. | ||||
* @default true | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
CONSTRAIN_TO_VIEWPORT_CONFIG.key, | ||||
{ | ||||
handler: this.configConstrainToViewport, | ||||
value: CONSTRAIN_TO_VIEWPORT_CONFIG.value, | ||||
validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator, | ||||
supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes | ||||
} | ||||
); | ||||
/* | ||||
Change the default value for the "preventcontextoverlap" configuration | ||||
property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property. | ||||
*/ | ||||
/** | ||||
* @config preventcontextoverlap | ||||
* @description Boolean indicating whether or not a submenu should overlap its parent MenuItem | ||||
* when the "constraintoviewport" configuration property is set to "true". | ||||
* @type Boolean | ||||
* @default true | ||||
*/ | ||||
oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, { | ||||
value: PREVENT_CONTEXT_OVERLAP_CONFIG.value, | ||||
validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator, | ||||
supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes | ||||
}); | ||||
/** | ||||
* @config position | ||||
* @description String indicating how a menu should be positioned on the | ||||
* screen. Possible values are "static" and "dynamic." Static menus are | ||||
* visible by default and reside in the normal flow of the document | ||||
* (CSS position: static). Dynamic menus are hidden by default, reside | ||||
* out of the normal flow of the document (CSS position: absolute), and | ||||
* can overlay other elements on the screen. | ||||
* @default dynamic | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
POSITION_CONFIG.key, | ||||
{ | ||||
handler: this.configPosition, | ||||
value: POSITION_CONFIG.value, | ||||
validator: POSITION_CONFIG.validator, | ||||
supercedes: POSITION_CONFIG.supercedes | ||||
} | ||||
); | ||||
/** | ||||
* @config submenualignment | ||||
* @description Array defining how submenus should be aligned to their | ||||
* parent menu item. The format is: [itemCorner, submenuCorner]. By default | ||||
* a submenu's top left corner is aligned to its parent menu item's top | ||||
* right corner. | ||||
* @default ["tl","tr"] | ||||
* @type Array | ||||
*/ | ||||
oConfig.addProperty( | ||||
SUBMENU_ALIGNMENT_CONFIG.key, | ||||
{ | ||||
value: SUBMENU_ALIGNMENT_CONFIG.value, | ||||
suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config autosubmenudisplay | ||||
* @description Boolean indicating if submenus are automatically made | ||||
* visible when the user mouses over the menu's items. | ||||
* @default true | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
AUTO_SUBMENU_DISPLAY_CONFIG.key, | ||||
{ | ||||
value: AUTO_SUBMENU_DISPLAY_CONFIG.value, | ||||
validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator, | ||||
suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config showdelay | ||||
* @description Number indicating the time (in milliseconds) that should | ||||
* expire before a submenu is made visible when the user mouses over | ||||
* the menu's items. This property is only applied when the "position" | ||||
* configuration property is set to dynamic and is automatically applied | ||||
* to all submenus. | ||||
* @default 250 | ||||
* @type Number | ||||
*/ | ||||
oConfig.addProperty( | ||||
SHOW_DELAY_CONFIG.key, | ||||
{ | ||||
value: SHOW_DELAY_CONFIG.value, | ||||
validator: SHOW_DELAY_CONFIG.validator, | ||||
suppressEvent: SHOW_DELAY_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config hidedelay | ||||
* @description Number indicating the time (in milliseconds) that should | ||||
* expire before the menu is hidden. This property is only applied when | ||||
* the "position" configuration property is set to dynamic and is | ||||
* automatically applied to all submenus. | ||||
* @default 0 | ||||
* @type Number | ||||
*/ | ||||
oConfig.addProperty( | ||||
HIDE_DELAY_CONFIG.key, | ||||
{ | ||||
handler: this.configHideDelay, | ||||
value: HIDE_DELAY_CONFIG.value, | ||||
validator: HIDE_DELAY_CONFIG.validator, | ||||
suppressEvent: HIDE_DELAY_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config submenuhidedelay | ||||
* @description Number indicating the time (in milliseconds) that should | ||||
* expire before a submenu is hidden when the user mouses out of a menu item | ||||
* heading in the direction of a submenu. The value must be greater than or | ||||
* equal to the value specified for the "showdelay" configuration property. | ||||
* This property is only applied when the "position" configuration property | ||||
* is set to dynamic and is automatically applied to all submenus. | ||||
* @default 250 | ||||
* @type Number | ||||
*/ | ||||
oConfig.addProperty( | ||||
SUBMENU_HIDE_DELAY_CONFIG.key, | ||||
{ | ||||
value: SUBMENU_HIDE_DELAY_CONFIG.value, | ||||
validator: SUBMENU_HIDE_DELAY_CONFIG.validator, | ||||
suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config clicktohide | ||||
* @description Boolean indicating if the menu will automatically be | ||||
* hidden if the user clicks outside of it. This property is only | ||||
* applied when the "position" configuration property is set to dynamic | ||||
* and is automatically applied to all submenus. | ||||
* @default true | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
CLICK_TO_HIDE_CONFIG.key, | ||||
{ | ||||
value: CLICK_TO_HIDE_CONFIG.value, | ||||
validator: CLICK_TO_HIDE_CONFIG.validator, | ||||
suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config container | ||||
* @description HTML element reference or string specifying the id | ||||
* attribute of the HTML element that the menu's markup should be | ||||
* rendered into. | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-58190037">HTMLElement</a>|String | ||||
* @default document.body | ||||
*/ | ||||
oConfig.addProperty( | ||||
CONTAINER_CONFIG.key, | ||||
{ | ||||
handler: this.configContainer, | ||||
value: document.body, | ||||
suppressEvent: CONTAINER_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config scrollincrement | ||||
* @description Number used to control the scroll speed of a menu. Used to | ||||
* increment the "scrollTop" property of the menu's body by when a menu's | ||||
* content is scrolling. When set this property is automatically applied | ||||
* to all submenus. | ||||
* @default 1 | ||||
* @type Number | ||||
*/ | ||||
oConfig.addProperty( | ||||
SCROLL_INCREMENT_CONFIG.key, | ||||
{ | ||||
value: SCROLL_INCREMENT_CONFIG.value, | ||||
validator: SCROLL_INCREMENT_CONFIG.validator, | ||||
supercedes: SCROLL_INCREMENT_CONFIG.supercedes, | ||||
suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config minscrollheight | ||||
* @description Number defining the minimum threshold for the "maxheight" | ||||
* configuration property. When set this property is automatically applied | ||||
* to all submenus. | ||||
* @default 90 | ||||
* @type Number | ||||
*/ | ||||
oConfig.addProperty( | ||||
MIN_SCROLL_HEIGHT_CONFIG.key, | ||||
{ | ||||
value: MIN_SCROLL_HEIGHT_CONFIG.value, | ||||
validator: MIN_SCROLL_HEIGHT_CONFIG.validator, | ||||
supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes, | ||||
suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config maxheight | ||||
* @description Number defining the maximum height (in pixels) for a menu's | ||||
* body element (<code><div class="bd"></code>). Once a menu's body | ||||
* exceeds this height, the contents of the body are scrolled to maintain | ||||
* this value. This value cannot be set lower than the value of the | ||||
* "minscrollheight" configuration property. | ||||
* @default 0 | ||||
* @type Number | ||||
*/ | ||||
oConfig.addProperty( | ||||
MAX_HEIGHT_CONFIG.key, | ||||
{ | ||||
handler: this.configMaxHeight, | ||||
value: MAX_HEIGHT_CONFIG.value, | ||||
validator: MAX_HEIGHT_CONFIG.validator, | ||||
suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent, | ||||
supercedes: MAX_HEIGHT_CONFIG.supercedes | ||||
} | ||||
); | ||||
/** | ||||
* @config classname | ||||
* @description String representing the CSS class to be applied to the | ||||
* menu's root <code><div></code> element. The specified class(es) | ||||
* are appended in addition to the default class as specified by the menu's | ||||
* CSS_CLASS_NAME constant. When set this property is automatically | ||||
* applied to all submenus. | ||||
* @default null | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
CLASS_NAME_CONFIG.key, | ||||
{ | ||||
handler: this.configClassName, | ||||
value: CLASS_NAME_CONFIG.value, | ||||
validator: CLASS_NAME_CONFIG.validator, | ||||
supercedes: CLASS_NAME_CONFIG.supercedes | ||||
} | ||||
); | ||||
/** | ||||
* @config disabled | ||||
* @description Boolean indicating if the menu should be disabled. | ||||
* Disabling a menu disables each of its items. (Disabled menu items are | ||||
* dimmed and will not respond to user input or fire events.) Disabled | ||||
* menus have a corresponding "disabled" CSS class applied to their root | ||||
* <code><div></code> element. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
DISABLED_CONFIG.key, | ||||
{ | ||||
handler: this.configDisabled, | ||||
value: DISABLED_CONFIG.value, | ||||
validator: DISABLED_CONFIG.validator, | ||||
suppressEvent: DISABLED_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config shadow | ||||
* @description Boolean indicating if the menu should have a shadow. | ||||
* @default true | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
SHADOW_CONFIG.key, | ||||
{ | ||||
handler: this.configShadow, | ||||
value: SHADOW_CONFIG.value, | ||||
validator: SHADOW_CONFIG.validator | ||||
} | ||||
); | ||||
/** | ||||
* @config keepopen | ||||
* @description Boolean indicating if the menu should remain open when clicked. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
KEEP_OPEN_CONFIG.key, | ||||
{ | ||||
value: KEEP_OPEN_CONFIG.value, | ||||
validator: KEEP_OPEN_CONFIG.validator | ||||
} | ||||
); | ||||
} | ||||
}); // END YAHOO.lang.extend | ||||
})(); | ||||
(function () { | ||||
/** | ||||
* Creates an item for a menu. | ||||
* | ||||
* @param {String} p_oObject String specifying the text of the menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying | ||||
* the <code><li></code> element of the menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object | ||||
* specifying the <code><optgroup></code> element of the menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object | ||||
* specifying the <code><option></code> element of the menu item. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu item. See configuration class documentation | ||||
* for more details. | ||||
* @class MenuItem | ||||
* @constructor | ||||
*/ | ||||
YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) { | ||||
if (p_oObject) { | ||||
if (p_oConfig) { | ||||
this.parent = p_oConfig.parent; | ||||
this.value = p_oConfig.value; | ||||
this.id = p_oConfig.id; | ||||
} | ||||
this.init(p_oObject, p_oConfig); | ||||
} | ||||
}; | ||||
var Dom = YAHOO.util.Dom, | ||||
Module = YAHOO.widget.Module, | ||||
Menu = YAHOO.widget.Menu, | ||||
MenuItem = YAHOO.widget.MenuItem, | ||||
CustomEvent = YAHOO.util.CustomEvent, | ||||
UA = YAHOO.env.ua, | ||||
Lang = YAHOO.lang, | ||||
// Private string constants | ||||
_TEXT = "text", | ||||
_HASH = "#", | ||||
_HYPHEN = "-", | ||||
_HELP_TEXT = "helptext", | ||||
_URL = "url", | ||||
_TARGET = "target", | ||||
_EMPHASIS = "emphasis", | ||||
_STRONG_EMPHASIS = "strongemphasis", | ||||
_CHECKED = "checked", | ||||
_SUBMENU = "submenu", | ||||
_DISABLED = "disabled", | ||||
_SELECTED = "selected", | ||||
_HAS_SUBMENU = "hassubmenu", | ||||
_CHECKED_DISABLED = "checked-disabled", | ||||
_HAS_SUBMENU_DISABLED = "hassubmenu-disabled", | ||||
_HAS_SUBMENU_SELECTED = "hassubmenu-selected", | ||||
_CHECKED_SELECTED = "checked-selected", | ||||
_ONCLICK = "onclick", | ||||
_CLASSNAME = "classname", | ||||
_EMPTY_STRING = "", | ||||
_OPTION = "OPTION", | ||||
_OPTGROUP = "OPTGROUP", | ||||
_LI_UPPERCASE = "LI", | ||||
_HREF = "href", | ||||
_SELECT = "SELECT", | ||||
_DIV = "DIV", | ||||
_START_HELP_TEXT = "<em class=\"helptext\">", | ||||
_START_EM = "<em>", | ||||
_END_EM = "</em>", | ||||
_START_STRONG = "<strong>", | ||||
_END_STRONG = "</strong>", | ||||
_PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap", | ||||
_OBJ = "obj", | ||||
_SCOPE = "scope", | ||||
_NONE = "none", | ||||
_VISIBLE = "visible", | ||||
_SPACE = " ", | ||||
_MENUITEM = "MenuItem", | ||||
_CLICK = "click", | ||||
_SHOW = "show", | ||||
_HIDE = "hide", | ||||
_LI_LOWERCASE = "li", | ||||
_ANCHOR_TEMPLATE = "<a href=\"#\"></a>", | ||||
EVENT_TYPES = [ | ||||
["mouseOverEvent", "mouseover"], | ||||
["mouseOutEvent", "mouseout"], | ||||
["mouseDownEvent", "mousedown"], | ||||
["mouseUpEvent", "mouseup"], | ||||
["clickEvent", _CLICK], | ||||
["keyPressEvent", "keypress"], | ||||
["keyDownEvent", "keydown"], | ||||
["keyUpEvent", "keyup"], | ||||
["focusEvent", "focus"], | ||||
["blurEvent", "blur"], | ||||
["destroyEvent", "destroy"] | ||||
], | ||||
TEXT_CONFIG = { | ||||
key: _TEXT, | ||||
value: _EMPTY_STRING, | ||||
validator: Lang.isString, | ||||
suppressEvent: true | ||||
}, | ||||
HELP_TEXT_CONFIG = { | ||||
key: _HELP_TEXT, | ||||
supercedes: [_TEXT], | ||||
suppressEvent: true | ||||
}, | ||||
URL_CONFIG = { | ||||
key: _URL, | ||||
value: _HASH, | ||||
suppressEvent: true | ||||
}, | ||||
TARGET_CONFIG = { | ||||
key: _TARGET, | ||||
suppressEvent: true | ||||
}, | ||||
EMPHASIS_CONFIG = { | ||||
key: _EMPHASIS, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true, | ||||
supercedes: [_TEXT] | ||||
}, | ||||
STRONG_EMPHASIS_CONFIG = { | ||||
key: _STRONG_EMPHASIS, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true, | ||||
supercedes: [_TEXT] | ||||
}, | ||||
CHECKED_CONFIG = { | ||||
key: _CHECKED, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true, | ||||
supercedes: [_DISABLED, _SELECTED] | ||||
}, | ||||
SUBMENU_CONFIG = { | ||||
key: _SUBMENU, | ||||
suppressEvent: true, | ||||
supercedes: [_DISABLED, _SELECTED] | ||||
}, | ||||
DISABLED_CONFIG = { | ||||
key: _DISABLED, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true, | ||||
supercedes: [_TEXT, _SELECTED] | ||||
}, | ||||
SELECTED_CONFIG = { | ||||
key: _SELECTED, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true | ||||
}, | ||||
ONCLICK_CONFIG = { | ||||
key: _ONCLICK, | ||||
suppressEvent: true | ||||
}, | ||||
CLASS_NAME_CONFIG = { | ||||
key: _CLASSNAME, | ||||
value: null, | ||||
validator: Lang.isString, | ||||
suppressEvent: true | ||||
}, | ||||
KEY_LISTENER_CONFIG = { | ||||
key: "keylistener", | ||||
value: null, | ||||
suppressEvent: true | ||||
}, | ||||
m_oMenuItemTemplate = null, | ||||
CLASS_NAMES = {}; | ||||
/** | ||||
* @method getClassNameForState | ||||
* @description Returns a class name for the specified prefix and state. If the class name does not | ||||
* yet exist, it is created and stored in the CLASS_NAMES object to increase performance. | ||||
* @private | ||||
* @param {String} prefix String representing the prefix for the class name | ||||
* @param {String} state String representing a state - "disabled," "checked," etc. | ||||
*/ | ||||
var getClassNameForState = function (prefix, state) { | ||||
var oClassNames = CLASS_NAMES[prefix]; | ||||
if (!oClassNames) { | ||||
CLASS_NAMES[prefix] = {}; | ||||
oClassNames = CLASS_NAMES[prefix]; | ||||
} | ||||
var sClassName = oClassNames[state]; | ||||
if (!sClassName) { | ||||
sClassName = prefix + _HYPHEN + state; | ||||
oClassNames[state] = sClassName; | ||||
} | ||||
return sClassName; | ||||
}; | ||||
/** | ||||
* @method addClassNameForState | ||||
* @description Applies a class name to a MenuItem instance's <LI> and <A> elements | ||||
* that represents a MenuItem's state - "disabled," "checked," etc. | ||||
* @private | ||||
* @param {String} state String representing a state - "disabled," "checked," etc. | ||||
*/ | ||||
var addClassNameForState = function (state) { | ||||
Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state)); | ||||
Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state)); | ||||
}; | ||||
/** | ||||
* @method removeClassNameForState | ||||
* @description Removes a class name from a MenuItem instance's <LI> and <A> elements | ||||
* that represents a MenuItem's state - "disabled," "checked," etc. | ||||
* @private | ||||
* @param {String} state String representing a state - "disabled," "checked," etc. | ||||
*/ | ||||
var removeClassNameForState = function (state) { | ||||
Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state)); | ||||
Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state)); | ||||
}; | ||||
MenuItem.prototype = { | ||||
/** | ||||
* @property CSS_CLASS_NAME | ||||
* @description String representing the CSS class(es) to be applied to the | ||||
* <code><li></code> element of the menu item. | ||||
* @default "yuimenuitem" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
CSS_CLASS_NAME: "yuimenuitem", | ||||
/** | ||||
* @property CSS_LABEL_CLASS_NAME | ||||
* @description String representing the CSS class(es) to be applied to the | ||||
* menu item's <code><a></code> element. | ||||
* @default "yuimenuitemlabel" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
CSS_LABEL_CLASS_NAME: "yuimenuitemlabel", | ||||
/** | ||||
* @property SUBMENU_TYPE | ||||
* @description Object representing the type of menu to instantiate and | ||||
* add when parsing the child nodes of the menu item's source HTML element. | ||||
* @final | ||||
* @type YAHOO.widget.Menu | ||||
*/ | ||||
SUBMENU_TYPE: null, | ||||
// Private member variables | ||||
/** | ||||
* @property _oAnchor | ||||
* @description Object reference to the menu item's | ||||
* <code><a></code> element. | ||||
* @default null | ||||
* @private | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-48250443">HTMLAnchorElement</a> | ||||
*/ | ||||
_oAnchor: null, | ||||
/** | ||||
* @property _oHelpTextEM | ||||
* @description Object reference to the menu item's help text | ||||
* <code><em></code> element. | ||||
* @default null | ||||
* @private | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-58190037">HTMLElement</a> | ||||
*/ | ||||
_oHelpTextEM: null, | ||||
/** | ||||
* @property _oSubmenu | ||||
* @description Object reference to the menu item's submenu. | ||||
* @default null | ||||
* @private | ||||
* @type YAHOO.widget.Menu | ||||
*/ | ||||
_oSubmenu: null, | ||||
/** | ||||
* @property _oOnclickAttributeValue | ||||
* @description Object reference to the menu item's current value for the | ||||
* "onclick" configuration attribute. | ||||
* @default null | ||||
* @private | ||||
* @type Object | ||||
*/ | ||||
_oOnclickAttributeValue: null, | ||||
/** | ||||
* @property _sClassName | ||||
* @description The current value of the "classname" configuration attribute. | ||||
* @default null | ||||
* @private | ||||
* @type String | ||||
*/ | ||||
_sClassName: null, | ||||
// Public properties | ||||
/** | ||||
* @property constructor | ||||
* @description Object reference to the menu item's constructor function. | ||||
* @default YAHOO.widget.MenuItem | ||||
* @type YAHOO.widget.MenuItem | ||||
*/ | ||||
constructor: MenuItem, | ||||
/** | ||||
* @property index | ||||
* @description Number indicating the ordinal position of the menu item in | ||||
* its group. | ||||
* @default null | ||||
* @type Number | ||||
*/ | ||||
index: null, | ||||
/** | ||||
* @property groupIndex | ||||
* @description Number indicating the index of the group to which the menu | ||||
* item belongs. | ||||
* @default null | ||||
* @type Number | ||||
*/ | ||||
groupIndex: null, | ||||
/** | ||||
* @property parent | ||||
* @description Object reference to the menu item's parent menu. | ||||
* @default null | ||||
* @type YAHOO.widget.Menu | ||||
*/ | ||||
parent: null, | ||||
/** | ||||
* @property element | ||||
* @description Object reference to the menu item's | ||||
* <code><li></code> element. | ||||
* @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level | ||||
* -one-html.html#ID-74680021">HTMLLIElement</a> | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a> | ||||
*/ | ||||
element: null, | ||||
/** | ||||
* @property srcElement | ||||
* @description Object reference to the HTML element (either | ||||
* <code><li></code>, <code><optgroup></code> or | ||||
* <code><option></code>) used create the menu item. | ||||
* @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www. | ||||
* w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247" | ||||
* >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM- | ||||
* Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a> | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3. | ||||
* org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"> | ||||
* HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM- | ||||
* Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a> | ||||
*/ | ||||
srcElement: null, | ||||
/** | ||||
* @property value | ||||
* @description Object reference to the menu item's value. | ||||
* @default null | ||||
* @type Object | ||||
*/ | ||||
value: null, | ||||
/** | ||||
* @property browser | ||||
* @deprecated Use YAHOO.env.ua | ||||
* @description String representing the browser. | ||||
* @type String | ||||
*/ | ||||
browser: Module.prototype.browser, | ||||
/** | ||||
* @property id | ||||
* @description Id of the menu item's root <code><li></code> | ||||
* element. This property should be set via the constructor using the | ||||
* configuration object literal. If an id is not specified, then one will | ||||
* be created using the "generateId" method of the Dom utility. | ||||
* @default null | ||||
* @type String | ||||
*/ | ||||
id: null, | ||||
// Events | ||||
/** | ||||
* @event destroyEvent | ||||
* @description Fires when the menu item's <code><li></code> | ||||
* element is removed from its parent <code><ul></code> element. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event mouseOverEvent | ||||
* @description Fires when the mouse has entered the menu item. Passes | ||||
* back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event mouseOutEvent | ||||
* @description Fires when the mouse has left the menu item. Passes back | ||||
* the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event mouseDownEvent | ||||
* @description Fires when the user mouses down on the menu item. Passes | ||||
* back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event mouseUpEvent | ||||
* @description Fires when the user releases a mouse button while the mouse | ||||
* is over the menu item. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event clickEvent | ||||
* @description Fires when the user clicks the on the menu item. Passes | ||||
* back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event keyPressEvent | ||||
* @description Fires when the user presses an alphanumeric key when the | ||||
* menu item has focus. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event keyDownEvent | ||||
* @description Fires when the user presses a key when the menu item has | ||||
* focus. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event keyUpEvent | ||||
* @description Fires when the user releases a key when the menu item has | ||||
* focus. Passes back the DOM Event object as an argument. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event focusEvent | ||||
* @description Fires when the menu item receives focus. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @event blurEvent | ||||
* @description Fires when the menu item loses the input focus. | ||||
* @type YAHOO.util.CustomEvent | ||||
*/ | ||||
/** | ||||
* @method init | ||||
* @description The MenuItem class's initialization method. This method is | ||||
* automatically called by the constructor, and sets up all DOM references | ||||
* for pre-existing markup, and creates required markup if it is not | ||||
* already present. | ||||
* @param {String} p_oObject String specifying the text of the menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying | ||||
* the <code><li></code> element of the menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object | ||||
* specifying the <code><optgroup></code> element of the menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object | ||||
* specifying the <code><option></code> element of the menu item. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu item. See configuration class documentation | ||||
* for more details. | ||||
*/ | ||||
init: function (p_oObject, p_oConfig) { | ||||
if (!this.SUBMENU_TYPE) { | ||||
this.SUBMENU_TYPE = Menu; | ||||
} | ||||
// Create the config object | ||||
this.cfg = new YAHOO.util.Config(this); | ||||
this.initDefaultConfig(); | ||||
var oConfig = this.cfg, | ||||
sURL = _HASH, | ||||
oCustomEvent, | ||||
aEventData, | ||||
oAnchor, | ||||
sTarget, | ||||
sText, | ||||
sId, | ||||
i; | ||||
if (Lang.isString(p_oObject)) { | ||||
this._createRootNodeStructure(); | ||||
oConfig.queueProperty(_TEXT, p_oObject); | ||||
} | ||||
else if (p_oObject && p_oObject.tagName) { | ||||
switch(p_oObject.tagName.toUpperCase()) { | ||||
case _OPTION: | ||||
this._createRootNodeStructure(); | ||||
oConfig.queueProperty(_TEXT, p_oObject.text); | ||||
oConfig.queueProperty(_DISABLED, p_oObject.disabled); | ||||
this.value = p_oObject.value; | ||||
this.srcElement = p_oObject; | ||||
break; | ||||
case _OPTGROUP: | ||||
this._createRootNodeStructure(); | ||||
oConfig.queueProperty(_TEXT, p_oObject.label); | ||||
oConfig.queueProperty(_DISABLED, p_oObject.disabled); | ||||
this.srcElement = p_oObject; | ||||
this._initSubTree(); | ||||
break; | ||||
case _LI_UPPERCASE: | ||||
// Get the anchor node (if it exists) | ||||
oAnchor = Dom.getFirstChild(p_oObject); | ||||
// Capture the "text" and/or the "URL" | ||||
if (oAnchor) { | ||||
sURL = oAnchor.getAttribute(_HREF, 2); | ||||
sTarget = oAnchor.getAttribute(_TARGET); | ||||
sText = oAnchor.innerHTML; | ||||
} | ||||
this.srcElement = p_oObject; | ||||
this.element = p_oObject; | ||||
this._oAnchor = oAnchor; | ||||
/* | ||||
Set these properties silently to sync up the | ||||
configuration object without making changes to the | ||||
element's DOM | ||||
*/ | ||||
oConfig.setProperty(_TEXT, sText, true); | ||||
oConfig.setProperty(_URL, sURL, true); | ||||
oConfig.setProperty(_TARGET, sTarget, true); | ||||
this._initSubTree(); | ||||
break; | ||||
} | ||||
} | ||||
if (this.element) { | ||||
sId = (this.srcElement || this.element).id; | ||||
if (!sId) { | ||||
sId = this.id || Dom.generateId(); | ||||
this.element.id = sId; | ||||
} | ||||
this.id = sId; | ||||
Dom.addClass(this.element, this.CSS_CLASS_NAME); | ||||
Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME); | ||||
i = EVENT_TYPES.length - 1; | ||||
do { | ||||
aEventData = EVENT_TYPES[i]; | ||||
oCustomEvent = this.createEvent(aEventData[1]); | ||||
oCustomEvent.signature = CustomEvent.LIST; | ||||
this[aEventData[0]] = oCustomEvent; | ||||
} | ||||
while (i--); | ||||
if (p_oConfig) { | ||||
oConfig.applyConfig(p_oConfig); | ||||
} | ||||
oConfig.fireQueue(); | ||||
} | ||||
}, | ||||
// Private methods | ||||
/** | ||||
* @method _createRootNodeStructure | ||||
* @description Creates the core DOM structure for the menu item. | ||||
* @private | ||||
*/ | ||||
_createRootNodeStructure: function () { | ||||
var oElement, | ||||
oAnchor; | ||||
if (!m_oMenuItemTemplate) { | ||||
m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE); | ||||
m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE; | ||||
} | ||||
oElement = m_oMenuItemTemplate.cloneNode(true); | ||||
oElement.className = this.CSS_CLASS_NAME; | ||||
oAnchor = oElement.firstChild; | ||||
oAnchor.className = this.CSS_LABEL_CLASS_NAME; | ||||
this.element = oElement; | ||||
this._oAnchor = oAnchor; | ||||
}, | ||||
/** | ||||
* @method _initSubTree | ||||
* @description Iterates the source element's childNodes collection and uses | ||||
* the child nodes to instantiate other menus. | ||||
* @private | ||||
*/ | ||||
_initSubTree: function () { | ||||
var oSrcEl = this.srcElement, | ||||
oConfig = this.cfg, | ||||
oNode, | ||||
aOptions, | ||||
nOptions, | ||||
oMenu, | ||||
n; | ||||
if (oSrcEl.childNodes.length > 0) { | ||||
if (this.parent.lazyLoad && this.parent.srcElement && | ||||
this.parent.srcElement.tagName.toUpperCase() == _SELECT) { | ||||
oConfig.setProperty( | ||||
_SUBMENU, | ||||
{ id: Dom.generateId(), itemdata: oSrcEl.childNodes } | ||||
); | ||||
} | ||||
else { | ||||
oNode = oSrcEl.firstChild; | ||||
aOptions = []; | ||||
do { | ||||
if (oNode && oNode.tagName) { | ||||
switch(oNode.tagName.toUpperCase()) { | ||||
case _DIV: | ||||
oConfig.setProperty(_SUBMENU, oNode); | ||||
break; | ||||
case _OPTION: | ||||
aOptions[aOptions.length] = oNode; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
while((oNode = oNode.nextSibling)); | ||||
nOptions = aOptions.length; | ||||
if (nOptions > 0) { | ||||
oMenu = new this.SUBMENU_TYPE(Dom.generateId()); | ||||
oConfig.setProperty(_SUBMENU, oMenu); | ||||
for(n=0; n<nOptions; n++) { | ||||
oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n]))); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
}, | ||||
// Event handlers for configuration properties | ||||
/** | ||||
* @method configText | ||||
* @description Event handler for when the "text" configuration property of | ||||
* the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configText: function (p_sType, p_aArgs, p_oItem) { | ||||
var sText = p_aArgs[0], | ||||
oConfig = this.cfg, | ||||
oAnchor = this._oAnchor, | ||||
sHelpText = oConfig.getProperty(_HELP_TEXT), | ||||
sHelpTextHTML = _EMPTY_STRING, | ||||
sEmphasisStartTag = _EMPTY_STRING, | ||||
sEmphasisEndTag = _EMPTY_STRING; | ||||
if (sText) { | ||||
if (sHelpText) { | ||||
sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM; | ||||
} | ||||
if (oConfig.getProperty(_EMPHASIS)) { | ||||
sEmphasisStartTag = _START_EM; | ||||
sEmphasisEndTag = _END_EM; | ||||
} | ||||
if (oConfig.getProperty(_STRONG_EMPHASIS)) { | ||||
sEmphasisStartTag = _START_STRONG; | ||||
sEmphasisEndTag = _END_STRONG; | ||||
} | ||||
oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configHelpText | ||||
* @description Event handler for when the "helptext" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configHelpText: function (p_sType, p_aArgs, p_oItem) { | ||||
this.cfg.refireEvent(_TEXT); | ||||
}, | ||||
/** | ||||
* @method configURL | ||||
* @description Event handler for when the "url" configuration property of | ||||
* the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configURL: function (p_sType, p_aArgs, p_oItem) { | ||||
var sURL = p_aArgs[0]; | ||||
if (!sURL) { | ||||
sURL = _HASH; | ||||
} | ||||
var oAnchor = this._oAnchor; | ||||
if (UA.opera) { | ||||
oAnchor.removeAttribute(_HREF); | ||||
} | ||||
oAnchor.setAttribute(_HREF, sURL); | ||||
}, | ||||
/** | ||||
* @method configTarget | ||||
* @description Event handler for when the "target" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configTarget: function (p_sType, p_aArgs, p_oItem) { | ||||
var sTarget = p_aArgs[0], | ||||
oAnchor = this._oAnchor; | ||||
if (sTarget && sTarget.length > 0) { | ||||
oAnchor.setAttribute(_TARGET, sTarget); | ||||
} | ||||
else { | ||||
oAnchor.removeAttribute(_TARGET); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configEmphasis | ||||
* @description Event handler for when the "emphasis" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configEmphasis: function (p_sType, p_aArgs, p_oItem) { | ||||
var bEmphasis = p_aArgs[0], | ||||
oConfig = this.cfg; | ||||
if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) { | ||||
oConfig.setProperty(_STRONG_EMPHASIS, false); | ||||
} | ||||
oConfig.refireEvent(_TEXT); | ||||
}, | ||||
/** | ||||
* @method configStrongEmphasis | ||||
* @description Event handler for when the "strongemphasis" configuration | ||||
* property of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) { | ||||
var bStrongEmphasis = p_aArgs[0], | ||||
oConfig = this.cfg; | ||||
if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) { | ||||
oConfig.setProperty(_EMPHASIS, false); | ||||
} | ||||
oConfig.refireEvent(_TEXT); | ||||
}, | ||||
/** | ||||
* @method configChecked | ||||
* @description Event handler for when the "checked" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configChecked: function (p_sType, p_aArgs, p_oItem) { | ||||
var bChecked = p_aArgs[0], | ||||
oConfig = this.cfg; | ||||
if (bChecked) { | ||||
addClassNameForState.call(this, _CHECKED); | ||||
} | ||||
else { | ||||
removeClassNameForState.call(this, _CHECKED); | ||||
} | ||||
oConfig.refireEvent(_TEXT); | ||||
if (oConfig.getProperty(_DISABLED)) { | ||||
oConfig.refireEvent(_DISABLED); | ||||
} | ||||
if (oConfig.getProperty(_SELECTED)) { | ||||
oConfig.refireEvent(_SELECTED); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configDisabled | ||||
* @description Event handler for when the "disabled" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configDisabled: function (p_sType, p_aArgs, p_oItem) { | ||||
var bDisabled = p_aArgs[0], | ||||
oConfig = this.cfg, | ||||
oSubmenu = oConfig.getProperty(_SUBMENU), | ||||
bChecked = oConfig.getProperty(_CHECKED); | ||||
if (bDisabled) { | ||||
if (oConfig.getProperty(_SELECTED)) { | ||||
oConfig.setProperty(_SELECTED, false); | ||||
} | ||||
addClassNameForState.call(this, _DISABLED); | ||||
if (oSubmenu) { | ||||
addClassNameForState.call(this, _HAS_SUBMENU_DISABLED); | ||||
} | ||||
if (bChecked) { | ||||
addClassNameForState.call(this, _CHECKED_DISABLED); | ||||
} | ||||
} | ||||
else { | ||||
removeClassNameForState.call(this, _DISABLED); | ||||
if (oSubmenu) { | ||||
removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED); | ||||
} | ||||
if (bChecked) { | ||||
removeClassNameForState.call(this, _CHECKED_DISABLED); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method configSelected | ||||
* @description Event handler for when the "selected" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configSelected: function (p_sType, p_aArgs, p_oItem) { | ||||
var oConfig = this.cfg, | ||||
oAnchor = this._oAnchor, | ||||
bSelected = p_aArgs[0], | ||||
bChecked = oConfig.getProperty(_CHECKED), | ||||
oSubmenu = oConfig.getProperty(_SUBMENU); | ||||
if (UA.opera) { | ||||
oAnchor.blur(); | ||||
} | ||||
if (bSelected && !oConfig.getProperty(_DISABLED)) { | ||||
addClassNameForState.call(this, _SELECTED); | ||||
if (oSubmenu) { | ||||
addClassNameForState.call(this, _HAS_SUBMENU_SELECTED); | ||||
} | ||||
if (bChecked) { | ||||
addClassNameForState.call(this, _CHECKED_SELECTED); | ||||
} | ||||
} | ||||
else { | ||||
removeClassNameForState.call(this, _SELECTED); | ||||
if (oSubmenu) { | ||||
removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED); | ||||
} | ||||
if (bChecked) { | ||||
removeClassNameForState.call(this, _CHECKED_SELECTED); | ||||
} | ||||
} | ||||
if (this.hasFocus() && UA.opera) { | ||||
oAnchor.focus(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onSubmenuBeforeHide | ||||
* @description "beforehide" Custom Event handler for a submenu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
_onSubmenuBeforeHide: function (p_sType, p_aArgs) { | ||||
var oItem = this.parent, | ||||
oMenu; | ||||
function onHide() { | ||||
oItem._oAnchor.blur(); | ||||
oMenu.beforeHideEvent.unsubscribe(onHide); | ||||
} | ||||
if (oItem.hasFocus()) { | ||||
oMenu = oItem.parent; | ||||
oMenu.beforeHideEvent.subscribe(onHide); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configSubmenu | ||||
* @description Event handler for when the "submenu" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configSubmenu: function (p_sType, p_aArgs, p_oItem) { | ||||
var oSubmenu = p_aArgs[0], | ||||
oConfig = this.cfg, | ||||
bLazyLoad = this.parent && this.parent.lazyLoad, | ||||
oMenu, | ||||
sSubmenuId, | ||||
oSubmenuConfig; | ||||
if (oSubmenu) { | ||||
if (oSubmenu instanceof Menu) { | ||||
oMenu = oSubmenu; | ||||
oMenu.parent = this; | ||||
oMenu.lazyLoad = bLazyLoad; | ||||
} | ||||
else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) { | ||||
sSubmenuId = oSubmenu.id; | ||||
oSubmenuConfig = oSubmenu; | ||||
oSubmenuConfig.lazyload = bLazyLoad; | ||||
oSubmenuConfig.parent = this; | ||||
oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig); | ||||
// Set the value of the property to the Menu instance | ||||
oConfig.setProperty(_SUBMENU, oMenu, true); | ||||
} | ||||
else { | ||||
oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this }); | ||||
// Set the value of the property to the Menu instance | ||||
oConfig.setProperty(_SUBMENU, oMenu, true); | ||||
} | ||||
if (oMenu) { | ||||
oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true); | ||||
addClassNameForState.call(this, _HAS_SUBMENU); | ||||
if (oConfig.getProperty(_URL) === _HASH) { | ||||
oConfig.setProperty(_URL, (_HASH + oMenu.id)); | ||||
} | ||||
this._oSubmenu = oMenu; | ||||
if (UA.opera) { | ||||
oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide); | ||||
} | ||||
} | ||||
} | ||||
else { | ||||
removeClassNameForState.call(this, _HAS_SUBMENU); | ||||
if (this._oSubmenu) { | ||||
this._oSubmenu.destroy(); | ||||
} | ||||
} | ||||
if (oConfig.getProperty(_DISABLED)) { | ||||
oConfig.refireEvent(_DISABLED); | ||||
} | ||||
if (oConfig.getProperty(_SELECTED)) { | ||||
oConfig.refireEvent(_SELECTED); | ||||
} | ||||
}, | ||||
/** | ||||
* @method configOnClick | ||||
* @description Event handler for when the "onclick" configuration property | ||||
* of the menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configOnClick: function (p_sType, p_aArgs, p_oItem) { | ||||
var oObject = p_aArgs[0]; | ||||
/* | ||||
Remove any existing listeners if a "click" event handler has | ||||
already been specified. | ||||
*/ | ||||
if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) { | ||||
this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn, | ||||
this._oOnclickAttributeValue.obj); | ||||
this._oOnclickAttributeValue = null; | ||||
} | ||||
if (!this._oOnclickAttributeValue && Lang.isObject(oObject) && | ||||
Lang.isFunction(oObject.fn)) { | ||||
this.clickEvent.subscribe(oObject.fn, | ||||
((_OBJ in oObject) ? oObject.obj : this), | ||||
((_SCOPE in oObject) ? oObject.scope : null) ); | ||||
this._oOnclickAttributeValue = oObject; | ||||
} | ||||
}, | ||||
/** | ||||
* @method configClassName | ||||
* @description Event handler for when the "classname" configuration | ||||
* property of a menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item | ||||
* that fired the event. | ||||
*/ | ||||
configClassName: function (p_sType, p_aArgs, p_oItem) { | ||||
var sClassName = p_aArgs[0]; | ||||
if (this._sClassName) { | ||||
Dom.removeClass(this.element, this._sClassName); | ||||
} | ||||
Dom.addClass(this.element, sClassName); | ||||
this._sClassName = sClassName; | ||||
}, | ||||
/** | ||||
* @method _dispatchClickEvent | ||||
* @description Dispatches a DOM "click" event to the anchor element of a | ||||
* MenuItem instance. | ||||
* @private | ||||
*/ | ||||
_dispatchClickEvent: function () { | ||||
var oMenuItem = this, | ||||
oAnchor, | ||||
oEvent; | ||||
if (!oMenuItem.cfg.getProperty(_DISABLED)) { | ||||
oAnchor = Dom.getFirstChild(oMenuItem.element); | ||||
// Dispatch a "click" event to the MenuItem's anchor so that its | ||||
// "click" event handlers will get called in response to the user | ||||
// pressing the keyboard shortcut defined by the "keylistener" | ||||
// configuration property. | ||||
if (UA.ie) { | ||||
oAnchor.fireEvent(_ONCLICK); | ||||
} | ||||
else { | ||||
if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) { | ||||
oEvent = document.createEvent("HTMLEvents"); | ||||
oEvent.initEvent(_CLICK, true, true); | ||||
} | ||||
else { | ||||
oEvent = document.createEvent("MouseEvents"); | ||||
oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0, | ||||
0, 0, false, false, false, false, 0, null); | ||||
} | ||||
oAnchor.dispatchEvent(oEvent); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* @method _createKeyListener | ||||
* @description "show" event handler for a Menu instance - responsible for | ||||
* setting up the KeyListener instance for a MenuItem. | ||||
* @private | ||||
* @param {String} type String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} args Array of arguments sent when the event was fired. | ||||
* @param {Array} keyData Array of arguments sent when the event was fired. | ||||
*/ | ||||
_createKeyListener: function (type, args, keyData) { | ||||
var oMenuItem = this, | ||||
oMenu = oMenuItem.parent; | ||||
var oKeyListener = new YAHOO.util.KeyListener( | ||||
oMenu.element.ownerDocument, | ||||
keyData, | ||||
{ | ||||
fn: oMenuItem._dispatchClickEvent, | ||||
scope: oMenuItem, | ||||
correctScope: true }); | ||||
if (oMenu.cfg.getProperty(_VISIBLE)) { | ||||
oKeyListener.enable(); | ||||
} | ||||
oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener); | ||||
oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener); | ||||
oMenuItem._keyListener = oKeyListener; | ||||
oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData); | ||||
}, | ||||
/** | ||||
* @method configKeyListener | ||||
* @description Event handler for when the "keylistener" configuration | ||||
* property of a menu item changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
*/ | ||||
configKeyListener: function (p_sType, p_aArgs) { | ||||
var oKeyData = p_aArgs[0], | ||||
oMenuItem = this, | ||||
oMenu = oMenuItem.parent; | ||||
if (oMenuItem._keyData) { | ||||
// Unsubscribe from the "show" event in case the keylistener | ||||
// config was changed before the Menu was ever made visible. | ||||
oMenu.unsubscribe(_SHOW, | ||||
oMenuItem._createKeyListener, oMenuItem._keyData); | ||||
oMenuItem._keyData = null; | ||||
} | ||||
// Tear down for the previous value of the "keylistener" property | ||||
if (oMenuItem._keyListener) { | ||||
oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable); | ||||
oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable); | ||||
oMenuItem._keyListener.disable(); | ||||
oMenuItem._keyListener = null; | ||||
} | ||||
if (oKeyData) { | ||||
oMenuItem._keyData = oKeyData; | ||||
// Defer the creation of the KeyListener instance until the | ||||
// parent Menu is visible. This is necessary since the | ||||
// KeyListener instance needs to be bound to the document the | ||||
// Menu has been rendered into. Deferring creation of the | ||||
// KeyListener instance also improves performance. | ||||
oMenu.subscribe(_SHOW, oMenuItem._createKeyListener, | ||||
oKeyData, oMenuItem); | ||||
} | ||||
}, | ||||
// Public methods | ||||
/** | ||||
* @method initDefaultConfig | ||||
* @description Initializes an item's configurable properties. | ||||
*/ | ||||
initDefaultConfig : function () { | ||||
var oConfig = this.cfg; | ||||
// Define the configuration attributes | ||||
/** | ||||
* @config text | ||||
* @description String specifying the text label for the menu item. | ||||
* When building a menu from existing HTML the value of this property | ||||
* will be interpreted from the menu's markup. | ||||
* @default "" | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
TEXT_CONFIG.key, | ||||
{ | ||||
handler: this.configText, | ||||
value: TEXT_CONFIG.value, | ||||
validator: TEXT_CONFIG.validator, | ||||
suppressEvent: TEXT_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config helptext | ||||
* @description String specifying additional instructional text to | ||||
* accompany the text for the menu item. | ||||
* @deprecated Use "text" configuration property to add help text markup. | ||||
* For example: <code>oMenuItem.cfg.setProperty("text", "Copy <em | ||||
* class=\"helptext\">Ctrl + C</em>");</code> | ||||
* @default null | ||||
* @type String|<a href="http://www.w3.org/TR/ | ||||
* 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037"> | ||||
* HTMLElement</a> | ||||
*/ | ||||
oConfig.addProperty( | ||||
HELP_TEXT_CONFIG.key, | ||||
{ | ||||
handler: this.configHelpText, | ||||
supercedes: HELP_TEXT_CONFIG.supercedes, | ||||
suppressEvent: HELP_TEXT_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config url | ||||
* @description String specifying the URL for the menu item's anchor's | ||||
* "href" attribute. When building a menu from existing HTML the value | ||||
* of this property will be interpreted from the menu's markup. | ||||
* @default "#" | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
URL_CONFIG.key, | ||||
{ | ||||
handler: this.configURL, | ||||
value: URL_CONFIG.value, | ||||
suppressEvent: URL_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config target | ||||
* @description String specifying the value for the "target" attribute | ||||
* of the menu item's anchor element. <strong>Specifying a target will | ||||
* require the user to click directly on the menu item's anchor node in | ||||
* order to cause the browser to navigate to the specified URL.</strong> | ||||
* When building a menu from existing HTML the value of this property | ||||
* will be interpreted from the menu's markup. | ||||
* @default null | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
TARGET_CONFIG.key, | ||||
{ | ||||
handler: this.configTarget, | ||||
suppressEvent: TARGET_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config emphasis | ||||
* @description Boolean indicating if the text of the menu item will be | ||||
* rendered with emphasis. | ||||
* @deprecated Use the "text" configuration property to add emphasis. | ||||
* For example: <code>oMenuItem.cfg.setProperty("text", "<em>Some | ||||
* Text</em>");</code> | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
EMPHASIS_CONFIG.key, | ||||
{ | ||||
handler: this.configEmphasis, | ||||
value: EMPHASIS_CONFIG.value, | ||||
validator: EMPHASIS_CONFIG.validator, | ||||
suppressEvent: EMPHASIS_CONFIG.suppressEvent, | ||||
supercedes: EMPHASIS_CONFIG.supercedes | ||||
} | ||||
); | ||||
/** | ||||
* @config strongemphasis | ||||
* @description Boolean indicating if the text of the menu item will be | ||||
* rendered with strong emphasis. | ||||
* @deprecated Use the "text" configuration property to add strong emphasis. | ||||
* For example: <code>oMenuItem.cfg.setProperty("text", "<strong> | ||||
* Some Text</strong>");</code> | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
STRONG_EMPHASIS_CONFIG.key, | ||||
{ | ||||
handler: this.configStrongEmphasis, | ||||
value: STRONG_EMPHASIS_CONFIG.value, | ||||
validator: STRONG_EMPHASIS_CONFIG.validator, | ||||
suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent, | ||||
supercedes: STRONG_EMPHASIS_CONFIG.supercedes | ||||
} | ||||
); | ||||
/** | ||||
* @config checked | ||||
* @description Boolean indicating if the menu item should be rendered | ||||
* with a checkmark. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
CHECKED_CONFIG.key, | ||||
{ | ||||
handler: this.configChecked, | ||||
value: CHECKED_CONFIG.value, | ||||
validator: CHECKED_CONFIG.validator, | ||||
suppressEvent: CHECKED_CONFIG.suppressEvent, | ||||
supercedes: CHECKED_CONFIG.supercedes | ||||
} | ||||
); | ||||
/** | ||||
* @config disabled | ||||
* @description Boolean indicating if the menu item should be disabled. | ||||
* (Disabled menu items are dimmed and will not respond to user input | ||||
* or fire events.) | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
DISABLED_CONFIG.key, | ||||
{ | ||||
handler: this.configDisabled, | ||||
value: DISABLED_CONFIG.value, | ||||
validator: DISABLED_CONFIG.validator, | ||||
suppressEvent: DISABLED_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config selected | ||||
* @description Boolean indicating if the menu item should | ||||
* be highlighted. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
SELECTED_CONFIG.key, | ||||
{ | ||||
handler: this.configSelected, | ||||
value: SELECTED_CONFIG.value, | ||||
validator: SELECTED_CONFIG.validator, | ||||
suppressEvent: SELECTED_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config submenu | ||||
* @description Object specifying the submenu to be appended to the | ||||
* menu item. The value can be one of the following: <ul><li>Object | ||||
* specifying a Menu instance.</li><li>Object literal specifying the | ||||
* menu to be created. Format: <code>{ id: [menu id], itemdata: | ||||
* [<a href="YAHOO.widget.Menu.html#itemData">array of values for | ||||
* items</a>] }</code>.</li><li>String specifying the id attribute | ||||
* of the <code><div></code> element of the menu.</li><li> | ||||
* Object specifying the <code><div></code> element of the | ||||
* menu.</li></ul> | ||||
* @default null | ||||
* @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/ | ||||
* WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037"> | ||||
* HTMLElement</a> | ||||
*/ | ||||
oConfig.addProperty( | ||||
SUBMENU_CONFIG.key, | ||||
{ | ||||
handler: this.configSubmenu, | ||||
supercedes: SUBMENU_CONFIG.supercedes, | ||||
suppressEvent: SUBMENU_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config onclick | ||||
* @description Object literal representing the code to be executed when | ||||
* the item is clicked. Format:<br> <code> {<br> | ||||
* <strong>fn:</strong> Function, // The handler to call when | ||||
* the event fires.<br> <strong>obj:</strong> Object, // An | ||||
* object to pass back to the handler.<br> <strong>scope:</strong> | ||||
* Object // The object to use for the scope of the handler. | ||||
* <br> } </code> | ||||
* @type Object | ||||
* @default null | ||||
*/ | ||||
oConfig.addProperty( | ||||
ONCLICK_CONFIG.key, | ||||
{ | ||||
handler: this.configOnClick, | ||||
suppressEvent: ONCLICK_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config classname | ||||
* @description CSS class to be applied to the menu item's root | ||||
* <code><li></code> element. The specified class(es) are | ||||
* appended in addition to the default class as specified by the menu | ||||
* item's CSS_CLASS_NAME constant. | ||||
* @default null | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
CLASS_NAME_CONFIG.key, | ||||
{ | ||||
handler: this.configClassName, | ||||
value: CLASS_NAME_CONFIG.value, | ||||
validator: CLASS_NAME_CONFIG.validator, | ||||
suppressEvent: CLASS_NAME_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config keylistener | ||||
* @description Object literal representing the key(s) that can be used | ||||
* to trigger the MenuItem's "click" event. Possible attributes are | ||||
* shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int | ||||
* or an array of ints representing keycodes). | ||||
* @default null | ||||
* @type Object | ||||
*/ | ||||
oConfig.addProperty( | ||||
KEY_LISTENER_CONFIG.key, | ||||
{ | ||||
handler: this.configKeyListener, | ||||
value: KEY_LISTENER_CONFIG.value, | ||||
suppressEvent: KEY_LISTENER_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
}, | ||||
/** | ||||
* @method getNextSibling | ||||
* @description Finds the menu item's next sibling. | ||||
* @return YAHOO.widget.MenuItem | ||||
*/ | ||||
getNextSibling: function () { | ||||
var isUL = function (el) { | ||||
return (el.nodeName.toLowerCase() === "ul"); | ||||
}, | ||||
menuitemEl = this.element, | ||||
next = Dom.getNextSibling(menuitemEl), | ||||
parent, | ||||
sibling, | ||||
list; | ||||
if (!next) { | ||||
parent = menuitemEl.parentNode; | ||||
sibling = Dom.getNextSiblingBy(parent, isUL); | ||||
if (sibling) { | ||||
list = sibling; | ||||
} | ||||
else { | ||||
list = Dom.getFirstChildBy(parent.parentNode, isUL); | ||||
} | ||||
next = Dom.getFirstChild(list); | ||||
} | ||||
return YAHOO.widget.MenuManager.getMenuItem(next.id); | ||||
}, | ||||
/** | ||||
* @method getNextEnabledSibling | ||||
* @description Finds the menu item's next enabled sibling. | ||||
* @return YAHOO.widget.MenuItem | ||||
*/ | ||||
getNextEnabledSibling: function () { | ||||
var next = this.getNextSibling(); | ||||
return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next; | ||||
}, | ||||
/** | ||||
* @method getPreviousSibling | ||||
* @description Finds the menu item's previous sibling. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
getPreviousSibling: function () { | ||||
var isUL = function (el) { | ||||
return (el.nodeName.toLowerCase() === "ul"); | ||||
}, | ||||
menuitemEl = this.element, | ||||
next = Dom.getPreviousSibling(menuitemEl), | ||||
parent, | ||||
sibling, | ||||
list; | ||||
if (!next) { | ||||
parent = menuitemEl.parentNode; | ||||
sibling = Dom.getPreviousSiblingBy(parent, isUL); | ||||
if (sibling) { | ||||
list = sibling; | ||||
} | ||||
else { | ||||
list = Dom.getLastChildBy(parent.parentNode, isUL); | ||||
} | ||||
next = Dom.getLastChild(list); | ||||
} | ||||
return YAHOO.widget.MenuManager.getMenuItem(next.id); | ||||
}, | ||||
/** | ||||
* @method getPreviousEnabledSibling | ||||
* @description Finds the menu item's previous enabled sibling. | ||||
* @return {YAHOO.widget.MenuItem} | ||||
*/ | ||||
getPreviousEnabledSibling: function () { | ||||
var next = this.getPreviousSibling(); | ||||
return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next; | ||||
}, | ||||
/** | ||||
* @method focus | ||||
* @description Causes the menu item to receive the focus and fires the | ||||
* focus event. | ||||
*/ | ||||
focus: function () { | ||||
var oParent = this.parent, | ||||
oAnchor = this._oAnchor, | ||||
oActiveItem = oParent.activeItem; | ||||
function setFocus() { | ||||
try { | ||||
if (!(UA.ie && !document.hasFocus())) { | ||||
if (oActiveItem) { | ||||
oActiveItem.blurEvent.fire(); | ||||
} | ||||
oAnchor.focus(); | ||||
this.focusEvent.fire(); | ||||
} | ||||
} | ||||
catch(e) { | ||||
} | ||||
} | ||||
if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) && | ||||
this.element.style.display != _NONE) { | ||||
/* | ||||
Setting focus via a timer fixes a race condition in Firefox, IE | ||||
and Opera where the browser viewport jumps as it trys to | ||||
position and focus the menu. | ||||
*/ | ||||
Lang.later(0, this, setFocus); | ||||
} | ||||
}, | ||||
/** | ||||
* @method blur | ||||
* @description Causes the menu item to lose focus and fires the | ||||
* blur event. | ||||
*/ | ||||
blur: function () { | ||||
var oParent = this.parent; | ||||
if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) { | ||||
Lang.later(0, this, function () { | ||||
try { | ||||
this._oAnchor.blur(); | ||||
this.blurEvent.fire(); | ||||
} | ||||
catch (e) { | ||||
} | ||||
}, 0); | ||||
} | ||||
}, | ||||
/** | ||||
* @method hasFocus | ||||
* @description Returns a boolean indicating whether or not the menu item | ||||
* has focus. | ||||
* @return {Boolean} | ||||
*/ | ||||
hasFocus: function () { | ||||
return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this); | ||||
}, | ||||
/** | ||||
* @method destroy | ||||
* @description Removes the menu item's <code><li></code> element | ||||
* from its parent <code><ul></code> element. | ||||
*/ | ||||
destroy: function () { | ||||
var oEl = this.element, | ||||
oSubmenu, | ||||
oParentNode, | ||||
aEventData, | ||||
i; | ||||
if (oEl) { | ||||
// If the item has a submenu, destroy it first | ||||
oSubmenu = this.cfg.getProperty(_SUBMENU); | ||||
if (oSubmenu) { | ||||
oSubmenu.destroy(); | ||||
} | ||||
// Remove the element from the parent node | ||||
oParentNode = oEl.parentNode; | ||||
if (oParentNode) { | ||||
oParentNode.removeChild(oEl); | ||||
this.destroyEvent.fire(); | ||||
} | ||||
// Remove CustomEvent listeners | ||||
i = EVENT_TYPES.length - 1; | ||||
do { | ||||
aEventData = EVENT_TYPES[i]; | ||||
this[aEventData[0]].unsubscribeAll(); | ||||
} | ||||
while (i--); | ||||
this.cfg.configChangedEvent.unsubscribeAll(); | ||||
} | ||||
}, | ||||
/** | ||||
* @method toString | ||||
* @description Returns a string representing the menu item. | ||||
* @return {String} | ||||
*/ | ||||
toString: function () { | ||||
var sReturnVal = _MENUITEM, | ||||
sId = this.id; | ||||
if (sId) { | ||||
sReturnVal += (_SPACE + sId); | ||||
} | ||||
return sReturnVal; | ||||
} | ||||
}; | ||||
Lang.augmentProto(MenuItem, YAHOO.util.EventProvider); | ||||
})(); | ||||
(function () { | ||||
var _XY = "xy", | ||||
_MOUSEDOWN = "mousedown", | ||||
_CONTEXTMENU = "ContextMenu", | ||||
_SPACE = " "; | ||||
/** | ||||
* Creates a list of options or commands which are made visible in response to | ||||
* an HTML element's "contextmenu" event ("mousedown" for Opera). | ||||
* | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><div></code> element of the context menu. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><select></code> element to be used as the data source for the | ||||
* context menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one- | ||||
* html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the | ||||
* <code><div></code> element of the context menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one- | ||||
* html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying | ||||
* the <code><select></code> element to be used as the data source for | ||||
* the context menu. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the context menu. See configuration class documentation | ||||
* for more details. | ||||
* @class ContextMenu | ||||
* @constructor | ||||
* @extends YAHOO.widget.Menu | ||||
* @namespace YAHOO.widget | ||||
*/ | ||||
YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) { | ||||
YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig); | ||||
}; | ||||
var Event = YAHOO.util.Event, | ||||
UA = YAHOO.env.ua, | ||||
ContextMenu = YAHOO.widget.ContextMenu, | ||||
/** | ||||
* Constant representing the name of the ContextMenu's events | ||||
* @property EVENT_TYPES | ||||
* @private | ||||
* @final | ||||
* @type Object | ||||
*/ | ||||
EVENT_TYPES = { | ||||
"TRIGGER_CONTEXT_MENU": "triggerContextMenu", | ||||
"CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"), | ||||
"CLICK": "click" | ||||
}, | ||||
/** | ||||
* Constant representing the ContextMenu's configuration properties | ||||
* @property DEFAULT_CONFIG | ||||
* @private | ||||
* @final | ||||
* @type Object | ||||
*/ | ||||
TRIGGER_CONFIG = { | ||||
key: "trigger", | ||||
suppressEvent: true | ||||
}; | ||||
/** | ||||
* @method position | ||||
* @description "beforeShow" event handler used to position the contextmenu. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {Array} p_aPos Array representing the xy position for the context menu. | ||||
*/ | ||||
function position(p_sType, p_aArgs, p_aPos) { | ||||
this.cfg.setProperty(_XY, p_aPos); | ||||
this.beforeShowEvent.unsubscribe(position, p_aPos); | ||||
} | ||||
YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, { | ||||
// Private properties | ||||
/** | ||||
* @property _oTrigger | ||||
* @description Object reference to the current value of the "trigger" | ||||
* configuration property. | ||||
* @default null | ||||
* @private | ||||
* @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve | ||||
* l-one-html.html#ID-58190037">HTMLElement</a>|Array | ||||
*/ | ||||
_oTrigger: null, | ||||
/** | ||||
* @property _bCancelled | ||||
* @description Boolean indicating if the display of the context menu should | ||||
* be cancelled. | ||||
* @default false | ||||
* @private | ||||
* @type Boolean | ||||
*/ | ||||
_bCancelled: false, | ||||
// Public properties | ||||
/** | ||||
* @property contextEventTarget | ||||
* @description Object reference for the HTML element that was the target of the | ||||
* "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of | ||||
* the context menu. | ||||
* @default null | ||||
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one- | ||||
* html.html#ID-58190037">HTMLElement</a> | ||||
*/ | ||||
contextEventTarget: null, | ||||
// Events | ||||
/** | ||||
* @event triggerContextMenuEvent | ||||
* @description Custom Event wrapper for the "contextmenu" DOM event | ||||
* ("mousedown" for Opera) fired by the element(s) that trigger the display of | ||||
* the context menu. | ||||
*/ | ||||
triggerContextMenuEvent: null, | ||||
/** | ||||
* @method init | ||||
* @description The ContextMenu class's initialization method. This method is | ||||
* automatically called by the constructor, and sets up all DOM references for | ||||
* pre-existing markup, and creates required markup if it is not already present. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><div></code> element of the context menu. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><select></code> element to be used as the data source for | ||||
* the context menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one- | ||||
* html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the | ||||
* <code><div></code> element of the context menu. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one- | ||||
* html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying | ||||
* the <code><select></code> element to be used as the data source for | ||||
* the context menu. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the context menu. See configuration class documentation | ||||
* for more details. | ||||
*/ | ||||
init: function(p_oElement, p_oConfig) { | ||||
// Call the init of the superclass (YAHOO.widget.Menu) | ||||
ContextMenu.superclass.init.call(this, p_oElement); | ||||
this.beforeInitEvent.fire(ContextMenu); | ||||
if (p_oConfig) { | ||||
this.cfg.applyConfig(p_oConfig, true); | ||||
} | ||||
this.initEvent.fire(ContextMenu); | ||||
}, | ||||
/** | ||||
* @method initEvents | ||||
* @description Initializes the custom events for the context menu. | ||||
*/ | ||||
initEvents: function() { | ||||
ContextMenu.superclass.initEvents.call(this); | ||||
// Create custom events | ||||
this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU); | ||||
this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST; | ||||
}, | ||||
/** | ||||
* @method cancel | ||||
* @description Cancels the display of the context menu. | ||||
*/ | ||||
cancel: function() { | ||||
this._bCancelled = true; | ||||
}, | ||||
// Private methods | ||||
/** | ||||
* @method _removeEventHandlers | ||||
* @description Removes all of the DOM event handlers from the HTML element(s) | ||||
* whose "context menu" event ("click" for Opera) trigger the display of | ||||
* the context menu. | ||||
* @private | ||||
*/ | ||||
_removeEventHandlers: function() { | ||||
var oTrigger = this._oTrigger; | ||||
// Remove the event handlers from the trigger(s) | ||||
if (oTrigger) { | ||||
Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu); | ||||
if (UA.opera) { | ||||
Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick); | ||||
} | ||||
} | ||||
}, | ||||
// Private event handlers | ||||
/** | ||||
* @method _onTriggerClick | ||||
* @description "click" event handler for the HTML element(s) identified as the | ||||
* "trigger" for the context menu. Used to cancel default behaviors in Opera. | ||||
* @private | ||||
* @param {Event} p_oEvent Object representing the DOM event object passed back | ||||
* by the event utility (YAHOO.util.Event). | ||||
* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context | ||||
* menu that is handling the event. | ||||
*/ | ||||
_onTriggerClick: function(p_oEvent, p_oMenu) { | ||||
if (p_oEvent.ctrlKey) { | ||||
Event.stopEvent(p_oEvent); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onTriggerContextMenu | ||||
* @description "contextmenu" event handler ("mousedown" for Opera) for the HTML | ||||
* element(s) that trigger the display of the context menu. | ||||
* @private | ||||
* @param {Event} p_oEvent Object representing the DOM event object passed back | ||||
* by the event utility (YAHOO.util.Event). | ||||
* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context | ||||
* menu that is handling the event. | ||||
*/ | ||||
_onTriggerContextMenu: function(p_oEvent, p_oMenu) { | ||||
var aXY; | ||||
if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) { | ||||
this.contextEventTarget = Event.getTarget(p_oEvent); | ||||
this.triggerContextMenuEvent.fire(p_oEvent); | ||||
if (!this._bCancelled) { | ||||
/* | ||||
Prevent the browser's default context menu from appearing and | ||||
stop the propagation of the "contextmenu" event so that | ||||
other ContextMenu instances are not displayed. | ||||
*/ | ||||
Event.stopEvent(p_oEvent); | ||||
// Hide any other Menu instances that might be visible | ||||
YAHOO.widget.MenuManager.hideVisible(); | ||||
// Position and display the context menu | ||||
aXY = Event.getXY(p_oEvent); | ||||
if (!YAHOO.util.Dom.inDocument(this.element)) { | ||||
this.beforeShowEvent.subscribe(position, aXY); | ||||
} | ||||
else { | ||||
this.cfg.setProperty(_XY, aXY); | ||||
} | ||||
this.show(); | ||||
} | ||||
this._bCancelled = false; | ||||
} | ||||
}, | ||||
// Public methods | ||||
/** | ||||
* @method toString | ||||
* @description Returns a string representing the context menu. | ||||
* @return {String} | ||||
*/ | ||||
toString: function() { | ||||
var sReturnVal = _CONTEXTMENU, | ||||
sId = this.id; | ||||
if (sId) { | ||||
sReturnVal += (_SPACE + sId); | ||||
} | ||||
return sReturnVal; | ||||
}, | ||||
/** | ||||
* @method initDefaultConfig | ||||
* @description Initializes the class's configurable properties which can be | ||||
* changed using the context menu's Config object ("cfg"). | ||||
*/ | ||||
initDefaultConfig: function() { | ||||
ContextMenu.superclass.initDefaultConfig.call(this); | ||||
/** | ||||
* @config trigger | ||||
* @description The HTML element(s) whose "contextmenu" event ("mousedown" | ||||
* for Opera) trigger the display of the context menu. Can be a string | ||||
* representing the id attribute of the HTML element, an object reference | ||||
* for the HTML element, or an array of strings or HTML element references. | ||||
* @default null | ||||
* @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/ | ||||
* level-one-html.html#ID-58190037">HTMLElement</a>|Array | ||||
*/ | ||||
this.cfg.addProperty(TRIGGER_CONFIG.key, | ||||
{ | ||||
handler: this.configTrigger, | ||||
suppressEvent: TRIGGER_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
}, | ||||
/** | ||||
* @method destroy | ||||
* @description Removes the context menu's <code><div></code> element | ||||
* (and accompanying child nodes) from the document. | ||||
*/ | ||||
destroy: function() { | ||||
// Remove the DOM event handlers from the current trigger(s) | ||||
this._removeEventHandlers(); | ||||
// Continue with the superclass implementation of this method | ||||
ContextMenu.superclass.destroy.call(this); | ||||
}, | ||||
// Public event handlers for configuration properties | ||||
/** | ||||
* @method configTrigger | ||||
* @description Event handler for when the value of the "trigger" configuration | ||||
* property changes. | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context | ||||
* menu that fired the event. | ||||
*/ | ||||
configTrigger: function(p_sType, p_aArgs, p_oMenu) { | ||||
var oTrigger = p_aArgs[0]; | ||||
if (oTrigger) { | ||||
/* | ||||
If there is a current "trigger" - remove the event handlers | ||||
from that element(s) before assigning new ones | ||||
*/ | ||||
if (this._oTrigger) { | ||||
this._removeEventHandlers(); | ||||
} | ||||
this._oTrigger = oTrigger; | ||||
/* | ||||
Listen for the "mousedown" event in Opera b/c it does not | ||||
support the "contextmenu" event | ||||
*/ | ||||
Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true); | ||||
/* | ||||
Assign a "click" event handler to the trigger element(s) for | ||||
Opera to prevent default browser behaviors. | ||||
*/ | ||||
if (UA.opera) { | ||||
Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true); | ||||
} | ||||
} | ||||
else { | ||||
this._removeEventHandlers(); | ||||
} | ||||
} | ||||
}); // END YAHOO.lang.extend | ||||
}()); | ||||
/** | ||||
* Creates an item for a context menu. | ||||
* | ||||
* @param {String} p_oObject String specifying the text of the context menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the | ||||
* <code><li></code> element of the context menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object | ||||
* specifying the <code><optgroup></code> element of the context | ||||
* menu item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying | ||||
* the <code><option></code> element of the context menu item. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the context menu item. See configuration class | ||||
* documentation for more details. | ||||
* @class ContextMenuItem | ||||
* @constructor | ||||
* @extends YAHOO.widget.MenuItem | ||||
* @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances | ||||
* are of type YAHOO.widget.MenuItem. | ||||
*/ | ||||
YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem; | ||||
(function () { | ||||
var Lang = YAHOO.lang, | ||||
// String constants | ||||
_STATIC = "static", | ||||
_DYNAMIC_STATIC = "dynamic," + _STATIC, | ||||
_DISABLED = "disabled", | ||||
_SELECTED = "selected", | ||||
_AUTO_SUBMENU_DISPLAY = "autosubmenudisplay", | ||||
_SUBMENU = "submenu", | ||||
_VISIBLE = "visible", | ||||
_SPACE = " ", | ||||
_SUBMENU_TOGGLE_REGION = "submenutoggleregion", | ||||
_MENUBAR = "MenuBar"; | ||||
/** | ||||
* Horizontal collection of items, each of which can contain a submenu. | ||||
* | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><div></code> element of the menu bar. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><select></code> element to be used as the data source for the | ||||
* menu bar. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying | ||||
* the <code><div></code> element of the menu bar. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object | ||||
* specifying the <code><select></code> element to be used as the data | ||||
* source for the menu bar. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu bar. See configuration class documentation for | ||||
* more details. | ||||
* @class MenuBar | ||||
* @constructor | ||||
* @extends YAHOO.widget.Menu | ||||
* @namespace YAHOO.widget | ||||
*/ | ||||
YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) { | ||||
YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig); | ||||
}; | ||||
/** | ||||
* @method checkPosition | ||||
* @description Checks to make sure that the value of the "position" property | ||||
* is one of the supported strings. Returns true if the position is supported. | ||||
* @private | ||||
* @param {Object} p_sPosition String specifying the position of the menu. | ||||
* @return {Boolean} | ||||
*/ | ||||
function checkPosition(p_sPosition) { | ||||
var returnVal = false; | ||||
if (Lang.isString(p_sPosition)) { | ||||
returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1); | ||||
} | ||||
return returnVal; | ||||
} | ||||
var Event = YAHOO.util.Event, | ||||
MenuBar = YAHOO.widget.MenuBar, | ||||
POSITION_CONFIG = { | ||||
key: "position", | ||||
value: _STATIC, | ||||
validator: checkPosition, | ||||
supercedes: [_VISIBLE] | ||||
}, | ||||
SUBMENU_ALIGNMENT_CONFIG = { | ||||
key: "submenualignment", | ||||
value: ["tl","bl"] | ||||
}, | ||||
AUTO_SUBMENU_DISPLAY_CONFIG = { | ||||
key: _AUTO_SUBMENU_DISPLAY, | ||||
value: false, | ||||
validator: Lang.isBoolean, | ||||
suppressEvent: true | ||||
}, | ||||
SUBMENU_TOGGLE_REGION_CONFIG = { | ||||
key: _SUBMENU_TOGGLE_REGION, | ||||
value: false, | ||||
validator: Lang.isBoolean | ||||
}; | ||||
Lang.extend(MenuBar, YAHOO.widget.Menu, { | ||||
/** | ||||
* @method init | ||||
* @description The MenuBar class's initialization method. This method is | ||||
* automatically called by the constructor, and sets up all DOM references for | ||||
* pre-existing markup, and creates required markup if it is not already present. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><div></code> element of the menu bar. | ||||
* @param {String} p_oElement String specifying the id attribute of the | ||||
* <code><select></code> element to be used as the data source for the | ||||
* menu bar. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying | ||||
* the <code><div></code> element of the menu bar. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object | ||||
* specifying the <code><select></code> element to be used as the data | ||||
* source for the menu bar. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu bar. See configuration class documentation for | ||||
* more details. | ||||
*/ | ||||
init: function(p_oElement, p_oConfig) { | ||||
if(!this.ITEM_TYPE) { | ||||
this.ITEM_TYPE = YAHOO.widget.MenuBarItem; | ||||
} | ||||
// Call the init of the superclass (YAHOO.widget.Menu) | ||||
MenuBar.superclass.init.call(this, p_oElement); | ||||
this.beforeInitEvent.fire(MenuBar); | ||||
if(p_oConfig) { | ||||
this.cfg.applyConfig(p_oConfig, true); | ||||
} | ||||
this.initEvent.fire(MenuBar); | ||||
}, | ||||
// Constants | ||||
/** | ||||
* @property CSS_CLASS_NAME | ||||
* @description String representing the CSS class(es) to be applied to the menu | ||||
* bar's <code><div></code> element. | ||||
* @default "yuimenubar" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
CSS_CLASS_NAME: "yuimenubar", | ||||
/** | ||||
* @property SUBMENU_TOGGLE_REGION_WIDTH | ||||
* @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the | ||||
* display of the MenuBarItem's submenu. | ||||
* @default 20 | ||||
* @final | ||||
* @type Number | ||||
*/ | ||||
SUBMENU_TOGGLE_REGION_WIDTH: 20, | ||||
// Protected event handlers | ||||
/** | ||||
* @method _onKeyDown | ||||
* @description "keydown" Custom Event handler for the menu bar. | ||||
* @private | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar | ||||
* that fired the event. | ||||
*/ | ||||
_onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) { | ||||
var oEvent = p_aArgs[0], | ||||
oItem = p_aArgs[1], | ||||
oSubmenu, | ||||
oItemCfg, | ||||
oNextItem; | ||||
if(oItem && !oItem.cfg.getProperty(_DISABLED)) { | ||||
oItemCfg = oItem.cfg; | ||||
switch(oEvent.keyCode) { | ||||
case 37: // Left arrow | ||||
case 39: // Right arrow | ||||
if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) { | ||||
oItemCfg.setProperty(_SELECTED, true); | ||||
} | ||||
else { | ||||
oNextItem = (oEvent.keyCode == 37) ? | ||||
oItem.getPreviousEnabledSibling() : | ||||
oItem.getNextEnabledSibling(); | ||||
if(oNextItem) { | ||||
this.clearActiveItem(); | ||||
oNextItem.cfg.setProperty(_SELECTED, true); | ||||
oSubmenu = oNextItem.cfg.getProperty(_SUBMENU); | ||||
if(oSubmenu) { | ||||
oSubmenu.show(); | ||||
oSubmenu.setInitialFocus(); | ||||
} | ||||
else { | ||||
oNextItem.focus(); | ||||
} | ||||
} | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
break; | ||||
case 40: // Down arrow | ||||
if(this.activeItem != oItem) { | ||||
this.clearActiveItem(); | ||||
oItemCfg.setProperty(_SELECTED, true); | ||||
oItem.focus(); | ||||
} | ||||
oSubmenu = oItemCfg.getProperty(_SUBMENU); | ||||
if(oSubmenu) { | ||||
if(oSubmenu.cfg.getProperty(_VISIBLE)) { | ||||
oSubmenu.setInitialSelection(); | ||||
oSubmenu.setInitialFocus(); | ||||
} | ||||
else { | ||||
oSubmenu.show(); | ||||
oSubmenu.setInitialFocus(); | ||||
} | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
break; | ||||
} | ||||
} | ||||
if(oEvent.keyCode == 27 && this.activeItem) { // Esc key | ||||
oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU); | ||||
if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) { | ||||
oSubmenu.hide(); | ||||
this.activeItem.focus(); | ||||
} | ||||
else { | ||||
this.activeItem.cfg.setProperty(_SELECTED, false); | ||||
this.activeItem.blur(); | ||||
} | ||||
Event.preventDefault(oEvent); | ||||
} | ||||
}, | ||||
/** | ||||
* @method _onClick | ||||
* @description "click" event handler for the menu bar. | ||||
* @protected | ||||
* @param {String} p_sType String representing the name of the event that | ||||
* was fired. | ||||
* @param {Array} p_aArgs Array of arguments sent when the event was fired. | ||||
* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar | ||||
* that fired the event. | ||||
*/ | ||||
_onClick: function(p_sType, p_aArgs, p_oMenuBar) { | ||||
MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar); | ||||
var oItem = p_aArgs[1], | ||||
bReturnVal = true, | ||||
oItemEl, | ||||
oEvent, | ||||
oTarget, | ||||
oActiveItem, | ||||
oConfig, | ||||
oSubmenu, | ||||
nMenuItemX, | ||||
nToggleRegion; | ||||
var toggleSubmenuDisplay = function () { | ||||
if(oSubmenu.cfg.getProperty(_VISIBLE)) { | ||||
oSubmenu.hide(); | ||||
} | ||||
else { | ||||
oSubmenu.show(); | ||||
} | ||||
}; | ||||
if(oItem && !oItem.cfg.getProperty(_DISABLED)) { | ||||
oEvent = p_aArgs[0]; | ||||
oTarget = Event.getTarget(oEvent); | ||||
oActiveItem = this.activeItem; | ||||
oConfig = this.cfg; | ||||
// Hide any other submenus that might be visible | ||||
if(oActiveItem && oActiveItem != oItem) { | ||||
this.clearActiveItem(); | ||||
} | ||||
oItem.cfg.setProperty(_SELECTED, true); | ||||
// Show the submenu for the item | ||||
oSubmenu = oItem.cfg.getProperty(_SUBMENU); | ||||
if(oSubmenu) { | ||||
oItemEl = oItem.element; | ||||
nMenuItemX = YAHOO.util.Dom.getX(oItemEl); | ||||
nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH); | ||||
if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) { | ||||
if (Event.getPageX(oEvent) > nToggleRegion) { | ||||
toggleSubmenuDisplay(); | ||||
Event.preventDefault(oEvent); | ||||
/* | ||||
Return false so that other click event handlers are not called when the | ||||
user clicks inside the toggle region. | ||||
*/ | ||||
bReturnVal = false; | ||||
} | ||||
} | ||||
else { | ||||
toggleSubmenuDisplay(); | ||||
} | ||||
} | ||||
} | ||||
return bReturnVal; | ||||
}, | ||||
// Public methods | ||||
/** | ||||
* @method configSubmenuToggle | ||||
* @description Event handler for when the "submenutoggleregion" configuration property of | ||||
* a MenuBar changes. | ||||
* @param {String} p_sType The name of the event that was fired. | ||||
* @param {Array} p_aArgs Collection of arguments sent when the event was fired. | ||||
*/ | ||||
configSubmenuToggle: function (p_sType, p_aArgs) { | ||||
var bSubmenuToggle = p_aArgs[0]; | ||||
if (bSubmenuToggle) { | ||||
this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false); | ||||
} | ||||
}, | ||||
/** | ||||
* @method toString | ||||
* @description Returns a string representing the menu bar. | ||||
* @return {String} | ||||
*/ | ||||
toString: function() { | ||||
var sReturnVal = _MENUBAR, | ||||
sId = this.id; | ||||
if(sId) { | ||||
sReturnVal += (_SPACE + sId); | ||||
} | ||||
return sReturnVal; | ||||
}, | ||||
/** | ||||
* @description Initializes the class's configurable properties which can be | ||||
* changed using the menu bar's Config object ("cfg"). | ||||
* @method initDefaultConfig | ||||
*/ | ||||
initDefaultConfig: function() { | ||||
MenuBar.superclass.initDefaultConfig.call(this); | ||||
var oConfig = this.cfg; | ||||
// Add configuration properties | ||||
/* | ||||
Set the default value for the "position" configuration property | ||||
to "static" by re-adding the property. | ||||
*/ | ||||
/** | ||||
* @config position | ||||
* @description String indicating how a menu bar should be positioned on the | ||||
* screen. Possible values are "static" and "dynamic." Static menu bars | ||||
* are visible by default and reside in the normal flow of the document | ||||
* (CSS position: static). Dynamic menu bars are hidden by default, reside | ||||
* out of the normal flow of the document (CSS position: absolute), and can | ||||
* overlay other elements on the screen. | ||||
* @default static | ||||
* @type String | ||||
*/ | ||||
oConfig.addProperty( | ||||
POSITION_CONFIG.key, | ||||
{ | ||||
handler: this.configPosition, | ||||
value: POSITION_CONFIG.value, | ||||
validator: POSITION_CONFIG.validator, | ||||
supercedes: POSITION_CONFIG.supercedes | ||||
} | ||||
); | ||||
/* | ||||
Set the default value for the "submenualignment" configuration property | ||||
to ["tl","bl"] by re-adding the property. | ||||
*/ | ||||
/** | ||||
* @config submenualignment | ||||
* @description Array defining how submenus should be aligned to their | ||||
* parent menu bar item. The format is: [itemCorner, submenuCorner]. | ||||
* @default ["tl","bl"] | ||||
* @type Array | ||||
*/ | ||||
oConfig.addProperty( | ||||
SUBMENU_ALIGNMENT_CONFIG.key, | ||||
{ | ||||
value: SUBMENU_ALIGNMENT_CONFIG.value, | ||||
suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/* | ||||
Change the default value for the "autosubmenudisplay" configuration | ||||
property to "false" by re-adding the property. | ||||
*/ | ||||
/** | ||||
* @config autosubmenudisplay | ||||
* @description Boolean indicating if submenus are automatically made | ||||
* visible when the user mouses over the menu bar's items. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
AUTO_SUBMENU_DISPLAY_CONFIG.key, | ||||
{ | ||||
value: AUTO_SUBMENU_DISPLAY_CONFIG.value, | ||||
validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator, | ||||
suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent | ||||
} | ||||
); | ||||
/** | ||||
* @config submenutoggleregion | ||||
* @description Boolean indicating if only a specific region of a MenuBarItem should toggle the | ||||
* display of a submenu. The default width of the region is determined by the value of the | ||||
* SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay | ||||
* configuration property will be set to false, and any click event listeners will not be | ||||
* called when the user clicks inside the submenu toggle region of a MenuBarItem. If the | ||||
* user clicks outside of the submenu toggle region, the MenuBarItem will maintain its | ||||
* standard behavior. | ||||
* @default false | ||||
* @type Boolean | ||||
*/ | ||||
oConfig.addProperty( | ||||
SUBMENU_TOGGLE_REGION_CONFIG.key, | ||||
{ | ||||
value: SUBMENU_TOGGLE_REGION_CONFIG.value, | ||||
validator: SUBMENU_TOGGLE_REGION_CONFIG.validator, | ||||
handler: this.configSubmenuToggle | ||||
} | ||||
); | ||||
} | ||||
}); // END YAHOO.lang.extend | ||||
}()); | ||||
/** | ||||
* Creates an item for a menu bar. | ||||
* | ||||
* @param {String} p_oObject String specifying the text of the menu bar item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the | ||||
* <code><li></code> element of the menu bar item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object | ||||
* specifying the <code><optgroup></code> element of the menu bar item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying | ||||
* the <code><option></code> element of the menu bar item. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu bar item. See configuration class documentation | ||||
* for more details. | ||||
* @class MenuBarItem | ||||
* @constructor | ||||
* @extends YAHOO.widget.MenuItem | ||||
*/ | ||||
YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) { | ||||
YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig); | ||||
}; | ||||
YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, { | ||||
/** | ||||
* @method init | ||||
* @description The MenuBarItem class's initialization method. This method is | ||||
* automatically called by the constructor, and sets up all DOM references for | ||||
* pre-existing markup, and creates required markup if it is not already present. | ||||
* @param {String} p_oObject String specifying the text of the menu bar item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the | ||||
* <code><li></code> element of the menu bar item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object | ||||
* specifying the <code><optgroup></code> element of the menu bar item. | ||||
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level- | ||||
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying | ||||
* the <code><option></code> element of the menu bar item. | ||||
* @param {Object} p_oConfig Optional. Object literal specifying the | ||||
* configuration for the menu bar item. See configuration class documentation | ||||
* for more details. | ||||
*/ | ||||
init: function(p_oObject, p_oConfig) { | ||||
if(!this.SUBMENU_TYPE) { | ||||
this.SUBMENU_TYPE = YAHOO.widget.Menu; | ||||
} | ||||
/* | ||||
Call the init of the superclass (YAHOO.widget.MenuItem) | ||||
Note: We don't pass the user config in here yet | ||||
because we only want it executed once, at the lowest | ||||
subclass level. | ||||
*/ | ||||
YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject); | ||||
var oConfig = this.cfg; | ||||
if(p_oConfig) { | ||||
oConfig.applyConfig(p_oConfig, true); | ||||
} | ||||
oConfig.fireQueue(); | ||||
}, | ||||
// Constants | ||||
/** | ||||
* @property CSS_CLASS_NAME | ||||
* @description String representing the CSS class(es) to be applied to the | ||||
* <code><li></code> element of the menu bar item. | ||||
* @default "yuimenubaritem" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
CSS_CLASS_NAME: "yuimenubaritem", | ||||
/** | ||||
* @property CSS_LABEL_CLASS_NAME | ||||
* @description String representing the CSS class(es) to be applied to the | ||||
* menu bar item's <code><a></code> element. | ||||
* @default "yuimenubaritemlabel" | ||||
* @final | ||||
* @type String | ||||
*/ | ||||
CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel", | ||||
// Public methods | ||||
/** | ||||
* @method toString | ||||
* @description Returns a string representing the menu bar item. | ||||
* @return {String} | ||||
*/ | ||||
toString: function() { | ||||
var sReturnVal = "MenuBarItem"; | ||||
if(this.cfg && this.cfg.getProperty("text")) { | ||||
sReturnVal += (": " + this.cfg.getProperty("text")); | ||||
} | ||||
return sReturnVal; | ||||
} | ||||
}); // END YAHOO.lang.extend | ||||
YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.8.0r4", build: "2449"}); | ||||