|
1 /* |
|
2 * jQuery Tooltip plugin 1.3 |
|
3 * |
|
4 * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/ |
|
5 * http://docs.jquery.com/Plugins/Tooltip |
|
6 * |
|
7 * Copyright (c) 2006 - 2008 Jörn Zaefferer |
|
8 * |
|
9 * $Id: jquery.tooltip.js 5741 2008-06-21 15:22:16Z joern.zaefferer $ |
|
10 * |
|
11 * Dual licensed under the MIT and GPL licenses: |
|
12 * http://www.opensource.org/licenses/mit-license.php |
|
13 * http://www.gnu.org/licenses/gpl.html |
|
14 */ |
|
15 |
|
16 ;(function($) { |
|
17 |
|
18 // the tooltip element |
|
19 var helper = {}, |
|
20 // the current tooltipped element |
|
21 current, |
|
22 // the title of the current element, used for restoring |
|
23 title, |
|
24 // timeout id for delayed tooltips |
|
25 tID, |
|
26 // IE 5.5 or 6 |
|
27 IE = $.browser.msie && /MSIE\s(5\.5|6\.)/.test(navigator.userAgent), |
|
28 // flag for mouse tracking |
|
29 track = false; |
|
30 |
|
31 $.tooltip = { |
|
32 blocked: false, |
|
33 defaults: { |
|
34 delay: 200, |
|
35 fade: false, |
|
36 showURL: true, |
|
37 extraClass: "", |
|
38 top: 15, |
|
39 left: 15, |
|
40 id: "tooltip" |
|
41 }, |
|
42 block: function() { |
|
43 $.tooltip.blocked = !$.tooltip.blocked; |
|
44 } |
|
45 }; |
|
46 |
|
47 $.fn.extend({ |
|
48 tooltip: function(settings) { |
|
49 settings = $.extend({}, $.tooltip.defaults, settings); |
|
50 createHelper(settings); |
|
51 return this.each(function() { |
|
52 $.data(this, "tooltip", settings); |
|
53 this.tOpacity = helper.parent.css("opacity"); |
|
54 // copy tooltip into its own expando and remove the title |
|
55 this.tooltipText = this.title; |
|
56 $(this).removeAttr("title"); |
|
57 // also remove alt attribute to prevent default tooltip in IE |
|
58 this.alt = ""; |
|
59 }) |
|
60 .mouseover(save) |
|
61 .mouseout(hide) |
|
62 .click(hide); |
|
63 }, |
|
64 fixPNG: IE ? function() { |
|
65 return this.each(function () { |
|
66 var image = $(this).css('backgroundImage'); |
|
67 if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) { |
|
68 image = RegExp.$1; |
|
69 $(this).css({ |
|
70 'backgroundImage': 'none', |
|
71 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" |
|
72 }).each(function () { |
|
73 var position = $(this).css('position'); |
|
74 if (position != 'absolute' && position != 'relative') |
|
75 $(this).css('position', 'relative'); |
|
76 }); |
|
77 } |
|
78 }); |
|
79 } : function() { return this; }, |
|
80 unfixPNG: IE ? function() { |
|
81 return this.each(function () { |
|
82 $(this).css({'filter': '', backgroundImage: ''}); |
|
83 }); |
|
84 } : function() { return this; }, |
|
85 hideWhenEmpty: function() { |
|
86 return this.each(function() { |
|
87 $(this)[ $(this).html() ? "show" : "hide" ](); |
|
88 }); |
|
89 }, |
|
90 url: function() { |
|
91 return this.attr('href') || this.attr('src'); |
|
92 } |
|
93 }); |
|
94 |
|
95 function createHelper(settings) { |
|
96 // there can be only one tooltip helper |
|
97 if( helper.parent ) |
|
98 return; |
|
99 // create the helper, h3 for title, div for url |
|
100 helper.parent = $('<div id="' + settings.id + '"><h3></h3><div class="body"></div><div class="url"></div></div>') |
|
101 // add to document |
|
102 .appendTo(document.body) |
|
103 // hide it at first |
|
104 .hide(); |
|
105 |
|
106 // apply bgiframe if available |
|
107 if ( $.fn.bgiframe ) |
|
108 helper.parent.bgiframe(); |
|
109 |
|
110 // save references to title and url elements |
|
111 helper.title = $('h3', helper.parent); |
|
112 helper.body = $('div.body', helper.parent); |
|
113 helper.url = $('div.url', helper.parent); |
|
114 } |
|
115 |
|
116 function settings(element) { |
|
117 return $.data(element, "tooltip"); |
|
118 } |
|
119 |
|
120 // main event handler to start showing tooltips |
|
121 function handle(event) { |
|
122 // show helper, either with timeout or on instant |
|
123 if( settings(this).delay ) |
|
124 tID = setTimeout(show, settings(this).delay); |
|
125 else |
|
126 show(); |
|
127 |
|
128 // if selected, update the helper position when the mouse moves |
|
129 track = !!settings(this).track; |
|
130 $(document.body).bind('mousemove', update); |
|
131 |
|
132 // update at least once |
|
133 update(event); |
|
134 } |
|
135 |
|
136 // save elements title before the tooltip is displayed |
|
137 function save() { |
|
138 // if this is the current source, or it has no title (occurs with click event), stop |
|
139 if ( $.tooltip.blocked || this == current || (!this.tooltipText && !settings(this).bodyHandler) ) |
|
140 return; |
|
141 |
|
142 // save current |
|
143 current = this; |
|
144 title = this.tooltipText; |
|
145 |
|
146 if ( settings(this).bodyHandler ) { |
|
147 helper.title.hide(); |
|
148 var bodyContent = settings(this).bodyHandler.call(this); |
|
149 if (bodyContent.nodeType || bodyContent.jquery) { |
|
150 helper.body.empty().append(bodyContent) |
|
151 } else { |
|
152 helper.body.html( bodyContent ); |
|
153 } |
|
154 helper.body.show(); |
|
155 } else if ( settings(this).showBody ) { |
|
156 var parts = title.split(settings(this).showBody); |
|
157 helper.title.html(parts.shift()).show(); |
|
158 helper.body.empty(); |
|
159 for(var i = 0, part; (part = parts[i]); i++) { |
|
160 if(i > 0) |
|
161 helper.body.append("<br/>"); |
|
162 helper.body.append(part); |
|
163 } |
|
164 helper.body.hideWhenEmpty(); |
|
165 } else { |
|
166 helper.title.html(title).show(); |
|
167 helper.body.hide(); |
|
168 } |
|
169 |
|
170 // if element has href or src, add and show it, otherwise hide it |
|
171 if( settings(this).showURL && $(this).url() ) |
|
172 helper.url.html( $(this).url().replace('http://', '') ).show(); |
|
173 else |
|
174 helper.url.hide(); |
|
175 |
|
176 // add an optional class for this tip |
|
177 helper.parent.addClass(settings(this).extraClass); |
|
178 |
|
179 // fix PNG background for IE |
|
180 if (settings(this).fixPNG ) |
|
181 helper.parent.fixPNG(); |
|
182 |
|
183 handle.apply(this, arguments); |
|
184 } |
|
185 |
|
186 // delete timeout and show helper |
|
187 function show() { |
|
188 tID = null; |
|
189 if ((!IE || !$.fn.bgiframe) && settings(current).fade) { |
|
190 if (helper.parent.is(":animated")) |
|
191 helper.parent.stop().show().fadeTo(settings(current).fade, current.tOpacity); |
|
192 else |
|
193 helper.parent.is(':visible') ? helper.parent.fadeTo(settings(current).fade, current.tOpacity) : helper.parent.fadeIn(settings(current).fade); |
|
194 } else { |
|
195 helper.parent.show(); |
|
196 } |
|
197 update(); |
|
198 } |
|
199 |
|
200 /** |
|
201 * callback for mousemove |
|
202 * updates the helper position |
|
203 * removes itself when no current element |
|
204 */ |
|
205 function update(event) { |
|
206 if($.tooltip.blocked) |
|
207 return; |
|
208 |
|
209 if (event && event.target.tagName == "OPTION") { |
|
210 return; |
|
211 } |
|
212 |
|
213 // stop updating when tracking is disabled and the tooltip is visible |
|
214 if ( !track && helper.parent.is(":visible")) { |
|
215 $(document.body).unbind('mousemove', update) |
|
216 } |
|
217 |
|
218 // if no current element is available, remove this listener |
|
219 if( current == null ) { |
|
220 $(document.body).unbind('mousemove', update); |
|
221 return; |
|
222 } |
|
223 |
|
224 // remove position helper classes |
|
225 helper.parent.removeClass("viewport-right").removeClass("viewport-bottom"); |
|
226 |
|
227 var left = helper.parent[0].offsetLeft; |
|
228 var top = helper.parent[0].offsetTop; |
|
229 if (event) { |
|
230 // position the helper 15 pixel to bottom right, starting from mouse position |
|
231 left = event.pageX + settings(current).left; |
|
232 top = event.pageY + settings(current).top; |
|
233 var right='auto'; |
|
234 if (settings(current).positionLeft) { |
|
235 right = $(window).width() - left; |
|
236 left = 'auto'; |
|
237 } |
|
238 helper.parent.css({ |
|
239 left: left, |
|
240 right: right, |
|
241 top: top |
|
242 }); |
|
243 } |
|
244 |
|
245 var v = viewport(), |
|
246 h = helper.parent[0]; |
|
247 // check horizontal position |
|
248 if (v.x + v.cx < h.offsetLeft + h.offsetWidth) { |
|
249 left -= h.offsetWidth + 20 + settings(current).left; |
|
250 helper.parent.css({left: left + 'px'}).addClass("viewport-right"); |
|
251 } |
|
252 // check vertical position |
|
253 if (v.y + v.cy < h.offsetTop + h.offsetHeight) { |
|
254 top -= h.offsetHeight + 20 + settings(current).top; |
|
255 helper.parent.css({top: top + 'px'}).addClass("viewport-bottom"); |
|
256 } |
|
257 } |
|
258 |
|
259 function viewport() { |
|
260 return { |
|
261 x: $(window).scrollLeft(), |
|
262 y: $(window).scrollTop(), |
|
263 cx: $(window).width(), |
|
264 cy: $(window).height() |
|
265 }; |
|
266 } |
|
267 |
|
268 // hide helper and restore added classes and the title |
|
269 function hide(event) { |
|
270 if($.tooltip.blocked) |
|
271 return; |
|
272 // clear timeout if possible |
|
273 if(tID) |
|
274 clearTimeout(tID); |
|
275 // no more current element |
|
276 current = null; |
|
277 |
|
278 var tsettings = settings(this); |
|
279 function complete() { |
|
280 helper.parent.removeClass( tsettings.extraClass ).hide().css("opacity", ""); |
|
281 } |
|
282 if ((!IE || !$.fn.bgiframe) && tsettings.fade) { |
|
283 if (helper.parent.is(':animated')) |
|
284 helper.parent.stop().fadeTo(tsettings.fade, 0, complete); |
|
285 else |
|
286 helper.parent.stop().fadeOut(tsettings.fade, complete); |
|
287 } else |
|
288 complete(); |
|
289 |
|
290 if( settings(this).fixPNG ) |
|
291 helper.parent.unfixPNG(); |
|
292 } |
|
293 |
|
294 })(jQuery); |