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         
52         Roo.log(el);
53         if (this.currentEl) {
54             //Roo.log(dom);
55             //Roo.log(this.currentEl);
56             //Roo.log(this.currentEl.contains(dom));
57             if (this.currentEl == el) {
58                 return;
59             }
60             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
61                 return;
62             }
63
64         }
65         
66         
67         
68         if (this.currentTip.el) {
69             this.currentTip.el.hide(); // force hiding...
70         }    
71         //Roo.log(ev);
72         var bindEl = el;
73         
74         // you can not look for children, as if el is the body.. then everythign is the child..
75         if (!el.attr('tooltip')) { //
76             if (!el.select("[tooltip]").elements.length) {
77                 return;
78             }
79             // is the mouse over this child...?
80             bindEl = el.select("[tooltip]").first();
81             var xy = ev.getXY();
82             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
83                 //Roo.log("not in region.");
84                 return;
85             }
86             //Roo.log("child element over..");
87             
88         }
89         this.currentEl = bindEl;
90         this.currentTip.bind(bindEl);
91         this.currentRegion = Roo.lib.Region.getRegion(dom);
92         this.currentTip.enter();
93         
94     },
95     leave : function(ev)
96     {
97         var dom = ev.getTarget();
98         //Roo.log(['leave',dom]);
99         if (!this.currentEl) {
100             return;
101         }
102         
103         
104         if (dom != this.currentEl.dom) {
105             return;
106         }
107         var xy = ev.getXY();
108         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
109             return;
110         }
111         // only activate leave if mouse cursor is outside... bounding box..
112         
113         
114         
115         
116         if (this.currentTip) {
117             this.currentTip.leave();
118         }
119         //Roo.log('clear currentEl');
120         this.currentEl = false;
121         
122         
123     },
124     alignment : {
125         'left' : ['r-l', [-2,0], 'right'],
126         'right' : ['l-r', [2,0], 'left'],
127         'bottom' : ['t-b', [0,2], 'top'],
128         'top' : [ 'b-t', [0,-2], 'bottom']
129     }
130     
131 });
132
133
134 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
135     
136     
137     bindEl : false,
138     
139     delay : null, // can be { show : 300 , hide: 500}
140     
141     timeout : null,
142     
143     hoverState : null, //???
144     
145     placement : 'bottom', 
146     
147     getAutoCreate : function(){
148     
149         var cfg = {
150            cls : 'tooltip',
151            role : 'tooltip',
152            cn : [
153                 {
154                     cls : 'tooltip-arrow'
155                 },
156                 {
157                     cls : 'tooltip-inner'
158                 }
159            ]
160         };
161         
162         return cfg;
163     },
164     bind : function(el)
165     {
166         this.bindEl = el;
167     },
168       
169     
170     enter : function () {
171        
172         if (this.timeout != null) {
173             clearTimeout(this.timeout);
174         }
175         
176         this.hoverState = 'in';
177          //Roo.log("enter - show");
178         if (!this.delay || !this.delay.show) {
179             this.show();
180             return;
181         }
182         var _t = this;
183         this.timeout = setTimeout(function () {
184             if (_t.hoverState == 'in') {
185                 _t.show();
186             }
187         }, this.delay.show);
188     },
189     leave : function()
190     {
191         clearTimeout(this.timeout);
192     
193         this.hoverState = 'out';
194          if (!this.delay || !this.delay.hide) {
195             this.hide();
196             return;
197         }
198        
199         var _t = this;
200         this.timeout = setTimeout(function () {
201             //Roo.log("leave - timeout");
202             
203             if (_t.hoverState == 'out') {
204                 _t.hide();
205                 Roo.bootstrap.Tooltip.currentEl = false;
206             }
207         }, delay);
208     },
209     
210     show : function ()
211     {
212         if (!this.el) {
213             this.render(document.body);
214         }
215         // set content.
216         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
217         
218         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
219         
220         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
221         
222         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
223         
224         var placement = typeof this.placement == 'function' ?
225             this.placement.call(this, this.el, on_el) :
226             this.placement;
227             
228         var autoToken = /\s?auto?\s?/i;
229         var autoPlace = autoToken.test(placement);
230         if (autoPlace) {
231             placement = placement.replace(autoToken, '') || 'top';
232         }
233         
234         //this.el.detach()
235         //this.el.setXY([0,0]);
236         this.el.show();
237         //this.el.dom.style.display='block';
238         
239         //this.el.appendTo(on_el);
240         
241         var p = this.getPosition();
242         var box = this.el.getBox();
243         
244         if (autoPlace) {
245             // fixme..
246         }
247         
248         var align = Roo.bootstrap.Tooltip.alignment[placement];
249         
250         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
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         
262         align = Roo.bootstrap.Tooltip.alignment[placement];
263         
264         this.el.alignTo(this.bindEl, align[0],align[1]);
265         //var arrow = this.el.select('.arrow',true).first();
266         //arrow.set(align[2], 
267         
268         this.el.addClass(placement);
269         
270         this.el.addClass('in fade');
271         
272         this.hoverState = null;
273         
274         if (this.el.hasClass('fade')) {
275             // fade it?
276         }
277         
278     },
279     hide : function()
280     {
281          
282         if (!this.el) {
283             return;
284         }
285         //this.el.setXY([0,0]);
286         this.el.removeClass('in');
287         //this.el.hide();
288         
289     }
290     
291 });
292  
293
294