PageSourceSearch

https://www.godiva.co.jp/lib/jquery.balloon.js

js godiva.co.jp collected 2026-09-24 09:16:26 UTC 11,193 bytes, 276 lines download raw bytes

1/**
2 * Hover balloon on elements without css and images.
3 *
4 * Copyright (c) 2011 Hayato Takenaka
5 * Dual licensed under the MIT and GPL licenses:
6 * http://www.opensource.org/licenses/mit-license.php
7 * http://www.gnu.org/licenses/gpl.html
8 * @author: Hayato Takenaka (http://urin.github.com)
9 * @version: 0.3.5 - 2013/06/26
10**/
11(function($) {
12	//-----------------------------------------------------------------------------
13	// Private
14	//-----------------------------------------------------------------------------
15	// Helper for meta programming
16	var Meta = {};
17	Meta.pos  = $.extend(["top", "bottom", "left", "right"], {camel: ["Top", "Bottom", "Left", "Right"]});
18	Meta.size = $.extend(["height", "width"], {camel: ["Height", "Width"]});
19	Meta.getRelativeNames = function(position) {
20		var idx = {
21			pos: {
22				o: position,                                          // origin
23				f: (position % 2 == 0) ? position + 1 : position - 1, // faced
24				p1: (position % 2 == 0) ? position : position - 1,
25				p2: (position % 2 == 0) ? position + 1 : position,
26				c1: (position < 2) ? 2 : 0,
27				c2: (position < 2) ? 3 : 1
28			},
29			size: {
30				p: (position < 2) ? 0 : 1, // parallel
31				c: (position < 2) ? 1 : 0  // cross
32			}
33		};
34		var names = {};
35		for(var m1 in idx) {
36			if(!names[m1]) names[m1] = {};
37			for(var m2 in idx[m1]) {
38				names[m1][m2] = Meta[m1][idx[m1][m2]];
39				if(!names.camel) names.camel = {};
40				if(!names.camel[m1]) names.camel[m1] = {};
41				names.camel[m1][m2] = Meta[m1].camel[idx[m1][m2]];
42			}
43		}
44		names.isTopLeft = (names.pos.o == names.pos.p1);
45		return names;
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		var 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		function digitalize(box, isVertical) {
88			if(isVertical == undefined) { digitalize(box, true); return digitalize(box, false); }
89			var m = Meta.getRelativeNames((isVertical) ? 0 : 2);
90			box[m.size.p] = box.$["outer" + m.camel.size.p]();
91			box[m.pos.f] = box[m.pos.o] + box[m.size.p];
92			box.center[m.pos.o] = box[m.pos.o] + box[m.size.p] / 2;
93			box.inner[m.pos.o] = box[m.pos.o] + box["border" + m.camel.pos.o];
94			box.inner[m.size.p] = box.$["inner" + m.camel.size.p]();
95			box.inner[m.pos.f] = box.inner[m.pos.o] + box.inner[m.size.p];
96			box.inner.center[m.pos.o] = box.inner[m.pos.f] + box.inner[m.size.p] / 2;
97			return box;
98		}
99	})();
100
101	// Adjust position of balloon body
102	function makeupBalloon($target, $balloon, options) {
103		$balloon.stop(true, true);
104		var outerTip, innerTip,
105			initTipStyle = {position: "absolute", height: "0", width: "0", border: "solid 0 transparent"},
106			target = new NumericalBoxElement($target),
107			balloon = new NumericalBoxElement($balloon);
108		balloon.setTop(-options.offsetY
109			+ ((options.position && options.position.indexOf("top") >= 0) ? target.top - balloon.height
110			: ((options.position && options.position.indexOf("bottom") >= 0) ? target.bottom
111			: target.center.top - balloon.height / 2)));
112		balloon.setLeft(options.offsetX
113			+ ((options.position && options.position.indexOf("left") >= 0) ? target.left - balloon.width
114			: ((options.position && options.position.indexOf("right") >= 0) ? target.right
115			: target.center.left - balloon.width / 2)));
116		if(options.tipSize > 0) {
117			// Add hidden balloon tips into balloon body.
118			if($balloon.data("outerTip")) { $balloon.data("outerTip").remove(); $balloon.removeData("outerTip"); }
119			if($balloon.data("innerTip")) { $balloon.data("innerTip").remove(); $balloon.removeData("innerTip"); }
120			outerTip = new NumericalBoxElement($("<div>").css(initTipStyle).appendTo($balloon));
121			innerTip = new NumericalBoxElement($("<div>").css(initTipStyle).appendTo($balloon));
122			// Make tip triangle, adjust position of tips.
123			var m;
124			for(var i = 0; i < Meta.pos.length; i++) {
125				m = Meta.getRelativeNames(i);
126				if(balloon.center[m.pos.c1] >= target[m.pos.c1] &&
127					balloon.center[m.pos.c1] <= target[m.pos.c2]) {
128					if(i % 2 == 0) {
129						if(balloon[m.pos.o] >= target[m.pos.o] && balloon[m.pos.f] >= target[m.pos.f]) break;
130					} else {
131						if(balloon[m.pos.o] <= target[m.pos.o] && balloon[m.pos.f] <= target[m.pos.f]) break;
132					}
133				}
134				m = null;
135			}
136			if(m) {
137				balloon["set" + m.camel.pos.p1]
138					(balloon[m.pos.p1] + ((m.isTopLeft) ? 1 : -1) * (options.tipSize - balloon["border" + m.camel.pos.o]));
139				makeTip(balloon, outerTip, m, options.tipSize, $balloon.css("border-" + m.pos.o + "-color"));
140				makeTip(balloon, innerTip, m, options.tipSize - 2 * balloon["border" + m.camel.pos.o], $balloon.css("background-color"));
141				$balloon.data("outerTip", outerTip.$).data("innerTip", innerTip.$);
142			} else {
143				$.each([outerTip.$, innerTip.$], function() { this.remove(); });
144			}
145		}
146		// Make up balloon tip.
147		function makeTip(balloon, tip, m, tipSize, color) {
148			var len = Math.round(tipSize / 1.7320508);
149			tip.inactive()
150				["setBorder" + m.camel.pos.f](tipSize)
151				["setBorder" + m.camel.pos.c1](len)
152				["setBorder" + m.camel.pos.c2](len)
153				["set" + m.camel.pos.p1]((m.isTopLeft) ? -tipSize : balloon.inner[m.size.p])
154				["set" + m.camel.pos.c1](balloon.inner[m.size.c] / 2 - len)
155				.active()
156				.$.css("border-" + m.pos.f + "-color", color);
157		}
158	}
159
160	// True if the event comes from the target or balloon.
161	function isValidTargetEvent($target, e) {
162		var b = $target.data("balloon") && $target.data("balloon").get(0);
163		return !(b && (b == e.relatedTarget || $.contains(b, e.relatedTarget)));
164	}
165
166	//-----------------------------------------------------------------------------
167	// Public
168	//-----------------------------------------------------------------------------
169	$.fn.balloon = function(options) {
170		options = $.extend(true, {}, $.balloon.defaults, options);
171		return this.one("mouseenter", function(e) {
172			var $target = $(this), t = this;
173			var $balloon = $target.unbind("mouseenter", arguments.callee)
174				.showBalloon(options).mouseenter(function(e) {
175					isValidTargetEvent($target, e) && $target.showBalloon();
176				}).data("balloon");
177			if($balloon) {
178				$balloon.mouseleave(function(e) {
179					if(t == e.relatedTarget || $.contains(t, e.relatedTarget)) return;
180					$target.hideBalloon();
181				}).mouseenter(function(e) { $target.showBalloon(); });
182			}
183		}).mouseleave(function(e) {
184			var $target = $(this);
185			isValidTargetEvent($target, e) && $target.hideBalloon();
186		});
187	};
188
189	$.fn.showBalloon = function(options) {
190		var $target, $balloon, offTimer;
191		if(!$.balloon.defaults.css) $.balloon.defaults.css = {};
192		if(options || !this.data("options"))
193			this.data("options", $.extend(true, {}, $.balloon.defaults, options || {}));
194		options = this.data("options");
195		return this.each(function() {
196			$target = $(this);
197			(offTimer = $target.data("offTimer")) && clearTimeout(offTimer);
198			var contents = $.isFunction(options.contents)
199				? options.contents()
200				: (options.contents || $target.attr("title"));
201			var isNew = !($balloon = $target.data("balloon"));
202			if(isNew) $balloon = $("<div>").append(contents);
203			if(!options.url && (!$balloon || $balloon.html() == "")) return;
204			if(!isNew && contents && contents != $balloon.html()) $balloon.empty().append(contents);
205			$target.removeAttr("title");
206			if(options.url) {
207				$balloon.load($.isFunction(options.url) ? options.url(this) : options.url, function(res, sts, xhr) {
208					if(options.ajaxComplete) options.ajaxComplete(res, sts, xhr);
209					makeupBalloon($target, $balloon, options);
210				});
211			}
212			if(isNew) {
213				$balloon
214					.addClass(options.classname)
215					.css(options.css)
216					.css({visibility: "hidden", position: "absolute"})
217					.appendTo("body");
218				$target.data("balloon", $balloon);
219				makeupBalloon($target, $balloon, options);
220				$balloon.hide().css("visibility", "visible");
221			} else {
222				makeupBalloon($target, $balloon, options);
223			}
224			$target.data("onTimer", setTimeout(function() {
225				if(options.showAnimation) {
226					options.showAnimation.apply($balloon.stop(true, true), [options.showDuration]);
227				} else {
228					$balloon.show(options.showDuration, function() {
229						if(this.style.removeAttribute) { this.style.removeAttribute("filter"); }
230					});
231				}
232			}, options.delay));
233		});
234	};
235
236	$.fn.hideBalloon = function() {
237		var options = this.data("options"), onTimer, offTimer;
238		if(!this.data("balloon")) return this;
239		return this.each(function() {
240			var $target = $(this);
241			(onTimer = $target.data("onTimer")) && clearTimeout(onTimer);
242			(offTimer = $target.data("offTimer")) && clearTimeout(offTimer);
243			$target.data("offTimer", setTimeout(function() {
244				var $balloon = $target.data("balloon");
245				if(options.hideAnimation) {
246					$balloon && options.hideAnimation.apply($balloon.stop(true, true), [options.hideDuration]);
247				} else {
248					$balloon && $balloon.stop(true, true).hide(options.hideDuration);
249				}
250			},
251			options.minLifetime));
252		});
253	};
254
255	$.balloon = {
256		defaults: {
257			contents: null, url: null, ajaxComplete: null, classname: null,
258			position: "top", offsetX: 0, offsetY: 0, tipSize: 12,
259			delay: 0, minLifetime: 200,
260			showDuration: 100, showAnimation: null,
261			hideDuration:  80, hideAnimation: function(d) { this.fadeOut(d); },
262			css: {
263				minWidth       : "20px",
264				padding        : "5px",
265				borderRadius   : "6px",
266				border         : "solid 1px #777",
267				boxShadow      : "4px 4px 4px #555",
268				color          : "#666",
269				backgroundColor: "#efefef",
270				opacity        : ($.support.opacity) ? "0.85" : null,
271				zIndex         : "32767",
272				textAlign      : "left"
273			}
274		}
275	};
276})(jQuery);

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.