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);