Upgrade to ExtJS 3.2.2 - Released 06/02/2010
[extjs.git] / src / widgets / tips / QuickTip.js
1 /*!
2  * Ext JS Library 3.2.2
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.QuickTip
9  * @extends Ext.ToolTip
10  * @xtype quicktip
11  * A specialized tooltip class for tooltips that can be specified in markup and automatically managed by the global
12  * {@link Ext.QuickTips} instance.  See the QuickTips class header for additional usage details and examples.
13  * @constructor
14  * Create a new Tip
15  * @param {Object} config The configuration options
16  */
17 Ext.QuickTip = Ext.extend(Ext.ToolTip, {
18     /**
19      * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to associate with this quicktip (defaults to the document).
20      */
21     /**
22      * @cfg {Boolean} interceptTitles True to automatically use the element's DOM title value if available (defaults to false).
23      */
24     interceptTitles : false,
25
26     // private
27     tagConfig : {
28         namespace : "ext",
29         attribute : "qtip",
30         width : "qwidth",
31         target : "target",
32         title : "qtitle",
33         hide : "hide",
34         cls : "qclass",
35         align : "qalign",
36         anchor : "anchor"
37     },
38
39     // private
40     initComponent : function(){
41         this.target = this.target || Ext.getDoc();
42         this.targets = this.targets || {};
43         Ext.QuickTip.superclass.initComponent.call(this);
44     },
45
46     /**
47      * Configures a new quick tip instance and assigns it to a target element.  The following config values are
48      * supported (for example usage, see the {@link Ext.QuickTips} class header):
49      * <div class="mdetail-params"><ul>
50      * <li>autoHide</li>
51      * <li>cls</li>
52      * <li>dismissDelay (overrides the singleton value)</li>
53      * <li>target (required)</li>
54      * <li>text (required)</li>
55      * <li>title</li>
56      * <li>width</li></ul></div>
57      * @param {Object} config The config object
58      */
59     register : function(config){
60         var cs = Ext.isArray(config) ? config : arguments;
61         for(var i = 0, len = cs.length; i < len; i++){
62             var c = cs[i];
63             var target = c.target;
64             if(target){
65                 if(Ext.isArray(target)){
66                     for(var j = 0, jlen = target.length; j < jlen; j++){
67                         this.targets[Ext.id(target[j])] = c;
68                     }
69                 } else{
70                     this.targets[Ext.id(target)] = c;
71                 }
72             }
73         }
74     },
75
76     /**
77      * Removes this quick tip from its element and destroys it.
78      * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
79      */
80     unregister : function(el){
81         delete this.targets[Ext.id(el)];
82     },
83     
84     /**
85      * Hides a visible tip or cancels an impending show for a particular element.
86      * @param {String/HTMLElement/Element} el The element that is the target of the tip.
87      */
88     cancelShow: function(el){
89         var at = this.activeTarget;
90         el = Ext.get(el).dom;
91         if(this.isVisible()){
92             if(at && at.el == el){
93                 this.hide();
94             }
95         }else if(at && at.el == el){
96             this.clearTimer('show');
97         }
98     },
99     
100     getTipCfg: function(e) {
101         var t = e.getTarget(), 
102             ttp, 
103             cfg;
104         if(this.interceptTitles && t.title && Ext.isString(t.title)){
105             ttp = t.title;
106             t.qtip = ttp;
107             t.removeAttribute("title");
108             e.preventDefault();
109         }else{
110             cfg = this.tagConfig;
111             ttp = t.qtip || Ext.fly(t).getAttribute(cfg.attribute, cfg.namespace);
112         }
113         return ttp;
114     },
115
116     // private
117     onTargetOver : function(e){
118         if(this.disabled){
119             return;
120         }
121         this.targetXY = e.getXY();
122         var t = e.getTarget();
123         if(!t || t.nodeType !== 1 || t == document || t == document.body){
124             return;
125         }
126         if(this.activeTarget && ((t == this.activeTarget.el) || Ext.fly(this.activeTarget.el).contains(t))){
127             this.clearTimer('hide');
128             this.show();
129             return;
130         }
131         if(t && this.targets[t.id]){
132             this.activeTarget = this.targets[t.id];
133             this.activeTarget.el = t;
134             this.anchor = this.activeTarget.anchor;
135             if(this.anchor){
136                 this.anchorTarget = t;
137             }
138             this.delayShow();
139             return;
140         }
141         var ttp, et = Ext.fly(t), cfg = this.tagConfig, ns = cfg.namespace;
142         if(ttp = this.getTipCfg(e)){
143             var autoHide = et.getAttribute(cfg.hide, ns);
144             this.activeTarget = {
145                 el: t,
146                 text: ttp,
147                 width: et.getAttribute(cfg.width, ns),
148                 autoHide: autoHide != "user" && autoHide !== 'false',
149                 title: et.getAttribute(cfg.title, ns),
150                 cls: et.getAttribute(cfg.cls, ns),
151                 align: et.getAttribute(cfg.align, ns)
152                 
153             };
154             this.anchor = et.getAttribute(cfg.anchor, ns);
155             if(this.anchor){
156                 this.anchorTarget = t;
157             }
158             this.delayShow();
159         }
160     },
161
162     // private
163     onTargetOut : function(e){
164
165         // If moving within the current target, and it does not have a new tip, ignore the mouseout
166         if (this.activeTarget && e.within(this.activeTarget.el) && !this.getTipCfg(e)) {
167             return;
168         }
169
170         this.clearTimer('show');
171         if(this.autoHide !== false){
172             this.delayHide();
173         }
174     },
175
176     // inherit docs
177     showAt : function(xy){
178         var t = this.activeTarget;
179         if(t){
180             if(!this.rendered){
181                 this.render(Ext.getBody());
182                 this.activeTarget = t;
183             }
184             if(t.width){
185                 this.setWidth(t.width);
186                 this.body.setWidth(this.adjustBodyWidth(t.width - this.getFrameWidth()));
187                 this.measureWidth = false;
188             } else{
189                 this.measureWidth = true;
190             }
191             this.setTitle(t.title || '');
192             this.body.update(t.text);
193             this.autoHide = t.autoHide;
194             this.dismissDelay = t.dismissDelay || this.dismissDelay;
195             if(this.lastCls){
196                 this.el.removeClass(this.lastCls);
197                 delete this.lastCls;
198             }
199             if(t.cls){
200                 this.el.addClass(t.cls);
201                 this.lastCls = t.cls;
202             }
203             if(this.anchor){
204                 this.constrainPosition = false;
205             }else if(t.align){ // TODO: this doesn't seem to work consistently
206                 xy = this.el.getAlignToXY(t.el, t.align);
207                 this.constrainPosition = false;
208             }else{
209                 this.constrainPosition = true;
210             }
211         }
212         Ext.QuickTip.superclass.showAt.call(this, xy);
213     },
214
215     // inherit docs
216     hide: function(){
217         delete this.activeTarget;
218         Ext.QuickTip.superclass.hide.call(this);
219     }
220 });
221 Ext.reg('quicktip', Ext.QuickTip);