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