1 /* 2 * JBoss, Home of Professional Open Source 3 * Copyright ${year}, Red Hat, Inc. and individual contributors 4 * by the @authors tag. See the copyright.txt in the distribution for a 5 * full listing of individual contributors. 6 * 7 * This is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of 10 * the License, or (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this software; if not, write to the Free 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 */ 22 23 24 (function ($, rf) { 25 26 rf.ui = rf.ui || {}; 27 28 rf.ui.TooltipMode = { 29 client : "client", 30 ajax : "ajax", 31 DEFAULT: "client" 32 }; 33 34 var TooltipMode = rf.ui.TooltipMode; 35 36 var DEFAULT_OPTIONS = { 37 jointPoint : "AA", 38 direction : "AA", 39 offset : [10, 10], 40 attached : true, 41 mode : TooltipMode.DEFAULT, 42 hideDelay : 0, 43 hideEvent : "mouseleave", 44 showDelay : 0, 45 showEvent : "mouseenter", 46 followMouse : true 47 }; 48 49 var SHOW_ACTION = { 50 51 /** 52 * 53 * @return {void} 54 * */ 55 exec : function (tooltip, event) { 56 var mode = tooltip.mode; 57 if (mode == TooltipMode.ajax) { 58 return this.execAjax(tooltip, event); 59 } else if (mode == TooltipMode.client) { 60 return this.execClient(tooltip, event); 61 } else { 62 rf.log.error("SHOW_ACTION.exec : unknown mode (" + mode + ")"); 63 } 64 }, 65 66 /** 67 * @protected 68 * 69 * @return {Boolean} false 70 * */ 71 execAjax : function (tooltip, event) { 72 tooltip.__loading().show(); 73 tooltip.__content().hide(); 74 tooltip.__show(event); 75 76 rf.ajax(tooltip.id, null, $.extend({}, tooltip.options["ajax"], {})); 77 78 return true; 79 }, 80 81 /** 82 * @protected 83 * 84 * @return {undefined} 85 * - false - if process has been terminated 86 * - true - in other cases 87 * */ 88 execClient : function (tooltip, event) { 89 tooltip.__show(event); 90 91 return tooltip.__fireShow(); 92 } 93 }; 94 95 rf.ui.Tooltip = rf.BaseComponent.extendClass({ 96 // class name 97 name:"Tooltip", 98 99 /** 100 * @class Tooltip 101 * @name Tooltip 102 * 103 * @constructor 104 * @param {String} componentId - component id 105 * */ 106 init : function (componentId, options) { 107 $super.constructor.call(this, componentId); 108 this.namespace = "." + rf.Event.createNamespace(this.name, this.id); 109 this.options = $.extend(this.options, DEFAULT_OPTIONS, options || {}); 110 this.attachToDom(); 111 112 this.mode = this.options.mode; 113 this.target = this.options.target; 114 this.shown = false; 115 116 this.__addUserEventHandler("hide"); 117 this.__addUserEventHandler("show"); 118 this.__addUserEventHandler("beforehide"); 119 this.__addUserEventHandler("beforeshow"); 120 this.popupId = this.id + ':wrp'; 121 this.popup = new rf.ui.Popup(this.popupId, { 122 attachTo: this.target, 123 attachToBody: true, 124 positionType: "TOOLTIP", 125 positionOffset: this.options.offset, 126 jointPoint: this.options.jointPoint, 127 direction: this.options.direction 128 }); 129 130 var handlers = {}; 131 handlers[this.options.showEvent + this.namespace] = this.__showHandler; 132 handlers[this.options.hideEvent + this.namespace] = this.__hideHandler; 133 134 rf.Event.bindById(this.target, handlers, this); 135 136 if (this.options.hideEvent == 'mouseleave') { 137 rf.Event.bindById(this.popupId, this.options.hideEvent + this.namespace, this.__hideHandler, this); 138 } 139 }, 140 141 /***************************** Public Methods ****************************************************************/ 142 /** 143 * @methodOf 144 * @name PanelMenuItem#hide 145 * 146 * TODO ... 147 * 148 * @return {void} TODO ... 149 */ 150 hide: function () { 151 152 var tooltip = this; 153 if (tooltip.hidingTimerHandle) { 154 window.clearTimeout(tooltip.hidingTimerHandle); 155 tooltip.hidingTimerHandle = undefined; 156 } 157 if (this.shown) { 158 this.__hide(); 159 } 160 }, 161 162 __hideHandler: function(event) { 163 if (event.type == 'mouseleave' && this.__isInside(event.relatedTarget)) { 164 return; 165 } 166 167 this.hide(); 168 169 if (this.options.followMouse) { 170 rf.Event.unbindById(this.target, "mousemove" + this.namespace); 171 } 172 173 }, 174 175 /** 176 * @private 177 * @return {void} TODO ... 178 */ 179 __hide: function () { 180 var tooltip = this; 181 this.__delay(this.options.hideDelay, function () { 182 tooltip.__fireBeforeHide(); 183 tooltip.popup.hide(); 184 tooltip.shown = false; 185 tooltip.__fireHide(); 186 }); 187 }, 188 189 __mouseMoveHandler: function(event) { 190 this.saveShowEvent = event; 191 if (this.shown) { 192 this.popup.show(this.saveShowEvent); 193 } 194 }, 195 196 __showHandler: function(event) { 197 this.show(event); 198 var tooltip = this; 199 200 if (tooltip.options.followMouse) { 201 rf.Event.bindById(tooltip.target, "mousemove" + tooltip.namespace, tooltip.__mouseMoveHandler, tooltip); 202 } 203 }, 204 205 /** 206 * @methodOf 207 * @name PanelMenuItem#show 208 * 209 * TODO ... 210 * 211 * @return {void} TODO ... 212 */ 213 show: function (event) { 214 var tooltip = this; 215 if (tooltip.hidingTimerHandle) { 216 window.clearTimeout(tooltip.hidingTimerHandle); 217 tooltip.hidingTimerHandle = undefined; 218 } 219 220 if (!this.shown) { 221 SHOW_ACTION.exec(this, event); 222 } 223 224 }, 225 226 onCompleteHandler : function () { 227 this.__content().show(); 228 this.__loading().hide(); 229 230 return this.__fireShow(); 231 }, 232 233 /** 234 * @private 235 * @return {void} TODO ... 236 */ 237 __show: function (event) { 238 var tooltip = this; 239 this.__delay(this.options.showDelay, function () { 240 if (!tooltip.options.followMouse) { 241 tooltip.saveShowEvent = event; 242 } 243 if (!tooltip.shown) { 244 tooltip.__fireBeforeShow(); 245 tooltip.popup.show(tooltip.saveShowEvent); 246 } 247 //for showing tooltip in followMouse mode 248 tooltip.shown = true; 249 }); 250 }, 251 252 /***************************** Private Methods ****************************************************************/ 253 __delay : function (delay, action) { 254 var tooltip = this; 255 256 if (delay > 0) { 257 tooltip.hidingTimerHandle = window.setTimeout(function() { 258 action(); 259 260 if (tooltip.hidingTimerHandle) { 261 window.clearTimeout(tooltip.hidingTimerHandle); 262 tooltip.hidingTimerHandle = undefined; 263 } 264 }, delay); 265 } else { 266 action(); 267 } 268 }, 269 270 __detectAncestorNode: function(leaf, element) { 271 // Return true if "element" is "leaf" or one of its parents 272 var node = leaf; 273 while (node != null && node != element) { 274 node = node.parentNode; 275 } 276 return (node != null); 277 }, 278 279 __loading : function () { 280 return $(document.getElementById(this.id + ":loading")); 281 }, 282 283 __content : function () { 284 return $(document.getElementById(this.id + ":content")); 285 }, 286 287 __fireHide : function () { 288 return rf.Event.fireById(this.id, "hide", { id: this.id }); 289 }, 290 291 __fireShow : function () { 292 return rf.Event.fireById(this.id, "show", { id: this.id }); 293 }, 294 295 __fireBeforeHide : function () { 296 return rf.Event.fireById(this.id, "beforehide", { id: this.id }); 297 }, 298 299 __fireBeforeShow : function () { 300 return rf.Event.fireById(this.id, "beforeshow", { id: this.id }); 301 }, 302 303 /** 304 * @private 305 * */ 306 __addUserEventHandler : function (name) { 307 var handler = this.options["on" + name]; 308 if (handler) { 309 rf.Event.bindById(this.id, name + this.namespace, handler); 310 } 311 }, 312 313 __contains: function(id, elt) { 314 while (elt) { 315 if (id == elt.id) { 316 return true; 317 } 318 319 elt = elt.parentNode; 320 } 321 return false; 322 }, 323 324 __isInside: function(elt) { 325 return this.__contains(this.target, elt) || this.__contains(this.popupId, elt); 326 }, 327 328 destroy: function () { 329 rf.Event.unbindById(this.popupId, this.namespace); 330 rf.Event.unbindById(this.target, this.namespace); 331 this.popup.destroy(); 332 this.popup = null; 333 $super.destroy.call(this); 334 } 335 }); 336 337 // define super class link 338 var $super = rf.ui.Tooltip.$super; 339 })(RichFaces.jQuery, RichFaces);