[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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