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