vendor: 11,251 bytes, lines 1-266
1/** 2 * Hover balloon on elements without css and images. 3 * 4 * Copyright (c) 2011 Hayato Takenaka 5 * Licensed under the MIT license: 6 * http://www.opensource.org/licenses/mit-license.php 7 * @author: Hayato Takenaka (https://urin.github.io) 8 * @version: 1.1.2 - 2017/04/30 9**/ 10(function($) { 11 //----------------------------------------------------------------------------- 12 // Private 13 //----------------------------------------------------------------------------- 14 // Helper for meta programming 15 const Meta = { 16 pos: $.extend(['top', 'bottom', 'left', 'right'], {camel: ['Top', 'Bottom', 'Left', 'Right']}), 17 size: $.extend(['height', 'width'], {camel: ['Height', 'Width']}), 18 getRelativeNames: function(position) { 19 const idx = { 20 pos: { 21 o: position, // origin 22 f: (position % 2 === 0) ? position + 1 : position - 1, // faced 23 p1: (position % 2 === 0) ? position : position - 1, 24 p2: (position % 2 === 0) ? position + 1 : position, 25 c1: (position < 2) ? 2 : 0, 26 c2: (position < 2) ? 3 : 1 27 }, 28 size: { 29 p: (position < 2) ? 0 : 1, // parallel 30 c: (position < 2) ? 1 : 0 // cross 31 } 32 }; 33 const names = {}; 34 for(var m1 in idx) { 35 if(!names[m1]) { names[m1] = {}; } 36 for(var m2 in idx[m1]) { 37 names[m1][m2] = Meta[m1][idx[m1][m2]]; 38 if(!names.camel) { names.camel = {}; } 39 if(!names.camel[m1]) { names.camel[m1] = {}; } 40 names.camel[m1][m2] = Meta[m1].camel[idx[m1][m2]]; 41 } 42 } 43 names.isTopLeft = (names.pos.o === names.pos.p1); 44 return names; 45 } 46 }; 47 48 // Helper class to handle position and size as numerical pixels. 49 function NumericalBoxElement() { this.initialize.apply(this, arguments); } 50 (function() { 51 // Method factories 52 const Methods = { 53 setBorder: function(pos, isVertical) { 54 return function(value) { 55 this.$.css('border-' + pos.toLowerCase() + '-width', value + 'px'); 56 this['border' + pos] = value; 57 return (this.isActive) ? digitalize(this, isVertical) : this; 58 } 59 }, 60 setPosition: function(pos, isVertical) { 61 return function(value) { 62 this.$.css(pos.toLowerCase(), value + 'px'); 63 this[pos.toLowerCase()] = value; 64 return (this.isActive) ? digitalize(this, isVertical) : this; 65 } 66 } 67 }; 68 69 NumericalBoxElement.prototype = { 70 initialize: function($element) { 71 this.$ = $element; 72 $.extend(true, this, this.$.offset(), {center: {}, inner: {center: {}}}); 73 for(var i = 0; i < Meta.pos.length; i++) { 74 this['border' + Meta.pos.camel[i]] = parseInt(this.$.css('border-' + Meta.pos[i] + '-width')) || 0; 75 } 76 this.active(); 77 }, 78 active: function() { this.isActive = true; digitalize(this); return this; }, 79 inactive: function() { this.isActive = false; return this; } 80 }; 81 for(var i = 0; i < Meta.pos.length; i++) { 82 NumericalBoxElement.prototype['setBorder' + Meta.pos.camel[i]] = Methods.setBorder(Meta.pos.camel[i], (i < 2)); 83 if(i % 2 === 0) { 84 NumericalBoxElement.prototype['set' + Meta.pos.camel[i]] = Methods.setPosition(Meta.pos.camel[i], (i < 2)); 85 } 86 } 87 88 function digitalize(box, isVertical) { 89 if(isVertical == null) { digitalize(box, true); return digitalize(box, false); } 90 const m = Meta.getRelativeNames((isVertical) ? 0 : 2); 91 box[m.size.p] = box.$['outer' + m.camel.size.p](); 92 box[m.pos.f] = box[m.pos.o] + box[m.size.p]; 93 box.center[m.pos.o] = box[m.pos.o] + box[m.size.p] / 2; 94 box.inner[m.pos.o] = box[m.pos.o] + box['border' + m.camel.pos.o]; 95 box.inner[m.size.p] = box.$['inner' + m.camel.size.p](); 96 box.inner[m.pos.f] = box.inner[m.pos.o] + box.inner[m.size.p]; 97 box.inner.center[m.pos.o] = box.inner[m.pos.f] + box.inner[m.size.p] / 2; 98 return box; 99 } 100 })(); 101 102 // Adjust position of balloon body 103 function makeupBalloon($target, $balloon, options) { 104 $balloon.stop(true, true); 105 var outerTip, innerTip; 106 const initTipStyle = {position: 'absolute', height: '0', width: '0', border: 'solid 0 transparent'}, 107 target = new NumericalBoxElement($target), 108 balloon = new NumericalBoxElement($balloon); 109 const balloonTop = -options.offsetY 110 + ((options.position && options.position.indexOf('top') >= 0) ? target.top - balloon.height 111 : ((options.position && options.position.indexOf('bottom') >= 0) ? target.bottom 112 : target.center.top - balloon.height / 2)); 113 const balloonLeft = options.offsetX 114 + ((options.position && options.position.indexOf('left') >= 0) ? target.left - balloon.width 115 : ((options.position && options.position.indexOf('right') >= 0) ? target.right 116 : target.center.left - balloon.width / 2)); 117 balloon.setTop(balloonTop < 0 ? 0 : balloonTop); 118 balloon.setLeft(balloonLeft < 0 ? 0 : balloonLeft); 119 if(options.tipSize > 0) { 120 // Add hidden balloon tips into balloon body. 121 if($balloon.data('outerTip')) { $balloon.data('outerTip').remove(); $balloon.removeData('outerTip'); } 122 if($balloon.data('innerTip')) { $balloon.data('innerTip').remove(); $balloon.removeData('innerTip'); } 123 outerTip = new NumericalBoxElement($('<div>').css(initTipStyle).appendTo($balloon)); 124 innerTip = new NumericalBoxElement($('<div>').css(initTipStyle).appendTo($balloon)); 125 // Make tip triangle, adjust position of tips. 126 var m; 127 for(var i = 0; i < Meta.pos.length; i++) { 128 m = Meta.getRelativeNames(i); 129 if(balloon.center[m.pos.c1] >= target[m.pos.c1] && 130 balloon.center[m.pos.c1] <= target[m.pos.c2]) { 131 if(i % 2 === 0) { 132 if(balloon[m.pos.o] >= target[m.pos.o] && balloon[m.pos.f] >= target[m.pos.f]) { break; } 133 } else { 134 if(balloon[m.pos.o] <= target[m.pos.o] && balloon[m.pos.f] <= target[m.pos.f]) { break; } 135 } 136 } 137 m = null; 138 } 139 if(m) { 140 balloon['set' + m.camel.pos.p1]( 141 balloon[m.pos.p1] + ((m.isTopLeft) ? 1 : -1) * (options.tipSize - balloon['border' + m.camel.pos.o]) 142 ); 143 makeTip( 144 balloon, outerTip, m, options.tipSize, 145 $balloon.css('border-' + m.pos.o + '-color'), 146 options.tipPosition 147 ); 148 makeTip( 149 balloon, innerTip, m, options.tipSize - 2 * balloon['border' + m.camel.pos.o], 150 $balloon.css('background-color'), 151 options.tipPosition 152 ); 153 $balloon.data('outerTip', outerTip.$).data('innerTip', innerTip.$); 154 } else { 155 $.each([outerTip.$, innerTip.$], function() { this.remove(); }); 156 } 157 } 158 // Make up balloon tip. 159 function makeTip(balloon, tip, m, tipSize, color, pos) { 160 const len = Math.round(tipSize / 1.7320508); 161 tip.inactive() 162 ['setBorder' + m.camel.pos.f](tipSize) 163 ['setBorder' + m.camel.pos.c1](len) 164 ['setBorder' + m.camel.pos.c2](len) 165 ['set' + m.camel.pos.p1]((m.isTopLeft) ? -tipSize : balloon.inner[m.size.p]) 166 ['set' + m.camel.pos.c1](balloon.inner[m.size.c] / pos - len) 167 .active() 168 .$.css('border-' + m.pos.f + '-color', color); 169 } 170 } 171 172 // True if the event comes from the target or balloon. 173 function isValidTargetEvent($target, e) { 174 const b = $target.data('balloon') && $target.data('balloon').get(0); 175 return !(b && (b === e.relatedTarget || $.contains(b, e.relatedTarget))); 176 } 177 178 // Assign plain text or HTML to the balloon's body 179 function assignContents($balloon, options, contents) { 180 if(options.html) { 181 $balloon.empty().append(contents); 182 } else { 183 $balloon.text(contents); 184 } 185 } 186 187 // Actions common to the `options.url` and `options.ajax` 188 // callbacks on successful completion of the AJAX request 189 function onAjaxContents($target, $balloon, options) { 190 $balloon.data('ajaxDisabled', true); 191 if(options.ajaxContentsMaxAge >= 0) { 192 setTimeout( 193 function() { $balloon.data('ajaxDisabled', false); }, 194 options.ajaxContentsMaxAge 195 ); 196 } 197 makeupBalloon($target, $balloon, options); 198 } 199 200 //----------------------------------------------------------------------------- 201 // Public 202 //----------------------------------------------------------------------------- 203 $.fn.balloon = function(options) { 204 return this.one('mouseenter', function first(e) { 205 const $target = $(this), t = this 206 const $balloon = $target.on('mouseenter', function(e) { 207 isValidTargetEvent($target, e) && $target.showBalloon(); 208 }).off('mouseenter', first).showBalloon(options).data('balloon'); 209 if($balloon) { 210 $balloon.on('mouseleave', function(e) { 211 if(t === e.relatedTarget || $.contains(t, e.relatedTarget)) { return; } 212 $target.hideBalloon(); 213 }).on('mouseenter', function(e) { 214 if(t === e.relatedTarget || $.contains(t, e.relatedTarget)) { return; } 215 $balloon.stop(true, true); 216 $target.showBalloon(); 217 }); 218 } 219 }).on('mouseleave', function(e) { 220 const $target = $(this); 221 isValidTargetEvent($target, e) && $target.hideBalloon(); 222 }); 223 }; 224 225 $.fn.showBalloon = function(options) { 226 var optionsOld = this.data('options') ? this.data('options') : options || {}; 227 if(options || !this.data('options')) { 228 if($.balloon.defaults.css === null) { $.balloon.defaults.css = {}; } 229 this.data('options', $.extend(true, {}, $.balloon.defaults, options || {})); 230 } 231 options = this.data('options'); 232 return this.each(function() { 233 var target = this, $target = $(target); 234 var isNew = !$target.data('balloon'); 235 var $balloon = $target.data('balloon') || $('<div>'); 236 if(!isNew && $balloon.data('active')) { return; } 237 $balloon.data('active', true); 238 clearTimeout($balloon.data('minLifetime')); 239 const contents = $.isFunction(options.contents) ? options.contents.call(target) 240 : (options.contents || $target.attr('title') || $target.attr('alt')); 241 $target.removeAttr('title'); 242 var ajax = $.isFunction(options.ajax) || options.url; 243 if(!ajax && contents === '' || contents == null) { return; } 244 if(!$.isFunction(options.contents)) { options.contents = contents; } 245 if(!ajax) { 246 assignContents($balloon, options, contents); 247 } else if(!$balloon.data('ajaxDisabled')) { 248 if(contents !== '' && contents != null) { 249 assignContents($balloon, options, contents) 250 } 251 clearTimeout($balloon.data('ajaxDelay')); 252 if(options.url) { 253 ajax = function() { 254 $balloon.load( 255 $.isFunction(options.url) ? options.url.call(target) : options.url, 256 function(res, sts, xhr) { 257 if(options.ajaxComplete) { options.ajaxComplete.call(target, res, sts, xhr); } 258 if(sts === 'success' || sts === 'notmodified') { 259 onAjaxContents($target, $balloon, options); 260 } 261 } 262 ); 263 } 264 } else { 265 ajax = function() { 266 var called = false;
267 function done(error, contents) { 268 if(!called) { 269 called = true; 270 if(error) { return; } 271 assignContents($balloon, options, contents); 272 onAjaxContents($target, $balloon, options); 273 } 274 } 275 const promise = options.ajax.call(target, done); 276 if(promise && $.isFunction(promise.then)) { 277 promise.then( 278 function (contents) { done(null, contents); }, 279 function (error) { done(error); } 280 ); 281 } 282 }; 283 } 284 $balloon.data('ajaxDelay', setTimeout(ajax, options.ajaxDelay)); 285 } 286 287 $balloon.css(options.css || {}) 288 .removeClass(optionsOld.classname) 289 .addClass(options.classname); 290 if(isNew) { 291 $balloon.css({ visibility: 'hidden', position: 'absolute' }).appendTo('body'); 292 $target.data('balloon', $balloon); 293 makeupBalloon($target, $balloon, options); 294 $balloon.hide().css('visibility', 'visible'); 295 } else { 296 makeupBalloon($target, $balloon, options); 297 } 298 $balloon.data('delay', setTimeout(function() { 299 if(options.showAnimation) { 300 options.showAnimation.apply( 301 $balloon.stop(true, true), [ 302 options.showDuration, function() { 303 options.showComplete && options.showComplete.apply($balloon); 304 } 305 ] 306 ); 307 } else { 308 $balloon.show(options.showDuration, function() { 309 if(this.style.removeAttribute) { this.style.removeAttribute('filter'); } 310 options.showComplete && options.showComplete.apply($balloon); 311 }); 312 } 313 if(options.maxLifetime) { 314 clearTimeout($balloon.data('maxLifetime')); 315 $balloon.data('maxLifetime', 316 setTimeout(function() { $target.hideBalloon(); }, options.maxLifetime) 317 ); 318 } 319 }, options.delay)); 320 }); 321 }; 322 323 $.fn.hideBalloon = function() { 324 const options = this.data('options'); 325 if(!this.data('balloon')) { return this; } 326 return this.each(function() { 327 const $target = $(this), $balloon = $target.data('balloon'); 328 clearTimeout($balloon.data('delay')); 329 clearTimeout($balloon.data('minLifetime')); 330 clearTimeout($balloon.data('ajaxDelay')); 331 $balloon.data('minLifetime', setTimeout(function() { 332 if(options.hideAnimation) { 333 options.hideAnimation.apply( 334 $balloon.stop(true, true), 335 [ 336 options.hideDuration, 337 function(d) { 338 $(this).data('active', false); 339 options.hideComplete && options.hideComplete(d); 340 } 341 ] 342 ); 343 } else { 344 $balloon.stop(true, true).hide( 345 options.hideDuration, 346 function(d) { 347 $(this).data('active', false); 348 options.hideComplete && options.hideComplete(d); 349 } 350 ); 351 } 352 }, 353 options.minLifetime)); 354 }); 355 }; 356 357 $.balloon = { 358 defaults: { 359 contents: null, html: false, classname: null, 360 url: null, ajax: null, ajaxComplete: null, ajaxDelay: 500, ajaxContentsMaxAge: -1, 361 delay: 0, minLifetime: 200, maxLifetime: 0, 362 position: 'top', offsetX: 0, offsetY: 0, tipSize: 8, tipPosition: 2, 363 showDuration: 100, showAnimation: null, 364 hideDuration: 80, hideAnimation: function(d, c) { this.fadeOut(d, c); }, 365 showComplete: null, hideComplete: null, 366 css: { 367 fontSize : '.7rem', 368 minWidth : '.7rem', 369 padding : '.2rem .5rem', 370 border : '1px solid rgba(212, 212, 212, .4)', 371 borderRadius : '3px', 372 boxShadow : '2px 2px 4px #555', 373 color : '#eee', 374 backgroundColor: '#111', 375 opacity : 0.85, 376 zIndex : '32767', 377 textAlign : 'left' 378 } 379 } 380 }; 381})(jQuery); 382
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.