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