Roo/bootstrap/Tooltip.js
[roojs1] / Roo / bootstrap / Tooltip.js
1 /*
2  * - LGPL
3  *
4  * Tooltip
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.Tooltip
10  * Bootstrap Tooltip class
11  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
12  * to determine which dom element triggers the tooltip.
13  * 
14  * It needs to add support for additional attributes like tooltip-position
15  * 
16  * @constructor
17  * Create a new Toolti
18  * @param {Object} config The config object
19  */
20
21 Roo.bootstrap.Tooltip = function(config){
22     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
23 };
24
25 Roo.apply(Roo.bootstrap.Tooltip, {
26     /**
27      * @function init initialize tooltip monitoring.
28      * @static
29      */
30     currentEl : false,
31     currentTip : false,
32     currentRegion : false,
33     
34     //  init : delay?
35     
36     init : function()
37     {
38         Roo.get(document).on('mouseover', this.enter ,this);
39         Roo.get(document).on('mouseout', this.leave, this);
40          
41         
42         this.currentTip = new Roo.bootstrap.Tooltip();
43     },
44     
45     enter : function(ev)
46     {
47         var dom = ev.getTarget();
48         
49         //Roo.log(['enter',dom]);
50         var el = Roo.fly(dom);
51         if (this.currentEl) {
52             //Roo.log(dom);
53             //Roo.log(this.currentEl);
54             //Roo.log(this.currentEl.contains(dom));
55             if (this.currentEl == el) {
56                 return;
57             }
58             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
59                 return;
60             }
61
62         }
63         
64         if (this.currentTip.el) {
65             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
66         }    
67         //Roo.log(ev);
68         var bindEl = el;
69         
70         // you can not look for children, as if el is the body.. then everythign is the child..
71         if (!el.attr('tooltip')) { //
72             if (!el.select("[tooltip]").elements.length) {
73                 return;
74             }
75             // is the mouse over this child...?
76             bindEl = el.select("[tooltip]").first();
77             var xy = ev.getXY();
78             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
79                 //Roo.log("not in region.");
80                 return;
81             }
82             //Roo.log("child element over..");
83             
84         }
85         this.currentEl = bindEl;
86         this.currentTip.bind(bindEl);
87         this.currentRegion = Roo.lib.Region.getRegion(dom);
88         this.currentTip.enter();
89         
90     },
91     leave : function(ev)
92     {
93         var dom = ev.getTarget();
94         //Roo.log(['leave',dom]);
95         if (!this.currentEl) {
96             return;
97         }
98         
99         
100         if (dom != this.currentEl.dom) {
101             return;
102         }
103         var xy = ev.getXY();
104         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
105             return;
106         }
107         // only activate leave if mouse cursor is outside... bounding box..
108         
109         
110         
111         
112         if (this.currentTip) {
113             this.currentTip.leave();
114         }
115         //Roo.log('clear currentEl');
116         this.currentEl = false;
117         
118         
119     },
120     alignment : {
121         'left' : ['r-l', [-2,0], 'right'],
122         'right' : ['l-r', [2,0], 'left'],
123         'bottom' : ['t-b', [0,2], 'top'],
124         'top' : [ 'b-t', [0,-2], 'bottom']
125     }
126     
127 });
128
129
130 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
131     
132     
133     bindEl : false,
134     
135     delay : null, // can be { show : 300 , hide: 500}
136     
137     timeout : null,
138     
139     hoverState : null, //???
140     
141     placement : 'bottom', 
142     
143     getAutoCreate : function(){
144     
145         var cfg = {
146            cls : 'tooltip',
147            role : 'tooltip',
148            cn : [
149                 {
150                     cls : 'tooltip-arrow'
151                 },
152                 {
153                     cls : 'tooltip-inner'
154                 }
155            ]
156         };
157         
158         return cfg;
159     },
160     bind : function(el)
161     {
162         this.bindEl = el;
163     },
164       
165     
166     enter : function () {
167        
168         if (this.timeout != null) {
169             clearTimeout(this.timeout);
170         }
171         
172         this.hoverState = 'in';
173          //Roo.log("enter - show");
174         if (!this.delay || !this.delay.show) {
175             this.show();
176             return;
177         }
178         var _t = this;
179         this.timeout = setTimeout(function () {
180             if (_t.hoverState == 'in') {
181                 _t.show();
182             }
183         }, this.delay.show);
184     },
185     leave : function()
186     {
187         clearTimeout(this.timeout);
188     
189         this.hoverState = 'out';
190          if (!this.delay || !this.delay.hide) {
191             this.hide();
192             return;
193         }
194        
195         var _t = this;
196         this.timeout = setTimeout(function () {
197             //Roo.log("leave - timeout");
198             
199             if (_t.hoverState == 'out') {
200                 _t.hide();
201                 Roo.bootstrap.Tooltip.currentEl = false;
202             }
203         }, delay);
204     },
205     
206     show : function ()
207     {
208         if (!this.el) {
209             this.render(document.body);
210         }
211         // set content.
212         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
213         
214         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
215         
216         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
217         
218         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
219         
220         var placement = typeof this.placement == 'function' ?
221             this.placement.call(this, this.el, on_el) :
222             this.placement;
223             
224         var autoToken = /\s?auto?\s?/i;
225         var autoPlace = autoToken.test(placement);
226         if (autoPlace) {
227             placement = placement.replace(autoToken, '') || 'top';
228         }
229         
230         //this.el.detach()
231         //this.el.setXY([0,0]);
232         this.el.show();
233         //this.el.dom.style.display='block';
234         
235         //this.el.appendTo(on_el);
236         
237         var p = this.getPosition();
238         var box = this.el.getBox();
239         
240         if (autoPlace) {
241             // fixme..
242         }
243         
244         var align = Roo.bootstrap.Tooltip.alignment[placement];
245         
246         Roo.log(align);
247         
248         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
249         
250         Roo.log(xy);
251         
252         if(placement == 'top' || placement == 'bottom'){
253             if(xy[0] < 0){
254                 placement = 'right';
255             }
256             
257             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
258                 placement = 'left';
259             }
260             
261             var scroll = Roo.select('body', true).first().getScroll();
262             
263             if(xy[1] < Roo.lib.Dom.getViewHeight() + scroll.top){
264                 placement = 'top';
265             }
266             
267         }
268         
269         align = Roo.bootstrap.Tooltip.alignment[placement];
270         
271         this.el.alignTo(this.bindEl, align[0],align[1]);
272         //var arrow = this.el.select('.arrow',true).first();
273         //arrow.set(align[2], 
274         
275         this.el.addClass(placement);
276         
277         this.el.addClass('in fade');
278         
279         this.hoverState = null;
280         
281         if (this.el.hasClass('fade')) {
282             // fade it?
283         }
284         
285     },
286     hide : function()
287     {
288          
289         if (!this.el) {
290             return;
291         }
292         //this.el.setXY([0,0]);
293         this.el.removeClass('in');
294         //this.el.hide();
295         
296     }
297     
298 });
299  
300
301