[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-menu/ -> yui2-menu-debug.js (source)

   1  YUI.add('yui2-menu', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  
  10  
  11  /**
  12  * @module menu
  13  * @description <p>The Menu family of components features a collection of 
  14  * controls that make it easy to add menus to your website or web application.  
  15  * With the Menu Controls you can create website fly-out menus, customized 
  16  * context menus, or application-style menu bars with just a small amount of 
  17  * scripting.</p><p>The Menu family of controls features:</p>
  18  * <ul>
  19  *    <li>Keyboard and mouse navigation.</li>
  20  *    <li>A rich event model that provides access to all of a menu's 
  21  *    interesting moments.</li>
  22  *    <li>Support for 
  23  *    <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
  24  *    Enhancement</a>; Menus can be created from simple, 
  25  *    semantic markup on the page or purely through JavaScript.</li>
  26  * </ul>
  27  * @title Menu
  28  * @namespace YAHOO.widget
  29  * @requires Event, Dom, Container
  30  */
  31  (function () {
  32  
  33      var UA = YAHOO.env.ua,
  34          Dom = YAHOO.util.Dom,
  35          Event = YAHOO.util.Event,
  36          Lang = YAHOO.lang,
  37  
  38          _DIV = "DIV",
  39          _HD = "hd",
  40          _BD = "bd",
  41          _FT = "ft",
  42          _LI = "LI",
  43          _DISABLED = "disabled",
  44          _MOUSEOVER = "mouseover",
  45          _MOUSEOUT = "mouseout",
  46          _MOUSEDOWN = "mousedown",
  47          _MOUSEUP = "mouseup",
  48          _CLICK = "click",
  49          _KEYDOWN = "keydown",
  50          _KEYUP = "keyup",
  51          _KEYPRESS = "keypress",
  52          _CLICK_TO_HIDE = "clicktohide",
  53          _POSITION = "position", 
  54          _DYNAMIC = "dynamic",
  55          _SHOW_DELAY = "showdelay",
  56          _SELECTED = "selected",
  57          _VISIBLE = "visible",
  58          _UL = "UL",
  59          _MENUMANAGER = "MenuManager";
  60  
  61  
  62      /**
  63      * Singleton that manages a collection of all menus and menu items.  Listens 
  64      * for DOM events at the document level and dispatches the events to the 
  65      * corresponding menu or menu item.
  66      *
  67      * @namespace YAHOO.widget
  68      * @class MenuManager
  69      * @static
  70      */
  71      YAHOO.widget.MenuManager = function () {
  72      
  73          // Private member variables
  74      
  75      
  76          // Flag indicating if the DOM event handlers have been attached
  77      
  78          var m_bInitializedEventHandlers = false,
  79      
  80      
  81          // Collection of menus
  82  
  83          m_oMenus = {},
  84  
  85  
  86          // Collection of visible menus
  87      
  88          m_oVisibleMenus = {},
  89      
  90      
  91          //  Collection of menu items 
  92  
  93          m_oItems = {},
  94  
  95  
  96          // Map of DOM event types to their equivalent CustomEvent types
  97          
  98          m_oEventTypes = {
  99              "click": "clickEvent",
 100              "mousedown": "mouseDownEvent",
 101              "mouseup": "mouseUpEvent",
 102              "mouseover": "mouseOverEvent",
 103              "mouseout": "mouseOutEvent",
 104              "keydown": "keyDownEvent",
 105              "keyup": "keyUpEvent",
 106              "keypress": "keyPressEvent",
 107              "focus": "focusEvent",
 108              "focusin": "focusEvent",
 109              "blur": "blurEvent",
 110              "focusout": "blurEvent"
 111          },
 112      
 113      
 114          m_oFocusedMenuItem = null;
 115      
 116      
 117      
 118          // Private methods
 119      
 120      
 121          /**
 122          * @method getMenuRootElement
 123          * @description Finds the root DIV node of a menu or the root LI node of 
 124          * a menu item.
 125          * @private
 126          * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
 127          * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object 
 128          * specifying an HTML element.
 129          */
 130          function getMenuRootElement(p_oElement) {
 131          
 132              var oParentNode,
 133                  returnVal;
 134      
 135              if (p_oElement && p_oElement.tagName) {
 136              
 137                  switch (p_oElement.tagName.toUpperCase()) {
 138                          
 139                  case _DIV:
 140      
 141                      oParentNode = p_oElement.parentNode;
 142      
 143                      // Check if the DIV is the inner "body" node of a menu
 144  
 145                      if ((
 146                              Dom.hasClass(p_oElement, _HD) ||
 147                              Dom.hasClass(p_oElement, _BD) ||
 148                              Dom.hasClass(p_oElement, _FT)
 149                          ) && 
 150                          oParentNode && 
 151                          oParentNode.tagName && 
 152                          oParentNode.tagName.toUpperCase() == _DIV) {
 153                      
 154                          returnVal = oParentNode;
 155                      
 156                      }
 157                      else {
 158                      
 159                          returnVal = p_oElement;
 160                      
 161                      }
 162                  
 163                      break;
 164  
 165                  case _LI:
 166      
 167                      returnVal = p_oElement;
 168                      
 169                      break;
 170  
 171                  default:
 172      
 173                      oParentNode = p_oElement.parentNode;
 174      
 175                      if (oParentNode) {
 176                      
 177                          returnVal = getMenuRootElement(oParentNode);
 178                      
 179                      }
 180                  
 181                      break;
 182                  
 183                  }
 184      
 185              }
 186              
 187              return returnVal;
 188              
 189          }
 190      
 191      
 192      
 193          // Private event handlers
 194      
 195      
 196          /**
 197          * @method onDOMEvent
 198          * @description Generic, global event handler for all of a menu's 
 199          * DOM-based events.  This listens for events against the document 
 200          * object.  If the target of a given event is a member of a menu or 
 201          * menu item's DOM, the instance's corresponding Custom Event is fired.
 202          * @private
 203          * @param {Event} p_oEvent Object representing the DOM event object  
 204          * passed back by the event utility (YAHOO.util.Event).
 205          */
 206          function onDOMEvent(p_oEvent) {
 207      
 208              // Get the target node of the DOM event
 209          
 210              var oTarget = Event.getTarget(p_oEvent),
 211                  
 212              // See if the target of the event was a menu, or a menu item
 213      
 214              oElement = getMenuRootElement(oTarget),
 215              bFireEvent = true,
 216              sEventType = p_oEvent.type,
 217              sCustomEventType,
 218              sTagName,
 219              sId,
 220              oMenuItem,
 221              oMenu; 
 222      
 223      
 224              if (oElement) {
 225      
 226                  sTagName = oElement.tagName.toUpperCase();
 227          
 228                  if (sTagName == _LI) {
 229              
 230                      sId = oElement.id;
 231              
 232                      if (sId && m_oItems[sId]) {
 233              
 234                          oMenuItem = m_oItems[sId];
 235                          oMenu = oMenuItem.parent;
 236              
 237                      }
 238                  
 239                  }
 240                  else if (sTagName == _DIV) {
 241                  
 242                      if (oElement.id) {
 243                      
 244                          oMenu = m_oMenus[oElement.id];
 245                      
 246                      }
 247                  
 248                  }
 249      
 250              }
 251      
 252      
 253              if (oMenu) {
 254      
 255                  sCustomEventType = m_oEventTypes[sEventType];
 256  
 257                  /*
 258                      There is an inconsistency between Firefox for Mac OS X and 
 259                      Firefox Windows & Linux regarding the triggering of the 
 260                      display of the browser's context menu and the subsequent 
 261                      firing of the "click" event. In Firefox for Windows & Linux, 
 262                      when the user triggers the display of the browser's context 
 263                      menu the "click" event also fires for the document object, 
 264                      even though the "click" event did not fire for the element 
 265                      that was the original target of the "contextmenu" event. 
 266                      This is unique to Firefox on Windows & Linux.  For all 
 267                      other A-Grade browsers, including Firefox for Mac OS X, the 
 268                      "click" event doesn't fire for the document object. 
 269  
 270                      This bug in Firefox for Windows affects Menu, as Menu 
 271                      instances listen for events at the document level and 
 272                      dispatches Custom Events of the same name.  Therefore users
 273                      of Menu will get an unwanted firing of the "click" 
 274                      custom event.  The following line fixes this bug.
 275                  */
 276                  
 277  
 278  
 279                  if (sEventType == "click" && 
 280                      (UA.gecko && oMenu.platform != "mac") && 
 281                      p_oEvent.button > 0) {
 282  
 283                      bFireEvent = false;
 284  
 285                  }
 286      
 287                  // Fire the Custom Event that corresponds the current DOM event    
 288          
 289                  if (bFireEvent && oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
 290                      oMenuItem[sCustomEventType].fire(p_oEvent);                   
 291                  }
 292          
 293                  if (bFireEvent) {
 294                      oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
 295                  }
 296              
 297              }
 298              else if (sEventType == _MOUSEDOWN) {
 299      
 300                  /*
 301                      If the target of the event wasn't a menu, hide all 
 302                      dynamically positioned menus
 303                  */
 304                  
 305                  for (var i in m_oVisibleMenus) {
 306          
 307                      if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
 308          
 309                          oMenu = m_oVisibleMenus[i];
 310  
 311                          if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) && 
 312                              !(oMenu instanceof YAHOO.widget.MenuBar) && 
 313                              oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
 314  
 315                              oMenu.hide();
 316  
 317                              //    In IE when the user mouses down on a focusable 
 318                              //    element that element will be focused and become 
 319                              //    the "activeElement".
 320                              //    (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
 321                              //    However, there is a bug in IE where if there is 
 322                              //    a positioned element with a focused descendant 
 323                              //    that is hidden in response to the mousedown 
 324                              //    event, the target of the mousedown event will 
 325                              //    appear to have focus, but will not be set as 
 326                              //    the activeElement.  This will result in the 
 327                              //    element not firing key events, even though it
 328                              //    appears to have focus.  The following call to 
 329                              //    "setActive" fixes this bug.
 330  
 331                              if (UA.ie && oTarget.focus && (UA.ie < 9)) {
 332                                  oTarget.setActive();
 333                              }
 334          
 335                          }
 336                          else {
 337                              
 338                              if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
 339                              
 340                                  oMenu._cancelShowDelay();
 341                              
 342                              }
 343  
 344  
 345                              if (oMenu.activeItem) {
 346                          
 347                                  oMenu.activeItem.blur();
 348                                  oMenu.activeItem.cfg.setProperty(_SELECTED, false);
 349                          
 350                                  oMenu.activeItem = null;            
 351                          
 352                              }
 353          
 354                          }
 355          
 356                      }
 357          
 358                  } 
 359      
 360              }
 361              
 362          }
 363      
 364      
 365          /**
 366          * @method onMenuDestroy
 367          * @description "destroy" event handler for a menu.
 368          * @private
 369          * @param {String} p_sType String representing the name of the event 
 370          * that was fired.
 371          * @param {Array} p_aArgs Array of arguments sent when the event 
 372          * was fired.
 373          * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
 374          */
 375          function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
 376      
 377              if (m_oMenus[p_oMenu.id]) {
 378      
 379                  this.removeMenu(p_oMenu);
 380      
 381              }
 382      
 383          }
 384      
 385      
 386          /**
 387          * @method onMenuFocus
 388          * @description "focus" event handler for a MenuItem instance.
 389          * @private
 390          * @param {String} p_sType String representing the name of the event 
 391          * that was fired.
 392          * @param {Array} p_aArgs Array of arguments sent when the event 
 393          * was fired.
 394          */
 395          function onMenuFocus(p_sType, p_aArgs) {
 396      
 397              var oItem = p_aArgs[1];
 398      
 399              if (oItem) {
 400      
 401                  m_oFocusedMenuItem = oItem;
 402              
 403              }
 404      
 405          }
 406      
 407      
 408          /**
 409          * @method onMenuBlur
 410          * @description "blur" event handler for a MenuItem instance.
 411          * @private
 412          * @param {String} p_sType String representing the name of the event  
 413          * that was fired.
 414          * @param {Array} p_aArgs Array of arguments sent when the event 
 415          * was fired.
 416          */
 417          function onMenuBlur(p_sType, p_aArgs) {
 418      
 419              m_oFocusedMenuItem = null;
 420      
 421          }
 422  
 423      
 424          /**
 425          * @method onMenuVisibleConfigChange
 426          * @description Event handler for when the "visible" configuration  
 427          * property of a Menu instance changes.
 428          * @private
 429          * @param {String} p_sType String representing the name of the event  
 430          * that was fired.
 431          * @param {Array} p_aArgs Array of arguments sent when the event 
 432          * was fired.
 433          */
 434          function onMenuVisibleConfigChange(p_sType, p_aArgs) {
 435      
 436              var bVisible = p_aArgs[0],
 437                  sId = this.id;
 438              
 439              if (bVisible) {
 440      
 441                  m_oVisibleMenus[sId] = this;
 442                  
 443                  YAHOO.log(this + " added to the collection of visible menus.", 
 444                      "info", _MENUMANAGER);
 445              
 446              }
 447              else if (m_oVisibleMenus[sId]) {
 448              
 449                  delete m_oVisibleMenus[sId];
 450                  
 451                  YAHOO.log(this + " removed from the collection of visible menus.", 
 452                      "info", _MENUMANAGER);
 453              
 454              }
 455          
 456          }
 457      
 458      
 459          /**
 460          * @method onItemDestroy
 461          * @description "destroy" event handler for a MenuItem instance.
 462          * @private
 463          * @param {String} p_sType String representing the name of the event  
 464          * that was fired.
 465          * @param {Array} p_aArgs Array of arguments sent when the event 
 466          * was fired.
 467          */
 468          function onItemDestroy(p_sType, p_aArgs) {
 469      
 470              removeItem(this);
 471      
 472          }
 473  
 474  
 475          /**
 476          * @method removeItem
 477          * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
 478          * @private
 479          * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
 480          */    
 481          function removeItem(p_oMenuItem) {
 482  
 483              var sId = p_oMenuItem.id;
 484      
 485              if (sId && m_oItems[sId]) {
 486      
 487                  if (m_oFocusedMenuItem == p_oMenuItem) {
 488      
 489                      m_oFocusedMenuItem = null;
 490      
 491                  }
 492      
 493                  delete m_oItems[sId];
 494                  
 495                  p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
 496      
 497                  YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
 498      
 499              }
 500  
 501          }
 502      
 503      
 504          /**
 505          * @method onItemAdded
 506          * @description "itemadded" event handler for a Menu instance.
 507          * @private
 508          * @param {String} p_sType String representing the name of the event  
 509          * that was fired.
 510          * @param {Array} p_aArgs Array of arguments sent when the event 
 511          * was fired.
 512          */
 513          function onItemAdded(p_sType, p_aArgs) {
 514      
 515              var oItem = p_aArgs[0],
 516                  sId;
 517      
 518              if (oItem instanceof YAHOO.widget.MenuItem) { 
 519      
 520                  sId = oItem.id;
 521          
 522                  if (!m_oItems[sId]) {
 523              
 524                      m_oItems[sId] = oItem;
 525          
 526                      oItem.destroyEvent.subscribe(onItemDestroy);
 527          
 528                      YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
 529          
 530                  }
 531      
 532              }
 533          
 534          }
 535      
 536      
 537          return {
 538      
 539              // Privileged methods
 540      
 541      
 542              /**
 543              * @method addMenu
 544              * @description Adds a menu to the collection of known menus.
 545              * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
 546              * instance to be added.
 547              */
 548              addMenu: function (p_oMenu) {
 549      
 550                  var oDoc;
 551      
 552                  if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id && 
 553                      !m_oMenus[p_oMenu.id]) {
 554          
 555                      m_oMenus[p_oMenu.id] = p_oMenu;
 556                  
 557              
 558                      if (!m_bInitializedEventHandlers) {
 559              
 560                          oDoc = document;
 561                  
 562                          Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
 563                          Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
 564                          Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
 565                          Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
 566                          Event.on(oDoc, _CLICK, onDOMEvent, this, true);
 567                          Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
 568                          Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
 569                          Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
 570      
 571                          Event.onFocus(oDoc, onDOMEvent, this, true);
 572                          Event.onBlur(oDoc, onDOMEvent, this, true);                        
 573      
 574                          m_bInitializedEventHandlers = true;
 575                          
 576                          YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
 577              
 578                      }
 579              
 580                      p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
 581                      p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
 582                      p_oMenu.itemAddedEvent.subscribe(onItemAdded);
 583                      p_oMenu.focusEvent.subscribe(onMenuFocus);
 584                      p_oMenu.blurEvent.subscribe(onMenuBlur);
 585          
 586                      YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
 587          
 588                  }
 589          
 590              },
 591      
 592          
 593              /**
 594              * @method removeMenu
 595              * @description Removes a menu from the collection of known menus.
 596              * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
 597              * instance to be removed.
 598              */
 599              removeMenu: function (p_oMenu) {
 600      
 601                  var sId,
 602                      aItems,
 603                      i;
 604          
 605                  if (p_oMenu) {
 606      
 607                      sId = p_oMenu.id;
 608          
 609                      if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
 610  
 611                          // Unregister each menu item
 612  
 613                          aItems = p_oMenu.getItems();
 614  
 615                          if (aItems && aItems.length > 0) {
 616  
 617                              i = aItems.length - 1;
 618  
 619                              do {
 620  
 621                                  removeItem(aItems[i]);
 622  
 623                              }
 624                              while (i--);
 625  
 626                          }
 627  
 628  
 629                          // Unregister the menu
 630  
 631                          delete m_oMenus[sId];
 632              
 633                          YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
 634          
 635  
 636                          /*
 637                               Unregister the menu from the collection of 
 638                               visible menus
 639                          */
 640  
 641                          if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
 642              
 643                              delete m_oVisibleMenus[sId];
 644                              
 645                              YAHOO.log(p_oMenu + " unregistered from the" + 
 646                                          " collection of visible menus.", "info", _MENUMANAGER);
 647         
 648                          }
 649  
 650  
 651                          // Unsubscribe event listeners
 652  
 653                          if (p_oMenu.cfg) {
 654  
 655                              p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE, 
 656                                  onMenuVisibleConfigChange);
 657                              
 658                          }
 659  
 660                          p_oMenu.destroyEvent.unsubscribe(onMenuDestroy, 
 661                              p_oMenu);
 662                  
 663                          p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
 664                          p_oMenu.focusEvent.unsubscribe(onMenuFocus);
 665                          p_oMenu.blurEvent.unsubscribe(onMenuBlur);
 666  
 667                      }
 668                  
 669                  }
 670      
 671              },
 672          
 673          
 674              /**
 675              * @method hideVisible
 676              * @description Hides all visible, dynamically positioned menus 
 677              * (excluding instances of YAHOO.widget.MenuBar).
 678              */
 679              hideVisible: function () {
 680          
 681                  var oMenu;
 682          
 683                  for (var i in m_oVisibleMenus) {
 684          
 685                      if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
 686          
 687                          oMenu = m_oVisibleMenus[i];
 688          
 689                          if (!(oMenu instanceof YAHOO.widget.MenuBar) && 
 690                              oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
 691          
 692                              oMenu.hide();
 693          
 694                          }
 695          
 696                      }
 697          
 698                  }        
 699      
 700              },
 701  
 702  
 703              /**
 704              * @method getVisible
 705              * @description Returns a collection of all visible menus registered
 706              * with the menu manger.
 707              * @return {Object}
 708              */
 709              getVisible: function () {
 710              
 711                  return m_oVisibleMenus;
 712              
 713              },
 714  
 715      
 716              /**
 717              * @method getMenus
 718              * @description Returns a collection of all menus registered with the 
 719              * menu manger.
 720              * @return {Object}
 721              */
 722              getMenus: function () {
 723      
 724                  return m_oMenus;
 725              
 726              },
 727      
 728      
 729              /**
 730              * @method getMenu
 731              * @description Returns a menu with the specified id.
 732              * @param {String} p_sId String specifying the id of the 
 733              * <code>&#60;div&#62;</code> element representing the menu to
 734              * be retrieved.
 735              * @return {YAHOO.widget.Menu}
 736              */
 737              getMenu: function (p_sId) {
 738                  
 739                  var returnVal;
 740                  
 741                  if (p_sId in m_oMenus) {
 742                  
 743                      returnVal = m_oMenus[p_sId];
 744                  
 745                  }
 746              
 747                  return returnVal;
 748              
 749              },
 750      
 751      
 752              /**
 753              * @method getMenuItem
 754              * @description Returns a menu item with the specified id.
 755              * @param {String} p_sId String specifying the id of the 
 756              * <code>&#60;li&#62;</code> element representing the menu item to
 757              * be retrieved.
 758              * @return {YAHOO.widget.MenuItem}
 759              */
 760              getMenuItem: function (p_sId) {
 761      
 762                  var returnVal;
 763      
 764                  if (p_sId in m_oItems) {
 765      
 766                      returnVal = m_oItems[p_sId];
 767                  
 768                  }
 769                  
 770                  return returnVal;
 771              
 772              },
 773  
 774  
 775              /**
 776              * @method getMenuItemGroup
 777              * @description Returns an array of menu item instances whose 
 778              * corresponding <code>&#60;li&#62;</code> elements are child 
 779              * nodes of the <code>&#60;ul&#62;</code> element with the 
 780              * specified id.
 781              * @param {String} p_sId String specifying the id of the 
 782              * <code>&#60;ul&#62;</code> element representing the group of 
 783              * menu items to be retrieved.
 784              * @return {Array}
 785              */
 786              getMenuItemGroup: function (p_sId) {
 787  
 788                  var oUL = Dom.get(p_sId),
 789                      aItems,
 790                      oNode,
 791                      oItem,
 792                      sId,
 793                      returnVal;
 794      
 795  
 796                  if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
 797  
 798                      oNode = oUL.firstChild;
 799  
 800                      if (oNode) {
 801  
 802                          aItems = [];
 803                          
 804                          do {
 805  
 806                              sId = oNode.id;
 807  
 808                              if (sId) {
 809                              
 810                                  oItem = this.getMenuItem(sId);
 811                                  
 812                                  if (oItem) {
 813                                  
 814                                      aItems[aItems.length] = oItem;
 815                                  
 816                                  }
 817                              
 818                              }
 819                          
 820                          }
 821                          while ((oNode = oNode.nextSibling));
 822  
 823  
 824                          if (aItems.length > 0) {
 825  
 826                              returnVal = aItems;
 827                          
 828                          }
 829  
 830                      }
 831                  
 832                  }
 833  
 834                  return returnVal;
 835              
 836              },
 837  
 838      
 839              /**
 840              * @method getFocusedMenuItem
 841              * @description Returns a reference to the menu item that currently 
 842              * has focus.
 843              * @return {YAHOO.widget.MenuItem}
 844              */
 845              getFocusedMenuItem: function () {
 846      
 847                  return m_oFocusedMenuItem;
 848      
 849              },
 850      
 851      
 852              /**
 853              * @method getFocusedMenu
 854              * @description Returns a reference to the menu that currently 
 855              * has focus.
 856              * @return {YAHOO.widget.Menu}
 857              */
 858              getFocusedMenu: function () {
 859  
 860                  var returnVal;
 861      
 862                  if (m_oFocusedMenuItem) {
 863      
 864                      returnVal = m_oFocusedMenuItem.parent.getRoot();
 865                  
 866                  }
 867      
 868                  return returnVal;
 869      
 870              },
 871      
 872          
 873              /**
 874              * @method toString
 875              * @description Returns a string representing the menu manager.
 876              * @return {String}
 877              */
 878              toString: function () {
 879              
 880                  return _MENUMANAGER;
 881              
 882              }
 883      
 884          };
 885      
 886      }();
 887  
 888  })();
 889  
 890  
 891  
 892  (function () {
 893  
 894      var Lang = YAHOO.lang,
 895  
 896      // String constants
 897      
 898          _MENU = "Menu",
 899          _DIV_UPPERCASE = "DIV",
 900          _DIV_LOWERCASE = "div",
 901          _ID = "id",
 902          _SELECT = "SELECT",
 903          _XY = "xy",
 904          _Y = "y",
 905          _UL_UPPERCASE = "UL",
 906          _UL_LOWERCASE = "ul",
 907          _FIRST_OF_TYPE = "first-of-type",
 908          _LI = "LI",
 909          _OPTGROUP = "OPTGROUP",
 910          _OPTION = "OPTION",
 911          _DISABLED = "disabled",
 912          _NONE = "none",
 913          _SELECTED = "selected",
 914          _GROUP_INDEX = "groupindex",
 915          _INDEX = "index",
 916          _SUBMENU = "submenu",
 917          _VISIBLE = "visible",
 918          _HIDE_DELAY = "hidedelay",
 919          _POSITION = "position",
 920          _DYNAMIC = "dynamic",
 921          _STATIC = "static",
 922          _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
 923          _URL = "url",
 924          _HASH = "#",
 925          _TARGET = "target",
 926          _MAX_HEIGHT = "maxheight",
 927          _TOP_SCROLLBAR = "topscrollbar",
 928          _BOTTOM_SCROLLBAR = "bottomscrollbar",
 929          _UNDERSCORE = "_",
 930          _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
 931          _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
 932          _MOUSEMOVE = "mousemove",
 933          _SHOW_DELAY = "showdelay",
 934          _SUBMENU_HIDE_DELAY = "submenuhidedelay",
 935          _IFRAME = "iframe",
 936          _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
 937          _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
 938          _SUBMENU_ALIGNMENT = "submenualignment",
 939          _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
 940          _CLICK_TO_HIDE = "clicktohide",
 941          _CONTAINER = "container",
 942          _SCROLL_INCREMENT = "scrollincrement",
 943          _MIN_SCROLL_HEIGHT = "minscrollheight",
 944          _CLASSNAME = "classname",
 945          _SHADOW = "shadow",
 946          _KEEP_OPEN = "keepopen",
 947          _HD = "hd",
 948          _HAS_TITLE = "hastitle",
 949          _CONTEXT = "context",
 950          _EMPTY_STRING = "",
 951          _MOUSEDOWN = "mousedown",
 952          _KEYDOWN = "keydown",
 953          _HEIGHT = "height",
 954          _WIDTH = "width",
 955          _PX = "px",
 956          _EFFECT = "effect",
 957          _MONITOR_RESIZE = "monitorresize",
 958          _DISPLAY = "display",
 959          _BLOCK = "block",
 960          _VISIBILITY = "visibility",
 961          _ABSOLUTE = "absolute",
 962          _ZINDEX = "zindex",
 963          _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
 964          _NON_BREAKING_SPACE = "&#32;",
 965          _SPACE = " ",
 966          _MOUSEOVER = "mouseover",
 967          _MOUSEOUT = "mouseout",
 968          _ITEM_ADDED = "itemAdded",
 969          _ITEM_REMOVED = "itemRemoved",
 970          _HIDDEN = "hidden",
 971          _YUI_MENU_SHADOW = "yui-menu-shadow",
 972          _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
 973          _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
 974  
 975  
 976  /**
 977  * The Menu class creates a container that holds a vertical list representing 
 978  * a set of options or commands.  Menu is the base class for all 
 979  * menu containers. 
 980  * @param {String} p_oElement String specifying the id attribute of the 
 981  * <code>&#60;div&#62;</code> element of the menu.
 982  * @param {String} p_oElement String specifying the id attribute of the 
 983  * <code>&#60;select&#62;</code> element to be used as the data source 
 984  * for the menu.
 985  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
 986  * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
 987  * specifying the <code>&#60;div&#62;</code> element of the menu.
 988  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
 989  * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
 990  * Object specifying the <code>&#60;select&#62;</code> element to be used as 
 991  * the data source for the menu.
 992  * @param {Object} p_oConfig Optional. Object literal specifying the 
 993  * configuration for the menu. See configuration class documentation for 
 994  * more details.
 995  * @namespace YAHOO.widget
 996  * @class Menu
 997  * @constructor
 998  * @extends YAHOO.widget.Overlay
 999  */
1000  YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
1001  
1002      if (p_oConfig) {
1003          this.parent = p_oConfig.parent;
1004          this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
1005          this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
1006      }
1007  
1008      YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
1009  };
1010  
1011  
1012  
1013  /**
1014  * @method checkPosition
1015  * @description Checks to make sure that the value of the "position" property 
1016  * is one of the supported strings. Returns true if the position is supported.
1017  * @private
1018  * @param {Object} p_sPosition String specifying the position of the menu.
1019  * @return {Boolean}
1020  */
1021  function checkPosition(p_sPosition) {
1022  
1023      var returnVal = false;
1024  
1025      if (Lang.isString(p_sPosition)) {
1026  
1027          returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
1028  
1029      }
1030  
1031      return returnVal;
1032  
1033  }
1034  
1035  
1036  var Dom = YAHOO.util.Dom,
1037      Event = YAHOO.util.Event,
1038      Module = YAHOO.widget.Module,
1039      Overlay = YAHOO.widget.Overlay,
1040      Menu = YAHOO.widget.Menu,
1041      MenuManager = YAHOO.widget.MenuManager,
1042      CustomEvent = YAHOO.util.CustomEvent,
1043      UA = YAHOO.env.ua,
1044      
1045      m_oShadowTemplate,
1046  
1047      bFocusListenerInitialized = false,
1048  
1049      oFocusedElement,
1050  
1051      EVENT_TYPES = [
1052      
1053          ["mouseOverEvent", _MOUSEOVER],
1054          ["mouseOutEvent", _MOUSEOUT],
1055          ["mouseDownEvent", _MOUSEDOWN],
1056          ["mouseUpEvent", "mouseup"],
1057          ["clickEvent", "click"],
1058          ["keyPressEvent", "keypress"],
1059          ["keyDownEvent", _KEYDOWN],
1060          ["keyUpEvent", "keyup"],
1061          ["focusEvent", "focus"],
1062          ["blurEvent", "blur"],
1063          ["itemAddedEvent", _ITEM_ADDED],
1064          ["itemRemovedEvent", _ITEM_REMOVED]
1065  
1066      ],
1067  
1068      VISIBLE_CONFIG =  { 
1069          key: _VISIBLE, 
1070          value: false, 
1071          validator: Lang.isBoolean
1072      }, 
1073  
1074      CONSTRAIN_TO_VIEWPORT_CONFIG =  {
1075          key: _CONSTRAIN_TO_VIEWPORT, 
1076          value: true, 
1077          validator: Lang.isBoolean, 
1078          supercedes: [_IFRAME,"x",_Y,_XY]
1079      }, 
1080  
1081      PREVENT_CONTEXT_OVERLAP_CONFIG =  {
1082          key: _PREVENT_CONTEXT_OVERLAP,
1083          value: true,
1084          validator: Lang.isBoolean,  
1085          supercedes: [_CONSTRAIN_TO_VIEWPORT]
1086      },
1087  
1088      POSITION_CONFIG =  { 
1089          key: _POSITION, 
1090          value: _DYNAMIC, 
1091          validator: checkPosition, 
1092          supercedes: [_VISIBLE, _IFRAME]
1093      }, 
1094  
1095      SUBMENU_ALIGNMENT_CONFIG =  { 
1096          key: _SUBMENU_ALIGNMENT, 
1097          value: ["tl","tr"]
1098      },
1099  
1100      AUTO_SUBMENU_DISPLAY_CONFIG =  { 
1101          key: _AUTO_SUBMENU_DISPLAY, 
1102          value: true, 
1103          validator: Lang.isBoolean,
1104          suppressEvent: true
1105      }, 
1106  
1107      SHOW_DELAY_CONFIG =  { 
1108          key: _SHOW_DELAY, 
1109          value: 250, 
1110          validator: Lang.isNumber, 
1111          suppressEvent: true
1112      }, 
1113  
1114      HIDE_DELAY_CONFIG =  { 
1115          key: _HIDE_DELAY, 
1116          value: 0, 
1117          validator: Lang.isNumber, 
1118          suppressEvent: true
1119      }, 
1120  
1121      SUBMENU_HIDE_DELAY_CONFIG =  { 
1122          key: _SUBMENU_HIDE_DELAY, 
1123          value: 250, 
1124          validator: Lang.isNumber,
1125          suppressEvent: true
1126      }, 
1127  
1128      CLICK_TO_HIDE_CONFIG =  { 
1129          key: _CLICK_TO_HIDE, 
1130          value: true, 
1131          validator: Lang.isBoolean,
1132          suppressEvent: true
1133      },
1134  
1135      CONTAINER_CONFIG =  { 
1136          key: _CONTAINER,
1137          suppressEvent: true
1138      }, 
1139  
1140      SCROLL_INCREMENT_CONFIG =  { 
1141          key: _SCROLL_INCREMENT, 
1142          value: 1, 
1143          validator: Lang.isNumber,
1144          supercedes: [_MAX_HEIGHT],
1145          suppressEvent: true
1146      },
1147  
1148      MIN_SCROLL_HEIGHT_CONFIG =  { 
1149          key: _MIN_SCROLL_HEIGHT, 
1150          value: 90, 
1151          validator: Lang.isNumber,
1152          supercedes: [_MAX_HEIGHT],
1153          suppressEvent: true
1154      },    
1155  
1156      MAX_HEIGHT_CONFIG =  { 
1157          key: _MAX_HEIGHT, 
1158          value: 0, 
1159          validator: Lang.isNumber,
1160          supercedes: [_IFRAME],
1161          suppressEvent: true
1162      }, 
1163  
1164      CLASS_NAME_CONFIG =  { 
1165          key: _CLASSNAME, 
1166          value: null, 
1167          validator: Lang.isString,
1168          suppressEvent: true
1169      }, 
1170  
1171      DISABLED_CONFIG =  { 
1172          key: _DISABLED, 
1173          value: false, 
1174          validator: Lang.isBoolean,
1175          suppressEvent: true
1176      },
1177      
1178      SHADOW_CONFIG =  { 
1179          key: _SHADOW, 
1180          value: true, 
1181          validator: Lang.isBoolean,
1182          suppressEvent: true,
1183          supercedes: [_VISIBLE]
1184      },
1185      
1186      KEEP_OPEN_CONFIG = {
1187          key: _KEEP_OPEN, 
1188          value: false, 
1189          validator: Lang.isBoolean
1190      };
1191  
1192  
1193  function onDocFocus(event) {
1194  
1195      oFocusedElement = Event.getTarget(event);
1196  
1197  }
1198  
1199  
1200  
1201  YAHOO.lang.extend(Menu, Overlay, {
1202  
1203  
1204  // Constants
1205  
1206  
1207  /**
1208  * @property CSS_CLASS_NAME
1209  * @description String representing the CSS class(es) to be applied to the 
1210  * menu's <code>&#60;div&#62;</code> element.
1211  * @default "yuimenu"
1212  * @final
1213  * @type String
1214  */
1215  CSS_CLASS_NAME: "yuimenu",
1216  
1217  
1218  /**
1219  * @property ITEM_TYPE
1220  * @description Object representing the type of menu item to instantiate and 
1221  * add when parsing the child nodes (either <code>&#60;li&#62;</code> element, 
1222  * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>) 
1223  * of the menu's source HTML element.
1224  * @default YAHOO.widget.MenuItem
1225  * @final
1226  * @type YAHOO.widget.MenuItem
1227  */
1228  ITEM_TYPE: null,
1229  
1230  
1231  /**
1232  * @property GROUP_TITLE_TAG_NAME
1233  * @description String representing the tagname of the HTML element used to 
1234  * title the menu's item groups.
1235  * @default H6
1236  * @final
1237  * @type String
1238  */
1239  GROUP_TITLE_TAG_NAME: "h6",
1240  
1241  
1242  /**
1243  * @property OFF_SCREEN_POSITION
1244  * @description Array representing the default x and y position that a menu 
1245  * should have when it is positioned outside the viewport by the 
1246  * "poistionOffScreen" method.
1247  * @default "-999em"
1248  * @final
1249  * @type String
1250  */
1251  OFF_SCREEN_POSITION: "-999em",
1252  
1253  
1254  // Private properties
1255  
1256  
1257  /** 
1258  * @property _useHideDelay
1259  * @description Boolean indicating if the "mouseover" and "mouseout" event 
1260  * handlers used for hiding the menu via a call to "YAHOO.lang.later" have 
1261  * already been assigned.
1262  * @default false
1263  * @private
1264  * @type Boolean
1265  */
1266  _useHideDelay: false,
1267  
1268  
1269  /**
1270  * @property _bHandledMouseOverEvent
1271  * @description Boolean indicating the current state of the menu's 
1272  * "mouseover" event.
1273  * @default false
1274  * @private
1275  * @type Boolean
1276  */
1277  _bHandledMouseOverEvent: false,
1278  
1279  
1280  /**
1281  * @property _bHandledMouseOutEvent
1282  * @description Boolean indicating the current state of the menu's
1283  * "mouseout" event.
1284  * @default false
1285  * @private
1286  * @type Boolean
1287  */
1288  _bHandledMouseOutEvent: false,
1289  
1290  
1291  /**
1292  * @property _aGroupTitleElements
1293  * @description Array of HTML element used to title groups of menu items.
1294  * @default []
1295  * @private
1296  * @type Array
1297  */
1298  _aGroupTitleElements: null,
1299  
1300  
1301  /**
1302  * @property _aItemGroups
1303  * @description Multi-dimensional Array representing the menu items as they
1304  * are grouped in the menu.
1305  * @default []
1306  * @private
1307  * @type Array
1308  */
1309  _aItemGroups: null,
1310  
1311  
1312  /**
1313  * @property _aListElements
1314  * @description Array of <code>&#60;ul&#62;</code> elements, each of which is 
1315  * the parent node for each item's <code>&#60;li&#62;</code> element.
1316  * @default []
1317  * @private
1318  * @type Array
1319  */
1320  _aListElements: null,
1321  
1322  
1323  /**
1324  * @property _nCurrentMouseX
1325  * @description The current x coordinate of the mouse inside the area of 
1326  * the menu.
1327  * @default 0
1328  * @private
1329  * @type Number
1330  */
1331  _nCurrentMouseX: 0,
1332  
1333  
1334  /**
1335  * @property _bStopMouseEventHandlers
1336  * @description Stops "mouseover," "mouseout," and "mousemove" event handlers 
1337  * from executing.
1338  * @default false
1339  * @private
1340  * @type Boolean
1341  */
1342  _bStopMouseEventHandlers: false,
1343  
1344  
1345  /**
1346  * @property _sClassName
1347  * @description The current value of the "classname" configuration attribute.
1348  * @default null
1349  * @private
1350  * @type String
1351  */
1352  _sClassName: null,
1353  
1354  
1355  
1356  // Public properties
1357  
1358  
1359  /**
1360  * @property lazyLoad
1361  * @description Boolean indicating if the menu's "lazy load" feature is 
1362  * enabled.  If set to "true," initialization and rendering of the menu's 
1363  * items will be deferred until the first time it is made visible.  This 
1364  * property should be set via the constructor using the configuration 
1365  * object literal.
1366  * @default false
1367  * @type Boolean
1368  */
1369  lazyLoad: false,
1370  
1371  
1372  /**
1373  * @property itemData
1374  * @description Array of items to be added to the menu.  The array can contain 
1375  * strings representing the text for each item to be created, object literals 
1376  * representing the menu item configuration properties, or MenuItem instances.  
1377  * This property should be set via the constructor using the configuration 
1378  * object literal.
1379  * @default null
1380  * @type Array
1381  */
1382  itemData: null,
1383  
1384  
1385  /**
1386  * @property activeItem
1387  * @description Object reference to the item in the menu that has is selected.
1388  * @default null
1389  * @type YAHOO.widget.MenuItem
1390  */
1391  activeItem: null,
1392  
1393  
1394  /**
1395  * @property parent
1396  * @description Object reference to the menu's parent menu or menu item.  
1397  * This property can be set via the constructor using the configuration 
1398  * object literal.
1399  * @default null
1400  * @type YAHOO.widget.MenuItem
1401  */
1402  parent: null,
1403  
1404  
1405  /**
1406  * @property srcElement
1407  * @description Object reference to the HTML element (either 
1408  * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to 
1409  * create the menu.
1410  * @default null
1411  * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1412  * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a 
1413  * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
1414  * html#ID-22445964">HTMLDivElement</a>
1415  */
1416  srcElement: null,
1417  
1418  
1419  
1420  // Events
1421  
1422  
1423  /**
1424  * @event mouseOverEvent
1425  * @description Fires when the mouse has entered the menu.  Passes back 
1426  * the DOM Event object as an argument.
1427  */
1428  
1429  
1430  /**
1431  * @event mouseOutEvent
1432  * @description Fires when the mouse has left the menu.  Passes back the DOM 
1433  * Event object as an argument.
1434  * @type YAHOO.util.CustomEvent
1435  */
1436  
1437  
1438  /**
1439  * @event mouseDownEvent
1440  * @description Fires when the user mouses down on the menu.  Passes back the 
1441  * DOM Event object as an argument.
1442  * @type YAHOO.util.CustomEvent
1443  */
1444  
1445  
1446  /**
1447  * @event mouseUpEvent
1448  * @description Fires when the user releases a mouse button while the mouse is 
1449  * over the menu.  Passes back the DOM Event object as an argument.
1450  * @type YAHOO.util.CustomEvent
1451  */
1452  
1453  
1454  /**
1455  * @event clickEvent
1456  * @description Fires when the user clicks the on the menu.  Passes back the 
1457  * DOM Event object as an argument.
1458  * @type YAHOO.util.CustomEvent
1459  */
1460  
1461  
1462  /**
1463  * @event keyPressEvent
1464  * @description Fires when the user presses an alphanumeric key when one of the
1465  * menu's items has focus.  Passes back the DOM Event object as an argument.
1466  * @type YAHOO.util.CustomEvent
1467  */
1468  
1469  
1470  /**
1471  * @event keyDownEvent
1472  * @description Fires when the user presses a key when one of the menu's items 
1473  * has focus.  Passes back the DOM Event object as an argument.
1474  * @type YAHOO.util.CustomEvent
1475  */
1476  
1477  
1478  /**
1479  * @event keyUpEvent
1480  * @description Fires when the user releases a key when one of the menu's items 
1481  * has focus.  Passes back the DOM Event object as an argument.
1482  * @type YAHOO.util.CustomEvent
1483  */
1484  
1485  
1486  /**
1487  * @event itemAddedEvent
1488  * @description Fires when an item is added to the menu.
1489  * @type YAHOO.util.CustomEvent
1490  */
1491  
1492  
1493  /**
1494  * @event itemRemovedEvent
1495  * @description Fires when an item is removed to the menu.
1496  * @type YAHOO.util.CustomEvent
1497  */
1498  
1499  
1500  /**
1501  * @method init
1502  * @description The Menu class's initialization method. This method is 
1503  * automatically called by the constructor, and sets up all DOM references 
1504  * for pre-existing markup, and creates required markup if it is not 
1505  * already present.
1506  * @param {String} p_oElement String specifying the id attribute of the 
1507  * <code>&#60;div&#62;</code> element of the menu.
1508  * @param {String} p_oElement String specifying the id attribute of the 
1509  * <code>&#60;select&#62;</code> element to be used as the data source 
1510  * for the menu.
1511  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1512  * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
1513  * specifying the <code>&#60;div&#62;</code> element of the menu.
1514  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
1515  * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
1516  * Object specifying the <code>&#60;select&#62;</code> element to be used as 
1517  * the data source for the menu.
1518  * @param {Object} p_oConfig Optional. Object literal specifying the 
1519  * configuration for the menu. See configuration class documentation for 
1520  * more details.
1521  */
1522  init: function (p_oElement, p_oConfig) {
1523  
1524      this._aItemGroups = [];
1525      this._aListElements = [];
1526      this._aGroupTitleElements = [];
1527  
1528      if (!this.ITEM_TYPE) {
1529  
1530          this.ITEM_TYPE = YAHOO.widget.MenuItem;
1531  
1532      }
1533  
1534  
1535      var oElement;
1536  
1537      if (Lang.isString(p_oElement)) {
1538  
1539          oElement = Dom.get(p_oElement);
1540  
1541      }
1542      else if (p_oElement.tagName) {
1543  
1544          oElement = p_oElement;
1545  
1546      }
1547  
1548  
1549      if (oElement && oElement.tagName) {
1550  
1551          switch(oElement.tagName.toUpperCase()) {
1552      
1553              case _DIV_UPPERCASE:
1554  
1555                  this.srcElement = oElement;
1556  
1557                  if (!oElement.id) {
1558  
1559                      oElement.setAttribute(_ID, Dom.generateId());
1560  
1561                  }
1562  
1563  
1564                  /* 
1565                      Note: we don't pass the user config in here yet 
1566                      because we only want it executed once, at the lowest 
1567                      subclass level.
1568                  */ 
1569              
1570                  Menu.superclass.init.call(this, oElement);
1571  
1572                  this.beforeInitEvent.fire(Menu);
1573  
1574                  YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1575      
1576              break;
1577      
1578              case _SELECT:
1579      
1580                  this.srcElement = oElement;
1581  
1582      
1583                  /*
1584                      The source element is not something that we can use 
1585                      outright, so we need to create a new Overlay
1586  
1587                      Note: we don't pass the user config in here yet 
1588                      because we only want it executed once, at the lowest 
1589                      subclass level.
1590                  */ 
1591  
1592                  Menu.superclass.init.call(this, Dom.generateId());
1593  
1594                  this.beforeInitEvent.fire(Menu);
1595  
1596                  YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
1597  
1598              break;
1599  
1600          }
1601  
1602      }
1603      else {
1604  
1605          /* 
1606              Note: we don't pass the user config in here yet 
1607              because we only want it executed once, at the lowest 
1608              subclass level.
1609          */ 
1610      
1611          Menu.superclass.init.call(this, p_oElement);
1612  
1613          this.beforeInitEvent.fire(Menu);
1614  
1615          YAHOO.log("No source element found.  Created element with id: " + this.id, "info", this.toString());
1616  
1617      }
1618  
1619  
1620      if (this.element) {
1621          Dom.addClass(this.element, this.CSS_CLASS_NAME);
1622  
1623          // Subscribe to Custom Events
1624          this.initEvent.subscribe(this._onInit);
1625          this.beforeRenderEvent.subscribe(this._onBeforeRender);
1626          this.renderEvent.subscribe(this._onRender);
1627          this.beforeShowEvent.subscribe(this._onBeforeShow);
1628          this.hideEvent.subscribe(this._onHide);
1629          this.showEvent.subscribe(this._onShow);
1630          this.beforeHideEvent.subscribe(this._onBeforeHide);
1631          this.mouseOverEvent.subscribe(this._onMouseOver);
1632          this.mouseOutEvent.subscribe(this._onMouseOut);
1633          this.clickEvent.subscribe(this._onClick);
1634          this.keyDownEvent.subscribe(this._onKeyDown);
1635          this.keyPressEvent.subscribe(this._onKeyPress);
1636          this.blurEvent.subscribe(this._onBlur);
1637  
1638          if (!bFocusListenerInitialized) {
1639              Event.onFocus(document, onDocFocus);
1640              bFocusListenerInitialized = true;
1641          }
1642  
1643          //    Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY" 
1644          //    methods return values that don't take scrollTop into consideration 
1645  
1646          if ((UA.gecko && UA.gecko < 1.9) || (UA.webkit && UA.webkit < 523)) {
1647              this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
1648          }
1649  
1650  
1651          if (p_oConfig) {
1652              this.cfg.applyConfig(p_oConfig, true);
1653          }
1654  
1655          // Register the Menu instance with the MenuManager
1656          MenuManager.addMenu(this);
1657  
1658          this.initEvent.fire(Menu);
1659      }
1660  },
1661  
1662  
1663  
1664  // Private methods
1665  
1666  
1667  /**
1668  * @method _initSubTree
1669  * @description Iterates the childNodes of the source element to find nodes 
1670  * used to instantiate menu and menu items.
1671  * @private
1672  */
1673  _initSubTree: function () {
1674  
1675      var oSrcElement = this.srcElement,
1676          sSrcElementTagName,
1677          nGroup,
1678          sGroupTitleTagName,
1679          oNode,
1680          aListElements,
1681          nListElements,
1682          i;
1683  
1684  
1685      if (oSrcElement) {
1686      
1687          sSrcElementTagName = 
1688              (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
1689  
1690  
1691          if (sSrcElementTagName == _DIV_UPPERCASE) {
1692      
1693              //  Populate the collection of item groups and item group titles
1694      
1695              oNode = this.body.firstChild;
1696      
1697  
1698              if (oNode) {
1699      
1700                  nGroup = 0;
1701                  sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
1702          
1703                  do {
1704          
1705  
1706                      if (oNode && oNode.tagName) {
1707          
1708                          switch (oNode.tagName.toUpperCase()) {
1709          
1710                              case sGroupTitleTagName:
1711                              
1712                                  this._aGroupTitleElements[nGroup] = oNode;
1713          
1714                              break;
1715          
1716                              case _UL_UPPERCASE:
1717          
1718                                  this._aListElements[nGroup] = oNode;
1719                                  this._aItemGroups[nGroup] = [];
1720                                  nGroup++;
1721          
1722                              break;
1723          
1724                          }
1725                      
1726                      }
1727          
1728                  }
1729                  while ((oNode = oNode.nextSibling));
1730          
1731          
1732                  /*
1733                      Apply the "first-of-type" class to the first UL to mimic 
1734                      the ":first-of-type" CSS3 psuedo class.
1735                  */
1736          
1737                  if (this._aListElements[0]) {
1738          
1739                      Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
1740          
1741                  }
1742              
1743              }
1744      
1745          }
1746      
1747      
1748          oNode = null;
1749      
1750          YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
1751      
1752  
1753          if (sSrcElementTagName) {
1754      
1755              switch (sSrcElementTagName) {
1756          
1757                  case _DIV_UPPERCASE:
1758  
1759                      aListElements = this._aListElements;
1760                      nListElements = aListElements.length;
1761          
1762                      if (nListElements > 0) {
1763          
1764                          YAHOO.log("Found " + nListElements + " item groups to initialize.", 
1765                                      "info", this.toString());
1766          
1767                          i = nListElements - 1;
1768          
1769                          do {
1770          
1771                              oNode = aListElements[i].firstChild;
1772              
1773                              if (oNode) {
1774  
1775                                  YAHOO.log("Scanning " + 
1776                                      aListElements[i].childNodes.length + 
1777                                      " child nodes for items to initialize.", "info", this.toString());
1778              
1779                                  do {
1780                  
1781                                      if (oNode && oNode.tagName && 
1782                                          oNode.tagName.toUpperCase() == _LI) {
1783                  
1784                                          YAHOO.log("Initializing " + 
1785                                              oNode.tagName + " node.", "info", this.toString());
1786          
1787                                          this.addItem(new this.ITEM_TYPE(oNode, 
1788                                                      { parent: this }), i);
1789              
1790                                      }
1791                          
1792                                  }
1793                                  while ((oNode = oNode.nextSibling));
1794                              
1795                              }
1796                      
1797                          }
1798                          while (i--);
1799          
1800                      }
1801          
1802                  break;
1803          
1804                  case _SELECT:
1805          
1806                      YAHOO.log("Scanning " +  
1807                          oSrcElement.childNodes.length + 
1808                          " child nodes for items to initialize.", "info", this.toString());
1809          
1810                      oNode = oSrcElement.firstChild;
1811          
1812                      do {
1813          
1814                          if (oNode && oNode.tagName) {
1815                          
1816                              switch (oNode.tagName.toUpperCase()) {
1817              
1818                                  case _OPTGROUP:
1819                                  case _OPTION:
1820              
1821                                      YAHOO.log("Initializing " +  
1822                                          oNode.tagName + " node.", "info", this.toString());
1823              
1824                                      this.addItem(
1825                                              new this.ITEM_TYPE(
1826                                                      oNode, 
1827                                                      { parent: this }
1828                                                  )
1829                                              );
1830              
1831                                  break;
1832              
1833                              }
1834      
1835                          }
1836          
1837                      }
1838                      while ((oNode = oNode.nextSibling));
1839          
1840                  break;
1841          
1842              }
1843      
1844          }    
1845      
1846      }
1847  
1848  },
1849  
1850  
1851  /**
1852  * @method _getFirstEnabledItem
1853  * @description Returns the first enabled item in the menu.
1854  * @return {YAHOO.widget.MenuItem}
1855  * @private
1856  */
1857  _getFirstEnabledItem: function () {
1858  
1859      var aItems = this.getItems(),
1860          nItems = aItems.length,
1861          oItem,
1862          returnVal;
1863      
1864  
1865      for(var i=0; i<nItems; i++) {
1866  
1867          oItem = aItems[i];
1868  
1869          if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
1870  
1871              returnVal = oItem;
1872              break;
1873  
1874          }
1875      
1876      }
1877      
1878      return returnVal;
1879      
1880  },
1881  
1882  
1883  /**
1884  * @method _addItemToGroup
1885  * @description Adds a menu item to a group.
1886  * @private
1887  * @param {Number} p_nGroupIndex Number indicating the group to which the 
1888  * item belongs.
1889  * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
1890  * instance to be added to the menu.
1891  * @param {HTML} p_oItem String or markup specifying the content of the item to be added 
1892  * to the menu. The item is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
1893  * @param {Object} p_oItem Object literal containing a set of menu item 
1894  * configuration properties.
1895  * @param {Number} p_nItemIndex Optional. Number indicating the index at 
1896  * which the menu item should be added.
1897  * @return {YAHOO.widget.MenuItem}
1898  */
1899  _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
1900  
1901      var oItem,
1902          nGroupIndex,
1903          aGroup,
1904          oGroupItem,
1905          bAppend,
1906          oNextItemSibling,
1907          nItemIndex,
1908          returnVal;
1909  
1910  
1911      function getNextItemSibling(p_aArray, p_nStartIndex) {
1912  
1913          return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
1914  
1915      }
1916  
1917  
1918      if (p_oItem instanceof this.ITEM_TYPE) {
1919  
1920          oItem = p_oItem;
1921          oItem.parent = this;
1922  
1923      }
1924      else if (Lang.isString(p_oItem)) {
1925  
1926          oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
1927      
1928      }
1929      else if (Lang.isObject(p_oItem)) {
1930  
1931          p_oItem.parent = this;
1932  
1933          oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
1934  
1935      }
1936  
1937  
1938      if (oItem) {
1939  
1940          if (oItem.cfg.getProperty(_SELECTED)) {
1941  
1942              this.activeItem = oItem;
1943          
1944          }
1945  
1946  
1947          nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
1948          aGroup = this._getItemGroup(nGroupIndex);
1949  
1950  
1951  
1952          if (!aGroup) {
1953  
1954              aGroup = this._createItemGroup(nGroupIndex);
1955  
1956          }
1957  
1958  
1959          if (Lang.isNumber(p_nItemIndex)) {
1960  
1961              bAppend = (p_nItemIndex >= aGroup.length);            
1962  
1963  
1964              if (aGroup[p_nItemIndex]) {
1965      
1966                  aGroup.splice(p_nItemIndex, 0, oItem);
1967      
1968              }
1969              else {
1970      
1971                  aGroup[p_nItemIndex] = oItem;
1972      
1973              }
1974  
1975  
1976              oGroupItem = aGroup[p_nItemIndex];
1977  
1978              if (oGroupItem) {
1979  
1980                  if (bAppend && (!oGroupItem.element.parentNode || 
1981                          oGroupItem.element.parentNode.nodeType == 11)) {
1982          
1983                      this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
1984      
1985                  }
1986                  else {
1987      
1988                      oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
1989      
1990                      if (oNextItemSibling && (!oGroupItem.element.parentNode || 
1991                              oGroupItem.element.parentNode.nodeType == 11)) {
1992              
1993                          this._aListElements[nGroupIndex].insertBefore(
1994                                  oGroupItem.element, oNextItemSibling.element);
1995          
1996                      }
1997      
1998                  }
1999      
2000  
2001                  oGroupItem.parent = this;
2002          
2003                  this._subscribeToItemEvents(oGroupItem);
2004      
2005                  this._configureSubmenu(oGroupItem);
2006                  
2007                  this._updateItemProperties(nGroupIndex);
2008          
2009                  YAHOO.log("Item inserted." + 
2010                      " Text: " + oGroupItem.cfg.getProperty("text") + ", " + 
2011                      " Index: " + oGroupItem.index + ", " + 
2012                      " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2013  
2014                  this.itemAddedEvent.fire(oGroupItem);
2015                  this.changeContentEvent.fire();
2016  
2017                  returnVal = oGroupItem;
2018      
2019              }
2020  
2021          }
2022          else {
2023      
2024              nItemIndex = aGroup.length;
2025      
2026              aGroup[nItemIndex] = oItem;
2027  
2028              oGroupItem = aGroup[nItemIndex];
2029      
2030  
2031              if (oGroupItem) {
2032      
2033                  if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
2034      
2035                      this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
2036      
2037                  }
2038      
2039                  oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
2040                  oGroupItem.element.setAttribute(_INDEX, nItemIndex);
2041          
2042                  oGroupItem.parent = this;
2043      
2044                  oGroupItem.index = nItemIndex;
2045                  oGroupItem.groupIndex = nGroupIndex;
2046          
2047                  this._subscribeToItemEvents(oGroupItem);
2048      
2049                  this._configureSubmenu(oGroupItem);
2050      
2051                  if (nItemIndex === 0) {
2052          
2053                      Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
2054          
2055                  }
2056  
2057                  YAHOO.log("Item added." + 
2058                      " Text: " + oGroupItem.cfg.getProperty("text") + ", " + 
2059                      " Index: " + oGroupItem.index + ", " + 
2060                      " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
2061          
2062  
2063                  this.itemAddedEvent.fire(oGroupItem);
2064                  this.changeContentEvent.fire();
2065  
2066                  returnVal = oGroupItem;
2067      
2068              }
2069      
2070          }
2071  
2072      }
2073      
2074      return returnVal;
2075      
2076  },
2077  
2078  
2079  /**
2080  * @method _removeItemFromGroupByIndex
2081  * @description Removes a menu item from a group by index.  Returns the menu 
2082  * item that was removed.
2083  * @private
2084  * @param {Number} p_nGroupIndex Number indicating the group to which the menu 
2085  * item belongs.
2086  * @param {Number} p_nItemIndex Number indicating the index of the menu item 
2087  * to be removed.
2088  * @return {YAHOO.widget.MenuItem}
2089  */
2090  _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
2091  
2092      var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
2093          aGroup = this._getItemGroup(nGroupIndex),
2094          aArray,
2095          oItem,
2096          oUL;
2097  
2098      if (aGroup) {
2099  
2100          aArray = aGroup.splice(p_nItemIndex, 1);
2101          oItem = aArray[0];
2102      
2103          if (oItem) {
2104      
2105              // Update the index and className properties of each member        
2106              
2107              this._updateItemProperties(nGroupIndex);
2108      
2109              if (aGroup.length === 0) {
2110      
2111                  // Remove the UL
2112      
2113                  oUL = this._aListElements[nGroupIndex];
2114      
2115                  if (oUL && oUL.parentNode) {
2116                      oUL.parentNode.removeChild(oUL);
2117                  }
2118      
2119                  // Remove the group from the array of items
2120      
2121                  this._aItemGroups.splice(nGroupIndex, 1);
2122      
2123      
2124                  // Remove the UL from the array of ULs
2125      
2126                  this._aListElements.splice(nGroupIndex, 1);
2127      
2128      
2129                  /*
2130                       Assign the "first-of-type" class to the new first UL 
2131                       in the collection
2132                  */
2133      
2134                  oUL = this._aListElements[0];
2135      
2136                  if (oUL) {
2137      
2138                      Dom.addClass(oUL, _FIRST_OF_TYPE);
2139      
2140                  }            
2141      
2142              }
2143      
2144  
2145              this.itemRemovedEvent.fire(oItem);
2146              this.changeContentEvent.fire();
2147      
2148          }
2149  
2150      }
2151  
2152      // Return a reference to the item that was removed
2153  
2154      return oItem;
2155      
2156  },
2157  
2158  
2159  /**
2160  * @method _removeItemFromGroupByValue
2161  * @description Removes a menu item from a group by reference.  Returns the 
2162  * menu item that was removed.
2163  * @private
2164  * @param {Number} p_nGroupIndex Number indicating the group to which the
2165  * menu item belongs.
2166  * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2167  * instance to be removed.
2168  * @return {YAHOO.widget.MenuItem}
2169  */    
2170  _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
2171  
2172      var aGroup = this._getItemGroup(p_nGroupIndex),
2173          nItems,
2174          nItemIndex,
2175          returnVal,
2176          i;
2177  
2178      if (aGroup) {
2179  
2180          nItems = aGroup.length;
2181          nItemIndex = -1;
2182      
2183          if (nItems > 0) {
2184      
2185              i = nItems-1;
2186          
2187              do {
2188          
2189                  if (aGroup[i] == p_oItem) {
2190          
2191                      nItemIndex = i;
2192                      break;    
2193          
2194                  }
2195          
2196              }
2197              while (i--);
2198          
2199              if (nItemIndex > -1) {
2200          
2201                  returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
2202          
2203              }
2204      
2205          }
2206      
2207      }
2208      
2209      return returnVal;
2210  
2211  },
2212  
2213  
2214  /**
2215  * @method _updateItemProperties
2216  * @description Updates the "index," "groupindex," and "className" properties 
2217  * of the menu items in the specified group. 
2218  * @private
2219  * @param {Number} p_nGroupIndex Number indicating the group of items to update.
2220  */
2221  _updateItemProperties: function (p_nGroupIndex) {
2222  
2223      var aGroup = this._getItemGroup(p_nGroupIndex),
2224          nItems = aGroup.length,
2225          oItem,
2226          oLI,
2227          i;
2228  
2229  
2230      if (nItems > 0) {
2231  
2232          i = nItems - 1;
2233  
2234          // Update the index and className properties of each member
2235      
2236          do {
2237  
2238              oItem = aGroup[i];
2239  
2240              if (oItem) {
2241      
2242                  oLI = oItem.element;
2243  
2244                  oItem.index = i;
2245                  oItem.groupIndex = p_nGroupIndex;
2246  
2247                  oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
2248                  oLI.setAttribute(_INDEX, i);
2249  
2250                  Dom.removeClass(oLI, _FIRST_OF_TYPE);
2251  
2252              }
2253      
2254          }
2255          while (i--);
2256  
2257  
2258          if (oLI) {
2259  
2260              Dom.addClass(oLI, _FIRST_OF_TYPE);
2261  
2262          }
2263  
2264      }
2265  
2266  },
2267  
2268  
2269  /**
2270  * @method _createItemGroup
2271  * @description Creates a new menu item group (array) and its associated 
2272  * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
2273  * @private
2274  * @param {Number} p_nIndex Number indicating the group to create.
2275  * @return {Array}
2276  */
2277  _createItemGroup: function (p_nIndex) {
2278  
2279      var oUL,
2280          returnVal;
2281  
2282      if (!this._aItemGroups[p_nIndex]) {
2283  
2284          this._aItemGroups[p_nIndex] = [];
2285  
2286          oUL = document.createElement(_UL_LOWERCASE);
2287  
2288          this._aListElements[p_nIndex] = oUL;
2289  
2290          returnVal = this._aItemGroups[p_nIndex];
2291  
2292      }
2293      
2294      return returnVal;
2295  
2296  },
2297  
2298  
2299  /**
2300  * @method _getItemGroup
2301  * @description Returns the menu item group at the specified index.
2302  * @private
2303  * @param {Number} p_nIndex Number indicating the index of the menu item group 
2304  * to be retrieved.
2305  * @return {Array}
2306  */
2307  _getItemGroup: function (p_nIndex) {
2308  
2309      var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
2310          aGroups = this._aItemGroups,
2311          returnVal;
2312  
2313      if (nIndex in aGroups) {
2314  
2315          returnVal = aGroups[nIndex];
2316  
2317      }
2318      
2319      return returnVal;
2320  
2321  },
2322  
2323  
2324  /**
2325  * @method _configureSubmenu
2326  * @description Subscribes the menu item's submenu to its parent menu's events.
2327  * @private
2328  * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2329  * instance with the submenu to be configured.
2330  */
2331  _configureSubmenu: function (p_oItem) {
2332  
2333      var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
2334  
2335      if (oSubmenu) {
2336              
2337          /*
2338              Listen for configuration changes to the parent menu 
2339              so they they can be applied to the submenu.
2340          */
2341  
2342          this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
2343  
2344          this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
2345  
2346      }
2347  
2348  },
2349  
2350  
2351  
2352  
2353  /**
2354  * @method _subscribeToItemEvents
2355  * @description Subscribes a menu to a menu item's event.
2356  * @private
2357  * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
2358  * instance whose events should be subscribed to.
2359  */
2360  _subscribeToItemEvents: function (p_oItem) {
2361  
2362      p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
2363      p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
2364  
2365  },
2366  
2367  
2368  /**
2369  * @method _onVisibleChange
2370  * @description Change event handler for the the menu's "visible" configuration
2371  * property.
2372  * @private
2373  * @param {String} p_sType String representing the name of the event that 
2374  * was fired.
2375  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2376  */
2377  _onVisibleChange: function (p_sType, p_aArgs) {
2378  
2379      var bVisible = p_aArgs[0];
2380      
2381      if (bVisible) {
2382  
2383          Dom.addClass(this.element, _VISIBLE);
2384  
2385      }
2386      else {
2387  
2388          Dom.removeClass(this.element, _VISIBLE);
2389  
2390      }
2391  
2392  },
2393  
2394  
2395  /**
2396  * @method _cancelHideDelay
2397  * @description Cancels the call to "hideMenu."
2398  * @private
2399  */
2400  _cancelHideDelay: function () {
2401  
2402      var oTimer = this.getRoot()._hideDelayTimer;
2403  
2404      if (oTimer) {
2405  
2406          oTimer.cancel();
2407  
2408      }
2409  
2410  },
2411  
2412  
2413  /**
2414  * @method _execHideDelay
2415  * @description Hides the menu after the number of milliseconds specified by 
2416  * the "hidedelay" configuration property.
2417  * @private
2418  */
2419  _execHideDelay: function () {
2420  
2421      this._cancelHideDelay();
2422  
2423      var oRoot = this.getRoot();
2424  
2425      oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
2426      
2427          if (oRoot.activeItem) {
2428              if (oRoot.hasFocus()) {
2429                  oRoot.activeItem.focus();
2430              }
2431              oRoot.clearActiveItem();
2432          }
2433  
2434          if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) && 
2435              this.cfg.getProperty(_POSITION) == _DYNAMIC) {
2436              this.hide();
2437          }
2438      });
2439  
2440  },
2441  
2442  
2443  /**
2444  * @method _cancelShowDelay
2445  * @description Cancels the call to the "showMenu."
2446  * @private
2447  */
2448  _cancelShowDelay: function () {
2449      var oTimer = this.getRoot()._showDelayTimer;
2450      if (oTimer) {
2451          oTimer.cancel();
2452      }
2453  },
2454  
2455  
2456  /**
2457  * @method _execSubmenuHideDelay
2458  * @description Hides a submenu after the number of milliseconds specified by 
2459  * the "submenuhidedelay" configuration property have elapsed.
2460  * @private
2461  * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that  
2462  * should be hidden.
2463  * @param {Number} p_nMouseX The x coordinate of the mouse when it left 
2464  * the specified submenu's parent menu item.
2465  * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
2466  * before the submenu is hidden.
2467  */
2468  _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
2469  
2470      p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
2471  
2472          if (this._nCurrentMouseX > (p_nMouseX + 10)) {
2473  
2474              p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
2475          
2476                  this.hide();
2477  
2478              });
2479  
2480          }
2481          else {
2482  
2483              p_oSubmenu.hide();
2484          
2485          }
2486      
2487      });
2488  
2489  },
2490  
2491  
2492  
2493  // Protected methods
2494  
2495  
2496  /**
2497  * @method _disableScrollHeader
2498  * @description Disables the header used for scrolling the body of the menu.
2499  * @protected
2500  */
2501  _disableScrollHeader: function () {
2502  
2503      if (!this._bHeaderDisabled) {
2504  
2505          Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
2506          this._bHeaderDisabled = true;
2507  
2508      }
2509  
2510  },
2511  
2512  
2513  /**
2514  * @method _disableScrollFooter
2515  * @description Disables the footer used for scrolling the body of the menu.
2516  * @protected
2517  */
2518  _disableScrollFooter: function () {
2519  
2520      if (!this._bFooterDisabled) {
2521  
2522          Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2523          this._bFooterDisabled = true;
2524  
2525      }
2526  
2527  },
2528  
2529  
2530  /**
2531  * @method _enableScrollHeader
2532  * @description Enables the header used for scrolling the body of the menu.
2533  * @protected
2534  */
2535  _enableScrollHeader: function () {
2536  
2537      if (this._bHeaderDisabled) {
2538  
2539          Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
2540          this._bHeaderDisabled = false;
2541  
2542      }
2543  
2544  },
2545  
2546  
2547  /**
2548  * @method _enableScrollFooter
2549  * @description Enables the footer used for scrolling the body of the menu.
2550  * @protected
2551  */
2552  _enableScrollFooter: function () {
2553  
2554      if (this._bFooterDisabled) {
2555  
2556          Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
2557          this._bFooterDisabled = false;
2558  
2559      }
2560  
2561  },
2562  
2563  
2564  /**
2565  * @method _onMouseOver
2566  * @description "mouseover" event handler for the menu.
2567  * @protected
2568  * @param {String} p_sType String representing the name of the event that 
2569  * was fired.
2570  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2571  */
2572  _onMouseOver: function (p_sType, p_aArgs) {
2573  
2574      var oEvent = p_aArgs[0],
2575          oItem = p_aArgs[1],
2576          oTarget = Event.getTarget(oEvent),
2577          oRoot = this.getRoot(),
2578          oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
2579          oParentMenu,
2580          nShowDelay,
2581          bShowDelay,
2582          oActiveItem,
2583          oItemCfg,
2584          oSubmenu;
2585  
2586  
2587      var showSubmenu = function () {
2588  
2589          if (this.parent.cfg.getProperty(_SELECTED)) {
2590  
2591              this.show();
2592  
2593          }
2594  
2595      };
2596  
2597  
2598      if (!this._bStopMouseEventHandlers) {
2599      
2600          if (!this._bHandledMouseOverEvent && (oTarget == this.element || 
2601                  Dom.isAncestor(this.element, oTarget))) {
2602      
2603              // Menu mouseover logic
2604  
2605              if (this._useHideDelay) {
2606                  this._cancelHideDelay();
2607              }
2608      
2609              this._nCurrentMouseX = 0;
2610      
2611              Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
2612  
2613  
2614              /*
2615                  If the mouse is moving from the submenu back to its corresponding menu item, 
2616                  don't hide the submenu or clear the active MenuItem.
2617              */
2618  
2619              if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
2620  
2621                  this.clearActiveItem();
2622  
2623              }
2624      
2625  
2626              if (this.parent && oSubmenuHideDelayTimer) {
2627      
2628                  oSubmenuHideDelayTimer.cancel();
2629      
2630                  this.parent.cfg.setProperty(_SELECTED, true);
2631      
2632                  oParentMenu = this.parent.parent;
2633      
2634                  oParentMenu._bHandledMouseOutEvent = true;
2635                  oParentMenu._bHandledMouseOverEvent = false;
2636      
2637              }
2638      
2639      
2640              this._bHandledMouseOverEvent = true;
2641              this._bHandledMouseOutEvent = false;
2642          
2643          }
2644      
2645      
2646          if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) && 
2647              (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
2648      
2649              // Menu Item mouseover logic
2650      
2651              nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2652              bShowDelay = (nShowDelay > 0);
2653      
2654      
2655              if (bShowDelay) {
2656              
2657                  this._cancelShowDelay();
2658              
2659              }
2660      
2661      
2662              oActiveItem = this.activeItem;
2663          
2664              if (oActiveItem) {
2665          
2666                  oActiveItem.cfg.setProperty(_SELECTED, false);
2667          
2668              }
2669      
2670      
2671              oItemCfg = oItem.cfg;
2672          
2673              // Select and focus the current menu item
2674          
2675              oItemCfg.setProperty(_SELECTED, true);
2676      
2677      
2678              if (this.hasFocus() || oRoot._hasFocus) {
2679              
2680                  oItem.focus();
2681                  
2682                  oRoot._hasFocus = false;
2683              
2684              }
2685      
2686      
2687              if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
2688      
2689                  // Show the submenu this menu item
2690      
2691                  oSubmenu = oItemCfg.getProperty(_SUBMENU);
2692              
2693                  if (oSubmenu) {
2694              
2695                      if (bShowDelay) {
2696      
2697                          oRoot._showDelayTimer = 
2698                              Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
2699              
2700                      }
2701                      else {
2702      
2703                          oSubmenu.show();
2704      
2705                      }
2706      
2707                  }
2708      
2709              }                        
2710      
2711              oItem.handledMouseOverEvent = true;
2712              oItem.handledMouseOutEvent = false;
2713      
2714          }
2715      
2716      }
2717  
2718  },
2719  
2720  
2721  /**
2722  * @method _onMouseOut
2723  * @description "mouseout" event handler for the menu.
2724  * @protected
2725  * @param {String} p_sType String representing the name of the event that 
2726  * was fired.
2727  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2728  */
2729  _onMouseOut: function (p_sType, p_aArgs) {
2730  
2731      var oEvent = p_aArgs[0],
2732          oItem = p_aArgs[1],
2733          oRelatedTarget = Event.getRelatedTarget(oEvent),
2734          bMovingToSubmenu = false,
2735          oItemCfg,
2736          oSubmenu,
2737          nSubmenuHideDelay,
2738          nShowDelay;
2739  
2740  
2741      YAHOO.log("onMouseout: this == " + this);
2742  
2743      if (!this._bStopMouseEventHandlers) {
2744      
2745          if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
2746      
2747              oItemCfg = oItem.cfg;
2748              oSubmenu = oItemCfg.getProperty(_SUBMENU);
2749      
2750      
2751              if (oSubmenu && (oRelatedTarget == oSubmenu.element || Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
2752                  bMovingToSubmenu = true;
2753              }
2754      
2755              if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element && !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
2756                  if (!bMovingToSubmenu) {
2757                      oItem.cfg.setProperty(_SELECTED, false);
2758                      if (oSubmenu) {
2759                          
2760                          nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
2761                          nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
2762                          if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 && nSubmenuHideDelay >= nShowDelay) {
2763                              this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent), nSubmenuHideDelay);
2764                          } else {
2765                              oSubmenu.hide();
2766                          }
2767                      }
2768                  }
2769      
2770                  oItem.handledMouseOutEvent = true;
2771                  oItem.handledMouseOverEvent = false;
2772              }
2773          }
2774  
2775          YAHOO.log("onMouseout: oRelatedTarget = " + oRelatedTarget.className);
2776          YAHOO.log("onMouseout: this.element = " + this.element.id);
2777          YAHOO.log("onMouseout: Ancestorthis.element = " + Dom.isAncestor(this.element, oRelatedTarget));
2778          YAHOO.log("onMouseout: canHide = " + this._didMouseLeave(oRelatedTarget));        
2779  
2780          if (!this._bHandledMouseOutEvent) {
2781              if (this._didMouseLeave(oRelatedTarget) || bMovingToSubmenu) {
2782                  // Menu mouseout logic
2783                  if (this._useHideDelay) {
2784                      this._execHideDelay();
2785                  }
2786      
2787                  Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
2788          
2789                  this._nCurrentMouseX = Event.getPageX(oEvent);
2790          
2791                  this._bHandledMouseOutEvent = true;
2792                  this._bHandledMouseOverEvent = false;
2793              }
2794          }
2795      }
2796  
2797  },
2798  
2799  /**
2800   * Utilility method to determine if we really moused out of the menu based on the related target
2801   * @method _didMouseLeave
2802   * @protected
2803   * @param {HTMLElement} oRelatedTarget The related target based on which we're making the decision
2804   * @return {boolean} true if it's OK to hide based on the related target.
2805   */
2806  _didMouseLeave : function(oRelatedTarget) {
2807      // Hide if we're not moving back to the element from somewhere inside the element, or we're moving to an element inside the menu.
2808      // The shadow is treated as an edge case, inside inside the menu, but we get no further mouseouts, because it overflows the element,
2809      // so we need to close when moving to the menu. 
2810      return (oRelatedTarget === this._shadow || (oRelatedTarget != this.element && !Dom.isAncestor(this.element, oRelatedTarget)));
2811  },
2812  
2813  /**
2814  * @method _onMouseMove
2815  * @description "click" event handler for the menu.
2816  * @protected
2817  * @param {Event} p_oEvent Object representing the DOM event object passed 
2818  * back by the event utility (YAHOO.util.Event).
2819  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
2820  * fired the event.
2821  */
2822  _onMouseMove: function (p_oEvent, p_oMenu) {
2823  
2824      if (!this._bStopMouseEventHandlers) {
2825      
2826          this._nCurrentMouseX = Event.getPageX(p_oEvent);
2827      
2828      }
2829  
2830  },
2831  
2832  
2833  /**
2834  * @method _onClick
2835  * @description "click" event handler for the menu.
2836  * @protected
2837  * @param {String} p_sType String representing the name of the event that 
2838  * was fired.
2839  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2840  */
2841  _onClick: function (p_sType, p_aArgs) {
2842  
2843      var oEvent = p_aArgs[0],
2844          oItem = p_aArgs[1],
2845          bInMenuAnchor = false,
2846          oSubmenu,
2847          oMenu,
2848          oRoot,
2849          sId,
2850          sURL,
2851          nHashPos,
2852          nLen;
2853  
2854  
2855      var hide = function () {
2856          
2857          oRoot = this.getRoot();
2858  
2859          if (oRoot instanceof YAHOO.widget.MenuBar || 
2860              oRoot.cfg.getProperty(_POSITION) == _STATIC) {
2861  
2862              oRoot.clearActiveItem();
2863  
2864          }
2865          else {
2866  
2867              oRoot.hide();
2868          
2869          }
2870      
2871      };
2872  
2873  
2874      if (oItem) {
2875      
2876          if (oItem.cfg.getProperty(_DISABLED)) {
2877          
2878              Event.preventDefault(oEvent);
2879  
2880              hide.call(this);
2881  
2882          }
2883          else {
2884  
2885              oSubmenu = oItem.cfg.getProperty(_SUBMENU);
2886      
2887              
2888              /*
2889                   Check if the URL of the anchor is pointing to an element that is 
2890                   a child of the menu.
2891              */
2892              
2893              sURL = oItem.cfg.getProperty(_URL);
2894  
2895          
2896              if (sURL) {
2897      
2898                  nHashPos = sURL.indexOf(_HASH);
2899      
2900                  nLen = sURL.length;
2901      
2902      
2903                  if (nHashPos != -1) {
2904      
2905                      sURL = sURL.substr(nHashPos, nLen);
2906          
2907                      nLen = sURL.length;
2908      
2909      
2910                      if (nLen > 1) {
2911      
2912                          sId = sURL.substr(1, nLen);
2913      
2914                          oMenu = YAHOO.widget.MenuManager.getMenu(sId);
2915                          
2916                          if (oMenu) {
2917  
2918                              bInMenuAnchor = 
2919                                  (this.getRoot() === oMenu.getRoot());
2920  
2921                          }
2922                          
2923                      }
2924                      else if (nLen === 1) {
2925      
2926                          bInMenuAnchor = true;
2927                      
2928                      }
2929      
2930                  }
2931              
2932              }
2933  
2934      
2935              if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
2936      
2937                  Event.preventDefault(oEvent);
2938                  
2939  
2940                  if (UA.webkit) {
2941                  
2942                      oItem.focus();
2943                  
2944                  }
2945                  else {
2946  
2947                      oItem.focusEvent.fire();
2948                  
2949                  }
2950              
2951              }
2952      
2953      
2954              if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
2955      
2956                  hide.call(this);
2957      
2958              }
2959              
2960          }
2961      
2962      }
2963  
2964  },
2965  
2966  /*
2967      This function is called to prevent a bug in Firefox.  In Firefox,
2968      moving a DOM element into a stationary mouse pointer will cause the 
2969      browser to fire mouse events.  This can result in the menu mouse
2970      event handlers being called uncessarily, especially when menus are 
2971      moved into a stationary mouse pointer as a result of a 
2972      key event handler.
2973  */
2974  /**
2975   * Utility method to stop mouseevents from being fired if the DOM
2976   * changes under a stationary mouse pointer (as opposed to the mouse moving
2977   * over a DOM element).
2978   * 
2979   * @method _stopMouseEventHandlers
2980   * @private
2981   */
2982  _stopMouseEventHandlers: function() {
2983      this._bStopMouseEventHandlers = true;
2984  
2985      Lang.later(10, this, function () {
2986          this._bStopMouseEventHandlers = false;
2987      });
2988  },
2989  
2990  /**
2991  * @method _onKeyDown
2992  * @description "keydown" event handler for the menu.
2993  * @protected
2994  * @param {String} p_sType String representing the name of the event that 
2995  * was fired.
2996  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
2997  */
2998  _onKeyDown: function (p_sType, p_aArgs) {
2999  
3000      var oEvent = p_aArgs[0],
3001          oItem = p_aArgs[1],
3002          oSubmenu,
3003          oItemCfg,
3004          oParentItem,
3005          oRoot,
3006          oNextItem,
3007          oBody,
3008          nBodyScrollTop,
3009          nBodyOffsetHeight,
3010          aItems,
3011          nItems,
3012          nNextItemOffsetTop,
3013          nScrollTarget,
3014          oParentMenu,
3015          oFocusedEl;
3016  
3017  
3018      if (this._useHideDelay) {
3019          this._cancelHideDelay();
3020      }
3021  
3022      if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
3023  
3024          oItemCfg = oItem.cfg;
3025          oParentItem = this.parent;
3026  
3027          switch(oEvent.keyCode) {
3028      
3029              case 38:    // Up arrow
3030              case 40:    // Down arrow
3031      
3032                  oNextItem = (oEvent.keyCode == 38) ? 
3033                      oItem.getPreviousEnabledSibling() : 
3034                      oItem.getNextEnabledSibling();
3035          
3036                  if (oNextItem) {
3037  
3038                      this.clearActiveItem();
3039  
3040                      oNextItem.cfg.setProperty(_SELECTED, true);
3041                      oNextItem.focus();
3042  
3043                      if (this.cfg.getProperty(_MAX_HEIGHT) > 0 || Dom.hasClass(this.body, _YUI_MENU_BODY_SCROLLED)) {
3044  
3045                          oBody = this.body;
3046                          nBodyScrollTop = oBody.scrollTop;
3047                          nBodyOffsetHeight = oBody.offsetHeight;
3048                          aItems = this.getItems();
3049                          nItems = aItems.length - 1;
3050                          nNextItemOffsetTop = oNextItem.element.offsetTop;
3051  
3052  
3053                          if (oEvent.keyCode == 40 ) {    // Down
3054                         
3055                              if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
3056  
3057                                  oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
3058  
3059                              }
3060                              else if (nNextItemOffsetTop <= nBodyScrollTop) {
3061                              
3062                                  oBody.scrollTop = 0;
3063                              
3064                              }
3065  
3066  
3067                              if (oNextItem == aItems[nItems]) {
3068  
3069                                  oBody.scrollTop = oNextItem.element.offsetTop;
3070  
3071                              }
3072  
3073                          }
3074                          else {  // Up
3075  
3076                              if (nNextItemOffsetTop <= nBodyScrollTop) {
3077  
3078                                  oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
3079                              
3080                              }
3081                              else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
3082                              
3083                                  oBody.scrollTop = nNextItemOffsetTop;
3084                              
3085                              }
3086  
3087  
3088                              if (oNextItem == aItems[0]) {
3089                              
3090                                  oBody.scrollTop = 0;
3091                              
3092                              }
3093  
3094                          }
3095  
3096  
3097                          nBodyScrollTop = oBody.scrollTop;
3098                          nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3099  
3100                          if (nBodyScrollTop === 0) {
3101  
3102                              this._disableScrollHeader();
3103                              this._enableScrollFooter();
3104  
3105                          }
3106                          else if (nBodyScrollTop == nScrollTarget) {
3107  
3108                               this._enableScrollHeader();
3109                               this._disableScrollFooter();
3110  
3111                          }
3112                          else {
3113  
3114                              this._enableScrollHeader();
3115                              this._enableScrollFooter();
3116  
3117                          }
3118  
3119                      }
3120  
3121                  }
3122  
3123      
3124                  Event.preventDefault(oEvent);
3125  
3126                  this._stopMouseEventHandlers();
3127      
3128              break;
3129              
3130      
3131              case 39:    // Right arrow
3132      
3133                  oSubmenu = oItemCfg.getProperty(_SUBMENU);
3134      
3135                  if (oSubmenu) {
3136      
3137                      if (!oItemCfg.getProperty(_SELECTED)) {
3138          
3139                          oItemCfg.setProperty(_SELECTED, true);
3140          
3141                      }
3142      
3143                      oSubmenu.show();
3144                      oSubmenu.setInitialFocus();
3145                      oSubmenu.setInitialSelection();
3146      
3147                  }
3148                  else {
3149      
3150                      oRoot = this.getRoot();
3151                      
3152                      if (oRoot instanceof YAHOO.widget.MenuBar) {
3153      
3154                          oNextItem = oRoot.activeItem.getNextEnabledSibling();
3155      
3156                          if (oNextItem) {
3157                          
3158                              oRoot.clearActiveItem();
3159      
3160                              oNextItem.cfg.setProperty(_SELECTED, true);
3161      
3162                              oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3163      
3164                              if (oSubmenu) {
3165      
3166                                  oSubmenu.show();
3167                                  oSubmenu.setInitialFocus();
3168                              
3169                              }
3170                              else {
3171      
3172                                  oNextItem.focus();
3173                              
3174                              }
3175                          
3176                          }
3177                      
3178                      }
3179                  
3180                  }
3181      
3182      
3183                  Event.preventDefault(oEvent);
3184  
3185                  this._stopMouseEventHandlers();
3186  
3187              break;
3188      
3189      
3190              case 37:    // Left arrow
3191      
3192                  if (oParentItem) {
3193      
3194                      oParentMenu = oParentItem.parent;
3195      
3196                      if (oParentMenu instanceof YAHOO.widget.MenuBar) {
3197      
3198                          oNextItem = 
3199                              oParentMenu.activeItem.getPreviousEnabledSibling();
3200      
3201                          if (oNextItem) {
3202                          
3203                              oParentMenu.clearActiveItem();
3204      
3205                              oNextItem.cfg.setProperty(_SELECTED, true);
3206      
3207                              oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
3208      
3209                              if (oSubmenu) {
3210                              
3211                                  oSubmenu.show();
3212                                  oSubmenu.setInitialFocus();
3213                              
3214                              }
3215                              else {
3216      
3217                                  oNextItem.focus();
3218                              
3219                              }
3220                          
3221                          } 
3222                      
3223                      }
3224                      else {
3225      
3226                          this.hide();
3227      
3228                          oParentItem.focus();
3229                      
3230                      }
3231      
3232                  }
3233      
3234                  Event.preventDefault(oEvent);
3235  
3236                  this._stopMouseEventHandlers();
3237  
3238              break;        
3239      
3240          }
3241  
3242  
3243      }
3244  
3245  
3246      if (oEvent.keyCode == 27) { // Esc key
3247  
3248          if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3249          
3250              this.hide();
3251  
3252              if (this.parent) {
3253  
3254                  this.parent.focus();
3255              
3256              }
3257              else {
3258                  // Focus the element that previously had focus
3259  
3260                  oFocusedEl = this._focusedElement;
3261  
3262                  if (oFocusedEl && oFocusedEl.focus) {
3263  
3264                      try {
3265                          oFocusedEl.focus();
3266                      }
3267                      catch(ex) {
3268                      }
3269  
3270                  }
3271                  
3272              }
3273  
3274          }
3275          else if (this.activeItem) {
3276  
3277              oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
3278  
3279              if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
3280              
3281                  oSubmenu.hide();
3282                  this.activeItem.focus();
3283              
3284              }
3285              else {
3286  
3287                  this.activeItem.blur();
3288                  this.activeItem.cfg.setProperty(_SELECTED, false);
3289          
3290              }
3291          
3292          }
3293  
3294  
3295          Event.preventDefault(oEvent);
3296      
3297      }
3298      
3299  },
3300  
3301  
3302  /**
3303  * @method _onKeyPress
3304  * @description "keypress" event handler for a Menu instance.
3305  * @protected
3306  * @param {String} p_sType The name of the event that was fired.
3307  * @param {Array} p_aArgs Collection of arguments sent when the event 
3308  * was fired.
3309  */
3310  _onKeyPress: function (p_sType, p_aArgs) {
3311      
3312      var oEvent = p_aArgs[0];
3313  
3314  
3315      if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
3316  
3317          Event.preventDefault(oEvent);
3318  
3319      }
3320  
3321  },
3322  
3323  
3324  /**
3325  * @method _onBlur
3326  * @description "blur" event handler for a Menu instance.
3327  * @protected
3328  * @param {String} p_sType The name of the event that was fired.
3329  * @param {Array} p_aArgs Collection of arguments sent when the event 
3330  * was fired.
3331  */
3332  _onBlur: function (p_sType, p_aArgs) {
3333          
3334      if (this._hasFocus) {
3335          this._hasFocus = false;
3336      }
3337  
3338  },
3339  
3340  /**
3341  * @method _onYChange
3342  * @description "y" event handler for a Menu instance.
3343  * @protected
3344  * @param {String} p_sType The name of the event that was fired.
3345  * @param {Array} p_aArgs Collection of arguments sent when the event 
3346  * was fired.
3347  */
3348  _onYChange: function (p_sType, p_aArgs) {
3349  
3350      var oParent = this.parent,
3351          nScrollTop,
3352          oIFrame,
3353          nY;
3354  
3355  
3356      if (oParent) {
3357  
3358          nScrollTop = oParent.parent.body.scrollTop;
3359  
3360  
3361          if (nScrollTop > 0) {
3362      
3363              nY = (this.cfg.getProperty(_Y) - nScrollTop);
3364              
3365              Dom.setY(this.element, nY);
3366  
3367              oIFrame = this.iframe;            
3368      
3369  
3370              if (oIFrame) {
3371      
3372                  Dom.setY(oIFrame, nY);
3373      
3374              }
3375              
3376              this.cfg.setProperty(_Y, nY, true);
3377          
3378          }
3379      
3380      }
3381  
3382  },
3383  
3384  
3385  /**
3386  * @method _onScrollTargetMouseOver
3387  * @description "mouseover" event handler for the menu's "header" and "footer" 
3388  * elements.  Used to scroll the body of the menu up and down when the 
3389  * menu's "maxheight" configuration property is set to a value greater than 0.
3390  * @protected
3391  * @param {Event} p_oEvent Object representing the DOM event object passed 
3392  * back by the event utility (YAHOO.util.Event).
3393  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
3394  * fired the event.
3395  */
3396  _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
3397  
3398      var oBodyScrollTimer = this._bodyScrollTimer;
3399  
3400  
3401      if (oBodyScrollTimer) {
3402  
3403          oBodyScrollTimer.cancel();
3404  
3405      }
3406  
3407  
3408      this._cancelHideDelay();
3409  
3410  
3411      var oTarget = Event.getTarget(p_oEvent),
3412          oBody = this.body,
3413          nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
3414          nScrollTarget,
3415          fnScrollFunction;
3416  
3417  
3418      function scrollBodyDown() {
3419  
3420          var nScrollTop = oBody.scrollTop;
3421  
3422  
3423          if (nScrollTop < nScrollTarget) {
3424  
3425              oBody.scrollTop = (nScrollTop + nScrollIncrement);
3426  
3427              this._enableScrollHeader();
3428  
3429          }
3430          else {
3431  
3432              oBody.scrollTop = nScrollTarget;
3433  
3434              this._bodyScrollTimer.cancel();
3435  
3436              this._disableScrollFooter();
3437  
3438          }
3439  
3440      }
3441  
3442  
3443      function scrollBodyUp() {
3444  
3445          var nScrollTop = oBody.scrollTop;
3446  
3447  
3448          if (nScrollTop > 0) {
3449  
3450              oBody.scrollTop = (nScrollTop - nScrollIncrement);
3451  
3452              this._enableScrollFooter();
3453  
3454          }
3455          else {
3456  
3457              oBody.scrollTop = 0;
3458  
3459              this._bodyScrollTimer.cancel();
3460  
3461              this._disableScrollHeader();
3462  
3463          }
3464  
3465      }
3466  
3467      
3468      if (Dom.hasClass(oTarget, _HD)) {
3469  
3470          fnScrollFunction = scrollBodyUp;
3471      
3472      }
3473      else {
3474  
3475          nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
3476  
3477          fnScrollFunction = scrollBodyDown;
3478      
3479      }
3480      
3481  
3482      this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
3483  
3484  },
3485  
3486  
3487  /**
3488  * @method _onScrollTargetMouseOut
3489  * @description "mouseout" event handler for the menu's "header" and "footer" 
3490  * elements.  Used to stop scrolling the body of the menu up and down when the 
3491  * menu's "maxheight" configuration property is set to a value greater than 0.
3492  * @protected
3493  * @param {Event} p_oEvent Object representing the DOM event object passed 
3494  * back by the event utility (YAHOO.util.Event).
3495  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
3496  * fired the event.
3497  */
3498  _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
3499  
3500      var oBodyScrollTimer = this._bodyScrollTimer;
3501  
3502      if (oBodyScrollTimer) {
3503  
3504          oBodyScrollTimer.cancel();
3505  
3506      }
3507      
3508      this._cancelHideDelay();
3509  
3510  },
3511  
3512  
3513  
3514  // Private methods
3515  
3516  
3517  /**
3518  * @method _onInit
3519  * @description "init" event handler for the menu.
3520  * @private
3521  * @param {String} p_sType String representing the name of the event that 
3522  * was fired.
3523  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3524  */
3525  _onInit: function (p_sType, p_aArgs) {
3526  
3527      this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
3528  
3529      var bRootMenu = !this.parent,
3530          bLazyLoad = this.lazyLoad;
3531  
3532  
3533      /*
3534          Automatically initialize a menu's subtree if:
3535  
3536          1) This is the root menu and lazyload is off
3537          
3538          2) This is the root menu, lazyload is on, but the menu is 
3539             already visible
3540  
3541          3) This menu is a submenu and lazyload is off
3542      */
3543  
3544  
3545  
3546      if (((bRootMenu && !bLazyLoad) || 
3547          (bRootMenu && (this.cfg.getProperty(_VISIBLE) || 
3548          this.cfg.getProperty(_POSITION) == _STATIC)) || 
3549          (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
3550  
3551          if (this.srcElement) {
3552  
3553              this._initSubTree();
3554          
3555          }
3556  
3557  
3558          if (this.itemData) {
3559  
3560              this.addItems(this.itemData);
3561  
3562          }
3563      
3564      }
3565      else if (bLazyLoad) {
3566  
3567          this.cfg.fireQueue();
3568      
3569      }
3570  
3571  },
3572  
3573  
3574  /**
3575  * @method _onBeforeRender
3576  * @description "beforerender" event handler for the menu.  Appends all of the 
3577  * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying 
3578  * title elements to the body element of the menu.
3579  * @private
3580  * @param {String} p_sType String representing the name of the event that 
3581  * was fired.
3582  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3583  */
3584  _onBeforeRender: function (p_sType, p_aArgs) {
3585  
3586      var oEl = this.element,
3587          nListElements = this._aListElements.length,
3588          bFirstList = true,
3589          i = 0,
3590          oUL,
3591          oGroupTitle;
3592  
3593      if (nListElements > 0) {
3594  
3595          do {
3596  
3597              oUL = this._aListElements[i];
3598  
3599              if (oUL) {
3600  
3601                  if (bFirstList) {
3602          
3603                      Dom.addClass(oUL, _FIRST_OF_TYPE);
3604                      bFirstList = false;
3605          
3606                  }
3607  
3608  
3609                  if (!Dom.isAncestor(oEl, oUL)) {
3610  
3611                      this.appendToBody(oUL);
3612  
3613                  }
3614  
3615  
3616                  oGroupTitle = this._aGroupTitleElements[i];
3617  
3618                  if (oGroupTitle) {
3619  
3620                      if (!Dom.isAncestor(oEl, oGroupTitle)) {
3621  
3622                          oUL.parentNode.insertBefore(oGroupTitle, oUL);
3623  
3624                      }
3625  
3626  
3627                      Dom.addClass(oUL, _HAS_TITLE);
3628  
3629                  }
3630  
3631              }
3632  
3633              i++;
3634  
3635          }
3636          while (i < nListElements);
3637  
3638      }
3639  
3640  },
3641  
3642  
3643  /**
3644  * @method _onRender
3645  * @description "render" event handler for the menu.
3646  * @private
3647  * @param {String} p_sType String representing the name of the event that 
3648  * was fired.
3649  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3650  */
3651  _onRender: function (p_sType, p_aArgs) {
3652  
3653      if (this.cfg.getProperty(_POSITION) == _DYNAMIC) { 
3654  
3655          if (!this.cfg.getProperty(_VISIBLE)) {
3656  
3657              this.positionOffScreen();
3658  
3659          }
3660      
3661      }
3662  
3663  },
3664  
3665  
3666  
3667  
3668  
3669  /**
3670  * @method _onBeforeShow
3671  * @description "beforeshow" event handler for the menu.
3672  * @private
3673  * @param {String} p_sType String representing the name of the event that 
3674  * was fired.
3675  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
3676  */
3677  _onBeforeShow: function (p_sType, p_aArgs) {
3678  
3679      var nOptions,
3680          n,
3681          oSrcElement,
3682          oContainer = this.cfg.getProperty(_CONTAINER);
3683  
3684  
3685      if (this.lazyLoad && this.getItemGroups().length === 0) {
3686  
3687          if (this.srcElement) {
3688          
3689              this._initSubTree();
3690  
3691          }
3692  
3693  
3694          if (this.itemData) {
3695  
3696              if (this.parent && this.parent.parent && 
3697                  this.parent.parent.srcElement && 
3698                  this.parent.parent.srcElement.tagName.toUpperCase() == 
3699                  _SELECT) {
3700  
3701                  nOptions = this.itemData.length;
3702      
3703                  for(n=0; n<nOptions; n++) {
3704  
3705                      if (this.itemData[n].tagName) {
3706  
3707                          this.addItem((new this.ITEM_TYPE(this.itemData[n])));
3708      
3709                      }
3710      
3711                  }
3712              
3713              }
3714              else {
3715  
3716                  this.addItems(this.itemData);
3717              
3718              }
3719          
3720          }
3721  
3722  
3723          oSrcElement = this.srcElement;
3724  
3725          if (oSrcElement) {
3726  
3727              if (oSrcElement.tagName.toUpperCase() == _SELECT) {
3728  
3729                  if (Dom.inDocument(oSrcElement)) {
3730  
3731                      this.render(oSrcElement.parentNode);
3732                  
3733                  }
3734                  else {
3735                  
3736                      this.render(oContainer);
3737                  
3738                  }
3739  
3740              }
3741              else {
3742  
3743                  this.render();
3744  
3745              }
3746  
3747          }
3748          else {
3749  
3750              if (this.parent) {
3751  
3752                  this.render(this.parent.element);     
3753  
3754              }
3755              else {
3756  
3757                  this.render(oContainer);
3758  
3759              }                
3760  
3761          }
3762  
3763      }
3764  
3765  
3766  
3767      var oParent = this.parent,
3768          aAlignment;
3769  
3770  
3771      if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
3772  
3773          this.cfg.refireEvent(_XY);
3774     
3775      }
3776  
3777  
3778      if (oParent) {
3779  
3780          aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
3781          
3782          this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
3783          this.align();
3784      
3785      }
3786  
3787  },
3788  
3789  
3790  getConstrainedY: function (y) {
3791  
3792      var oMenu = this,
3793      
3794          aContext = oMenu.cfg.getProperty(_CONTEXT),
3795          nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
3796  
3797          nMaxHeight,
3798  
3799          oOverlapPositions = {
3800  
3801              "trbr": true,
3802              "tlbl": true,
3803              "bltl": true,
3804              "brtr": true
3805  
3806          },
3807  
3808          bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
3809      
3810          oMenuEl = oMenu.element,
3811          nMenuOffsetHeight = oMenuEl.offsetHeight,
3812      
3813          nViewportOffset = Overlay.VIEWPORT_OFFSET,
3814          viewPortHeight = Dom.getViewportHeight(),
3815          scrollY = Dom.getDocumentScrollTop(),
3816  
3817          bCanConstrain = 
3818              (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
3819  
3820          nAvailableHeight,
3821  
3822          oContextEl,
3823          nContextElY,
3824          nContextElHeight,
3825  
3826          bFlipped = false,
3827  
3828          nTopRegionHeight,
3829          nBottomRegionHeight,
3830  
3831          topConstraint = scrollY + nViewportOffset,
3832          bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
3833  
3834          yNew = y;
3835          
3836  
3837      var flipVertical = function () {
3838  
3839          var nNewY;
3840      
3841          // The Menu is below the context element, flip it above
3842          if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { 
3843              nNewY = (nContextElY - nMenuOffsetHeight);
3844          }
3845          else {    // The Menu is above the context element, flip it below
3846              nNewY = (nContextElY + nContextElHeight);
3847          }
3848  
3849          oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3850          
3851          return nNewY;
3852      
3853      };
3854  
3855  
3856      /*
3857           Uses the context element's position to calculate the availble height 
3858           above and below it to display its corresponding Menu.
3859      */
3860  
3861      var getDisplayRegionHeight = function () {
3862  
3863          // The Menu is below the context element
3864          if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
3865              return (nBottomRegionHeight - nViewportOffset);                
3866          }
3867          else {    // The Menu is above the context element
3868              return (nTopRegionHeight - nViewportOffset);                
3869          }
3870  
3871      };
3872  
3873  
3874      /*
3875          Sets the Menu's "y" configuration property to the correct value based on its
3876          current orientation.
3877      */ 
3878  
3879      var alignY = function () {
3880  
3881          var nNewY;
3882  
3883          if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) { 
3884              nNewY = (nContextElY + nContextElHeight);
3885          }
3886          else {    
3887              nNewY = (nContextElY - oMenuEl.offsetHeight);
3888          }
3889  
3890          oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
3891      
3892      };
3893  
3894  
3895      //    Resets the maxheight of the Menu to the value set by the user
3896  
3897      var resetMaxHeight = function () {
3898  
3899          oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
3900  
3901          oMenu.hideEvent.unsubscribe(resetMaxHeight);
3902      
3903      };
3904  
3905  
3906      /*
3907          Trys to place the Menu in the best possible position (either above or 
3908          below its corresponding context element).
3909      */
3910  
3911      var setVerticalPosition = function () {
3912  
3913          var nDisplayRegionHeight = getDisplayRegionHeight(),
3914              bMenuHasItems = (oMenu.getItems().length > 0),
3915              nMenuMinScrollHeight,
3916              fnReturnVal;
3917  
3918  
3919          if (nMenuOffsetHeight > nDisplayRegionHeight) {
3920  
3921              nMenuMinScrollHeight = 
3922                  bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
3923  
3924  
3925              if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
3926                  nMaxHeight = nDisplayRegionHeight;
3927              }
3928              else {
3929                  nMaxHeight = nInitialMaxHeight;
3930              }
3931  
3932  
3933              oMenu._setScrollHeight(nMaxHeight);
3934              oMenu.hideEvent.subscribe(resetMaxHeight);
3935              
3936  
3937              // Re-align the Menu since its height has just changed
3938              // as a result of the setting of the maxheight property.
3939  
3940              alignY();
3941              
3942  
3943              if (nDisplayRegionHeight < nMenuMinScrollHeight) {
3944  
3945                  if (bFlipped) {
3946      
3947                      /*
3948                           All possible positions and values for the "maxheight" 
3949                           configuration property have been tried, but none were 
3950                           successful, so fall back to the original size and position.
3951                      */
3952  
3953                      flipVertical();
3954                      
3955                  }
3956                  else {
3957      
3958                      flipVertical();
3959  
3960                      bFlipped = true;
3961      
3962                      fnReturnVal = setVerticalPosition();
3963      
3964                  }
3965                  
3966              }
3967          
3968          }
3969          else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
3970          
3971              oMenu._setScrollHeight(nInitialMaxHeight);
3972              oMenu.hideEvent.subscribe(resetMaxHeight);
3973  
3974              // Re-align the Menu since its height has just changed
3975              // as a result of the setting of the maxheight property.
3976  
3977              alignY();
3978          
3979          }
3980  
3981          return fnReturnVal;
3982  
3983      };
3984  
3985  
3986      // Determine if the current value for the Menu's "y" configuration property will
3987      // result in the Menu being positioned outside the boundaries of the viewport
3988  
3989      if (y < topConstraint || y  > bottomConstraint) {
3990  
3991          // The current value for the Menu's "y" configuration property WILL
3992          // result in the Menu being positioned outside the boundaries of the viewport
3993  
3994          if (bCanConstrain) {
3995  
3996              if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
3997          
3998                  //    SOLUTION #1:
3999                  //    If the "preventcontextoverlap" configuration property is set to "true", 
4000                  //    try to flip and/or scroll the Menu to both keep it inside the boundaries of the 
4001                  //    viewport AND from overlaping its context element (MenuItem or MenuBarItem).
4002  
4003                  oContextEl = aContext[0];
4004                  nContextElHeight = oContextEl.offsetHeight;
4005                  nContextElY = (Dom.getY(oContextEl) - scrollY);
4006      
4007                  nTopRegionHeight = nContextElY;
4008                  nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
4009      
4010                  setVerticalPosition();
4011                  
4012                  yNew = oMenu.cfg.getProperty(_Y);
4013          
4014              }
4015              else if (!(oMenu instanceof YAHOO.widget.MenuBar) && 
4016                  nMenuOffsetHeight >= viewPortHeight) {
4017  
4018                  //    SOLUTION #2:
4019                  //    If the Menu exceeds the height of the viewport, introduce scroll bars
4020                  //    to keep the Menu inside the boundaries of the viewport
4021  
4022                  nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
4023          
4024                  if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
4025          
4026                      oMenu._setScrollHeight(nAvailableHeight);
4027                      oMenu.hideEvent.subscribe(resetMaxHeight);
4028          
4029                      alignY();
4030                      
4031                      yNew = oMenu.cfg.getProperty(_Y);
4032                  
4033                  }
4034          
4035              }    
4036              else {
4037  
4038                  //    SOLUTION #3:
4039              
4040                  if (y < topConstraint) {
4041                      yNew  = topConstraint;
4042                  } else if (y  > bottomConstraint) {
4043                      yNew  = bottomConstraint;
4044                  }                
4045              
4046              }
4047  
4048          }
4049          else {
4050              //    The "y" configuration property cannot be set to a value that will keep
4051              //    entire Menu inside the boundary of the viewport.  Therefore, set  
4052              //    the "y" configuration property to scrollY to keep as much of the 
4053              //    Menu inside the viewport as possible.
4054              yNew = nViewportOffset + scrollY;
4055          }    
4056  
4057      }
4058  
4059      return yNew;
4060  
4061  },
4062  
4063  
4064  /**
4065  * @method _onHide
4066  * @description "hide" event handler for the menu.
4067  * @private
4068  * @param {String} p_sType String representing the name of the event that 
4069  * was fired.
4070  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4071  */
4072  _onHide: function (p_sType, p_aArgs) {
4073  
4074      if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4075      
4076          this.positionOffScreen();
4077      
4078      }
4079  
4080  },
4081  
4082  
4083  /**
4084  * @method _onShow
4085  * @description "show" event handler for the menu.
4086  * @private
4087  * @param {String} p_sType String representing the name of the event that 
4088  * was fired.
4089  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4090  */
4091  _onShow: function (p_sType, p_aArgs) {
4092  
4093      var oParent = this.parent,
4094          oParentMenu,
4095          oElement,
4096          nOffsetWidth,
4097          sWidth;        
4098  
4099  
4100      function disableAutoSubmenuDisplay(p_oEvent) {
4101  
4102          var oTarget;
4103  
4104          if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
4105  
4106              /*  
4107                  Set the "autosubmenudisplay" to "false" if the user
4108                  clicks outside the menu bar.
4109              */
4110  
4111              oTarget = Event.getTarget(p_oEvent);
4112  
4113              if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
4114  
4115                  oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
4116  
4117                  Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
4118                  Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
4119  
4120              }
4121          
4122          }
4123  
4124      }
4125  
4126  
4127      function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
4128      
4129          this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4130          this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
4131      
4132      }
4133  
4134  
4135      if (oParent) {
4136  
4137          oParentMenu = oParent.parent;
4138  
4139  
4140          if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) && 
4141              (oParentMenu instanceof YAHOO.widget.MenuBar || 
4142              oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
4143  
4144              oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
4145  
4146              Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);                             
4147              Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
4148  
4149          }
4150  
4151  
4152          //    The following fixes an issue with the selected state of a MenuItem 
4153          //    not rendering correctly when a submenu is aligned to the left of
4154          //    its parent Menu instance.
4155  
4156          if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) && 
4157              (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
4158  
4159              oElement = this.element;
4160              nOffsetWidth = oElement.offsetWidth;
4161              
4162              /*
4163                  Measuring the difference of the offsetWidth before and after
4164                  setting the "width" style attribute allows us to compute the 
4165                  about of padding and borders applied to the element, which in 
4166                  turn allows us to set the "width" property correctly.
4167              */
4168              
4169              oElement.style.width = nOffsetWidth + _PX;
4170              
4171              sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4172              
4173              this.cfg.setProperty(_WIDTH, sWidth);
4174          
4175              this.hideEvent.subscribe(onSubmenuHide, sWidth);
4176          
4177          }
4178  
4179      }
4180  
4181  
4182      /*
4183          Dynamically positioned, root Menus focus themselves when visible, and 
4184          will then, when hidden, restore focus to the UI control that had focus 
4185          before the Menu was made visible.
4186      */ 
4187  
4188      if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
4189  
4190          this._focusedElement = oFocusedElement;
4191          
4192          this.focus();
4193      
4194      }
4195  
4196  
4197  },
4198  
4199  
4200  /**
4201  * @method _onBeforeHide
4202  * @description "beforehide" event handler for the menu.
4203  * @private
4204  * @param {String} p_sType String representing the name of the event that 
4205  * was fired.
4206  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4207  */
4208  _onBeforeHide: function (p_sType, p_aArgs) {
4209  
4210      var oActiveItem = this.activeItem,
4211          oRoot = this.getRoot(),
4212          oConfig,
4213          oSubmenu;
4214  
4215  
4216      if (oActiveItem) {
4217  
4218          oConfig = oActiveItem.cfg;
4219  
4220          oConfig.setProperty(_SELECTED, false);
4221  
4222          oSubmenu = oConfig.getProperty(_SUBMENU);
4223  
4224          if (oSubmenu) {
4225  
4226              oSubmenu.hide();
4227  
4228          }
4229  
4230      }
4231  
4232  
4233      /*
4234          Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.  
4235          For this reason, it is necessary to maintain the focused state in a private property 
4236          so that the _onMouseOver event handler is able to determined whether or not to set focus
4237          to MenuItems as the user is moving the mouse.
4238      */ 
4239  
4240      if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
4241  
4242          oRoot._hasFocus = this.hasFocus();
4243      
4244      }
4245  
4246  
4247      if (oRoot == this) {
4248  
4249          oRoot.blur();
4250      
4251      }
4252  
4253  },
4254  
4255  
4256  /**
4257  * @method _onParentMenuConfigChange
4258  * @description "configchange" event handler for a submenu.
4259  * @private
4260  * @param {String} p_sType String representing the name of the event that 
4261  * was fired.
4262  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4263  * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
4264  * subscribed to the event.
4265  */
4266  _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
4267      
4268      var sPropertyName = p_aArgs[0][0],
4269          oPropertyValue = p_aArgs[0][1];
4270  
4271      switch(sPropertyName) {
4272  
4273          case _IFRAME:
4274          case _CONSTRAIN_TO_VIEWPORT:
4275          case _HIDE_DELAY:
4276          case _SHOW_DELAY:
4277          case _SUBMENU_HIDE_DELAY:
4278          case _CLICK_TO_HIDE:
4279          case _EFFECT:
4280          case _CLASSNAME:
4281          case _SCROLL_INCREMENT:
4282          case _MAX_HEIGHT:
4283          case _MIN_SCROLL_HEIGHT:
4284          case _MONITOR_RESIZE:
4285          case _SHADOW:
4286          case _PREVENT_CONTEXT_OVERLAP:
4287          case _KEEP_OPEN:
4288  
4289              p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4290                  
4291          break;
4292          
4293          case _SUBMENU_ALIGNMENT:
4294  
4295              if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
4296          
4297                  p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
4298          
4299              }
4300          
4301          break;
4302          
4303      }
4304      
4305  },
4306  
4307  
4308  /**
4309  * @method _onParentMenuRender
4310  * @description "render" event handler for a submenu.  Renders a  
4311  * submenu in response to the firing of its parent's "render" event.
4312  * @private
4313  * @param {String} p_sType String representing the name of the event that 
4314  * was fired.
4315  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4316  * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
4317  * subscribed to the event.
4318  */
4319  _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
4320  
4321      var oParentMenu = p_oSubmenu.parent.parent,
4322          oParentCfg = oParentMenu.cfg,
4323  
4324          oConfig = {
4325  
4326              constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
4327  
4328              xy: [0,0],
4329  
4330              clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
4331                  
4332              effect: oParentCfg.getProperty(_EFFECT),
4333  
4334              showdelay: oParentCfg.getProperty(_SHOW_DELAY),
4335              
4336              hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
4337  
4338              submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
4339  
4340              classname: oParentCfg.getProperty(_CLASSNAME),
4341              
4342              scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
4343              
4344              maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
4345  
4346              minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
4347              
4348              iframe: oParentCfg.getProperty(_IFRAME),
4349              
4350              shadow: oParentCfg.getProperty(_SHADOW),
4351  
4352              preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
4353              
4354              monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE),
4355  
4356              keepopen: oParentCfg.getProperty(_KEEP_OPEN)
4357  
4358          },
4359          
4360          oLI;
4361  
4362  
4363      
4364      if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
4365  
4366          oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
4367  
4368      }
4369  
4370  
4371      p_oSubmenu.cfg.applyConfig(oConfig);
4372  
4373  
4374      if (!this.lazyLoad) {
4375  
4376          oLI = this.parent.element;
4377  
4378          if (this.element.parentNode == oLI) {
4379      
4380              this.render();
4381      
4382          }
4383          else {
4384  
4385              this.render(oLI);
4386      
4387          }
4388  
4389      }
4390      
4391  },
4392  
4393  
4394  /**
4395  * @method _onMenuItemDestroy
4396  * @description "destroy" event handler for the menu's items.
4397  * @private
4398  * @param {String} p_sType String representing the name of the event 
4399  * that was fired.
4400  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4401  * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
4402  * that fired the event.
4403  */
4404  _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
4405  
4406      this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
4407  
4408  },
4409  
4410  
4411  /**
4412  * @method _onMenuItemConfigChange
4413  * @description "configchange" event handler for the menu's items.
4414  * @private
4415  * @param {String} p_sType String representing the name of the event that 
4416  * was fired.
4417  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4418  * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
4419  * that fired the event.
4420  */
4421  _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
4422  
4423      var sPropertyName = p_aArgs[0][0],
4424          oPropertyValue = p_aArgs[0][1],
4425          oSubmenu;
4426  
4427  
4428      switch(sPropertyName) {
4429  
4430          case _SELECTED:
4431  
4432              if (oPropertyValue === true) {
4433  
4434                  this.activeItem = p_oItem;
4435              
4436              }
4437  
4438          break;
4439  
4440          case _SUBMENU:
4441  
4442              oSubmenu = p_aArgs[0][1];
4443  
4444              if (oSubmenu) {
4445  
4446                  this._configureSubmenu(p_oItem);
4447  
4448              }
4449  
4450          break;
4451  
4452      }
4453  
4454  },
4455  
4456  
4457  
4458  // Public event handlers for configuration properties
4459  
4460  
4461  /**
4462  * @method configVisible
4463  * @description Event handler for when the "visible" configuration property 
4464  * the menu changes.
4465  * @param {String} p_sType String representing the name of the event that 
4466  * was fired.
4467  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4468  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4469  * fired the event.
4470  */
4471  configVisible: function (p_sType, p_aArgs, p_oMenu) {
4472  
4473      var bVisible,
4474          sDisplay;
4475  
4476      if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4477  
4478          Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
4479  
4480      }
4481      else {
4482  
4483          bVisible = p_aArgs[0];
4484          sDisplay = Dom.getStyle(this.element, _DISPLAY);
4485  
4486          Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
4487  
4488          if (bVisible) {
4489  
4490              if (sDisplay != _BLOCK) {
4491                  this.beforeShowEvent.fire();
4492                  Dom.setStyle(this.element, _DISPLAY, _BLOCK);
4493                  this.showEvent.fire();
4494              }
4495          
4496          }
4497          else {
4498  
4499              if (sDisplay == _BLOCK) {
4500                  this.beforeHideEvent.fire();
4501                  Dom.setStyle(this.element, _DISPLAY, _NONE);
4502                  this.hideEvent.fire();
4503              }
4504          
4505          }
4506  
4507      }
4508  
4509  },
4510  
4511  
4512  /**
4513  * @method configPosition
4514  * @description Event handler for when the "position" configuration property 
4515  * of the menu changes.
4516  * @param {String} p_sType String representing the name of the event that 
4517  * was fired.
4518  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4519  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4520  * fired the event.
4521  */
4522  configPosition: function (p_sType, p_aArgs, p_oMenu) {
4523  
4524      var oElement = this.element,
4525          sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
4526          oCfg = this.cfg,
4527          nZIndex;
4528  
4529  
4530      Dom.setStyle(oElement, _POSITION, sCSSPosition);
4531  
4532  
4533      if (sCSSPosition == _STATIC) {
4534  
4535          // Statically positioned menus are visible by default
4536          
4537          Dom.setStyle(oElement, _DISPLAY, _BLOCK);
4538  
4539          oCfg.setProperty(_VISIBLE, true);
4540  
4541      }
4542      else {
4543  
4544          /*
4545              Even though the "visible" property is queued to 
4546              "false" by default, we need to set the "visibility" property to 
4547              "hidden" since Overlay's "configVisible" implementation checks the 
4548              element's "visibility" style property before deciding whether 
4549              or not to show an Overlay instance.
4550          */
4551  
4552          Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
4553      
4554      }
4555  
4556  
4557       if (sCSSPosition == _ABSOLUTE) {
4558           nZIndex = oCfg.getProperty(_ZINDEX);
4559  
4560           if (!nZIndex || nZIndex === 0) {
4561               oCfg.setProperty(_ZINDEX, 1);
4562           }
4563  
4564       }
4565  
4566  },
4567  
4568  
4569  /**
4570  * @method configIframe
4571  * @description Event handler for when the "iframe" configuration property of 
4572  * the menu changes.
4573  * @param {String} p_sType String representing the name of the event that 
4574  * was fired.
4575  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4576  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4577  * fired the event.
4578  */
4579  configIframe: function (p_sType, p_aArgs, p_oMenu) {    
4580  
4581      if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
4582  
4583          Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
4584  
4585      }
4586  
4587  },
4588  
4589  
4590  /**
4591  * @method configHideDelay
4592  * @description Event handler for when the "hidedelay" configuration property 
4593  * of the menu changes.
4594  * @param {String} p_sType String representing the name of the event that 
4595  * was fired.
4596  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4597  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4598  * fired the event.
4599  */
4600  configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
4601  
4602      var nHideDelay = p_aArgs[0];
4603  
4604      this._useHideDelay = (nHideDelay > 0);
4605  
4606  },
4607  
4608  
4609  /**
4610  * @method configContainer
4611  * @description Event handler for when the "container" configuration property 
4612  * of the menu changes.
4613  * @param {String} p_sType String representing the name of the event that 
4614  * was fired.
4615  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
4616  * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
4617  * fired the event.
4618  */
4619  configContainer: function (p_sType, p_aArgs, p_oMenu) {
4620  
4621      var oElement = p_aArgs[0];
4622  
4623      if (Lang.isString(oElement)) {
4624  
4625          this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
4626  
4627      }
4628  
4629  },
4630  
4631  
4632  /**
4633  * @method _clearSetWidthFlag
4634  * @description Change event listener for the "width" configuration property.  This listener is 
4635  * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and 
4636  * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property 
4637  * is changed after it was set by the "_setScrollHeight" method.  If the "_widthSetForScroll" 
4638  * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down 
4639  * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
4640  * @private
4641  */
4642  _clearSetWidthFlag: function () {
4643  
4644      this._widthSetForScroll = false;
4645      
4646      this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4647  
4648  },
4649  
4650  /**
4651   * @method _subscribeScrollHandlers
4652   * @param {HTMLElement} oHeader The scroll header element
4653   * @param {HTMLElement} oFooter The scroll footer element
4654   */
4655  _subscribeScrollHandlers : function(oHeader, oFooter) {
4656      var fnMouseOver = this._onScrollTargetMouseOver;
4657      var fnMouseOut = this._onScrollTargetMouseOut;
4658  
4659      Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
4660      Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
4661      Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
4662      Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
4663  },
4664  
4665  /**
4666   * @method _unsubscribeScrollHandlers 
4667   * @param {HTMLElement} oHeader The scroll header element
4668   * @param {HTMLElement} oFooter The scroll footer element
4669   */
4670  _unsubscribeScrollHandlers : function(oHeader, oFooter) {
4671      var fnMouseOver = this._onScrollTargetMouseOver;
4672      var fnMouseOut = this._onScrollTargetMouseOut;
4673      
4674      Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
4675      Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
4676      Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
4677      Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
4678  },
4679  
4680  /**
4681  * @method _setScrollHeight
4682  * @description 
4683  * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
4684  * @private
4685  */
4686  _setScrollHeight: function (p_nScrollHeight) {
4687  
4688      var nScrollHeight = p_nScrollHeight,
4689          bRefireIFrameAndShadow = false,
4690          bSetWidth = false,
4691          oElement,
4692          oBody,
4693          oHeader,
4694          oFooter,
4695          nMinScrollHeight,
4696          nHeight,
4697          nOffsetWidth,
4698          sWidth;
4699  
4700      if (this.getItems().length > 0) {
4701  
4702          oElement = this.element;
4703          oBody = this.body;
4704          oHeader = this.header;
4705          oFooter = this.footer;
4706          nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
4707  
4708          if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
4709              nScrollHeight = nMinScrollHeight;
4710          }
4711  
4712          Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
4713          Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
4714          oBody.scrollTop = 0;
4715  
4716          //    Need to set a width for the Menu to fix the following problems in 
4717          //    Firefox 2 and IE:
4718  
4719          //    #1) Scrolled Menus will render at 1px wide in Firefox 2
4720  
4721          //    #2) There is a bug in gecko-based browsers where an element whose 
4722          //    "position" property is set to "absolute" and "overflow" property is 
4723          //    set to "hidden" will not render at the correct width when its 
4724          //    offsetParent's "position" property is also set to "absolute."  It is 
4725          //    possible to work around this bug by specifying a value for the width 
4726          //    property in addition to overflow.
4727  
4728          //    #3) In IE it is necessary to give the Menu a width before the 
4729          //    scrollbars are rendered to prevent the Menu from rendering with a 
4730          //    width that is 100% of the browser viewport.
4731  
4732          bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
4733  
4734          if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
4735  
4736              nOffsetWidth = oElement.offsetWidth;
4737      
4738              /*
4739                  Measuring the difference of the offsetWidth before and after
4740                  setting the "width" style attribute allows us to compute the 
4741                  about of padding and borders applied to the element, which in 
4742                  turn allows us to set the "width" property correctly.
4743              */
4744              
4745              oElement.style.width = nOffsetWidth + _PX;
4746      
4747              sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
4748  
4749  
4750              this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4751  
4752              YAHOO.log("Setting the \"width\" configuration property to " + sWidth + " for srolling.", 
4753                  "info", this.toString());
4754  
4755              this.cfg.setProperty(_WIDTH, sWidth);
4756  
4757  
4758              /*
4759                  Set a flag (_widthSetForScroll) to maintain some history regarding how the 
4760                  "width" configuration property was set.  If the "width" configuration property 
4761                  is set by something other than the "_setScrollHeight" method, it will be 
4762                  necessary to maintain that new value and not clear the width if scrolling 
4763                  is turned off.
4764              */
4765  
4766              this._widthSetForScroll = true;
4767  
4768              this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
4769      
4770          }
4771  
4772  
4773          if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
4774  
4775              YAHOO.log("Creating header and footer for scrolling.", "info", this.toString());
4776  
4777              this.setHeader(_NON_BREAKING_SPACE);
4778              this.setFooter(_NON_BREAKING_SPACE);
4779  
4780              oHeader = this.header;
4781              oFooter = this.footer;
4782  
4783              Dom.addClass(oHeader, _TOP_SCROLLBAR);
4784              Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
4785  
4786              oElement.insertBefore(oHeader, oBody);
4787              oElement.appendChild(oFooter);
4788          
4789          }
4790  
4791          nHeight = nScrollHeight;
4792  
4793          if (oHeader && oFooter) {
4794              nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
4795          }
4796      
4797      
4798          if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
4799  
4800              YAHOO.log("Setting up styles and event handlers for scrolling.", 
4801                  "info", this.toString());
4802      
4803              Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
4804              Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
4805  
4806              if (!this._hasScrollEventHandlers) {
4807                  this._subscribeScrollHandlers(oHeader, oFooter);
4808                  this._hasScrollEventHandlers = true;
4809              }
4810      
4811              this._disableScrollHeader();
4812              this._enableScrollFooter();
4813              
4814              bRefireIFrameAndShadow = true;            
4815      
4816          }
4817          else if (oHeader && oFooter) {
4818  
4819              YAHOO.log("Removing styles and event handlers for scrolling.", "info", this.toString());
4820      
4821  
4822              /*
4823                  Only clear the the "width" configuration property if it was set the 
4824                  "_setScrollHeight" method and wasn't changed by some other means after it was set.
4825              */    
4826      
4827              if (this._widthSetForScroll) {
4828      
4829                  YAHOO.log("Clearing width used for scrolling.", "info", this.toString());
4830  
4831                  this._widthSetForScroll = false;
4832  
4833                  this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
4834      
4835                  this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
4836              
4837              }
4838      
4839      
4840              this._enableScrollHeader();
4841              this._enableScrollFooter();
4842      
4843              if (this._hasScrollEventHandlers) {
4844                  this._unsubscribeScrollHandlers(oHeader, oFooter);    
4845                  this._hasScrollEventHandlers = false;
4846              }
4847  
4848              oElement.removeChild(oHeader);
4849              oElement.removeChild(oFooter);
4850      
4851              this.header = null;
4852              this.footer = null;
4853              
4854              bRefireIFrameAndShadow = true;
4855          
4856          }
4857  
4858  
4859          if (bRefireIFrameAndShadow) {
4860      
4861              this.cfg.refireEvent(_IFRAME);
4862              this.cfg.refireEvent(_SHADOW);
4863          
4864          }
4865      
4866      }
4867  
4868  },
4869  
4870  
4871  /**
4872  * @method _setMaxHeight
4873  * @description "renderEvent" handler used to defer the setting of the 
4874  * "maxheight" configuration property until the menu is rendered in lazy 
4875  * load scenarios.
4876  * @param {String} p_sType The name of the event that was fired.
4877  * @param {Array} p_aArgs Collection of arguments sent when the event 
4878  * was fired.
4879  * @param {Number} p_nMaxHeight Number representing the value to set for the 
4880  * "maxheight" configuration property.
4881  * @private
4882  */
4883  _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
4884  
4885      this._setScrollHeight(p_nMaxHeight);
4886      this.renderEvent.unsubscribe(this._setMaxHeight);
4887  
4888  },
4889  
4890  
4891  /**
4892  * @method configMaxHeight
4893  * @description Event handler for when the "maxheight" configuration property of 
4894  * a Menu changes.
4895  * @param {String} p_sType The name of the event that was fired.
4896  * @param {Array} p_aArgs Collection of arguments sent when the event 
4897  * was fired.
4898  * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
4899  * the event.
4900  */
4901  configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
4902  
4903      var nMaxHeight = p_aArgs[0];
4904  
4905      if (this.lazyLoad && !this.body && nMaxHeight > 0) {
4906      
4907          this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
4908  
4909      }
4910      else {
4911  
4912          this._setScrollHeight(nMaxHeight);
4913      
4914      }
4915  
4916  },
4917  
4918  
4919  /**
4920  * @method configClassName
4921  * @description Event handler for when the "classname" configuration property of 
4922  * a menu changes.
4923  * @param {String} p_sType The name of the event that was fired.
4924  * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4925  * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4926  */
4927  configClassName: function (p_sType, p_aArgs, p_oMenu) {
4928  
4929      var sClassName = p_aArgs[0];
4930  
4931      if (this._sClassName) {
4932  
4933          Dom.removeClass(this.element, this._sClassName);
4934  
4935      }
4936  
4937      Dom.addClass(this.element, sClassName);
4938      this._sClassName = sClassName;
4939  
4940  },
4941  
4942  
4943  /**
4944  * @method _onItemAdded
4945  * @description "itemadded" event handler for a Menu instance.
4946  * @private
4947  * @param {String} p_sType The name of the event that was fired.
4948  * @param {Array} p_aArgs Collection of arguments sent when the event 
4949  * was fired.
4950  */
4951  _onItemAdded: function (p_sType, p_aArgs) {
4952  
4953      var oItem = p_aArgs[0];
4954      
4955      if (oItem) {
4956  
4957          oItem.cfg.setProperty(_DISABLED, true);
4958      
4959      }
4960  
4961  },
4962  
4963  
4964  /**
4965  * @method configDisabled
4966  * @description Event handler for when the "disabled" configuration property of 
4967  * a menu changes.
4968  * @param {String} p_sType The name of the event that was fired.
4969  * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
4970  * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
4971  */
4972  configDisabled: function (p_sType, p_aArgs, p_oMenu) {
4973  
4974      var bDisabled = p_aArgs[0],
4975          aItems = this.getItems(),
4976          nItems,
4977          i;
4978  
4979      if (Lang.isArray(aItems)) {
4980  
4981          nItems = aItems.length;
4982      
4983          if (nItems > 0) {
4984          
4985              i = nItems - 1;
4986      
4987              do {
4988      
4989                  aItems[i].cfg.setProperty(_DISABLED, bDisabled);
4990              
4991              }
4992              while (i--);
4993          
4994          }
4995  
4996  
4997          if (bDisabled) {
4998  
4999              this.clearActiveItem(true);
5000  
5001              Dom.addClass(this.element, _DISABLED);
5002  
5003              this.itemAddedEvent.subscribe(this._onItemAdded);
5004  
5005          }
5006          else {
5007  
5008              Dom.removeClass(this.element, _DISABLED);
5009  
5010              this.itemAddedEvent.unsubscribe(this._onItemAdded);
5011  
5012          }
5013          
5014      }
5015  
5016  },
5017  
5018  /**
5019   * Resizes the shadow to match the container bounding element
5020   * 
5021   * @method _sizeShadow
5022   * @protected
5023   */
5024  _sizeShadow : function () {
5025  
5026      var oElement = this.element,
5027          oShadow = this._shadow;
5028  
5029      if (oShadow && oElement) {
5030          // Clear the previous width
5031          if (oShadow.style.width && oShadow.style.height) {
5032              oShadow.style.width = _EMPTY_STRING;
5033              oShadow.style.height = _EMPTY_STRING;
5034          }
5035  
5036          oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
5037          oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
5038      }
5039  },
5040  
5041  /**
5042   * Replaces the shadow element in the DOM with the current shadow element (this._shadow)
5043   * 
5044   * @method _replaceShadow
5045   * @protected 
5046   */
5047  _replaceShadow : function () {
5048      this.element.appendChild(this._shadow);
5049  },
5050  
5051  /**
5052   * Adds the classname marker for a visible shadow, to the shadow element
5053   * 
5054   * @method _addShadowVisibleClass
5055   * @protected
5056   */
5057  _addShadowVisibleClass : function () {
5058      Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5059  },
5060  
5061  /**
5062   * Removes the classname marker for a visible shadow, from the shadow element
5063   * 
5064   * @method _removeShadowVisibleClass
5065   * @protected
5066   */
5067  _removeShadowVisibleClass : function () {
5068      Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
5069  },
5070  
5071  /**
5072   * Removes the shadow element from the DOM, and unsubscribes all the listeners used to keep it in sync. Used
5073   * to handle setting the shadow to false.
5074   * 
5075   * @method _removeShadow
5076   * @protected
5077   */
5078  _removeShadow : function() {
5079  
5080      var p = (this._shadow && this._shadow.parentNode);
5081  
5082      if (p) {
5083          p.removeChild(this._shadow);
5084      }
5085  
5086      this.beforeShowEvent.unsubscribe(this._addShadowVisibleClass);
5087      this.beforeHideEvent.unsubscribe(this._removeShadowVisibleClass);
5088  
5089      this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._sizeShadow);
5090      this.cfg.unsubscribeFromConfigEvent(_HEIGHT, this._sizeShadow);
5091      this.cfg.unsubscribeFromConfigEvent(_MAX_HEIGHT, this._sizeShadow);
5092      this.cfg.unsubscribeFromConfigEvent(_MAX_HEIGHT, this._replaceShadow);
5093  
5094      this.changeContentEvent.unsubscribe(this._sizeShadow);
5095  
5096      Module.textResizeEvent.unsubscribe(this._sizeShadow);
5097  },
5098  
5099  /**
5100   * Used to create the shadow element, add it to the DOM, and subscribe listeners to keep it in sync.
5101   *
5102   * @method _createShadow
5103   * @protected
5104   */
5105  _createShadow : function () {
5106  
5107      var oShadow = this._shadow,
5108          oElement;
5109  
5110      if (!oShadow) {
5111          oElement = this.element;
5112  
5113          if (!m_oShadowTemplate) {
5114              m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
5115              m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
5116          }
5117  
5118          oShadow = m_oShadowTemplate.cloneNode(false);
5119  
5120          oElement.appendChild(oShadow);
5121          
5122          this._shadow = oShadow;
5123  
5124          this.beforeShowEvent.subscribe(this._addShadowVisibleClass);
5125          this.beforeHideEvent.subscribe(this._removeShadowVisibleClass);
5126  
5127          if (UA.ie) {
5128              /*
5129                   Need to call sizeShadow & syncIframe via setTimeout for 
5130                   IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode 
5131                   or the shadow and iframe shim will not be sized and 
5132                   positioned properly.
5133              */
5134              Lang.later(0, this, function () {
5135                  this._sizeShadow(); 
5136                  this.syncIframe();
5137              });
5138  
5139              this.cfg.subscribeToConfigEvent(_WIDTH, this._sizeShadow);
5140              this.cfg.subscribeToConfigEvent(_HEIGHT, this._sizeShadow);
5141              this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, this._sizeShadow);
5142              this.changeContentEvent.subscribe(this._sizeShadow);
5143  
5144              Module.textResizeEvent.subscribe(this._sizeShadow, this, true);
5145  
5146              this.destroyEvent.subscribe(function () {
5147                  Module.textResizeEvent.unsubscribe(this._sizeShadow, this);
5148              });
5149          }
5150  
5151          this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, this._replaceShadow);
5152      }
5153  },
5154  
5155  /**
5156   * The beforeShow event handler used to set up the shadow lazily when the menu is made visible.
5157   * @method _shadowBeforeShow
5158   * @protected 
5159   */
5160  _shadowBeforeShow : function () {
5161      if (this._shadow) {
5162  
5163          // If called because the "shadow" event was refired - just append again and resize
5164          this._replaceShadow();
5165  
5166          if (UA.ie) {
5167              this._sizeShadow();
5168          }
5169      } else {
5170          this._createShadow();
5171      }
5172  
5173      this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);
5174  },
5175  
5176  /**
5177  * @method configShadow
5178  * @description Event handler for when the "shadow" configuration property of 
5179  * a menu changes.
5180  * @param {String} p_sType The name of the event that was fired.
5181  * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
5182  * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
5183  */
5184  configShadow: function (p_sType, p_aArgs, p_oMenu) {
5185  
5186      var bShadow = p_aArgs[0];
5187  
5188      if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
5189          if (this.cfg.getProperty(_VISIBLE)) {
5190              if (this._shadow) {
5191                  // If the "shadow" event was refired - just append again and resize
5192                  this._replaceShadow();
5193                  
5194                  if (UA.ie) {
5195                      this._sizeShadow();
5196                  }
5197              } else {
5198                  this._createShadow();
5199              }
5200          } else {
5201              this.beforeShowEvent.subscribe(this._shadowBeforeShow);
5202          }
5203      } else if (!bShadow) {
5204          this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);
5205          this._removeShadow();
5206      }
5207  },
5208  
5209  // Public methods
5210  
5211  /**
5212  * @method initEvents
5213  * @description Initializes the custom events for the menu.
5214  */
5215  initEvents: function () {
5216  
5217      Menu.superclass.initEvents.call(this);
5218  
5219      // Create custom events
5220  
5221      var i = EVENT_TYPES.length - 1,
5222          aEventData,
5223          oCustomEvent;
5224  
5225  
5226      do {
5227  
5228          aEventData = EVENT_TYPES[i];
5229  
5230          oCustomEvent = this.createEvent(aEventData[1]);
5231          oCustomEvent.signature = CustomEvent.LIST;
5232          
5233          this[aEventData[0]] = oCustomEvent;
5234  
5235      }
5236      while (i--);
5237  
5238  },
5239  
5240  
5241  /**
5242  * @method positionOffScreen
5243  * @description Positions the menu outside of the boundaries of the browser's 
5244  * viewport.  Called automatically when a menu is hidden to ensure that 
5245  * it doesn't force the browser to render uncessary scrollbars.
5246  */
5247  positionOffScreen: function () {
5248  
5249      var oIFrame = this.iframe,
5250          oElement = this.element,
5251          sPos = this.OFF_SCREEN_POSITION;
5252      
5253      oElement.style.top = _EMPTY_STRING;
5254      oElement.style.left = _EMPTY_STRING;
5255      
5256      if (oIFrame) {
5257  
5258          oIFrame.style.top = sPos;
5259          oIFrame.style.left = sPos;
5260      
5261      }
5262  
5263  },
5264  
5265  
5266  /**
5267  * @method getRoot
5268  * @description Finds the menu's root menu.
5269  */
5270  getRoot: function () {
5271  
5272      var oItem = this.parent,
5273          oParentMenu,
5274          returnVal;
5275  
5276      if (oItem) {
5277  
5278          oParentMenu = oItem.parent;
5279  
5280          returnVal = oParentMenu ? oParentMenu.getRoot() : this;
5281  
5282      }
5283      else {
5284      
5285          returnVal = this;
5286      
5287      }
5288      
5289      return returnVal;
5290  
5291  },
5292  
5293  
5294  /**
5295  * @method toString
5296  * @description Returns a string representing the menu.
5297  * @return {String}
5298  */
5299  toString: function () {
5300  
5301      var sReturnVal = _MENU,
5302          sId = this.id;
5303  
5304      if (sId) {
5305  
5306          sReturnVal += (_SPACE + sId);
5307      
5308      }
5309  
5310      return sReturnVal;
5311  
5312  },
5313  
5314  
5315  /**
5316  * @method setItemGroupTitle
5317  * @description Sets the title of a group of menu items.
5318  * @param {HTML} p_sGroupTitle String or markup specifying the title of the group. The title is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5319  * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
5320  * the title belongs.
5321  */
5322  setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
5323  
5324      var nGroupIndex,
5325          oTitle,
5326          i,
5327          nFirstIndex;
5328          
5329      if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
5330  
5331          nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
5332          oTitle = this._aGroupTitleElements[nGroupIndex];
5333  
5334  
5335          if (oTitle) {
5336  
5337              oTitle.innerHTML = p_sGroupTitle;
5338              
5339          }
5340          else {
5341  
5342              oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
5343                      
5344              oTitle.innerHTML = p_sGroupTitle;
5345  
5346              this._aGroupTitleElements[nGroupIndex] = oTitle;
5347  
5348          }
5349  
5350  
5351          i = this._aGroupTitleElements.length - 1;
5352  
5353          do {
5354  
5355              if (this._aGroupTitleElements[i]) {
5356  
5357                  Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
5358  
5359                  nFirstIndex = i;
5360  
5361              }
5362  
5363          }
5364          while (i--);
5365  
5366  
5367          if (nFirstIndex !== null) {
5368  
5369              Dom.addClass(this._aGroupTitleElements[nFirstIndex], 
5370                  _FIRST_OF_TYPE);
5371  
5372          }
5373  
5374          this.changeContentEvent.fire();
5375  
5376      }
5377  
5378  },
5379  
5380  
5381  
5382  /**
5383  * @method addItem
5384  * @description Appends an item to the menu.
5385  * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
5386  * instance to be added to the menu.
5387  * @param {HTML} p_oItem String or markup specifying content of the item to be added 
5388  * to the menu. The item text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5389  * @param {Object} p_oItem Object literal containing a set of menu item 
5390  * configuration properties.
5391  * @param {Number} p_nGroupIndex Optional. Number indicating the group to
5392  * which the item belongs.
5393  * @return {YAHOO.widget.MenuItem}
5394  */
5395  addItem: function (p_oItem, p_nGroupIndex) {
5396  
5397      return this._addItemToGroup(p_nGroupIndex, p_oItem);
5398  
5399  },
5400  
5401  
5402  /**
5403  * @method addItems
5404  * @description Adds an array of items to the menu.
5405  * @param {Array} p_aItems Array of items to be added to the menu.  The array 
5406  * can contain strings specifying the markup for the content of each item to be created, object
5407  * literals specifying each of the menu item configuration properties, 
5408  * or MenuItem instances. The item content if provided as a string is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5409  * @param {Number} p_nGroupIndex Optional. Number specifying the group to 
5410  * which the items belongs.
5411  * @return {Array}
5412  */
5413  addItems: function (p_aItems, p_nGroupIndex) {
5414  
5415      var nItems,
5416          aItems,
5417          oItem,
5418          i,
5419          returnVal;
5420  
5421  
5422      if (Lang.isArray(p_aItems)) {
5423  
5424          nItems = p_aItems.length;
5425          aItems = [];
5426  
5427          for(i=0; i<nItems; i++) {
5428  
5429              oItem = p_aItems[i];
5430  
5431              if (oItem) {
5432  
5433                  if (Lang.isArray(oItem)) {
5434      
5435                      aItems[aItems.length] = this.addItems(oItem, i);
5436      
5437                  }
5438                  else {
5439      
5440                      aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
5441                  
5442                  }
5443  
5444              }
5445      
5446          }
5447  
5448  
5449          if (aItems.length) {
5450          
5451              returnVal = aItems;
5452          
5453          }
5454  
5455      }
5456  
5457      return returnVal;
5458  
5459  },
5460  
5461  
5462  /**
5463  * @method insertItem
5464  * @description Inserts an item into the menu at the specified index.
5465  * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
5466  * instance to be added to the menu.
5467  * @param {String} p_oItem String specifying the text of the item to be added 
5468  * to the menu.
5469  * @param {Object} p_oItem Object literal containing a set of menu item 
5470  * configuration properties.
5471  * @param {Number} p_nItemIndex Number indicating the ordinal position at which
5472  * the item should be added.
5473  * @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
5474  * the item belongs.
5475  * @return {YAHOO.widget.MenuItem}
5476  */
5477  insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
5478      
5479      return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
5480  
5481  },
5482  
5483  
5484  /**
5485  * @method removeItem
5486  * @description Removes the specified item from the menu.
5487  * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem 
5488  * instance to be removed from the menu.
5489  * @param {Number} p_oObject Number specifying the index of the item 
5490  * to be removed.
5491  * @param {Number} p_nGroupIndex Optional. Number specifying the group to 
5492  * which the item belongs.
5493  * @return {YAHOO.widget.MenuItem}
5494  */
5495  removeItem: function (p_oObject, p_nGroupIndex) {
5496  
5497      var oItem,
5498          returnVal;
5499      
5500      if (!Lang.isUndefined(p_oObject)) {
5501  
5502          if (p_oObject instanceof YAHOO.widget.MenuItem) {
5503  
5504              oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);           
5505  
5506          }
5507          else if (Lang.isNumber(p_oObject)) {
5508  
5509              oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
5510  
5511          }
5512  
5513          if (oItem) {
5514  
5515              oItem.destroy();
5516  
5517              YAHOO.log("Item removed." + 
5518                  " Text: " + oItem.cfg.getProperty("text") + ", " + 
5519                  " Index: " + oItem.index + ", " + 
5520                  " Group Index: " + oItem.groupIndex, "info", this.toString());
5521  
5522              returnVal = oItem;
5523  
5524          }
5525  
5526      }
5527  
5528      return returnVal;
5529  
5530  },
5531  
5532  
5533  /**
5534  * @method getItems
5535  * @description Returns an array of all of the items in the menu.
5536  * @return {Array}
5537  */
5538  getItems: function () {
5539  
5540      var aGroups = this._aItemGroups,
5541          nGroups,
5542          returnVal,
5543          aItems = [];
5544  
5545  
5546      if (Lang.isArray(aGroups)) {
5547  
5548          nGroups = aGroups.length;
5549  
5550          returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
5551  
5552      }
5553  
5554      return returnVal;
5555  
5556  },
5557  
5558  
5559  /**
5560  * @method getItemGroups
5561  * @description Multi-dimensional Array representing the menu items as they 
5562  * are grouped in the menu.
5563  * @return {Array}
5564  */        
5565  getItemGroups: function () {
5566  
5567      return this._aItemGroups;
5568  
5569  },
5570  
5571  
5572  /**
5573  * @method getItem
5574  * @description Returns the item at the specified index.
5575  * @param {Number} p_nItemIndex Number indicating the ordinal position of the 
5576  * item to be retrieved.
5577  * @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
5578  * the item belongs.
5579  * @return {YAHOO.widget.MenuItem}
5580  */
5581  getItem: function (p_nItemIndex, p_nGroupIndex) {
5582      
5583      var aGroup,
5584          returnVal;
5585      
5586      if (Lang.isNumber(p_nItemIndex)) {
5587  
5588          aGroup = this._getItemGroup(p_nGroupIndex);
5589  
5590          if (aGroup) {
5591  
5592              returnVal = aGroup[p_nItemIndex];
5593          
5594          }
5595  
5596      }
5597      
5598      return returnVal;
5599      
5600  },
5601  
5602  
5603  /**
5604  * @method getSubmenus
5605  * @description Returns an array of all of the submenus that are immediate 
5606  * children of the menu.
5607  * @return {Array}
5608  */
5609  getSubmenus: function () {
5610  
5611      var aItems = this.getItems(),
5612          nItems = aItems.length,
5613          aSubmenus,
5614          oSubmenu,
5615          oItem,
5616          i;
5617  
5618  
5619      if (nItems > 0) {
5620          
5621          aSubmenus = [];
5622  
5623          for(i=0; i<nItems; i++) {
5624  
5625              oItem = aItems[i];
5626              
5627              if (oItem) {
5628  
5629                  oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5630                  
5631                  if (oSubmenu) {
5632  
5633                      aSubmenus[aSubmenus.length] = oSubmenu;
5634  
5635                  }
5636              
5637              }
5638          
5639          }
5640      
5641      }
5642  
5643      return aSubmenus;
5644  
5645  },
5646  
5647  
5648  /**
5649  * @method clearContent
5650  * @description Removes all of the content from the menu, including the menu 
5651  * items, group titles, header and footer.
5652  */
5653  clearContent: function () {
5654  
5655      var aItems = this.getItems(),
5656          nItems = aItems.length,
5657          oElement = this.element,
5658          oBody = this.body,
5659          oHeader = this.header,
5660          oFooter = this.footer,
5661          oItem,
5662          oSubmenu,
5663          i;
5664  
5665  
5666      if (nItems > 0) {
5667  
5668          i = nItems - 1;
5669  
5670          do {
5671  
5672              oItem = aItems[i];
5673  
5674              if (oItem) {
5675  
5676                  oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5677  
5678                  if (oSubmenu) {
5679  
5680                      this.cfg.configChangedEvent.unsubscribe(
5681                          this._onParentMenuConfigChange, oSubmenu);
5682  
5683                      this.renderEvent.unsubscribe(this._onParentMenuRender, 
5684                          oSubmenu);
5685  
5686                  }
5687                  
5688                  this.removeItem(oItem, oItem.groupIndex);
5689  
5690              }
5691          
5692          }
5693          while (i--);
5694  
5695      }
5696  
5697  
5698      if (oHeader) {
5699  
5700          Event.purgeElement(oHeader);
5701          oElement.removeChild(oHeader);
5702  
5703      }
5704      
5705  
5706      if (oFooter) {
5707  
5708          Event.purgeElement(oFooter);
5709          oElement.removeChild(oFooter);
5710      }
5711  
5712  
5713      if (oBody) {
5714  
5715          Event.purgeElement(oBody);
5716  
5717          oBody.innerHTML = _EMPTY_STRING;
5718  
5719      }
5720  
5721      this.activeItem = null;
5722  
5723      this._aItemGroups = [];
5724      this._aListElements = [];
5725      this._aGroupTitleElements = [];
5726  
5727      this.cfg.setProperty(_WIDTH, null);
5728  
5729  },
5730  
5731  
5732  /**
5733  * @method destroy
5734  * @description Removes the menu's <code>&#60;div&#62;</code> element 
5735  * (and accompanying child nodes) from the document.
5736  * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 
5737  * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
5738  * 
5739  */
5740  destroy: function (shallowPurge) {
5741  
5742      // Remove all items
5743  
5744      this.clearContent();
5745  
5746      this._aItemGroups = null;
5747      this._aListElements = null;
5748      this._aGroupTitleElements = null;
5749  
5750  
5751      // Continue with the superclass implementation of this method
5752  
5753      Menu.superclass.destroy.call(this, shallowPurge);
5754      
5755      YAHOO.log("Destroyed.", "info", this.toString());
5756  
5757  },
5758  
5759  
5760  /**
5761  * @method setInitialFocus
5762  * @description Sets focus to the menu's first enabled item.
5763  */
5764  setInitialFocus: function () {
5765  
5766      var oItem = this._getFirstEnabledItem();
5767      
5768      if (oItem) {
5769  
5770          oItem.focus();
5771  
5772      }
5773      
5774  },
5775  
5776  
5777  /**
5778  * @method setInitialSelection
5779  * @description Sets the "selected" configuration property of the menu's first 
5780  * enabled item to "true."
5781  */
5782  setInitialSelection: function () {
5783  
5784      var oItem = this._getFirstEnabledItem();
5785      
5786      if (oItem) {
5787      
5788          oItem.cfg.setProperty(_SELECTED, true);
5789      }        
5790  
5791  },
5792  
5793  
5794  /**
5795  * @method clearActiveItem
5796  * @description Sets the "selected" configuration property of the menu's active
5797  * item to "false" and hides the item's submenu.
5798  * @param {Boolean} p_bBlur Boolean indicating if the menu's active item 
5799  * should be blurred.  
5800  */
5801  clearActiveItem: function (p_bBlur) {
5802  
5803      if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
5804      
5805          this._cancelShowDelay();
5806      
5807      }
5808  
5809  
5810      var oActiveItem = this.activeItem,
5811          oConfig,
5812          oSubmenu;
5813  
5814      if (oActiveItem) {
5815  
5816          oConfig = oActiveItem.cfg;
5817  
5818          if (p_bBlur) {
5819  
5820              oActiveItem.blur();
5821              
5822              this.getRoot()._hasFocus = true;
5823          
5824          }
5825  
5826          oConfig.setProperty(_SELECTED, false);
5827  
5828          oSubmenu = oConfig.getProperty(_SUBMENU);
5829  
5830  
5831          if (oSubmenu) {
5832  
5833              oSubmenu.hide();
5834  
5835          }
5836  
5837          this.activeItem = null;  
5838  
5839      }
5840  
5841  },
5842  
5843  
5844  /**
5845  * @method focus
5846  * @description Causes the menu to receive focus and fires the "focus" event.
5847  */
5848  focus: function () {
5849  
5850      if (!this.hasFocus()) {
5851  
5852          this.setInitialFocus();
5853      
5854      }
5855  
5856  },
5857  
5858  
5859  /**
5860  * @method blur
5861  * @description Causes the menu to lose focus and fires the "blur" event.
5862  */    
5863  blur: function () {
5864  
5865      var oItem;
5866  
5867      if (this.hasFocus()) {
5868      
5869          oItem = MenuManager.getFocusedMenuItem();
5870          
5871          if (oItem) {
5872  
5873              oItem.blur();
5874  
5875          }
5876  
5877      }
5878  
5879  },
5880  
5881  
5882  /**
5883  * @method hasFocus
5884  * @description Returns a boolean indicating whether or not the menu has focus.
5885  * @return {Boolean}
5886  */
5887  hasFocus: function () {
5888  
5889      return (MenuManager.getFocusedMenu() == this.getRoot());
5890  
5891  },
5892  
5893  
5894  _doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
5895  
5896      var oItem = p_aArgs[0],
5897          oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5898  
5899      if (oSubmenu) {
5900          oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5901      }
5902  
5903  },
5904  
5905  
5906  _doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) { 
5907  
5908      var oSubmenu = this.cfg.getProperty(_SUBMENU);
5909      
5910      if (oSubmenu) {
5911          oSubmenu.subscribe.apply(oSubmenu, p_oObject);
5912      }
5913  
5914  },
5915  
5916  
5917  /**
5918  * Adds the specified CustomEvent subscriber to the menu and each of 
5919  * its submenus.
5920  * @method subscribe
5921  * @param p_type     {string}   the type, or name of the event
5922  * @param p_fn       {function} the function to exectute when the event fires
5923  * @param p_obj      {Object}   An object to be passed along when the event 
5924  *                              fires
5925  * @param p_override {boolean}  If true, the obj passed in becomes the 
5926  *                              execution scope of the listener
5927  */
5928  subscribe: function () {
5929  
5930      //    Subscribe to the event for this Menu instance
5931      Menu.superclass.subscribe.apply(this, arguments);
5932  
5933      //    Subscribe to the "itemAdded" event so that all future submenus
5934      //    also subscribe to this event
5935      Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5936  
5937  
5938      var aItems = this.getItems(),
5939          nItems,
5940          oItem,
5941          oSubmenu,
5942          i;
5943          
5944  
5945      if (aItems) {
5946  
5947          nItems = aItems.length;
5948          
5949          if (nItems > 0) {
5950          
5951              i = nItems - 1;
5952              
5953              do {
5954  
5955                  oItem = aItems[i];
5956                  oSubmenu = oItem.cfg.getProperty(_SUBMENU);
5957                  
5958                  if (oSubmenu) {
5959                      oSubmenu.subscribe.apply(oSubmenu, arguments);
5960                  }
5961                  else {
5962                      oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
5963                  }
5964  
5965              }
5966              while (i--);
5967          
5968          }
5969  
5970      }
5971  
5972  },
5973  
5974  
5975  unsubscribe: function () {
5976  
5977      //    Remove the event for this Menu instance
5978      Menu.superclass.unsubscribe.apply(this, arguments);
5979  
5980      //    Remove the "itemAdded" event so that all future submenus don't have 
5981      //    the event handler
5982      Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
5983  
5984  
5985      var aItems = this.getItems(),
5986          nItems,
5987          oItem,
5988          oSubmenu,
5989          i;
5990          
5991  
5992      if (aItems) {
5993  
5994          nItems = aItems.length;
5995          
5996          if (nItems > 0) {
5997          
5998              i = nItems - 1;
5999              
6000              do {
6001  
6002                  oItem = aItems[i];
6003                  oSubmenu = oItem.cfg.getProperty(_SUBMENU);
6004                  
6005                  if (oSubmenu) {
6006                      oSubmenu.unsubscribe.apply(oSubmenu, arguments);
6007                  }
6008                  else {
6009                      oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
6010                  }
6011  
6012              }
6013              while (i--);
6014          
6015          }
6016  
6017      }
6018  
6019  },
6020  
6021  
6022  /**
6023  * @description Initializes the class's configurable properties which can be
6024  * changed using the menu's Config object ("cfg").
6025  * @method initDefaultConfig
6026  */
6027  initDefaultConfig: function () {
6028  
6029      Menu.superclass.initDefaultConfig.call(this);
6030  
6031      var oConfig = this.cfg;
6032  
6033  
6034      // Module documentation overrides
6035  
6036      /**
6037      * @config effect
6038      * @description Object or array of objects representing the ContainerEffect 
6039      * classes that are active for animating the container.  When set this 
6040      * property is automatically applied to all submenus.
6041      * @type Object
6042      * @default null
6043      */
6044  
6045      // Overlay documentation overrides
6046  
6047  
6048      /**
6049      * @config x
6050      * @description Number representing the absolute x-coordinate position of 
6051      * the Menu.  This property is only applied when the "position" 
6052      * configuration property is set to dynamic.
6053      * @type Number
6054      * @default null
6055      */
6056      
6057  
6058      /**
6059      * @config y
6060      * @description Number representing the absolute y-coordinate position of 
6061      * the Menu.  This property is only applied when the "position" 
6062      * configuration property is set to dynamic.
6063      * @type Number
6064      * @default null
6065      */
6066  
6067  
6068      /**
6069      * @description Array of the absolute x and y positions of the Menu.  This 
6070      * property is only applied when the "position" configuration property is 
6071      * set to dynamic.
6072      * @config xy
6073      * @type Number[]
6074      * @default null
6075      */
6076      
6077  
6078      /**
6079      * @config context
6080      * @description Array of context arguments for context-sensitive positioning.  
6081      * The format is: [id or element, element corner, context corner]. 
6082      * For example, setting this property to ["img1", "tl", "bl"] would 
6083      * align the Menu's top left corner to the context element's 
6084      * bottom left corner.  This property is only applied when the "position" 
6085      * configuration property is set to dynamic.
6086      * @type Array
6087      * @default null
6088      */
6089      
6090      
6091      /**
6092      * @config fixedcenter
6093      * @description Boolean indicating if the Menu should be anchored to the 
6094      * center of the viewport.  This property is only applied when the 
6095      * "position" configuration property is set to dynamic.
6096      * @type Boolean
6097      * @default false
6098      */
6099      
6100      
6101      /**
6102      * @config iframe
6103      * @description Boolean indicating whether or not the Menu should 
6104      * have an IFRAME shim; used to prevent SELECT elements from 
6105      * poking through an Overlay instance in IE6.  When set to "true", 
6106      * the iframe shim is created when the Menu instance is intially
6107      * made visible.  This property is only applied when the "position" 
6108      * configuration property is set to dynamic and is automatically applied 
6109      * to all submenus.
6110      * @type Boolean
6111      * @default true for IE6 and below, false for all other browsers.
6112      */
6113  
6114  
6115      // Add configuration attributes
6116  
6117      /*
6118          Change the default value for the "visible" configuration 
6119          property to "false" by re-adding the property.
6120      */
6121  
6122      /**
6123      * @config visible
6124      * @description Boolean indicating whether or not the menu is visible.  If 
6125      * the menu's "position" configuration property is set to "dynamic" (the 
6126      * default), this property toggles the menu's <code>&#60;div&#62;</code> 
6127      * element's "visibility" style property between "visible" (true) or 
6128      * "hidden" (false).  If the menu's "position" configuration property is 
6129      * set to "static" this property toggles the menu's 
6130      * <code>&#60;div&#62;</code> element's "display" style property 
6131      * between "block" (true) or "none" (false).
6132      * @default false
6133      * @type Boolean
6134      */
6135      oConfig.addProperty(
6136          VISIBLE_CONFIG.key, 
6137          {
6138              handler: this.configVisible, 
6139              value: VISIBLE_CONFIG.value, 
6140              validator: VISIBLE_CONFIG.validator
6141          }
6142       );
6143  
6144  
6145      /*
6146          Change the default value for the "constraintoviewport" configuration 
6147          property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6148      */
6149  
6150      /**
6151      * @config constraintoviewport
6152      * @description Boolean indicating if the menu will try to remain inside 
6153      * the boundaries of the size of viewport.  This property is only applied 
6154      * when the "position" configuration property is set to dynamic and is 
6155      * automatically applied to all submenus.
6156      * @default true
6157      * @type Boolean
6158      */
6159      oConfig.addProperty(
6160          CONSTRAIN_TO_VIEWPORT_CONFIG.key, 
6161          {
6162              handler: this.configConstrainToViewport, 
6163              value: CONSTRAIN_TO_VIEWPORT_CONFIG.value, 
6164              validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator, 
6165              supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes 
6166          } 
6167      );
6168  
6169  
6170      /*
6171          Change the default value for the "preventcontextoverlap" configuration 
6172          property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
6173      */
6174  
6175      /**
6176      * @config preventcontextoverlap
6177      * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem 
6178      * when the "constraintoviewport" configuration property is set to "true".
6179      * @type Boolean
6180      * @default true
6181      */
6182      oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
6183  
6184          value: PREVENT_CONTEXT_OVERLAP_CONFIG.value, 
6185          validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator, 
6186          supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
6187  
6188      });
6189  
6190  
6191      /**
6192      * @config position
6193      * @description String indicating how a menu should be positioned on the 
6194      * screen.  Possible values are "static" and "dynamic."  Static menus are 
6195      * visible by default and reside in the normal flow of the document 
6196      * (CSS position: static).  Dynamic menus are hidden by default, reside 
6197      * out of the normal flow of the document (CSS position: absolute), and 
6198      * can overlay other elements on the screen.
6199      * @default dynamic
6200      * @type String
6201      */
6202      oConfig.addProperty(
6203          POSITION_CONFIG.key, 
6204          {
6205              handler: this.configPosition,
6206              value: POSITION_CONFIG.value, 
6207              validator: POSITION_CONFIG.validator,
6208              supercedes: POSITION_CONFIG.supercedes
6209          }
6210      );
6211  
6212  
6213      /**
6214      * @config submenualignment
6215      * @description Array defining how submenus should be aligned to their 
6216      * parent menu item. The format is: [itemCorner, submenuCorner]. By default
6217      * a submenu's top left corner is aligned to its parent menu item's top 
6218      * right corner.
6219      * @default ["tl","tr"]
6220      * @type Array
6221      */
6222      oConfig.addProperty(
6223          SUBMENU_ALIGNMENT_CONFIG.key, 
6224          { 
6225              value: SUBMENU_ALIGNMENT_CONFIG.value,
6226              suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
6227          }
6228      );
6229  
6230  
6231      /**
6232      * @config autosubmenudisplay
6233      * @description Boolean indicating if submenus are automatically made 
6234      * visible when the user mouses over the menu's items.
6235      * @default true
6236      * @type Boolean
6237      */
6238      oConfig.addProperty(
6239         AUTO_SUBMENU_DISPLAY_CONFIG.key, 
6240         { 
6241             value: AUTO_SUBMENU_DISPLAY_CONFIG.value, 
6242             validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
6243             suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
6244         } 
6245      );
6246  
6247  
6248      /**
6249      * @config showdelay
6250      * @description Number indicating the time (in milliseconds) that should 
6251      * expire before a submenu is made visible when the user mouses over 
6252      * the menu's items.  This property is only applied when the "position" 
6253      * configuration property is set to dynamic and is automatically applied 
6254      * to all submenus.
6255      * @default 250
6256      * @type Number
6257      */
6258      oConfig.addProperty(
6259         SHOW_DELAY_CONFIG.key, 
6260         { 
6261             value: SHOW_DELAY_CONFIG.value, 
6262             validator: SHOW_DELAY_CONFIG.validator,
6263             suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
6264         } 
6265      );
6266  
6267  
6268      /**
6269      * @config hidedelay
6270      * @description Number indicating the time (in milliseconds) that should 
6271      * expire before the menu is hidden.  This property is only applied when 
6272      * the "position" configuration property is set to dynamic and is 
6273      * automatically applied to all submenus.
6274      * @default 0
6275      * @type Number
6276      */
6277      oConfig.addProperty(
6278         HIDE_DELAY_CONFIG.key, 
6279         { 
6280             handler: this.configHideDelay,
6281             value: HIDE_DELAY_CONFIG.value, 
6282             validator: HIDE_DELAY_CONFIG.validator, 
6283             suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
6284         } 
6285      );
6286  
6287  
6288      /**
6289      * @config submenuhidedelay
6290      * @description Number indicating the time (in milliseconds) that should 
6291      * expire before a submenu is hidden when the user mouses out of a menu item 
6292      * heading in the direction of a submenu.  The value must be greater than or 
6293      * equal to the value specified for the "showdelay" configuration property.
6294      * This property is only applied when the "position" configuration property 
6295      * is set to dynamic and is automatically applied to all submenus.
6296      * @default 250
6297      * @type Number
6298      */
6299      oConfig.addProperty(
6300         SUBMENU_HIDE_DELAY_CONFIG.key, 
6301         { 
6302             value: SUBMENU_HIDE_DELAY_CONFIG.value, 
6303             validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
6304             suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
6305         } 
6306      );
6307  
6308  
6309      /**
6310      * @config clicktohide
6311      * @description Boolean indicating if the menu will automatically be 
6312      * hidden if the user clicks outside of it.  This property is only 
6313      * applied when the "position" configuration property is set to dynamic 
6314      * and is automatically applied to all submenus.
6315      * @default true
6316      * @type Boolean
6317      */
6318      oConfig.addProperty(
6319          CLICK_TO_HIDE_CONFIG.key,
6320          {
6321              value: CLICK_TO_HIDE_CONFIG.value,
6322              validator: CLICK_TO_HIDE_CONFIG.validator,
6323              suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
6324          }
6325      );
6326  
6327  
6328      /**
6329      * @config container
6330      * @description HTML element reference or string specifying the id 
6331      * attribute of the HTML element that the menu's markup should be 
6332      * rendered into.
6333      * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6334      * level-one-html.html#ID-58190037">HTMLElement</a>|String
6335      * @default document.body
6336      */
6337      oConfig.addProperty(
6338         CONTAINER_CONFIG.key, 
6339         { 
6340             handler: this.configContainer,
6341             value: document.body,
6342             suppressEvent: CONTAINER_CONFIG.suppressEvent
6343         } 
6344     );
6345  
6346  
6347      /**
6348      * @config scrollincrement
6349      * @description Number used to control the scroll speed of a menu.  Used to 
6350      * increment the "scrollTop" property of the menu's body by when a menu's 
6351      * content is scrolling.  When set this property is automatically applied 
6352      * to all submenus.
6353      * @default 1
6354      * @type Number
6355      */
6356      oConfig.addProperty(
6357          SCROLL_INCREMENT_CONFIG.key, 
6358          { 
6359              value: SCROLL_INCREMENT_CONFIG.value, 
6360              validator: SCROLL_INCREMENT_CONFIG.validator,
6361              supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
6362              suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
6363          }
6364      );
6365  
6366  
6367      /**
6368      * @config minscrollheight
6369      * @description Number defining the minimum threshold for the "maxheight" 
6370      * configuration property.  When set this property is automatically applied 
6371      * to all submenus.
6372      * @default 90
6373      * @type Number
6374      */
6375      oConfig.addProperty(
6376          MIN_SCROLL_HEIGHT_CONFIG.key, 
6377          { 
6378              value: MIN_SCROLL_HEIGHT_CONFIG.value, 
6379              validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
6380              supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
6381              suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
6382          }
6383      );
6384  
6385  
6386      /**
6387      * @config maxheight
6388      * @description Number defining the maximum height (in pixels) for a menu's 
6389      * body element (<code>&#60;div class="bd"&#62;</code>).  Once a menu's body 
6390      * exceeds this height, the contents of the body are scrolled to maintain 
6391      * this value.  This value cannot be set lower than the value of the 
6392      * "minscrollheight" configuration property.
6393      * @default 0
6394      * @type Number
6395      */
6396      oConfig.addProperty(
6397         MAX_HEIGHT_CONFIG.key, 
6398         {
6399              handler: this.configMaxHeight,
6400              value: MAX_HEIGHT_CONFIG.value,
6401              validator: MAX_HEIGHT_CONFIG.validator,
6402              suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
6403              supercedes: MAX_HEIGHT_CONFIG.supercedes            
6404         } 
6405      );
6406  
6407  
6408      /**
6409      * @config classname
6410      * @description String representing the CSS class to be applied to the 
6411      * menu's root <code>&#60;div&#62;</code> element.  The specified class(es)  
6412      * are appended in addition to the default class as specified by the menu's
6413      * CSS_CLASS_NAME constant. When set this property is automatically 
6414      * applied to all submenus.
6415      * @default null
6416      * @type String
6417      */
6418      oConfig.addProperty(
6419          CLASS_NAME_CONFIG.key, 
6420          { 
6421              handler: this.configClassName,
6422              value: CLASS_NAME_CONFIG.value, 
6423              validator: CLASS_NAME_CONFIG.validator,
6424              supercedes: CLASS_NAME_CONFIG.supercedes      
6425          }
6426      );
6427  
6428  
6429      /**
6430      * @config disabled
6431      * @description Boolean indicating if the menu should be disabled.  
6432      * Disabling a menu disables each of its items.  (Disabled menu items are 
6433      * dimmed and will not respond to user input or fire events.)  Disabled
6434      * menus have a corresponding "disabled" CSS class applied to their root
6435      * <code>&#60;div&#62;</code> element.
6436      * @default false
6437      * @type Boolean
6438      */
6439      oConfig.addProperty(
6440          DISABLED_CONFIG.key, 
6441          { 
6442              handler: this.configDisabled,
6443              value: DISABLED_CONFIG.value, 
6444              validator: DISABLED_CONFIG.validator,
6445              suppressEvent: DISABLED_CONFIG.suppressEvent
6446          }
6447      );
6448  
6449  
6450      /**
6451      * @config shadow
6452      * @description Boolean indicating if the menu should have a shadow.
6453      * @default true
6454      * @type Boolean
6455      */
6456      oConfig.addProperty(
6457          SHADOW_CONFIG.key, 
6458          { 
6459              handler: this.configShadow,
6460              value: SHADOW_CONFIG.value, 
6461              validator: SHADOW_CONFIG.validator
6462          }
6463      );
6464  
6465  
6466      /**
6467      * @config keepopen
6468      * @description Boolean indicating if the menu should remain open when clicked.
6469      * @default false
6470      * @type Boolean
6471      */
6472      oConfig.addProperty(
6473          KEEP_OPEN_CONFIG.key, 
6474          { 
6475              value: KEEP_OPEN_CONFIG.value, 
6476              validator: KEEP_OPEN_CONFIG.validator
6477          }
6478      );
6479  
6480  }
6481  
6482  }); // END YAHOO.lang.extend
6483  
6484  })();
6485  
6486  
6487  
6488  (function () {
6489  
6490  /**
6491  * Creates an item for a menu.
6492  * 
6493  * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
6494  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6495  * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
6496  * the <code>&#60;li&#62;</code> element of the menu item.
6497  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6498  * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
6499  * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
6500  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6501  * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
6502  * specifying the <code>&#60;option&#62;</code> element of the menu item.
6503  * @param {Object} p_oConfig Optional. Object literal specifying the 
6504  * configuration for the menu item. See configuration class documentation 
6505  * for more details.
6506  * @class MenuItem
6507  * @constructor
6508  */
6509  YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
6510  
6511      if (p_oObject) {
6512  
6513          if (p_oConfig) {
6514      
6515              this.parent = p_oConfig.parent;
6516              this.value = p_oConfig.value;
6517              this.id = p_oConfig.id;
6518  
6519          }
6520  
6521          this.init(p_oObject, p_oConfig);
6522  
6523      }
6524  
6525  };
6526  
6527  
6528  var Dom = YAHOO.util.Dom,
6529      Module = YAHOO.widget.Module,
6530      Menu = YAHOO.widget.Menu,
6531      MenuItem = YAHOO.widget.MenuItem,
6532      CustomEvent = YAHOO.util.CustomEvent,
6533      UA = YAHOO.env.ua,
6534      Lang = YAHOO.lang,
6535  
6536      // Private string constants
6537  
6538      _TEXT = "text",
6539      _HASH = "#",
6540      _HYPHEN = "-",
6541      _HELP_TEXT = "helptext",
6542      _URL = "url",
6543      _TARGET = "target",
6544      _EMPHASIS = "emphasis",
6545      _STRONG_EMPHASIS = "strongemphasis",
6546      _CHECKED = "checked",
6547      _SUBMENU = "submenu",
6548      _DISABLED = "disabled",
6549      _SELECTED = "selected",
6550      _HAS_SUBMENU = "hassubmenu",
6551      _CHECKED_DISABLED = "checked-disabled",
6552      _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
6553      _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
6554      _CHECKED_SELECTED = "checked-selected",
6555      _ONCLICK = "onclick",
6556      _CLASSNAME = "classname",
6557      _EMPTY_STRING = "",
6558      _OPTION = "OPTION",
6559      _OPTGROUP = "OPTGROUP",
6560      _LI_UPPERCASE = "LI",
6561      _HREF = "href",
6562      _SELECT = "SELECT",
6563      _DIV = "DIV",
6564      _START_HELP_TEXT = "<em class=\"helptext\">",
6565      _START_EM = "<em>",
6566      _END_EM = "</em>",
6567      _START_STRONG = "<strong>",
6568      _END_STRONG = "</strong>",
6569      _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
6570      _OBJ = "obj",
6571      _SCOPE = "scope",
6572      _NONE = "none",
6573      _VISIBLE = "visible",
6574      _SPACE = " ",
6575      _MENUITEM = "MenuItem",
6576      _CLICK = "click",
6577      _SHOW = "show",
6578      _HIDE = "hide",
6579      _LI_LOWERCASE = "li",
6580      _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
6581  
6582      EVENT_TYPES = [
6583      
6584          ["mouseOverEvent", "mouseover"],
6585          ["mouseOutEvent", "mouseout"],
6586          ["mouseDownEvent", "mousedown"],
6587          ["mouseUpEvent", "mouseup"],
6588          ["clickEvent", _CLICK],
6589          ["keyPressEvent", "keypress"],
6590          ["keyDownEvent", "keydown"],
6591          ["keyUpEvent", "keyup"],
6592          ["focusEvent", "focus"],
6593          ["blurEvent", "blur"],
6594          ["destroyEvent", "destroy"]
6595      
6596      ],
6597  
6598      TEXT_CONFIG = { 
6599          key: _TEXT, 
6600          value: _EMPTY_STRING, 
6601          validator: Lang.isString, 
6602          suppressEvent: true 
6603      }, 
6604  
6605      HELP_TEXT_CONFIG = { 
6606          key: _HELP_TEXT,
6607          supercedes: [_TEXT], 
6608          suppressEvent: true 
6609      },
6610  
6611      URL_CONFIG = { 
6612          key: _URL, 
6613          value: _HASH, 
6614          suppressEvent: true 
6615      }, 
6616  
6617      TARGET_CONFIG = { 
6618          key: _TARGET, 
6619          suppressEvent: true 
6620      }, 
6621  
6622      EMPHASIS_CONFIG = { 
6623          key: _EMPHASIS, 
6624          value: false, 
6625          validator: Lang.isBoolean, 
6626          suppressEvent: true, 
6627          supercedes: [_TEXT]
6628      }, 
6629  
6630      STRONG_EMPHASIS_CONFIG = { 
6631          key: _STRONG_EMPHASIS, 
6632          value: false, 
6633          validator: Lang.isBoolean, 
6634          suppressEvent: true,
6635          supercedes: [_TEXT]
6636      },
6637  
6638      CHECKED_CONFIG = { 
6639          key: _CHECKED, 
6640          value: false, 
6641          validator: Lang.isBoolean, 
6642          suppressEvent: true, 
6643          supercedes: [_DISABLED, _SELECTED]
6644      }, 
6645  
6646      SUBMENU_CONFIG = { 
6647          key: _SUBMENU,
6648          suppressEvent: true,
6649          supercedes: [_DISABLED, _SELECTED]
6650      },
6651  
6652      DISABLED_CONFIG = { 
6653          key: _DISABLED, 
6654          value: false, 
6655          validator: Lang.isBoolean, 
6656          suppressEvent: true,
6657          supercedes: [_TEXT, _SELECTED]
6658      },
6659  
6660      SELECTED_CONFIG = { 
6661          key: _SELECTED, 
6662          value: false, 
6663          validator: Lang.isBoolean, 
6664          suppressEvent: true
6665      },
6666  
6667      ONCLICK_CONFIG = { 
6668          key: _ONCLICK,
6669          suppressEvent: true
6670      },
6671  
6672      CLASS_NAME_CONFIG = { 
6673          key: _CLASSNAME, 
6674          value: null, 
6675          validator: Lang.isString,
6676          suppressEvent: true
6677      },
6678      
6679      KEY_LISTENER_CONFIG = {
6680          key: "keylistener", 
6681          value: null, 
6682          suppressEvent: true
6683      },
6684  
6685      m_oMenuItemTemplate = null,
6686  
6687      CLASS_NAMES = {};
6688  
6689  
6690  /**
6691  * @method getClassNameForState
6692  * @description Returns a class name for the specified prefix and state.  If the class name does not 
6693  * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
6694  * @private
6695  * @param {String} prefix String representing the prefix for the class name
6696  * @param {String} state String representing a state - "disabled," "checked," etc.
6697  */  
6698  var getClassNameForState = function (prefix, state) {
6699  
6700      var oClassNames = CLASS_NAMES[prefix];
6701      
6702      if (!oClassNames) {
6703          CLASS_NAMES[prefix] = {};
6704          oClassNames = CLASS_NAMES[prefix];
6705      }
6706  
6707  
6708      var sClassName = oClassNames[state];
6709  
6710      if (!sClassName) {
6711          sClassName = prefix + _HYPHEN + state;
6712          oClassNames[state] = sClassName;
6713      }
6714  
6715      return sClassName;
6716      
6717  };
6718  
6719  
6720  /**
6721  * @method addClassNameForState
6722  * @description Applies a class name to a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
6723  * that represents a MenuItem's state - "disabled," "checked," etc.
6724  * @private
6725  * @param {String} state String representing a state - "disabled," "checked," etc.
6726  */  
6727  var addClassNameForState = function (state) {
6728  
6729      Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6730      Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6731  
6732  };
6733  
6734  /**
6735  * @method removeClassNameForState
6736  * @description Removes a class name from a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
6737  * that represents a MenuItem's state - "disabled," "checked," etc.
6738  * @private
6739  * @param {String} state String representing a state - "disabled," "checked," etc.
6740  */  
6741  var removeClassNameForState = function (state) {
6742  
6743      Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
6744      Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
6745  
6746  };
6747  
6748  
6749  MenuItem.prototype = {
6750  
6751      /**
6752      * @property CSS_CLASS_NAME
6753      * @description String representing the CSS class(es) to be applied to the 
6754      * <code>&#60;li&#62;</code> element of the menu item.
6755      * @default "yuimenuitem"
6756      * @final
6757      * @type String
6758      */
6759      CSS_CLASS_NAME: "yuimenuitem",
6760  
6761  
6762      /**
6763      * @property CSS_LABEL_CLASS_NAME
6764      * @description String representing the CSS class(es) to be applied to the 
6765      * menu item's <code>&#60;a&#62;</code> element.
6766      * @default "yuimenuitemlabel"
6767      * @final
6768      * @type String
6769      */
6770      CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
6771  
6772  
6773      /**
6774      * @property SUBMENU_TYPE
6775      * @description Object representing the type of menu to instantiate and 
6776      * add when parsing the child nodes of the menu item's source HTML element.
6777      * @final
6778      * @type YAHOO.widget.Menu
6779      */
6780      SUBMENU_TYPE: null,
6781  
6782  
6783  
6784      // Private member variables
6785      
6786  
6787      /**
6788      * @property _oAnchor
6789      * @description Object reference to the menu item's 
6790      * <code>&#60;a&#62;</code> element.
6791      * @default null 
6792      * @private
6793      * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6794      * one-html.html#ID-48250443">HTMLAnchorElement</a>
6795      */
6796      _oAnchor: null,
6797      
6798      
6799      /**
6800      * @property _oHelpTextEM
6801      * @description Object reference to the menu item's help text 
6802      * <code>&#60;em&#62;</code> element.
6803      * @default null
6804      * @private
6805      * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6806      * one-html.html#ID-58190037">HTMLElement</a>
6807      */
6808      _oHelpTextEM: null,
6809      
6810      
6811      /**
6812      * @property _oSubmenu
6813      * @description Object reference to the menu item's submenu.
6814      * @default null
6815      * @private
6816      * @type YAHOO.widget.Menu
6817      */
6818      _oSubmenu: null,
6819  
6820  
6821      /** 
6822      * @property _oOnclickAttributeValue
6823      * @description Object reference to the menu item's current value for the 
6824      * "onclick" configuration attribute.
6825      * @default null
6826      * @private
6827      * @type Object
6828      */
6829      _oOnclickAttributeValue: null,
6830  
6831  
6832      /**
6833      * @property _sClassName
6834      * @description The current value of the "classname" configuration attribute.
6835      * @default null
6836      * @private
6837      * @type String
6838      */
6839      _sClassName: null,
6840  
6841  
6842  
6843      // Public properties
6844  
6845  
6846      /**
6847      * @property constructor
6848      * @description Object reference to the menu item's constructor function.
6849      * @default YAHOO.widget.MenuItem
6850      * @type YAHOO.widget.MenuItem
6851      */
6852      constructor: MenuItem,
6853  
6854  
6855      /**
6856      * @property index
6857      * @description Number indicating the ordinal position of the menu item in 
6858      * its group.
6859      * @default null
6860      * @type Number
6861      */
6862      index: null,
6863  
6864  
6865      /**
6866      * @property groupIndex
6867      * @description Number indicating the index of the group to which the menu 
6868      * item belongs.
6869      * @default null
6870      * @type Number
6871      */
6872      groupIndex: null,
6873  
6874  
6875      /**
6876      * @property parent
6877      * @description Object reference to the menu item's parent menu.
6878      * @default null
6879      * @type YAHOO.widget.Menu
6880      */
6881      parent: null,
6882  
6883  
6884      /**
6885      * @property element
6886      * @description Object reference to the menu item's 
6887      * <code>&#60;li&#62;</code> element.
6888      * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
6889      * -one-html.html#ID-74680021">HTMLLIElement</a>
6890      * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6891      * one-html.html#ID-74680021">HTMLLIElement</a>
6892      */
6893      element: null,
6894  
6895  
6896      /**
6897      * @property srcElement
6898      * @description Object reference to the HTML element (either 
6899      * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or 
6900      * <code>&#60;option&#62;</code>) used create the menu item.
6901      * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6902      * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
6903      * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
6904      * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6905      * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6906      * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
6907      * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
6908      * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
6909      * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
6910      * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
6911      */
6912      srcElement: null,
6913  
6914  
6915      /**
6916      * @property value
6917      * @description Object reference to the menu item's value.
6918      * @default null
6919      * @type Object
6920      */
6921      value: null,
6922  
6923  
6924      /**
6925      * @property browser
6926      * @deprecated Use YAHOO.env.ua
6927      * @description String representing the browser.
6928      * @type String
6929      */
6930      browser: Module.prototype.browser,
6931  
6932  
6933      /**
6934      * @property id
6935      * @description Id of the menu item's root <code>&#60;li&#62;</code> 
6936      * element.  This property should be set via the constructor using the 
6937      * configuration object literal.  If an id is not specified, then one will 
6938      * be created using the "generateId" method of the Dom utility.
6939      * @default null
6940      * @type String
6941      */
6942      id: null,
6943  
6944  
6945  
6946      // Events
6947  
6948  
6949      /**
6950      * @event destroyEvent
6951      * @description Fires when the menu item's <code>&#60;li&#62;</code> 
6952      * element is removed from its parent <code>&#60;ul&#62;</code> element.
6953      * @type YAHOO.util.CustomEvent
6954      */
6955  
6956  
6957      /**
6958      * @event mouseOverEvent
6959      * @description Fires when the mouse has entered the menu item.  Passes 
6960      * back the DOM Event object as an argument.
6961      * @type YAHOO.util.CustomEvent
6962      */
6963  
6964  
6965      /**
6966      * @event mouseOutEvent
6967      * @description Fires when the mouse has left the menu item.  Passes back 
6968      * the DOM Event object as an argument.
6969      * @type YAHOO.util.CustomEvent
6970      */
6971  
6972  
6973      /**
6974      * @event mouseDownEvent
6975      * @description Fires when the user mouses down on the menu item.  Passes 
6976      * back the DOM Event object as an argument.
6977      * @type YAHOO.util.CustomEvent
6978      */
6979  
6980  
6981      /**
6982      * @event mouseUpEvent
6983      * @description Fires when the user releases a mouse button while the mouse 
6984      * is over the menu item.  Passes back the DOM Event object as an argument.
6985      * @type YAHOO.util.CustomEvent
6986      */
6987  
6988  
6989      /**
6990      * @event clickEvent
6991      * @description Fires when the user clicks the on the menu item.  Passes 
6992      * back the DOM Event object as an argument.
6993      * @type YAHOO.util.CustomEvent
6994      */
6995  
6996  
6997      /**
6998      * @event keyPressEvent
6999      * @description Fires when the user presses an alphanumeric key when the 
7000      * menu item has focus.  Passes back the DOM Event object as an argument.
7001      * @type YAHOO.util.CustomEvent
7002      */
7003  
7004  
7005      /**
7006      * @event keyDownEvent
7007      * @description Fires when the user presses a key when the menu item has 
7008      * focus.  Passes back the DOM Event object as an argument.
7009      * @type YAHOO.util.CustomEvent
7010      */
7011  
7012  
7013      /**
7014      * @event keyUpEvent
7015      * @description Fires when the user releases a key when the menu item has 
7016      * focus.  Passes back the DOM Event object as an argument.
7017      * @type YAHOO.util.CustomEvent
7018      */
7019  
7020  
7021      /**
7022      * @event focusEvent
7023      * @description Fires when the menu item receives focus.
7024      * @type YAHOO.util.CustomEvent
7025      */
7026  
7027  
7028      /**
7029      * @event blurEvent
7030      * @description Fires when the menu item loses the input focus.
7031      * @type YAHOO.util.CustomEvent
7032      */
7033  
7034  
7035      /**
7036      * @method init
7037      * @description The MenuItem class's initialization method. This method is 
7038      * automatically called by the constructor, and sets up all DOM references 
7039      * for pre-existing markup, and creates required markup if it is not 
7040      * already present.
7041      * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
7042      * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7043      * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
7044      * the <code>&#60;li&#62;</code> element of the menu item.
7045      * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7046      * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
7047      * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
7048      * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
7049      * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
7050      * specifying the <code>&#60;option&#62;</code> element of the menu item.
7051      * @param {Object} p_oConfig Optional. Object literal specifying the 
7052      * configuration for the menu item. See configuration class documentation 
7053      * for more details.
7054      */
7055      init: function (p_oObject, p_oConfig) {
7056  
7057  
7058          if (!this.SUBMENU_TYPE) {
7059      
7060              this.SUBMENU_TYPE = Menu;
7061      
7062          }
7063  
7064  
7065          // Create the config object
7066  
7067          this.cfg = new YAHOO.util.Config(this);
7068  
7069          this.initDefaultConfig();
7070  
7071          var oConfig = this.cfg,
7072              sURL = _HASH,
7073              oCustomEvent,
7074              aEventData,
7075              oAnchor,
7076              sTarget,
7077              sText,
7078              sId,
7079              i;
7080  
7081  
7082          if (Lang.isString(p_oObject)) {
7083  
7084              this._createRootNodeStructure();
7085  
7086              oConfig.queueProperty(_TEXT, p_oObject);
7087  
7088          }
7089          else if (p_oObject && p_oObject.tagName) {
7090  
7091              switch(p_oObject.tagName.toUpperCase()) {
7092  
7093                  case _OPTION:
7094  
7095                      this._createRootNodeStructure();
7096  
7097                      oConfig.queueProperty(_TEXT, p_oObject.text);
7098                      oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7099  
7100                      this.value = p_oObject.value;
7101  
7102                      this.srcElement = p_oObject;
7103  
7104                  break;
7105  
7106                  case _OPTGROUP:
7107  
7108                      this._createRootNodeStructure();
7109  
7110                      oConfig.queueProperty(_TEXT, p_oObject.label);
7111                      oConfig.queueProperty(_DISABLED, p_oObject.disabled);
7112  
7113                      this.srcElement = p_oObject;
7114  
7115                      this._initSubTree();
7116  
7117                  break;
7118  
7119                  case _LI_UPPERCASE:
7120  
7121                      // Get the anchor node (if it exists)
7122                      
7123                      oAnchor = Dom.getFirstChild(p_oObject);
7124  
7125  
7126                      // Capture the "text" and/or the "URL"
7127  
7128                      if (oAnchor) {
7129  
7130                          sURL = oAnchor.getAttribute(_HREF, 2);
7131                          sTarget = oAnchor.getAttribute(_TARGET);
7132  
7133                          sText = oAnchor.innerHTML;
7134  
7135                      }
7136  
7137                      this.srcElement = p_oObject;
7138                      this.element = p_oObject;
7139                      this._oAnchor = oAnchor;
7140  
7141                      /*
7142                          Set these properties silently to sync up the 
7143                          configuration object without making changes to the 
7144                          element's DOM
7145                      */ 
7146  
7147                      oConfig.setProperty(_TEXT, sText, true);
7148                      oConfig.setProperty(_URL, sURL, true);
7149                      oConfig.setProperty(_TARGET, sTarget, true);
7150  
7151                      this._initSubTree();
7152  
7153                  break;
7154  
7155              }            
7156  
7157          }
7158  
7159  
7160          if (this.element) {
7161  
7162              sId = (this.srcElement || this.element).id;
7163  
7164              if (!sId) {
7165  
7166                  sId = this.id || Dom.generateId();
7167  
7168                  this.element.id = sId;
7169  
7170              }
7171  
7172              this.id = sId;
7173  
7174  
7175              Dom.addClass(this.element, this.CSS_CLASS_NAME);
7176              Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
7177  
7178  
7179              i = EVENT_TYPES.length - 1;
7180  
7181              do {
7182  
7183                  aEventData = EVENT_TYPES[i];
7184  
7185                  oCustomEvent = this.createEvent(aEventData[1]);
7186                  oCustomEvent.signature = CustomEvent.LIST;
7187                  
7188                  this[aEventData[0]] = oCustomEvent;
7189  
7190              }
7191              while (i--);
7192  
7193  
7194              if (p_oConfig) {
7195      
7196                  oConfig.applyConfig(p_oConfig);
7197      
7198              }        
7199  
7200              oConfig.fireQueue();
7201  
7202          }
7203  
7204      },
7205  
7206  
7207  
7208      // Private methods
7209  
7210      /**
7211      * @method _createRootNodeStructure
7212      * @description Creates the core DOM structure for the menu item.
7213      * @private
7214      */
7215      _createRootNodeStructure: function () {
7216  
7217          var oElement,
7218              oAnchor;
7219  
7220          if (!m_oMenuItemTemplate) {
7221  
7222              m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
7223              m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
7224  
7225          }
7226  
7227          oElement = m_oMenuItemTemplate.cloneNode(true);
7228          oElement.className = this.CSS_CLASS_NAME;
7229  
7230          oAnchor = oElement.firstChild;
7231          oAnchor.className = this.CSS_LABEL_CLASS_NAME;
7232  
7233          this.element = oElement;
7234          this._oAnchor = oAnchor;
7235  
7236      },
7237  
7238  
7239      /**
7240      * @method _initSubTree
7241      * @description Iterates the source element's childNodes collection and uses 
7242      * the child nodes to instantiate other menus.
7243      * @private
7244      */
7245      _initSubTree: function () {
7246  
7247          var oSrcEl = this.srcElement,
7248              oConfig = this.cfg,
7249              oNode,
7250              aOptions,
7251              nOptions,
7252              oMenu,
7253              n;
7254  
7255  
7256          if (oSrcEl.childNodes.length > 0) {
7257  
7258              if (this.parent.lazyLoad && this.parent.srcElement && 
7259                  this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
7260  
7261                  oConfig.setProperty(
7262                          _SUBMENU, 
7263                          { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
7264                      );
7265  
7266              }
7267              else {
7268  
7269                  oNode = oSrcEl.firstChild;
7270                  aOptions = [];
7271      
7272                  do {
7273      
7274                      if (oNode && oNode.tagName) {
7275      
7276                          switch(oNode.tagName.toUpperCase()) {
7277                  
7278                              case _DIV:
7279                  
7280                                  oConfig.setProperty(_SUBMENU, oNode);
7281                  
7282                              break;
7283           
7284                              case _OPTION:
7285          
7286                                  aOptions[aOptions.length] = oNode;
7287          
7288                              break;
7289                 
7290                          }
7291                      
7292                      }
7293                  
7294                  }        
7295                  while((oNode = oNode.nextSibling));
7296      
7297      
7298                  nOptions = aOptions.length;
7299      
7300                  if (nOptions > 0) {
7301      
7302                      oMenu = new this.SUBMENU_TYPE(Dom.generateId());
7303                      
7304                      oConfig.setProperty(_SUBMENU, oMenu);
7305      
7306                      for(n=0; n<nOptions; n++) {
7307          
7308                          oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
7309          
7310                      }
7311          
7312                  }
7313              
7314              }
7315  
7316          }
7317  
7318      },
7319  
7320  
7321  
7322      // Event handlers for configuration properties
7323  
7324  
7325      /**
7326      * @method configText
7327      * @description Event handler for when the "text" configuration property of 
7328      * the menu item changes.
7329      * @param {String} p_sType String representing the name of the event that 
7330      * was fired.
7331      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7332      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7333      * that fired the event.
7334      */
7335      configText: function (p_sType, p_aArgs, p_oItem) {
7336  
7337          var sText = p_aArgs[0],
7338              oConfig = this.cfg,
7339              oAnchor = this._oAnchor,
7340              sHelpText = oConfig.getProperty(_HELP_TEXT),
7341              sHelpTextHTML = _EMPTY_STRING,
7342              sEmphasisStartTag = _EMPTY_STRING,
7343              sEmphasisEndTag = _EMPTY_STRING;
7344  
7345  
7346          if (sText) {
7347  
7348  
7349              if (sHelpText) {
7350                      
7351                  sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
7352              
7353              }
7354  
7355  
7356              if (oConfig.getProperty(_EMPHASIS)) {
7357  
7358                  sEmphasisStartTag = _START_EM;
7359                  sEmphasisEndTag = _END_EM;
7360  
7361              }
7362  
7363  
7364              if (oConfig.getProperty(_STRONG_EMPHASIS)) {
7365  
7366                  sEmphasisStartTag = _START_STRONG;
7367                  sEmphasisEndTag = _END_STRONG;
7368              
7369              }
7370  
7371  
7372              oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
7373  
7374          }
7375  
7376      },
7377  
7378  
7379      /**
7380      * @method configHelpText
7381      * @description Event handler for when the "helptext" configuration property 
7382      * of the menu item changes.
7383      * @param {String} p_sType String representing the name of the event that 
7384      * was fired.
7385      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7386      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7387      * that fired the event.
7388      */    
7389      configHelpText: function (p_sType, p_aArgs, p_oItem) {
7390  
7391          this.cfg.refireEvent(_TEXT);
7392  
7393      },
7394  
7395  
7396      /**
7397      * @method configURL
7398      * @description Event handler for when the "url" configuration property of 
7399      * the menu item changes.
7400      * @param {String} p_sType String representing the name of the event that 
7401      * was fired.
7402      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7403      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7404      * that fired the event.
7405      */    
7406      configURL: function (p_sType, p_aArgs, p_oItem) {
7407  
7408          var sURL = p_aArgs[0];
7409  
7410          if (!sURL) {
7411  
7412              sURL = _HASH;
7413  
7414          }
7415  
7416          var oAnchor = this._oAnchor;
7417  
7418          if (UA.opera) {
7419  
7420              oAnchor.removeAttribute(_HREF);
7421          
7422          }
7423  
7424          oAnchor.setAttribute(_HREF, sURL);
7425  
7426      },
7427  
7428  
7429      /**
7430      * @method configTarget
7431      * @description Event handler for when the "target" configuration property 
7432      * of the menu item changes.  
7433      * @param {String} p_sType String representing the name of the event that 
7434      * was fired.
7435      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7436      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7437      * that fired the event.
7438      */    
7439      configTarget: function (p_sType, p_aArgs, p_oItem) {
7440  
7441          var sTarget = p_aArgs[0],
7442              oAnchor = this._oAnchor;
7443  
7444          if (sTarget && sTarget.length > 0) {
7445  
7446              oAnchor.setAttribute(_TARGET, sTarget);
7447  
7448          }
7449          else {
7450  
7451              oAnchor.removeAttribute(_TARGET);
7452          
7453          }
7454  
7455      },
7456  
7457  
7458      /**
7459      * @method configEmphasis
7460      * @description Event handler for when the "emphasis" configuration property
7461      * of the menu item changes.
7462      * @param {String} p_sType String representing the name of the event that 
7463      * was fired.
7464      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7465      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7466      * that fired the event.
7467      */    
7468      configEmphasis: function (p_sType, p_aArgs, p_oItem) {
7469  
7470          var bEmphasis = p_aArgs[0],
7471              oConfig = this.cfg;
7472  
7473  
7474          if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
7475  
7476              oConfig.setProperty(_STRONG_EMPHASIS, false);
7477  
7478          }
7479  
7480  
7481          oConfig.refireEvent(_TEXT);
7482  
7483      },
7484  
7485  
7486      /**
7487      * @method configStrongEmphasis
7488      * @description Event handler for when the "strongemphasis" configuration 
7489      * property of the menu item changes.
7490      * @param {String} p_sType String representing the name of the event that 
7491      * was fired.
7492      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7493      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7494      * that fired the event.
7495      */    
7496      configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
7497  
7498          var bStrongEmphasis = p_aArgs[0],
7499              oConfig = this.cfg;
7500  
7501  
7502          if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
7503  
7504              oConfig.setProperty(_EMPHASIS, false);
7505  
7506          }
7507  
7508          oConfig.refireEvent(_TEXT);
7509  
7510      },
7511  
7512  
7513      /**
7514      * @method configChecked
7515      * @description Event handler for when the "checked" configuration property 
7516      * of the menu item changes. 
7517      * @param {String} p_sType String representing the name of the event that 
7518      * was fired.
7519      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7520      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7521      * that fired the event.
7522      */    
7523      configChecked: function (p_sType, p_aArgs, p_oItem) {
7524  
7525          var bChecked = p_aArgs[0],
7526              oConfig = this.cfg;
7527  
7528  
7529          if (bChecked) {
7530  
7531              addClassNameForState.call(this, _CHECKED);
7532  
7533          }
7534          else {
7535  
7536              removeClassNameForState.call(this, _CHECKED);
7537          }
7538  
7539  
7540          oConfig.refireEvent(_TEXT);
7541  
7542  
7543          if (oConfig.getProperty(_DISABLED)) {
7544  
7545              oConfig.refireEvent(_DISABLED);
7546  
7547          }
7548  
7549  
7550          if (oConfig.getProperty(_SELECTED)) {
7551  
7552              oConfig.refireEvent(_SELECTED);
7553  
7554          }
7555  
7556      },
7557  
7558  
7559  
7560      /**
7561      * @method configDisabled
7562      * @description Event handler for when the "disabled" configuration property 
7563      * of the menu item changes. 
7564      * @param {String} p_sType String representing the name of the event that 
7565      * was fired.
7566      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7567      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7568      * that fired the event.
7569      */    
7570      configDisabled: function (p_sType, p_aArgs, p_oItem) {
7571  
7572          var bDisabled = p_aArgs[0],
7573              oConfig = this.cfg,
7574              oSubmenu = oConfig.getProperty(_SUBMENU),
7575              bChecked = oConfig.getProperty(_CHECKED);
7576  
7577  
7578          if (bDisabled) {
7579  
7580              if (oConfig.getProperty(_SELECTED)) {
7581  
7582                  oConfig.setProperty(_SELECTED, false);
7583  
7584              }
7585  
7586  
7587              addClassNameForState.call(this, _DISABLED);
7588  
7589  
7590              if (oSubmenu) {
7591  
7592                  addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7593              
7594              }
7595              
7596  
7597              if (bChecked) {
7598  
7599                  addClassNameForState.call(this, _CHECKED_DISABLED);
7600  
7601              }
7602  
7603          }
7604          else {
7605  
7606              removeClassNameForState.call(this, _DISABLED);
7607  
7608  
7609              if (oSubmenu) {
7610  
7611                  removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
7612              
7613              }
7614              
7615  
7616              if (bChecked) {
7617  
7618                  removeClassNameForState.call(this, _CHECKED_DISABLED);
7619  
7620              }
7621  
7622          }
7623  
7624      },
7625  
7626  
7627      /**
7628      * @method configSelected
7629      * @description Event handler for when the "selected" configuration property 
7630      * of the menu item changes. 
7631      * @param {String} p_sType String representing the name of the event that 
7632      * was fired.
7633      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7634      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7635      * that fired the event.
7636      */    
7637      configSelected: function (p_sType, p_aArgs, p_oItem) {
7638  
7639          var oConfig = this.cfg,
7640              oAnchor = this._oAnchor,
7641              
7642              bSelected = p_aArgs[0],
7643              bChecked = oConfig.getProperty(_CHECKED),
7644              oSubmenu = oConfig.getProperty(_SUBMENU);
7645  
7646  
7647          if (UA.opera) {
7648  
7649              oAnchor.blur();
7650          
7651          }
7652  
7653  
7654          if (bSelected && !oConfig.getProperty(_DISABLED)) {
7655  
7656              addClassNameForState.call(this, _SELECTED);
7657  
7658  
7659              if (oSubmenu) {
7660  
7661                  addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7662              
7663              }
7664  
7665  
7666              if (bChecked) {
7667  
7668                  addClassNameForState.call(this, _CHECKED_SELECTED);
7669  
7670              }
7671  
7672          }
7673          else {
7674  
7675              removeClassNameForState.call(this, _SELECTED);
7676  
7677  
7678              if (oSubmenu) {
7679  
7680                  removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
7681              
7682              }
7683  
7684  
7685              if (bChecked) {
7686  
7687                  removeClassNameForState.call(this, _CHECKED_SELECTED);
7688  
7689              }
7690  
7691          }
7692  
7693  
7694          if (this.hasFocus() && UA.opera) {
7695          
7696              oAnchor.focus();
7697          
7698          }
7699  
7700      },
7701  
7702  
7703      /**
7704      * @method _onSubmenuBeforeHide
7705      * @description "beforehide" Custom Event handler for a submenu.
7706      * @private
7707      * @param {String} p_sType String representing the name of the event that 
7708      * was fired.
7709      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7710      */
7711      _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
7712  
7713          var oItem = this.parent,
7714              oMenu;
7715  
7716          function onHide() {
7717  
7718              oItem._oAnchor.blur();
7719              oMenu.beforeHideEvent.unsubscribe(onHide);
7720          
7721          }
7722  
7723  
7724          if (oItem.hasFocus()) {
7725  
7726              oMenu = oItem.parent;
7727  
7728              oMenu.beforeHideEvent.subscribe(onHide);
7729          
7730          }
7731      
7732      },
7733  
7734  
7735      /**
7736      * @method configSubmenu
7737      * @description Event handler for when the "submenu" configuration property 
7738      * of the menu item changes. 
7739      * @param {String} p_sType String representing the name of the event that 
7740      * was fired.
7741      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7742      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7743      * that fired the event.
7744      */
7745      configSubmenu: function (p_sType, p_aArgs, p_oItem) {
7746  
7747          var oSubmenu = p_aArgs[0],
7748              oConfig = this.cfg,
7749              bLazyLoad = this.parent && this.parent.lazyLoad,
7750              oMenu,
7751              sSubmenuId,
7752              oSubmenuConfig;
7753  
7754  
7755          if (oSubmenu) {
7756  
7757              if (oSubmenu instanceof Menu) {
7758  
7759                  oMenu = oSubmenu;
7760                  oMenu.parent = this;
7761                  oMenu.lazyLoad = bLazyLoad;
7762  
7763              }
7764              else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
7765  
7766                  sSubmenuId = oSubmenu.id;
7767                  oSubmenuConfig = oSubmenu;
7768  
7769                  oSubmenuConfig.lazyload = bLazyLoad;
7770                  oSubmenuConfig.parent = this;
7771  
7772                  oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
7773  
7774  
7775                  // Set the value of the property to the Menu instance
7776  
7777                  oConfig.setProperty(_SUBMENU, oMenu, true);
7778  
7779              }
7780              else {
7781  
7782                  oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
7783  
7784  
7785                  // Set the value of the property to the Menu instance
7786                  
7787                  oConfig.setProperty(_SUBMENU, oMenu, true);
7788  
7789              }
7790  
7791  
7792              if (oMenu) {
7793  
7794                  oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
7795  
7796                  addClassNameForState.call(this, _HAS_SUBMENU);
7797  
7798  
7799                  if (oConfig.getProperty(_URL) === _HASH) {
7800                  
7801                      oConfig.setProperty(_URL, (_HASH + oMenu.id));
7802                  
7803                  }
7804  
7805  
7806                  this._oSubmenu = oMenu;
7807  
7808  
7809                  if (UA.opera) {
7810                  
7811                      oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);               
7812                  
7813                  }
7814              
7815              }
7816  
7817          }
7818          else {
7819  
7820              removeClassNameForState.call(this, _HAS_SUBMENU);
7821  
7822              if (this._oSubmenu) {
7823  
7824                  this._oSubmenu.destroy();
7825  
7826              }
7827  
7828          }
7829  
7830  
7831          if (oConfig.getProperty(_DISABLED)) {
7832  
7833              oConfig.refireEvent(_DISABLED);
7834  
7835          }
7836  
7837  
7838          if (oConfig.getProperty(_SELECTED)) {
7839  
7840              oConfig.refireEvent(_SELECTED);
7841  
7842          }
7843  
7844      },
7845  
7846  
7847      /**
7848      * @method configOnClick
7849      * @description Event handler for when the "onclick" configuration property 
7850      * of the menu item changes. 
7851      * @param {String} p_sType String representing the name of the event that 
7852      * was fired.
7853      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7854      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7855      * that fired the event.
7856      */
7857      configOnClick: function (p_sType, p_aArgs, p_oItem) {
7858  
7859          var oObject = p_aArgs[0];
7860  
7861          /*
7862              Remove any existing listeners if a "click" event handler has 
7863              already been specified.
7864          */
7865  
7866          if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
7867  
7868              this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn, 
7869                                  this._oOnclickAttributeValue.obj);
7870  
7871              this._oOnclickAttributeValue = null;
7872  
7873          }
7874  
7875  
7876          if (!this._oOnclickAttributeValue && Lang.isObject(oObject) && 
7877              Lang.isFunction(oObject.fn)) {
7878              
7879              this.clickEvent.subscribe(oObject.fn, 
7880                  ((_OBJ in oObject) ? oObject.obj : this), 
7881                  ((_SCOPE in oObject) ? oObject.scope : null) );
7882  
7883              this._oOnclickAttributeValue = oObject;
7884  
7885          }
7886      
7887      },
7888  
7889  
7890      /**
7891      * @method configClassName
7892      * @description Event handler for when the "classname" configuration 
7893      * property of a menu item changes.
7894      * @param {String} p_sType String representing the name of the event that 
7895      * was fired.
7896      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
7897      * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
7898      * that fired the event.
7899      */
7900      configClassName: function (p_sType, p_aArgs, p_oItem) {
7901      
7902          var sClassName = p_aArgs[0];
7903      
7904          if (this._sClassName) {
7905      
7906              Dom.removeClass(this.element, this._sClassName);
7907      
7908          }
7909      
7910          Dom.addClass(this.element, sClassName);
7911          this._sClassName = sClassName;
7912      
7913      },
7914  
7915  
7916      /**
7917      * @method _dispatchClickEvent
7918      * @description Dispatches a DOM "click" event to the anchor element of a 
7919      * MenuItem instance.
7920      * @private    
7921      */
7922      _dispatchClickEvent: function () {
7923  
7924          var oMenuItem = this,
7925              oAnchor;
7926  
7927          if (!oMenuItem.cfg.getProperty(_DISABLED)) {
7928              oAnchor = Dom.getFirstChild(oMenuItem.element);
7929  
7930              //    Dispatch a "click" event to the MenuItem's anchor so that its
7931              //    "click" event handlers will get called in response to the user 
7932              //    pressing the keyboard shortcut defined by the "keylistener"
7933              //    configuration property.
7934  
7935              this._dispatchDOMClick(oAnchor);
7936          }
7937      },
7938  
7939      /**
7940       * Utility method to dispatch a DOM click event on the HTMLElement passed in
7941       *
7942       * @method _dispatchDOMClick
7943       * @protected
7944       * @param {HTMLElement} el
7945       */    
7946      _dispatchDOMClick : function(el) {
7947          var oEvent;
7948  
7949          // Choose the standards path for IE9
7950          if (UA.ie && UA.ie < 9) {
7951              el.fireEvent(_ONCLICK);
7952          } else {
7953              if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
7954                  oEvent = document.createEvent("HTMLEvents");
7955                  oEvent.initEvent(_CLICK, true, true);
7956              } else {
7957                  oEvent = document.createEvent("MouseEvents");
7958                  oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
7959              }
7960              el.dispatchEvent(oEvent);
7961          }
7962      },
7963  
7964      /**
7965      * @method _createKeyListener
7966      * @description "show" event handler for a Menu instance - responsible for 
7967      * setting up the KeyListener instance for a MenuItem.
7968      * @private    
7969      * @param {String} type String representing the name of the event that 
7970      * was fired.
7971      * @param {Array} args Array of arguments sent when the event was fired.
7972      * @param {Array} keyData Array of arguments sent when the event was fired.
7973      */
7974      _createKeyListener: function (type, args, keyData) {
7975  
7976          var oMenuItem = this,
7977              oMenu = oMenuItem.parent;
7978  
7979          var oKeyListener = new YAHOO.util.KeyListener(
7980                                          oMenu.element.ownerDocument, 
7981                                          keyData, 
7982                                          {
7983                                              fn: oMenuItem._dispatchClickEvent, 
7984                                              scope: oMenuItem, 
7985                                              correctScope: true });
7986  
7987  
7988          if (oMenu.cfg.getProperty(_VISIBLE)) {
7989              oKeyListener.enable();
7990          }
7991  
7992  
7993          oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
7994          oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
7995          
7996          oMenuItem._keyListener = oKeyListener;
7997          
7998          oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
7999          
8000      },
8001  
8002  
8003      /**
8004      * @method configKeyListener
8005      * @description Event handler for when the "keylistener" configuration 
8006      * property of a menu item changes.
8007      * @param {String} p_sType String representing the name of the event that 
8008      * was fired.
8009      * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8010      */
8011      configKeyListener: function (p_sType, p_aArgs) {
8012  
8013          var oKeyData = p_aArgs[0],
8014              oMenuItem = this,
8015              oMenu = oMenuItem.parent;
8016  
8017          if (oMenuItem._keyData) {
8018  
8019              //    Unsubscribe from the "show" event in case the keylistener 
8020              //    config was changed before the Menu was ever made visible.
8021  
8022              oMenu.unsubscribe(_SHOW, 
8023                      oMenuItem._createKeyListener, oMenuItem._keyData);
8024  
8025              oMenuItem._keyData = null;                    
8026                      
8027          }
8028  
8029  
8030          //    Tear down for the previous value of the "keylistener" property
8031  
8032          if (oMenuItem._keyListener) {
8033  
8034              oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
8035              oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
8036  
8037              oMenuItem._keyListener.disable();
8038              oMenuItem._keyListener = null;
8039  
8040          }
8041  
8042  
8043          if (oKeyData) {
8044      
8045              oMenuItem._keyData = oKeyData;
8046  
8047              //    Defer the creation of the KeyListener instance until the 
8048              //    parent Menu is visible.  This is necessary since the 
8049              //    KeyListener instance needs to be bound to the document the 
8050              //    Menu has been rendered into.  Deferring creation of the 
8051              //    KeyListener instance also improves performance.
8052  
8053              oMenu.subscribe(_SHOW, oMenuItem._createKeyListener, 
8054                  oKeyData, oMenuItem);
8055          }
8056      
8057      },
8058  
8059  
8060      // Public methods
8061  
8062  
8063      /**
8064      * @method initDefaultConfig
8065      * @description Initializes an item's configurable properties.
8066      */
8067      initDefaultConfig : function () {
8068  
8069          var oConfig = this.cfg;
8070  
8071  
8072          // Define the configuration attributes
8073  
8074          /**
8075          * @config text
8076          * @description String or markup specifying the text label for the menu item.  
8077          * When building a menu from existing HTML the value of this property
8078          * will be interpreted from the menu's markup. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8079          * @default ""
8080          * @type HTML
8081          */
8082          oConfig.addProperty(
8083              TEXT_CONFIG.key, 
8084              { 
8085                  handler: this.configText, 
8086                  value: TEXT_CONFIG.value, 
8087                  validator: TEXT_CONFIG.validator, 
8088                  suppressEvent: TEXT_CONFIG.suppressEvent 
8089              }
8090          );
8091          
8092  
8093          /**
8094          * @config helptext
8095          * @description String or markup specifying additional instructional text to 
8096          * accompany the text for the menu item. The helptext is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8097          * @deprecated Use "text" configuration property to add help text markup.  
8098          * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em 
8099          * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
8100          * @default null
8101          * @type HTML|<a href="http://www.w3.org/TR/
8102          * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8103          * HTMLElement</a>
8104          */
8105          oConfig.addProperty(
8106              HELP_TEXT_CONFIG.key,
8107              {
8108                  handler: this.configHelpText, 
8109                  supercedes: HELP_TEXT_CONFIG.supercedes,
8110                  suppressEvent: HELP_TEXT_CONFIG.suppressEvent 
8111              }
8112          );
8113  
8114  
8115          /**
8116          * @config url
8117          * @description String specifying the URL for the menu item's anchor's 
8118          * "href" attribute.  When building a menu from existing HTML the value 
8119          * of this property will be interpreted from the menu's markup. Markup for the menu item content. The url is inserted into the DOM as an attribute value, and should be escaped by the implementor if coming from an external source.
8120          * @default "#"
8121          * @type String
8122          */        
8123          oConfig.addProperty(
8124              URL_CONFIG.key, 
8125              {
8126                  handler: this.configURL, 
8127                  value: URL_CONFIG.value, 
8128                  suppressEvent: URL_CONFIG.suppressEvent
8129              }
8130          );
8131  
8132  
8133          /**
8134          * @config target
8135          * @description String specifying the value for the "target" attribute 
8136          * of the menu item's anchor element. <strong>Specifying a target will 
8137          * require the user to click directly on the menu item's anchor node in
8138          * order to cause the browser to navigate to the specified URL.</strong> 
8139          * When building a menu from existing HTML the value of this property 
8140          * will be interpreted from the menu's markup. The target is inserted into the DOM as an attribute value, and should be escaped by the implementor if coming from an external source.
8141          * @default null
8142          * @type String
8143          */        
8144          oConfig.addProperty(
8145              TARGET_CONFIG.key, 
8146              {
8147                  handler: this.configTarget, 
8148                  suppressEvent: TARGET_CONFIG.suppressEvent
8149              }
8150          );
8151  
8152  
8153          /**
8154          * @config emphasis
8155          * @description Boolean indicating if the text of the menu item will be 
8156          * rendered with emphasis.
8157          * @deprecated Use the "text" configuration property to add emphasis.  
8158          * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some 
8159          * Text&#60;/em&#62;");</code>
8160          * @default false
8161          * @type Boolean
8162          */
8163          oConfig.addProperty(
8164              EMPHASIS_CONFIG.key, 
8165              { 
8166                  handler: this.configEmphasis, 
8167                  value: EMPHASIS_CONFIG.value, 
8168                  validator: EMPHASIS_CONFIG.validator, 
8169                  suppressEvent: EMPHASIS_CONFIG.suppressEvent,
8170                  supercedes: EMPHASIS_CONFIG.supercedes
8171              }
8172          );
8173  
8174  
8175          /**
8176          * @config strongemphasis
8177          * @description Boolean indicating if the text of the menu item will be 
8178          * rendered with strong emphasis.
8179          * @deprecated Use the "text" configuration property to add strong emphasis.  
8180          * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62; 
8181          * Some Text&#60;/strong&#62;");</code>
8182          * @default false
8183          * @type Boolean
8184          */
8185          oConfig.addProperty(
8186              STRONG_EMPHASIS_CONFIG.key,
8187              {
8188                  handler: this.configStrongEmphasis,
8189                  value: STRONG_EMPHASIS_CONFIG.value,
8190                  validator: STRONG_EMPHASIS_CONFIG.validator,
8191                  suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
8192                  supercedes: STRONG_EMPHASIS_CONFIG.supercedes
8193              }
8194          );
8195  
8196  
8197          /**
8198          * @config checked
8199          * @description Boolean indicating if the menu item should be rendered 
8200          * with a checkmark.
8201          * @default false
8202          * @type Boolean
8203          */
8204          oConfig.addProperty(
8205              CHECKED_CONFIG.key, 
8206              {
8207                  handler: this.configChecked, 
8208                  value: CHECKED_CONFIG.value, 
8209                  validator: CHECKED_CONFIG.validator, 
8210                  suppressEvent: CHECKED_CONFIG.suppressEvent,
8211                  supercedes: CHECKED_CONFIG.supercedes
8212              } 
8213          );
8214  
8215  
8216          /**
8217          * @config disabled
8218          * @description Boolean indicating if the menu item should be disabled.  
8219          * (Disabled menu items are  dimmed and will not respond to user input 
8220          * or fire events.)
8221          * @default false
8222          * @type Boolean
8223          */
8224          oConfig.addProperty(
8225              DISABLED_CONFIG.key,
8226              {
8227                  handler: this.configDisabled,
8228                  value: DISABLED_CONFIG.value,
8229                  validator: DISABLED_CONFIG.validator,
8230                  suppressEvent: DISABLED_CONFIG.suppressEvent
8231              }
8232          );
8233  
8234  
8235          /**
8236          * @config selected
8237          * @description Boolean indicating if the menu item should 
8238          * be highlighted.
8239          * @default false
8240          * @type Boolean
8241          */
8242          oConfig.addProperty(
8243              SELECTED_CONFIG.key,
8244              {
8245                  handler: this.configSelected,
8246                  value: SELECTED_CONFIG.value,
8247                  validator: SELECTED_CONFIG.validator,
8248                  suppressEvent: SELECTED_CONFIG.suppressEvent
8249              }
8250          );
8251  
8252  
8253          /**
8254          * @config submenu
8255          * @description Object specifying the submenu to be appended to the 
8256          * menu item.  The value can be one of the following: <ul><li>Object 
8257          * specifying a Menu instance.</li><li>Object literal specifying the
8258          * menu to be created.  Format: <code>{ id: [menu id], itemdata: 
8259          * [<a href="YAHOO.widget.Menu.html#itemData">array of values for 
8260          * items</a>] }</code>.</li><li>String specifying the id attribute 
8261          * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
8262          * Object specifying the <code>&#60;div&#62;</code> element of the 
8263          * menu.</li></ul>
8264          * @default null
8265          * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
8266          * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
8267          * HTMLElement</a>
8268          */
8269          oConfig.addProperty(
8270              SUBMENU_CONFIG.key, 
8271              {
8272                  handler: this.configSubmenu, 
8273                  supercedes: SUBMENU_CONFIG.supercedes,
8274                  suppressEvent: SUBMENU_CONFIG.suppressEvent
8275              }
8276          );
8277  
8278  
8279          /**
8280          * @config onclick
8281          * @description Object literal representing the code to be executed when 
8282          * the item is clicked.  Format:<br> <code> {<br> 
8283          * <strong>fn:</strong> Function,   &#47;&#47; The handler to call when 
8284          * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An 
8285          * object to  pass back to the handler.<br> <strong>scope:</strong> 
8286          * Object &#47;&#47; The object to use for the scope of the handler.
8287          * <br> } </code>
8288          * @type Object
8289          * @default null
8290          */
8291          oConfig.addProperty(
8292              ONCLICK_CONFIG.key, 
8293              {
8294                  handler: this.configOnClick, 
8295                  suppressEvent: ONCLICK_CONFIG.suppressEvent 
8296              }
8297          );
8298  
8299  
8300          /**
8301          * @config classname
8302          * @description CSS class to be applied to the menu item's root 
8303          * <code>&#60;li&#62;</code> element.  The specified class(es) are 
8304          * appended in addition to the default class as specified by the menu 
8305          * item's CSS_CLASS_NAME constant.
8306          * @default null
8307          * @type String
8308          */
8309          oConfig.addProperty(
8310              CLASS_NAME_CONFIG.key, 
8311              { 
8312                  handler: this.configClassName,
8313                  value: CLASS_NAME_CONFIG.value, 
8314                  validator: CLASS_NAME_CONFIG.validator,
8315                  suppressEvent: CLASS_NAME_CONFIG.suppressEvent 
8316              }
8317          );
8318  
8319  
8320          /**
8321          * @config keylistener
8322          * @description Object literal representing the key(s) that can be used 
8323          * to trigger the MenuItem's "click" event.  Possible attributes are 
8324          * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int 
8325          * or an array of ints representing keycodes).
8326          * @default null
8327          * @type Object
8328          */
8329          oConfig.addProperty(
8330              KEY_LISTENER_CONFIG.key, 
8331              { 
8332                  handler: this.configKeyListener,
8333                  value: KEY_LISTENER_CONFIG.value, 
8334                  suppressEvent: KEY_LISTENER_CONFIG.suppressEvent 
8335              }
8336          );
8337  
8338      },
8339  
8340      /**
8341      * @method getNextSibling
8342      * @description Finds the menu item's next sibling.
8343      * @return YAHOO.widget.MenuItem
8344      */
8345      getNextSibling: function () {
8346      
8347          var isUL = function (el) {
8348                  return (el.nodeName.toLowerCase() === "ul");
8349              },
8350      
8351              menuitemEl = this.element,
8352              next = Dom.getNextSibling(menuitemEl),
8353              parent,
8354              sibling,
8355              list;
8356          
8357          if (!next) {
8358              
8359              parent = menuitemEl.parentNode;
8360              sibling = Dom.getNextSiblingBy(parent, isUL);
8361              
8362              if (sibling) {
8363                  list = sibling;
8364              }
8365              else {
8366                  list = Dom.getFirstChildBy(parent.parentNode, isUL);
8367              }
8368              
8369              next = Dom.getFirstChild(list);
8370              
8371          }
8372  
8373          return YAHOO.widget.MenuManager.getMenuItem(next.id);
8374  
8375      },
8376  
8377      /**
8378      * @method getNextEnabledSibling
8379      * @description Finds the menu item's next enabled sibling.
8380      * @return YAHOO.widget.MenuItem
8381      */
8382      getNextEnabledSibling: function () {
8383          
8384          var next = this.getNextSibling();
8385          
8386          return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next;
8387          
8388      },
8389  
8390  
8391      /**
8392      * @method getPreviousSibling
8393      * @description Finds the menu item's previous sibling.
8394      * @return {YAHOO.widget.MenuItem}
8395      */    
8396      getPreviousSibling: function () {
8397  
8398          var isUL = function (el) {
8399                  return (el.nodeName.toLowerCase() === "ul");
8400              },
8401  
8402              menuitemEl = this.element,
8403              next = Dom.getPreviousSibling(menuitemEl),
8404              parent,
8405              sibling,
8406              list;
8407          
8408          if (!next) {
8409              
8410              parent = menuitemEl.parentNode;
8411              sibling = Dom.getPreviousSiblingBy(parent, isUL);
8412              
8413              if (sibling) {
8414                  list = sibling;
8415              }
8416              else {
8417                  list = Dom.getLastChildBy(parent.parentNode, isUL);
8418              }
8419              
8420              next = Dom.getLastChild(list);
8421              
8422          }
8423  
8424          return YAHOO.widget.MenuManager.getMenuItem(next.id);
8425          
8426      },
8427  
8428  
8429      /**
8430      * @method getPreviousEnabledSibling
8431      * @description Finds the menu item's previous enabled sibling.
8432      * @return {YAHOO.widget.MenuItem}
8433      */
8434      getPreviousEnabledSibling: function () {
8435          
8436          var next = this.getPreviousSibling();
8437          
8438          return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next;
8439          
8440      },
8441  
8442  
8443      /**
8444      * @method focus
8445      * @description Causes the menu item to receive the focus and fires the 
8446      * focus event.
8447      */
8448      focus: function () {
8449  
8450          var oParent = this.parent,
8451              oAnchor = this._oAnchor,
8452              oActiveItem = oParent.activeItem;
8453  
8454  
8455          function setFocus() {
8456  
8457              try {
8458  
8459                  if (!(UA.ie && !document.hasFocus())) {
8460                  
8461                      if (oActiveItem) {
8462          
8463                          oActiveItem.blurEvent.fire();
8464          
8465                      }
8466      
8467                      oAnchor.focus();
8468                      
8469                      this.focusEvent.fire();
8470                  
8471                  }
8472  
8473              }
8474              catch(e) {
8475              
8476              }
8477  
8478          }
8479  
8480  
8481          if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) && 
8482              this.element.style.display != _NONE) {
8483  
8484  
8485              /*
8486                  Setting focus via a timer fixes a race condition in Firefox, IE 
8487                  and Opera where the browser viewport jumps as it trys to 
8488                  position and focus the menu.
8489              */
8490  
8491              Lang.later(0, this, setFocus);
8492  
8493          }
8494  
8495      },
8496  
8497  
8498      /**
8499      * @method blur
8500      * @description Causes the menu item to lose focus and fires the 
8501      * blur event.
8502      */    
8503      blur: function () {
8504  
8505          var oParent = this.parent;
8506  
8507          if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
8508  
8509              Lang.later(0, this, function () {
8510  
8511                  try {
8512      
8513                      this._oAnchor.blur();
8514                      this.blurEvent.fire();    
8515  
8516                  } 
8517                  catch (e) {
8518                  
8519                  }
8520                  
8521              }, 0);
8522  
8523          }
8524  
8525      },
8526  
8527  
8528      /**
8529      * @method hasFocus
8530      * @description Returns a boolean indicating whether or not the menu item
8531      * has focus.
8532      * @return {Boolean}
8533      */
8534      hasFocus: function () {
8535      
8536          return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
8537      
8538      },
8539  
8540  
8541      /**
8542      * @method destroy
8543      * @description Removes the menu item's <code>&#60;li&#62;</code> element 
8544      * from its parent <code>&#60;ul&#62;</code> element.
8545      */
8546      destroy: function () {
8547  
8548          var oEl = this.element,
8549              oSubmenu,
8550              oParentNode,
8551              aEventData,
8552              i;
8553  
8554  
8555          if (oEl) {
8556  
8557  
8558              // If the item has a submenu, destroy it first
8559  
8560              oSubmenu = this.cfg.getProperty(_SUBMENU);
8561  
8562              if (oSubmenu) {
8563              
8564                  oSubmenu.destroy();
8565              
8566              }
8567  
8568  
8569              // Remove the element from the parent node
8570  
8571              oParentNode = oEl.parentNode;
8572  
8573              if (oParentNode) {
8574  
8575                  oParentNode.removeChild(oEl);
8576  
8577                  this.destroyEvent.fire();
8578  
8579              }
8580  
8581  
8582              // Remove CustomEvent listeners
8583  
8584              i = EVENT_TYPES.length - 1;
8585  
8586              do {
8587  
8588                  aEventData = EVENT_TYPES[i];
8589                  
8590                  this[aEventData[0]].unsubscribeAll();
8591  
8592              }
8593              while (i--);
8594              
8595              
8596              this.cfg.configChangedEvent.unsubscribeAll();
8597  
8598          }
8599  
8600      },
8601  
8602  
8603      /**
8604      * @method toString
8605      * @description Returns a string representing the menu item.
8606      * @return {String}
8607      */
8608      toString: function () {
8609  
8610          var sReturnVal = _MENUITEM,
8611              sId = this.id;
8612  
8613          if (sId) {
8614      
8615              sReturnVal += (_SPACE + sId);
8616          
8617          }
8618  
8619          return sReturnVal;
8620      
8621      }
8622  
8623  };
8624  
8625  Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
8626  
8627  })();
8628  (function () {
8629  
8630      var _XY = "xy",
8631          _MOUSEDOWN = "mousedown",
8632          _CONTEXTMENU = "ContextMenu",
8633          _SPACE = " ";
8634  
8635  /**
8636  * Creates a list of options or commands which are made visible in response to 
8637  * an HTML element's "contextmenu" event ("mousedown" for Opera).
8638  *
8639  * @param {String} p_oElement String specifying the id attribute of the 
8640  * <code>&#60;div&#62;</code> element of the context menu.
8641  * @param {String} p_oElement String specifying the id attribute of the 
8642  * <code>&#60;select&#62;</code> element to be used as the data source for the 
8643  * context menu.
8644  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8645  * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
8646  * <code>&#60;div&#62;</code> element of the context menu.
8647  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8648  * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
8649  * the <code>&#60;select&#62;</code> element to be used as the data source for 
8650  * the context menu.
8651  * @param {Object} p_oConfig Optional. Object literal specifying the 
8652  * configuration for the context menu. See configuration class documentation 
8653  * for more details.
8654  * @class ContextMenu
8655  * @constructor
8656  * @extends YAHOO.widget.Menu
8657  * @namespace YAHOO.widget
8658  */
8659  YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
8660      YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
8661  };
8662  
8663  
8664  var Event = YAHOO.util.Event,
8665      UA = YAHOO.env.ua,
8666      ContextMenu = YAHOO.widget.ContextMenu,
8667  
8668  
8669  
8670      /**
8671      * Constant representing the name of the ContextMenu's events
8672      * @property EVENT_TYPES
8673      * @private
8674      * @final
8675      * @type Object
8676      */
8677      EVENT_TYPES = {
8678  
8679          "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
8680          "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
8681          "CLICK": "click"
8682  
8683      },
8684      
8685      
8686      /**
8687      * Constant representing the ContextMenu's configuration properties
8688      * @property DEFAULT_CONFIG
8689      * @private
8690      * @final
8691      * @type Object
8692      */
8693      TRIGGER_CONFIG = { 
8694          key: "trigger",
8695          suppressEvent: true
8696      };
8697  
8698  
8699  /**
8700  * @method position
8701  * @description "beforeShow" event handler used to position the contextmenu.
8702  * @private
8703  * @param {String} p_sType String representing the name of the event that 
8704  * was fired.
8705  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
8706  * @param {Array} p_aPos Array representing the xy position for the context menu.
8707  */
8708  function position(p_sType, p_aArgs, p_aPos) {
8709      this.cfg.setProperty(_XY, p_aPos);
8710      this.beforeShowEvent.unsubscribe(position, p_aPos);
8711  }
8712  
8713  
8714  YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
8715  
8716  
8717  
8718  // Private properties
8719  
8720  
8721  /**
8722  * @property _oTrigger
8723  * @description Object reference to the current value of the "trigger" 
8724  * configuration property.
8725  * @default null
8726  * @private
8727  * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
8728  * l-one-html.html#ID-58190037">HTMLElement</a>|Array
8729  */
8730  _oTrigger: null,
8731  
8732  
8733  /**
8734  * @property _bCancelled
8735  * @description Boolean indicating if the display of the context menu should 
8736  * be cancelled.
8737  * @default false
8738  * @private
8739  * @type Boolean
8740  */
8741  _bCancelled: false,
8742  
8743  
8744  
8745  // Public properties
8746  
8747  
8748  /**
8749  * @property contextEventTarget
8750  * @description Object reference for the HTML element that was the target of the
8751  * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of 
8752  * the context menu.
8753  * @default null
8754  * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8755  * html.html#ID-58190037">HTMLElement</a>
8756  */
8757  contextEventTarget: null,
8758  
8759  
8760  
8761  // Events
8762  
8763  
8764  /**
8765  * @event triggerContextMenuEvent
8766  * @param type {String} The name of the event, "triggerContextMenu"
8767  * @param args {Array} The array of event arguments. For this event, the underlying
8768  * DOM event is the only argument, available from args[0].
8769  * @description Custom Event wrapper for the "contextmenu" DOM event 
8770  * ("mousedown" for Opera) fired by the element(s) that trigger the display of 
8771  * the context menu.
8772  */
8773  triggerContextMenuEvent: null,
8774  
8775  
8776  
8777  /**
8778  * @method init
8779  * @description The ContextMenu class's initialization method. This method is 
8780  * automatically called by the constructor, and sets up all DOM references for 
8781  * pre-existing markup, and creates required markup if it is not already present.
8782  * @param {String} p_oElement String specifying the id attribute of the 
8783  * <code>&#60;div&#62;</code> element of the context menu.
8784  * @param {String} p_oElement String specifying the id attribute of the 
8785  * <code>&#60;select&#62;</code> element to be used as the data source for 
8786  * the context menu.
8787  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8788  * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
8789  * <code>&#60;div&#62;</code> element of the context menu.
8790  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
8791  * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
8792  * the <code>&#60;select&#62;</code> element to be used as the data source for 
8793  * the context menu.
8794  * @param {Object} p_oConfig Optional. Object literal specifying the 
8795  * configuration for the context menu. See configuration class documentation 
8796  * for more details.
8797  */
8798  init: function(p_oElement, p_oConfig) {
8799  
8800  
8801      // Call the init of the superclass (YAHOO.widget.Menu)
8802      
8803      ContextMenu.superclass.init.call(this, p_oElement);
8804  
8805      this.beforeInitEvent.fire(ContextMenu);
8806  
8807      if (p_oConfig) {
8808          this.cfg.applyConfig(p_oConfig, true);
8809      }
8810  
8811      this.initEvent.fire(ContextMenu);
8812  },
8813  
8814  
8815  /**
8816  * @method initEvents
8817  * @description Initializes the custom events for the context menu.
8818  */
8819  initEvents: function() {
8820      ContextMenu.superclass.initEvents.call(this);
8821  
8822      // Create custom events
8823      this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
8824      this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
8825  },
8826  
8827  /**
8828  * @method cancel
8829  * @description Cancels the display of the context menu.
8830  */
8831  cancel: function() {
8832      this._bCancelled = true;
8833  },
8834  
8835  // Private methods
8836  
8837  
8838  /**
8839  * @method _removeEventHandlers
8840  * @description Removes all of the DOM event handlers from the HTML element(s) 
8841  * whose "context menu" event ("click" for Opera) trigger the display of 
8842  * the context menu.
8843  * @private
8844  */
8845  _removeEventHandlers: function() {
8846  
8847      var oTrigger = this._oTrigger;
8848  
8849      // Remove the event handlers from the trigger(s)
8850      if (oTrigger) {
8851          Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);    
8852  
8853          if (UA.opera) {
8854              Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
8855          }
8856      }
8857  
8858  },
8859  
8860  // Private event handlers
8861  
8862  /**
8863  * @method _onTriggerClick
8864  * @description "click" event handler for the HTML element(s) identified as the 
8865  * "trigger" for the context menu.  Used to cancel default behaviors in Opera.
8866  * @private
8867  * @param {Event} p_oEvent Object representing the DOM event object passed back 
8868  * by the event utility (YAHOO.util.Event).
8869  * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8870  * menu that is handling the event.
8871  */
8872  _onTriggerClick: function(p_oEvent, p_oMenu) {
8873  
8874      if (p_oEvent.ctrlKey) {
8875          Event.stopEvent(p_oEvent);
8876      }
8877      
8878  },
8879  
8880  
8881  /**
8882  * @method _onTriggerContextMenu
8883  * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML 
8884  * element(s) that trigger the display of the context menu.
8885  * @private
8886  * @param {Event} p_oEvent Object representing the DOM event object passed back 
8887  * by the event utility (YAHOO.util.Event).
8888  * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
8889  * menu that is handling the event.
8890  */
8891  _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
8892  
8893      var aXY;
8894  
8895      if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
8896      
8897          this.contextEventTarget = Event.getTarget(p_oEvent);
8898      
8899          this.triggerContextMenuEvent.fire(p_oEvent);
8900          
8901      
8902          if (!this._bCancelled) {
8903  
8904              /*
8905                  Prevent the browser's default context menu from appearing and 
8906                  stop the propagation of the "contextmenu" event so that 
8907                  other ContextMenu instances are not displayed.
8908              */
8909  
8910              Event.stopEvent(p_oEvent);
8911  
8912  
8913              // Hide any other Menu instances that might be visible
8914  
8915              YAHOO.widget.MenuManager.hideVisible();
8916              
8917      
8918  
8919              // Position and display the context menu
8920      
8921              aXY = Event.getXY(p_oEvent);
8922      
8923      
8924              if (!YAHOO.util.Dom.inDocument(this.element)) {
8925      
8926                  this.beforeShowEvent.subscribe(position, aXY);
8927      
8928              }
8929              else {
8930      
8931                  this.cfg.setProperty(_XY, aXY);
8932              
8933              }
8934      
8935      
8936              this.show();
8937      
8938          }
8939      
8940          this._bCancelled = false;
8941  
8942      }
8943  
8944  },
8945  
8946  
8947  
8948  // Public methods
8949  
8950  
8951  /**
8952  * @method toString
8953  * @description Returns a string representing the context menu.
8954  * @return {String}
8955  */
8956  toString: function() {
8957  
8958      var sReturnVal = _CONTEXTMENU,
8959          sId = this.id;
8960  
8961      if (sId) {
8962  
8963          sReturnVal += (_SPACE + sId);
8964      
8965      }
8966  
8967      return sReturnVal;
8968  
8969  },
8970  
8971  
8972  /**
8973  * @method initDefaultConfig
8974  * @description Initializes the class's configurable properties which can be 
8975  * changed using the context menu's Config object ("cfg").
8976  */
8977  initDefaultConfig: function() {
8978  
8979      ContextMenu.superclass.initDefaultConfig.call(this);
8980  
8981      /**
8982      * @config trigger
8983      * @description The HTML element(s) whose "contextmenu" event ("mousedown" 
8984      * for Opera) trigger the display of the context menu.  Can be a string 
8985      * representing the id attribute of the HTML element, an object reference 
8986      * for the HTML element, or an array of strings or HTML element references.
8987      * @default null
8988      * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
8989      * level-one-html.html#ID-58190037">HTMLElement</a>|Array
8990      */
8991      this.cfg.addProperty(TRIGGER_CONFIG.key, 
8992          {
8993              handler: this.configTrigger, 
8994              suppressEvent: TRIGGER_CONFIG.suppressEvent 
8995          }
8996      );
8997  
8998  },
8999  
9000  
9001  /**
9002  * @method destroy
9003  * @description Removes the context menu's <code>&#60;div&#62;</code> element 
9004  * (and accompanying child nodes) from the document.
9005  * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 
9006  * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
9007  */
9008  destroy: function(shallowPurge) {
9009  
9010      // Remove the DOM event handlers from the current trigger(s)
9011  
9012      this._removeEventHandlers();
9013  
9014  
9015      // Continue with the superclass implementation of this method
9016  
9017      ContextMenu.superclass.destroy.call(this, shallowPurge);
9018  
9019  },
9020  
9021  
9022  
9023  // Public event handlers for configuration properties
9024  
9025  
9026  /**
9027  * @method configTrigger
9028  * @description Event handler for when the value of the "trigger" configuration 
9029  * property changes. 
9030  * @param {String} p_sType String representing the name of the event that 
9031  * was fired.
9032  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9033  * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
9034  * menu that fired the event.
9035  */
9036  configTrigger: function(p_sType, p_aArgs, p_oMenu) {
9037      
9038      var oTrigger = p_aArgs[0];
9039  
9040      if (oTrigger) {
9041  
9042          /*
9043              If there is a current "trigger" - remove the event handlers 
9044              from that element(s) before assigning new ones
9045          */
9046  
9047          if (this._oTrigger) {
9048          
9049              this._removeEventHandlers();
9050  
9051          }
9052  
9053          this._oTrigger = oTrigger;
9054  
9055  
9056          /*
9057              Listen for the "mousedown" event in Opera b/c it does not 
9058              support the "contextmenu" event
9059          */ 
9060    
9061          Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
9062  
9063  
9064          /*
9065              Assign a "click" event handler to the trigger element(s) for
9066              Opera to prevent default browser behaviors.
9067          */
9068  
9069          if (UA.opera) {
9070          
9071              Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
9072  
9073          }
9074  
9075      }
9076      else {
9077     
9078          this._removeEventHandlers();
9079      
9080      }
9081      
9082  }
9083  
9084  }); // END YAHOO.lang.extend
9085  
9086  }());
9087  
9088  
9089  
9090  /**
9091  * Creates an item for a context menu.
9092  * 
9093  * @param {String} p_oObject String specifying the text of the context menu item.
9094  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9095  * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9096  * <code>&#60;li&#62;</code> element of the context menu item.
9097  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9098  * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9099  * specifying the <code>&#60;optgroup&#62;</code> element of the context 
9100  * menu item.
9101  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9102  * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9103  * the <code>&#60;option&#62;</code> element of the context menu item.
9104  * @param {Object} p_oConfig Optional. Object literal specifying the 
9105  * configuration for the context menu item. See configuration class 
9106  * documentation for more details.
9107  * @class ContextMenuItem
9108  * @constructor
9109  * @extends YAHOO.widget.MenuItem
9110  * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
9111  * are of type YAHOO.widget.MenuItem.
9112  */
9113  YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
9114  (function () {
9115  
9116      var Lang = YAHOO.lang,
9117  
9118          // String constants
9119      
9120          _STATIC = "static",
9121          _DYNAMIC_STATIC = "dynamic," + _STATIC,
9122          _DISABLED = "disabled",
9123          _SELECTED = "selected",
9124          _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
9125          _SUBMENU = "submenu",
9126          _VISIBLE = "visible",
9127          _SPACE = " ",
9128          _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
9129          _MENUBAR = "MenuBar";
9130  
9131  /**
9132  * Horizontal collection of items, each of which can contain a submenu.
9133  * 
9134  * @param {String} p_oElement String specifying the id attribute of the 
9135  * <code>&#60;div&#62;</code> element of the menu bar.
9136  * @param {String} p_oElement String specifying the id attribute of the 
9137  * <code>&#60;select&#62;</code> element to be used as the data source for the 
9138  * menu bar.
9139  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9140  * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
9141  * the <code>&#60;div&#62;</code> element of the menu bar.
9142  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9143  * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
9144  * specifying the <code>&#60;select&#62;</code> element to be used as the data 
9145  * source for the menu bar.
9146  * @param {Object} p_oConfig Optional. Object literal specifying the 
9147  * configuration for the menu bar. See configuration class documentation for
9148  * more details.
9149  * @class MenuBar
9150  * @constructor
9151  * @extends YAHOO.widget.Menu
9152  * @namespace YAHOO.widget
9153  */
9154  YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
9155  
9156      YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
9157  
9158  };
9159  
9160  
9161  /**
9162  * @method checkPosition
9163  * @description Checks to make sure that the value of the "position" property 
9164  * is one of the supported strings. Returns true if the position is supported.
9165  * @private
9166  * @param {Object} p_sPosition String specifying the position of the menu.
9167  * @return {Boolean}
9168  */
9169  function checkPosition(p_sPosition) {
9170  
9171      var returnVal = false;
9172  
9173      if (Lang.isString(p_sPosition)) {
9174  
9175          returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
9176  
9177      }
9178      
9179      return returnVal;
9180  
9181  }
9182  
9183  
9184  var Event = YAHOO.util.Event,
9185      MenuBar = YAHOO.widget.MenuBar,
9186  
9187      POSITION_CONFIG =  { 
9188          key: "position", 
9189          value: _STATIC, 
9190          validator: checkPosition, 
9191          supercedes: [_VISIBLE] 
9192      }, 
9193  
9194      SUBMENU_ALIGNMENT_CONFIG =  { 
9195          key: "submenualignment", 
9196          value: ["tl","bl"]
9197      },
9198  
9199      AUTO_SUBMENU_DISPLAY_CONFIG =  { 
9200          key: _AUTO_SUBMENU_DISPLAY, 
9201          value: false, 
9202          validator: Lang.isBoolean,
9203          suppressEvent: true
9204      },
9205      
9206      SUBMENU_TOGGLE_REGION_CONFIG = {
9207          key: _SUBMENU_TOGGLE_REGION, 
9208          value: false, 
9209          validator: Lang.isBoolean
9210      };
9211  
9212  
9213  
9214  Lang.extend(MenuBar, YAHOO.widget.Menu, {
9215  
9216  /**
9217  * @method init
9218  * @description The MenuBar class's initialization method. This method is 
9219  * automatically called by the constructor, and sets up all DOM references for 
9220  * pre-existing markup, and creates required markup if it is not already present.
9221  * @param {String} p_oElement String specifying the id attribute of the 
9222  * <code>&#60;div&#62;</code> element of the menu bar.
9223  * @param {String} p_oElement String specifying the id attribute of the 
9224  * <code>&#60;select&#62;</code> element to be used as the data source for the 
9225  * menu bar.
9226  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9227  * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
9228  * the <code>&#60;div&#62;</code> element of the menu bar.
9229  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9230  * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
9231  * specifying the <code>&#60;select&#62;</code> element to be used as the data 
9232  * source for the menu bar.
9233  * @param {Object} p_oConfig Optional. Object literal specifying the 
9234  * configuration for the menu bar. See configuration class documentation for
9235  * more details.
9236  */
9237  init: function(p_oElement, p_oConfig) {
9238  
9239      if(!this.ITEM_TYPE) {
9240  
9241          this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
9242  
9243      }
9244  
9245  
9246      // Call the init of the superclass (YAHOO.widget.Menu)
9247  
9248      MenuBar.superclass.init.call(this, p_oElement);
9249  
9250  
9251      this.beforeInitEvent.fire(MenuBar);
9252  
9253  
9254      if(p_oConfig) {
9255  
9256          this.cfg.applyConfig(p_oConfig, true);
9257  
9258      }
9259  
9260      this.initEvent.fire(MenuBar);
9261  
9262  },
9263  
9264  
9265  
9266  // Constants
9267  
9268  
9269  /**
9270  * @property CSS_CLASS_NAME
9271  * @description String representing the CSS class(es) to be applied to the menu 
9272  * bar's <code>&#60;div&#62;</code> element.
9273  * @default "yuimenubar"
9274  * @final
9275  * @type String
9276  */
9277  CSS_CLASS_NAME: "yuimenubar",
9278  
9279  
9280  /**
9281  * @property SUBMENU_TOGGLE_REGION_WIDTH
9282  * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
9283  * display of the MenuBarItem's submenu.
9284  * @default 20
9285  * @final
9286  * @type Number
9287  */
9288  SUBMENU_TOGGLE_REGION_WIDTH: 20,
9289  
9290  
9291  // Protected event handlers
9292  
9293  
9294  /**
9295  * @method _onKeyDown
9296  * @description "keydown" Custom Event handler for the menu bar.
9297  * @private
9298  * @param {String} p_sType String representing the name of the event that 
9299  * was fired.
9300  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9301  * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
9302  * that fired the event.
9303  */
9304  _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
9305  
9306      var oEvent = p_aArgs[0],
9307          oItem = p_aArgs[1],
9308          oSubmenu,
9309          oItemCfg,
9310          oNextItem;
9311  
9312  
9313      if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9314  
9315          oItemCfg = oItem.cfg;
9316  
9317          switch(oEvent.keyCode) {
9318      
9319              case 37:    // Left arrow
9320              case 39:    // Right arrow
9321      
9322                  if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
9323      
9324                      oItemCfg.setProperty(_SELECTED, true);
9325      
9326                  }
9327                  else {
9328      
9329                      oNextItem = (oEvent.keyCode == 37) ? 
9330                          oItem.getPreviousEnabledSibling() : 
9331                          oItem.getNextEnabledSibling();
9332              
9333                      if(oNextItem) {
9334      
9335                          this.clearActiveItem();
9336      
9337                          oNextItem.cfg.setProperty(_SELECTED, true);
9338                          
9339                          oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
9340                          
9341                          if(oSubmenu) {
9342                      
9343                              oSubmenu.show();
9344                              oSubmenu.setInitialFocus();
9345                          
9346                          }
9347                          else {
9348                              oNextItem.focus();  
9349                          }
9350      
9351                      }
9352      
9353                  }
9354      
9355                  Event.preventDefault(oEvent);
9356      
9357              break;
9358      
9359              case 40:    // Down arrow
9360      
9361                  if(this.activeItem != oItem) {
9362      
9363                      this.clearActiveItem();
9364      
9365                      oItemCfg.setProperty(_SELECTED, true);
9366                      oItem.focus();
9367                  
9368                  }
9369      
9370                  oSubmenu = oItemCfg.getProperty(_SUBMENU);
9371      
9372                  if(oSubmenu) {
9373      
9374                      if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9375      
9376                          oSubmenu.setInitialSelection();
9377                          oSubmenu.setInitialFocus();
9378                      
9379                      }
9380                      else {
9381      
9382                          oSubmenu.show();
9383                          oSubmenu.setInitialFocus();
9384                      
9385                      }
9386      
9387                  }
9388      
9389                  Event.preventDefault(oEvent);
9390      
9391              break;
9392      
9393          }
9394  
9395      }
9396  
9397  
9398      if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
9399  
9400          oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
9401  
9402          if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
9403          
9404              oSubmenu.hide();
9405              this.activeItem.focus();
9406          
9407          }
9408          else {
9409  
9410              this.activeItem.cfg.setProperty(_SELECTED, false);
9411              this.activeItem.blur();
9412      
9413          }
9414  
9415          Event.preventDefault(oEvent);
9416      
9417      }
9418  
9419  },
9420  
9421  
9422  /**
9423  * @method _onClick
9424  * @description "click" event handler for the menu bar.
9425  * @protected
9426  * @param {String} p_sType String representing the name of the event that 
9427  * was fired.
9428  * @param {Array} p_aArgs Array of arguments sent when the event was fired.
9429  * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
9430  * that fired the event.
9431  */
9432  _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
9433  
9434      MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
9435  
9436      var oItem = p_aArgs[1],
9437          bReturnVal = true,
9438          oItemEl,
9439          oEvent,
9440          oTarget,
9441          oActiveItem,
9442          oConfig,
9443          oSubmenu,
9444          nMenuItemX,
9445          nToggleRegion;
9446  
9447  
9448      var toggleSubmenuDisplay = function () {
9449  
9450          if(oSubmenu.cfg.getProperty(_VISIBLE)) {
9451          
9452              oSubmenu.hide();
9453          
9454          }
9455          else {
9456          
9457              oSubmenu.show();                    
9458          
9459          }
9460      
9461      };
9462      
9463  
9464      if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
9465  
9466          oEvent = p_aArgs[0];
9467          oTarget = Event.getTarget(oEvent);
9468          oActiveItem = this.activeItem;
9469          oConfig = this.cfg;
9470  
9471  
9472          // Hide any other submenus that might be visible
9473      
9474          if(oActiveItem && oActiveItem != oItem) {
9475      
9476              this.clearActiveItem();
9477      
9478          }
9479  
9480      
9481          oItem.cfg.setProperty(_SELECTED, true);
9482      
9483  
9484          // Show the submenu for the item
9485      
9486          oSubmenu = oItem.cfg.getProperty(_SUBMENU);
9487  
9488  
9489          if(oSubmenu) {
9490  
9491              oItemEl = oItem.element;
9492              nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
9493              nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
9494  
9495              if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
9496  
9497                  if (Event.getPageX(oEvent) > nToggleRegion) {
9498  
9499                      toggleSubmenuDisplay();
9500  
9501                      Event.preventDefault(oEvent);
9502  
9503                      /*
9504                           Return false so that other click event handlers are not called when the 
9505                           user clicks inside the toggle region.
9506                      */
9507                      bReturnVal = false;
9508                  
9509                  }
9510          
9511              }
9512              else {
9513  
9514                  toggleSubmenuDisplay();
9515              
9516              }
9517          
9518          }
9519      
9520      }
9521  
9522  
9523      return bReturnVal;
9524  
9525  },
9526  
9527  
9528  
9529  // Public methods
9530  
9531  /**
9532  * @method configSubmenuToggle
9533  * @description Event handler for when the "submenutoggleregion" configuration property of 
9534  * a MenuBar changes.
9535  * @param {String} p_sType The name of the event that was fired.
9536  * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
9537  */
9538  configSubmenuToggle: function (p_sType, p_aArgs) {
9539  
9540      var bSubmenuToggle = p_aArgs[0];
9541      
9542      if (bSubmenuToggle) {
9543      
9544          this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
9545      
9546      }
9547  
9548  },
9549  
9550  
9551  /**
9552  * @method toString
9553  * @description Returns a string representing the menu bar.
9554  * @return {String}
9555  */
9556  toString: function() {
9557  
9558      var sReturnVal = _MENUBAR,
9559          sId = this.id;
9560  
9561      if(sId) {
9562  
9563          sReturnVal += (_SPACE + sId);
9564      
9565      }
9566  
9567      return sReturnVal;
9568  
9569  },
9570  
9571  
9572  /**
9573  * @description Initializes the class's configurable properties which can be
9574  * changed using the menu bar's Config object ("cfg").
9575  * @method initDefaultConfig
9576  */
9577  initDefaultConfig: function() {
9578  
9579      MenuBar.superclass.initDefaultConfig.call(this);
9580  
9581      var oConfig = this.cfg;
9582  
9583      // Add configuration properties
9584  
9585  
9586      /*
9587          Set the default value for the "position" configuration property
9588          to "static" by re-adding the property.
9589      */
9590  
9591  
9592      /**
9593      * @config position
9594      * @description String indicating how a menu bar should be positioned on the 
9595      * screen.  Possible values are "static" and "dynamic."  Static menu bars 
9596      * are visible by default and reside in the normal flow of the document 
9597      * (CSS position: static).  Dynamic menu bars are hidden by default, reside
9598      * out of the normal flow of the document (CSS position: absolute), and can 
9599      * overlay other elements on the screen.
9600      * @default static
9601      * @type String
9602      */
9603      oConfig.addProperty(
9604          POSITION_CONFIG.key, 
9605          {
9606              handler: this.configPosition, 
9607              value: POSITION_CONFIG.value, 
9608              validator: POSITION_CONFIG.validator,
9609              supercedes: POSITION_CONFIG.supercedes
9610          }
9611      );
9612  
9613  
9614      /*
9615          Set the default value for the "submenualignment" configuration property
9616          to ["tl","bl"] by re-adding the property.
9617      */
9618  
9619      /**
9620      * @config submenualignment
9621      * @description Array defining how submenus should be aligned to their 
9622      * parent menu bar item. The format is: [itemCorner, submenuCorner].
9623      * @default ["tl","bl"]
9624      * @type Array
9625      */
9626      oConfig.addProperty(
9627          SUBMENU_ALIGNMENT_CONFIG.key, 
9628          {
9629              value: SUBMENU_ALIGNMENT_CONFIG.value,
9630              suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
9631          }
9632      );
9633  
9634  
9635      /*
9636          Change the default value for the "autosubmenudisplay" configuration 
9637          property to "false" by re-adding the property.
9638      */
9639  
9640      /**
9641      * @config autosubmenudisplay
9642      * @description Boolean indicating if submenus are automatically made 
9643      * visible when the user mouses over the menu bar's items.
9644      * @default false
9645      * @type Boolean
9646      */
9647      oConfig.addProperty(
9648         AUTO_SUBMENU_DISPLAY_CONFIG.key, 
9649         {
9650             value: AUTO_SUBMENU_DISPLAY_CONFIG.value, 
9651             validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
9652             suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
9653         } 
9654      );
9655  
9656  
9657      /**
9658      * @config submenutoggleregion
9659      * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the 
9660      * display of a submenu.  The default width of the region is determined by the value of the
9661      * SUBMENU_TOGGLE_REGION_WIDTH property.  If set to true, the autosubmenudisplay 
9662      * configuration property will be set to false, and any click event listeners will not be 
9663      * called when the user clicks inside the submenu toggle region of a MenuBarItem.  If the 
9664      * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its 
9665      * standard behavior.
9666      * @default false
9667      * @type Boolean
9668      */
9669      oConfig.addProperty(
9670         SUBMENU_TOGGLE_REGION_CONFIG.key, 
9671         {
9672             value: SUBMENU_TOGGLE_REGION_CONFIG.value, 
9673             validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
9674             handler: this.configSubmenuToggle
9675         } 
9676      );
9677  
9678  }
9679   
9680  }); // END YAHOO.lang.extend
9681  
9682  }());
9683  
9684  
9685  
9686  /**
9687  * Creates an item for a menu bar.
9688  * 
9689  * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
9690  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9691  * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9692  * <code>&#60;li&#62;</code> element of the menu bar item.
9693  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9694  * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9695  * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
9696  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9697  * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9698  * the <code>&#60;option&#62;</code> element of the menu bar item.
9699  * @param {Object} p_oConfig Optional. Object literal specifying the 
9700  * configuration for the menu bar item. See configuration class documentation 
9701  * for more details.
9702  * @class MenuBarItem
9703  * @constructor
9704  * @extends YAHOO.widget.MenuItem
9705  */
9706  YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
9707  
9708      YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
9709  
9710  };
9711  
9712  YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
9713  
9714  
9715  
9716  /**
9717  * @method init
9718  * @description The MenuBarItem class's initialization method. This method is 
9719  * automatically called by the constructor, and sets up all DOM references for 
9720  * pre-existing markup, and creates required markup if it is not already present.
9721  * @param {HTML} p_oObject Markup for the menu item content. The markup is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
9722  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9723  * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
9724  * <code>&#60;li&#62;</code> element of the menu bar item.
9725  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9726  * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
9727  * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
9728  * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
9729  * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
9730  * the <code>&#60;option&#62;</code> element of the menu bar item.
9731  * @param {Object} p_oConfig Optional. Object literal specifying the 
9732  * configuration for the menu bar item. See configuration class documentation 
9733  * for more details.
9734  */
9735  init: function(p_oObject, p_oConfig) {
9736  
9737      if(!this.SUBMENU_TYPE) {
9738  
9739          this.SUBMENU_TYPE = YAHOO.widget.Menu;
9740  
9741      }
9742  
9743  
9744      /* 
9745          Call the init of the superclass (YAHOO.widget.MenuItem)
9746          Note: We don't pass the user config in here yet 
9747          because we only want it executed once, at the lowest 
9748          subclass level.
9749      */ 
9750  
9751      YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);  
9752  
9753  
9754      var oConfig = this.cfg;
9755  
9756      if(p_oConfig) {
9757  
9758          oConfig.applyConfig(p_oConfig, true);
9759  
9760      }
9761  
9762      oConfig.fireQueue();
9763  
9764  },
9765  
9766  
9767  
9768  // Constants
9769  
9770  
9771  /**
9772  * @property CSS_CLASS_NAME
9773  * @description String representing the CSS class(es) to be applied to the 
9774  * <code>&#60;li&#62;</code> element of the menu bar item.
9775  * @default "yuimenubaritem"
9776  * @final
9777  * @type String
9778  */
9779  CSS_CLASS_NAME: "yuimenubaritem",
9780  
9781  
9782  /**
9783  * @property CSS_LABEL_CLASS_NAME
9784  * @description String representing the CSS class(es) to be applied to the 
9785  * menu bar item's <code>&#60;a&#62;</code> element.
9786  * @default "yuimenubaritemlabel"
9787  * @final
9788  * @type String
9789  */
9790  CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
9791  
9792  
9793  
9794  // Public methods
9795  
9796  
9797  /**
9798  * @method toString
9799  * @description Returns a string representing the menu bar item.
9800  * @return {String}
9801  */
9802  toString: function() {
9803  
9804      var sReturnVal = "MenuBarItem";
9805  
9806      if(this.cfg && this.cfg.getProperty("text")) {
9807  
9808          sReturnVal += (": " + this.cfg.getProperty("text"));
9809  
9810      }
9811  
9812      return sReturnVal;
9813  
9814  }
9815      
9816  }); // END YAHOO.lang.extend
9817  YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.9.0", build: "2800"});
9818  
9819  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event", "yui2-containercore", "yui2-skin-sam-menu"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1