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