      1 (function($, rf) {
      2
      3     rf.ui = rf.ui || {};
      4
      5     var defaultOptions = {
      6         mode : 'server',
      7         attachToBody : false,
      8         showDelay : 50,
      9         hideDelay : 300,
     10         verticalOffset : 0,
     11         horizontalOffset : 0,
     12         showEvent : 'mouseover',
     13         positionOffset : [0, 0],
     14         cssRoot : "ddm",
     15         cssClasses : {}
     16     };
     17
     18     rf.ui.MenuBase = function(componentId, options) {
     19         $super.constructor.call(this, componentId, options);
     20         this.id = componentId;
     21         this.namespace = this.namespace || "." + rf.Event.createNamespace(this.name, this.id);
     22
     23         this.options = {};
     24         $.extend(this.options, defaultOptions, options || {});
     25         $.extend(this.options.cssClasses, buildCssClasses.call(this, this.options.cssRoot));
     26
     27         this.attachToDom(componentId);
     28
     29         this.element = rf.getDomElement(this.id);
     30
     31         this.displayed = false;
     32
     33         this.options.positionOffset = [this.options.horizontalOffset, this.options.verticalOffset];
     34         this.popup = new RichFaces.ui.Popup(this.id + "_list", {
     35                 attachTo : this.id,
     36                 direction : this.options.direction,
     37                 jointPoint : this.options.jointPoint,
     38                 positionType : this.options.positionType,
     39                 positionOffset : this.options.positionOffset,
     40                 attachToBody : this.options.attachToBody
     41             });
     42
     43         this.selectedGroup = null;
     44
     45         rf.Event.bindById(this.id, "mouseenter", $.proxy(this.__overHandler, this), this);
     46         rf.Event.bindById(this.id, "mouseleave", $.proxy(this.__leaveHandler, this), this);
     47
     48         this.popupElement = rf.getDomElement(this.popup.id);
     49         this.popupElement.tabIndex = -1;
     50
     51         this.__updateItemsList();
     52
     53         rf.Event.bind(this.items, "mouseenter", $.proxy(this.__itemMouseEnterHandler, this), this);
     54
     55         this.currentSelectedItemIndex = -1;
     56         var navEventHandlers;
     57         navEventHandlers = {};
     58         navEventHandlers["keydown" + this.namespace] = this.__keydownHandler;
     59
     60         rf.Event.bind(this.popupElement, navEventHandlers, this);
     61     };
     62
     63     var buildCssClasses = function(cssRoot) {
     64         var cssClasses = {
     65             itemCss : "rf-" +cssRoot+ "-itm",
     66             selectItemCss : "rf-" +cssRoot+ "-itm-sel",
     67             unselectItemCss : "rf-" +cssRoot+ "-itm-unsel",
     68             disabledItemCss : "rf-" +cssRoot+ "-itm-dis",
     69             labelCss: "rf-" +cssRoot+ "-lbl",
     70             listCss : "rf-" +cssRoot+ "-lst",
     71             listContainerCss : "rf-" +cssRoot+ "-lst-bg"
     72         }
     73         return cssClasses;
     74     }
     75
     76     rf.BaseComponent.extend(rf.ui.MenuBase);
     77
     78     // define super class link
     79     var $super = rf.ui.MenuBase.$super;
     80
     81     $.extend(rf.ui.MenuBase.prototype, (function() {
     82         return {
     83             name : "MenuBase",
     84
     85             show : function() {
     86                 this.__showPopup();
     87             },
     88
     89             hide : function() {
     90                 this.__hidePopup();
     91             },
     92
     93             processItem : function(item) {
     94                 if (item && item.attr('id') && !this.__isDisabled(item) && !this.__isGroup(item)) {
     95                     this.invokeEvent("itemclick", rf.getDomElement(this.id), null);
     96                     this.hide();
     97                 }
     98             },
     99
    100             activateItem : function(menuItemId) {
    101                 var item = $(RichFaces.getDomElement(menuItemId));
    102                 rf.Event.fireById(item.attr('id'), 'click');
    103             },
    104
    105             __showPopup : function(e) {
    106                 if (!this.__isShown()) {
    107                     this.invokeEvent("show", rf.getDomElement(this.id), null);
    108                     this.popup.show(e);
    109                     this.displayed = true;
    110                     rf.ui.MenuManager.setActiveSubMenu(rf.component(this.element));
    111                 }
    112                 this.popupElement.focus();
    113             },
    114
    115             __hidePopup : function() {
    116                 window.clearTimeout(this.showTimeoutId);
    117                 this.showTimeoutId = null;
    118                 if (this.__isShown()) {
    119                     this.invokeEvent("hide", rf.getDomElement(this.id), null);
    120                     this.__closeChildGroups();
    121                     this.popup.hide();
    122                     this.displayed = false;
    123                     this.__deselectCurrentItem();
    124                     this.currentSelectedItemIndex = -1;
    125                     var parentMenu = rf.component(this.__getParentMenu());
    126                     if (this.id != parentMenu.id) {
    127                         parentMenu.popupElement.focus();
    128                         rf.ui.MenuManager.setActiveSubMenu(parentMenu);
    129                     }
    130                 }
    131             },
    132
    133             __closeChildGroups : function() {
    134                 var i = 0;
    135                 var menuItem;
    136                 for (i in this.items) {
    137                     menuItem = this.items.eq(i);
    138                     if (this.__isGroup(menuItem)) {
    139                         rf.component(menuItem).hide();
    140                     }
    141                 }
    142             },
    143
    144             __getParentMenuFromItem : function(item) {
    145                 var menu;
    146                 if (item)
    147                     menu = item.parents('div.' + this.options.cssClasses.itemCss).has('div.' + this.options.cssClasses.listContainerCss).eq(1);
    148                 if (menu && menu.length > 0)
    149                     return menu;
    150                 else {
    151                     menu = item.parents('div.' + this.options.cssClasses.labelCss);
    152                     if (menu && menu.length > 0) {
    153                         return menu;
    154                     }
    155                     else {
    156                         return null;
    157                     }
    158                 }
    159             },
    160
    161             __getParentMenu : function() {
    162                 var menu = $(this.element).parents('div.' + this.options.cssClasses.itemCss).has('div.' + this.options.cssClasses.listContainerCss).eq(0);
    163                 if (menu && menu.length > 0) {
    164                     return menu;
    165                 }
    166                 else {
    167                     var item = this.items.eq(0);
    168                     return this.__getParentMenuFromItem(item);
    169                 }
    170             },
    171
    172             __isGroup : function(item) {
    173                 return item.find('div.' + this.options.cssClasses.listCss).length > 0;
    174             },
    175
    176             __isDisabled : function(item) {
    177                 return item.hasClass(this.options.cssClasses.disabledItemCss);
    178             },
    179
    180             __isShown : function() {
    181                 return this.displayed;
    182
    183             },
    184
    185             __itemMouseEnterHandler : function(e) {
    186                 var item = this.__getItemFromEvent(e);
    187                 if (item) {
    188                     //this.__selectItem(item);
    189                     if (this.currentSelectedItemIndex != this.items.index(item)) {
    190                         this.__deselectCurrentItem();
    191                         this.currentSelectedItemIndex = this.items.index(item);
    192                     }
    193                 }
    194             },
    195
    196             __selectItem : function(item) {
    197                 if (!rf.component(item).isSelected) {
    198                     rf.component(item).select();
    199                 }
    200             },
    201
    202             __getItemFromEvent : function(e) {
    203                 return $(e.target).closest("." + this.options.cssClasses.itemCss,e.currentTarget).eq(0);
    204             },
    205
    206             __showHandler : function(e) {
    207                 if (!this.__isShown()) {
    208                     this.showTimeoutId = window.setTimeout($.proxy(function() {
    209                         this.show(e);
    210                     }, this), this.options.showDelay);
    211                     return false;
    212                 }
    213             },
    214
    215             __leaveHandler : function() {
    216                 this.hideTimeoutId = window.setTimeout($.proxy(function() {
    217                     this.hide();
    218                 }, this), this.options.hideDelay);
    219             },
    220
    221             __overHandler : function() {
    222                 window.clearTimeout(this.hideTimeoutId);
    223                 this.hideTimeoutId = null;
    224             },
    225
    226             destroy : function() {
    227                 // clean up code here
    228                 this.detach(this.id);
    229
    230                 rf.Event.unbind(this.popupElement, "keydown" + this.namespace);
    231
    232                 this.popup.destroy();
    233                 this.popup = null;
    234
    235                 // call parent's destroy method
    236                 $super.destroy.call(this);
    237             }
    238         };
    239     })());
    240
    241 })(RichFaces.jQuery, RichFaces);