1/** 2 * @license 3 * jQuery Tools @VERSION Tooltip - UI essentials 4 * 5 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. 6 * 7 * http://flowplayer.org/tools/tooltip/ 8 * 9 * Since: November 2008 10 * Date: @DATE 11 */ 12(function($) { 13 // static constructs 14 $.tools = $.tools || {version: '@VERSION'}; 15 16 $.tools.tooltip = { 17 18 conf: { 19 20 // default effect variables 21 effect: 'toggle', 22 fadeOutSpeed: "fast", 23 predelay: 0, 24 delay: 30, 25 opacity: 1, 26 tip: 0, 27 28 // 'top', 'bottom', 'right', 'left', 'center' 29 position: ['top', 'center'], 30 offset: [0, 0], 31 relative: false, 32 cancelDefault: true, 33 34 // type to event mapping 35 events: { 36 def: "mouseenter,mouseleave", 37 input: "focus,blur", 38 widget: "focus mouseenter,blur mouseleave", 39 tooltip: "mouseenter,mouseleave" 40 }, 41 42 // 1.2 43 layout: '<div/>', 44 tipClass: 'tooltip' 45 }, 46 47 addEffect: function(name, loadFn, hideFn) { 48 effects[name] = [loadFn, hideFn]; 49 } 50 }; 51 52 53 var effects = { 54 toggle: [ 55 function(done) { 56 var conf = this.getConf(), tip = this.getTip(), o = conf.opacity; 57 if (o < 1) { tip.css({opacity: o}); } 58 tip.show(); 59 done.call(); 60 }, 61 62 function(done) { 63 this.getTip().hide(); 64 done.call(); 65 } 66 ], 67 68 fade: [ 69 function(done) { 70 var conf = this.getConf(); 71 this.getTip().fadeTo(conf.fadeInSpeed, conf.opacity, done); 72 }, 73 function(done) { 74 this.getTip().fadeOut(this.getConf().fadeOutSpeed, done); 75 } 76 ] 77 }; 78 79 80 /* calculate tip position relative to the trigger */ 81 function getPosition(trigger, tip, conf) { 82 83 84 // get origin top/left position 85 var top = conf.relative ? trigger.position().top : trigger.offset().top, 86 left = conf.relative ? trigger.position().left : trigger.offset().left, 87 pos = conf.position[0]; 88 89 top -= tip.outerHeight() - conf.offset[0]; 90 left += trigger.outerWidth() + conf.offset[1]; 91 92 // adjust Y 93 var height = tip.outerHeight() + trigger.outerHeight(); 94 if (pos == 'center') { top += height / 2; } 95 if (pos == 'bottom') { top += height; } 96 97 98 // adjust X 99 pos = conf.position[1]; 100 var width = tip.outerWidth() + trigger.outerWidth(); 101 if (pos == 'center') { left -= width / 2; } 102 if (pos == 'left') { left -= width; } 103 104 return {top: top, left: left}; 105 } 106 107 108
109 function Tooltip(trigger, conf) { 110 111 var self = this, 112 fire = trigger.add(self), 113 tip, 114 timer = 0, 115 pretimer = 0, 116 title = trigger.attr("title"), 117 tipAttr = trigger.attr("data-tooltip"), 118 effect = effects[conf.effect], 119 shown, 120 121 // get show/hide configuration 122 isInput = trigger.is(":input"), 123 isWidget = isInput && trigger.is(":checkbox, :radio, select, :button, :submit"), 124 type = trigger.attr("type"), 125 evt = conf.events[type] || conf.events[isInput ? (isWidget ? 'widget' : 'input') : 'def']; 126 127 128 // check that configuration is sane 129 if (!effect) { throw "Nonexistent effect \"" + conf.effect + "\""; } 130 131 evt = evt.split(/,\s*/); 132 if (evt.length != 2) { throw "Tooltip: bad events configuration for " + type; } 133 134 135 // trigger --> show 136 trigger.bind(evt[0], function(e) { 137 138 clearTimeout(timer); 139 if (conf.predelay) { 140 pretimer = setTimeout(function() { self.show(e); }, conf.predelay); 141 142 } else { 143 self.show(e); 144 } 145 146 // trigger --> hide 147 }).bind(evt[1], function(e) { 148 clearTimeout(pretimer); 149 if (conf.delay) { 150 timer = setTimeout(function() { self.hide(e); }, conf.delay); 151 152 } else { 153 self.hide(e); 154 } 155 156 }); 157 158 159 // remove default title 160 if (title && conf.cancelDefault) { 161 trigger.removeAttr("title"); 162 trigger.data("title", title); 163 } 164 165 $.extend(self, { 166 167 show: function(e) { 168 169 // tip not initialized yet 170 if (!tip) { 171 172 // data-tooltip 173 if (tipAttr) { 174 tip = $(tipAttr); 175 176 // autogenerated tooltip 177 } else if (title) { 178 tip = $(conf.layout).addClass(conf.tipClass).appendTo(document.body) 179 .hide().append(title); 180 181 // single tip element for all 182 } else if (conf.tip) { 183 tip = $(conf.tip).eq(0); 184 185 // manual tooltip 186 } else { 187 tip = trigger.next(); 188 if (!tip.length) { tip = trigger.parent().next(); } 189 } 190 191 if (!tip.length) { throw "Cannot find tooltip for " + trigger; } 192 } 193 194 if (self.isShown()) { return self; } 195 196 // stop previous animation 197 tip.stop(true, true); 198 199 // get position 200 var pos = getPosition(trigger, tip, conf); 201 202 203 // onBeforeShow 204 e = e || $.Event(); 205 e.type = "onBeforeShow"; 206 fire.trigger(e, [pos]); 207 if (e.isDefaultPrevented()) { return self; } 208 209 210 // onBeforeShow may have altered the configuration 211 pos = getPosition(trigger, tip, conf); 212 213 // set position 214 tip.css({position:'absolute', top: pos.top, left: pos.left}); 215 216 shown = true; 217 218 // invoke effect 219 effect[0].call(self, function() { 220 e.type = "onShow"; 221 shown = 'full'; 222 fire.trigger(e); 223 }); 224 225 226 // tooltip events 227 var event = conf.events.tooltip.split(/,\s*/); 228 229 tip.bind(event[0], function() { 230 clearTimeout(timer); 231 clearTimeout(pretimer); 232 }); 233 234 if (event[1] && !trigger.is("input:not(:checkbox, :radio), textarea")) { 235 tip.bind(event[1], function(e) { 236 237 // being moved to the trigger element 238 if (e.relatedTarget != trigger[0]) { 239 trigger.trigger(evt[1].split(" ")[0]); 240 } 241 }); 242 } 243 244 return self; 245 }, 246 247 hide: function(e) { 248 249 if (!tip || !self.isShown()) { return self; } 250 251 // onBeforeHide 252 e = e || $.Event(); 253 e.type = "onBeforeHide"; 254 fire.trigger(e); 255 if (e.isDefaultPrevented()) { return; } 256 257 shown = false; 258 259 effects[conf.effect][1].call(self, function() { 260 e.type = "onHide"; 261 fire.trigger(e); 262 }); 263 264 return self; 265 }, 266 267 isShown: function(fully) { 268 return fully ? shown == 'full' : shown; 269 }, 270 271 getConf: function() { 272 return conf; 273 }, 274 275 getTip: function() { 276 return tip; 277 }, 278 279 getTrigger: function() { 280 return trigger; 281 } 282 283 }); 284 285 // callbacks 286 $.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function(i, name) { 287 288 // configuration 289 if ($.isFunction(conf[name])) { 290 $(self).bind(name, conf[name]); 291 } 292 293 // API
294 self[name] = function(fn) { 295 $(self).bind(name, fn); 296 return self; 297 }; 298 }); 299 300 } 301 302 303 // jQuery plugin implementation 304 $.fn.tooltip = function(conf) { 305 306 // return existing instance 307 var api = this.data("tooltip"); 308 if (api) { return api; } 309 310 conf = $.extend(true, {}, $.tools.tooltip.conf, conf); 311 312 // position can also be given as string 313 if (typeof conf.position == 'string') { 314 conf.position = conf.position.split(/,?\s/); 315 } 316 317 // install tooltip for each entry in jQuery object 318 this.each(function() { 319 api = new Tooltip($(this), conf); 320 $(this).data("tooltip", api); 321 }); 322 323 return conf.api ? api: this; 324 }; 325 326}) (jQuery); 327 328 329
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.