[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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><div></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><li></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><li></code> elements are child 768 * nodes of the <code><ul></code> element with the 769 * specified id. 770 * @param {String} p_sId String specifying the id of the 771 * <code><ul></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 = " ", 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><div></code> element of the menu. 971 * @param {String} p_oElement String specifying the id attribute of the 972 * <code><select></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><div></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><select></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><div></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><li></code> element, 1211 * <code><optgroup></code> element or <code><option></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><ul></code> elements, each of which is 1304 * the parent node for each item's <code><li></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><select></code> or <code><div></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><div></code> element of the menu. 1497 * @param {String} p_oElement String specifying the id attribute of the 1498 * <code><select></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><div></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><select></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><ul></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><ul></code>, <code><li></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><div></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><div></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><div></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><div class="bd"></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><div></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><div></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><li></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><optgroup></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><option></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 <LI> and <A> 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 <LI> and <A> 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><li></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><a></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><a></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><em></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><li></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><li></code>, <code><optgroup></code> or 6848 * <code><option></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><li></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><li></code> 6900 * element is removed from its parent <code><ul></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><li></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><optgroup></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><option></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 <em 8047 * class=\"helptext\">Ctrl + C</em>");</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", "<em>Some 8107 * Text</em>");</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", "<strong> 8129 * Some Text</strong>");</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><div></code> element of the menu.</li><li> 8210 * Object specifying the <code><div></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, // The handler to call when 8232 * the event fires.<br> <strong>obj:</strong> Object, // An 8233 * object to pass back to the handler.<br> <strong>scope:</strong> 8234 * Object // 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><li></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><li></code> element 8492 * from its parent <code><ul></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><div></code> element of the context menu. 8589 * @param {String} p_oElement String specifying the id attribute of the 8590 * <code><select></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><div></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><select></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><div></code> element of the context menu. 8732 * @param {String} p_oElement String specifying the id attribute of the 8733 * <code><select></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><div></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><select></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><div></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><li></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><optgroup></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><option></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><div></code> element of the menu bar. 9084 * @param {String} p_oElement String specifying the id attribute of the 9085 * <code><select></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><div></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><select></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><div></code> element of the menu bar. 9171 * @param {String} p_oElement String specifying the id attribute of the 9172 * <code><select></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><div></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><select></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><div></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><li></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><optgroup></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><option></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><li></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><optgroup></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><option></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><li></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><a></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"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |