PageSourceSearch

https://www.yanbaru-oki.jp/themes/1dozen/js/ui.tabs.js

js yanbaru-oki.jp collected 2026-10-02 22:19:32 UTC 16,573 bytes, 560 lines download raw bytes

1/*
2 * jQuery UI Tabs @VERSION
3 *
4 * Copyright (c) 2007, 2008 Klaus Hartl (stilbuero.de)
5 * Dual licensed under the MIT (MIT-LICENSE.txt)
6 * and GPL (GPL-LICENSE.txt) licenses.
7 *
8 * http://docs.jquery.com/UI/Tabs
9 *
10 * Depends:
11 *	ui.core.js
12 */
13(function($) {
14
15$.widget("ui.tabs", {
16	_init: function() {
17		// create tabs
18		this._tabify(true);
19	},
20	_setData: function(key, value) {
21		if ((/^selected/).test(key))
22			this.select(value);
23		else {
24			this.options[key] = value;
25			this._tabify();
26		}
27	},
28	length: function() {
29		return this.$tabs.length;
30	},
31	_tabId: function(a) {
32		return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
33			|| this.options.idPrefix + $.data(a);
34	},
35	ui: function(tab, panel) {
36		return {
37			options: this.options,
38			tab: tab,
39			panel: panel,
40			index: this.$tabs.index(tab)
41		};
42	},
43	_sanitizeSelector: function(hash) {
44		return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
45	},
46	_cookie: function() {
47		var cookie = this.cookie || (this.cookie = 'ui-tabs-' + $.data(this.element[0]));
48		return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
49	},
50	_tabify: function(init) {
51		
52		this.$lis = $('li:has(a[href])', this.element);
53		this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
54		this.$panels = $([]);
55		
56		var self = this, o = this.options;
57		
58		this.$tabs.each(function(i, a) {
59			// inline tab
60			if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
61				self.$panels = self.$panels.add(self._sanitizeSelector(a.hash));
62			// remote tab
63			else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
64				$.data(a, 'href.tabs', a.href);
64 // required for restore on destroy
65				$.data(a, 'load.tabs', a.href); // mutable
66				var id = self._tabId(a);
67				a.href = '#' + id;
68				var $panel = $('#' + id);
69				if (!$panel.length) {
70					$panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
71						.insertAfter(self.$panels[i - 1] || self.element);
72					$panel.data('destroy.tabs', true);
73				}
74				self.$panels = self.$panels.add($panel);
75			}
76			// invalid tab href
77			else
78				o.disabled.push(i + 1);
79		});
80		
81		// initialization from scratch
82		if (init) {
83			
84			// attach necessary classes for styling if not present
85			this.element.addClass(o.navClass);
86			this.$panels.addClass(o.panelClass);
87			
88			// Selected tab
89			// use "selected" option or try to retrieve:
90			// 1. from fragment identifier in url
91			// 2. from cookie
92			// 3. from selected class attribute on <li>
93			if (o.selected === undefined) {
94				if (location.hash) {
95					this.$tabs.each(function(i, a) {
96						if (a.hash == location.hash) {
97							o.selected = i;
98							return false; // break
99						}
100					});
101				}
102				else if (o.cookie) {
103					var index = parseInt(self._cookie(), 10);
104					if (index && self.$tabs[index]) o.selected = index;
105				}
106				else if (self.$lis.filter('.' + o.selectedClass).length)
107					o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
108			}
109			o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default
110			
111			// Take disabling tabs via class attribute from HTML
112			// into account and update option properly.
113			// A selected tab cannot become disabled.
114			o.disabled = $.unique(o.disabled.concat(
115				$.map(this.$lis.filter('.' + o.disabledClass),
116					function(n, i) { return self.$lis.index(n); } )
117			)).sort();
118			if ($.inArray(o.selected, o.disabled) != -1)
119				o.disabled.splice($.inArray(o.selected, o.disabled), 1);
120			
121			// highlight selected tab
122			this.$panels.addClass(o.hideClass);
123			this.$lis.removeClass(o.selectedClass);
124			if (o.selected !== null) {
125				this.$panels.eq(o.selected).removeClass(o.hideClass);
126				var classes = [o.selectedClass];
127				if (o.deselectable) classes.push(o.deselectableClass);
128				this.$lis.eq(o.selected).addClass(classes.join(' '));
129				
130				// seems to be expected behavior that the show callback is fired
131				var onShow = function() {
132					self._trigger('show', null,
133						self.ui(self.$tabs[o.selected], self.$panels[o.selected]));
134				};
135				
136				// load if remote tab
137				if ($.data(this.$tabs[o.selected], 'load.tabs'))
138					this.load(o.selected, onShow);
139				// just trigger show event
140				else onShow();
141			}
142			
143			// clean up to avoid memory leaks in certain versions of IE 6
144			$(window).bind('unload', function() {
145				self.$tabs.unbind('.tabs');
146				self.$lis = self.$tabs = self.$panels = null;
147			});
148			
149		}
150		// update selected after add/remove
151		else
152			o.selected = this.$lis.index( this.$lis.filter('.' + o.selectedClass)[0] );
153		
154		// set or update cookie after init and add/remove respectively
155		if (o.cookie) this._cookie(o.selected, o.cookie);
156		
157		// disable tabs
158		for (var i = 0, li; li = this.$lis[i]; i++)
159			$(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
160		
161		// reset cache if switching from cached to not cached
162		if (o.cache === false) this.$tabs.removeData('cache.tabs');
163		
164		// set up animations
165		var hideFx, showFx;
166		if (o.fx) {
167			if (o.fx.constructor == Array) {
168				hideFx = o.fx[0];
169				showFx = o.fx[1];
170			}
171			else hideFx = showFx = o.fx;
172		}
173		
174		// Reset certain styles left over from animation
175		// and prevent IE's ClearType bug...
176		function resetStyle($el, fx) {
177			$el.css({ display: '' });
178			if ($.browser.msie && fx.opacity) $el[0].style.removeAttribute('filter');
179		}
180
181		// Show a tab...
182		var showTab = showFx ?
183			function(clicked, $show) {
184				$show.animate(showFx, showFx.duration || 'normal', function() {
185					$show.removeClass(o.hideClass);
186					resetStyle($show, showFx);
187					self._trigger('show', null, self.ui(clicked, $show[0]));
188				});
189			} :
190			function(clicked, $show) {
191				$show.removeClass(o.hideClass);
192				self._trigger('show', null, self.ui(clicked, $show[0]));
193			};
194		
195		// Hide a tab, $show is optional...
196		var hideTab = hideFx ? 
197			function(clicked, $hide, $show) {
198				$hide.animate(hideFx, hideFx.duration || 'normal', function() {
199					$hide.addClass(o.hideClass);
200					resetStyle($hide, hideFx);
201					if ($show) showTab(clicked, $show, $hide);
202				});
203			} :
204			function(clicked, $hide, $show) {
205				$hide.addClass(o.hideClass);
206				if ($show) showTab(clicked, $show);
207			};
208		
209		// Switch a tab...
210		function switchTab(clicked, $li, $hide, $show) {
211			var classes = [o.selectedClass];
212			if (o.deselectable) classes.push(o.deselectableClass);
213			$li.addClass(classes.join(' ')).siblings().removeClass(classes.join(' '));
214			hideTab(clicked, $hide, $show);
215		}
216		
217		// attach tab event handler, unbind to avoid duplicates from former tabifying...
218		this.$tabs.unbind('.tabs').bind(o.event + '.tabs', function() {
219			
220			//var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
221			var $li = $(this).parents('li:eq(0)'),
222				$hide = self.$panels.filter(':visible'),
223				$show = $(self._sanitizeSelector(this.hash));
224			
225			// If tab is already selected and not deselectable or tab disabled or 
226			// or is already loading or click callback returns false stop here.
227			// Check if click handler returns false last so that it is not executed
228			// for a disabled or loading tab!
229			if (($li.hasClass(o.selectedClass) && !o.deselectable)
230				|| $li.hasClass(o.disabledClass)
231				|| $(this).hasClass(o.loadingClass)
232				|| self._trigger('select', null, self.ui(this, $show[0])) === false
233				) {
234				this.blur();
235				return false;
236			}
237			
238			o.selected = self.$tabs.index(this);
239			
240			// if tab may be closed
241			if (o.deselectable) {
242				if ($li.hasClass(o.selectedClass)) {
243					self.options.selected = null;
244					$li.removeClass([o.selectedClass, o.deselectableClass].join(' '));
245					self.$panels.stop();
246					hideTab(this, $hide);
247					this.blur();
248					return false;
249				} else if (!$hide.length) {
250					self.$panels.stop();
251					var a = this;
252					self.load(self.$tabs.index(this), function() {
253						$li.addClass([o.selectedClass, o.deselectableClass].join(' '));
254						showTab(a, $show);
255					});
256					this.blur();
257					return false;
258				}
259			}
260			
261			if (o.cookie) self._cookie(o.selected, o.cookie);
262			
263			// stop possibly running animations
264			self.$panels.stop();
265			
266			// show new tab
267			if ($show.length) {
268				var a = this;
269				self.load(self.$tabs.index(this), $hide.length ? 
270					function() {
271						switchTab(a, $li, $hide, $show);
272					} :
273					function() {
274						$li.addClass(o.selectedClass);
275						showTab(a, $show);
276					}
277				);
278			} else
279				throw 'jQuery UI Tabs: Mismatching fragment identifier.';
280				
281			// Prevent IE from keeping other link focussed when using the back button
282			// and remove dotted border from clicked link. This is controlled via CSS
283			// in modern browsers; blur() removes focus from address bar in Firefox
284			// which can become a usability and annoying problem with tabs('rotate').
285			if ($.browser.msie) this.blur();
286			
287			return false;
288			
289		});
290		
291		// disable click if event is configured to something else
292		if (o.event != 'click') this.$tabs.bind('click.tabs', function(){return false;});
293		
294	},
295	add: function(url, label, index) {
296		if (index == undefined)
297			index = this.$tabs.length; // append by default
298		
299		var o = this.options;
300		var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
301		$li.data('destroy.tabs', true);
302		
303		var id = url.indexOf('#') == 0 ? url.replace('#', '') : this._tabId( $('a:first-child', $li)[0] );
304		
305		// try to find an existing element before creating a new one
306		var $panel = $('#' + id);
307		if (!$panel.length) {
308			$panel = $(o.panelTemplate).attr('id', id)
309				.addClass(o.hideClass)
310				.data('destroy.tabs', true);
311		}
312		$panel.addClass(o.panelClass);
313		if (index >= this.$lis.length) {
314			$li.appendTo(this.element);
315			$panel.appendTo(this.element[0].parentNode);
316		} else {
317			$li.insertBefore(this.$lis[index]);
318			$panel.insertBefore(this.$panels[index]);
319		}
320		
321		o.disabled = $.map(o.disabled,
322			function(n, i) { return n >= index ? ++n : n });
323		
324		this._tabify();
325		
326		if (this.$tabs.length == 1) {
327			$li.addClass(o.selectedClass);
328			$panel.removeClass(o.hideClass);
329			var href = $.data(this.$tabs[0], 'load.tabs');
330			if (href)
331				this.load(index, href);
332		}
333		
334		// callback
335		this._trigger('add', null, this.ui(this.$tabs[index], this.$panels[index]));
336	},
337	remove: function(index) {
338		var o = this.options, $li = this.$lis.eq(index).remove(),
339			$panel = this.$panels.eq(index).remove();
340		
341		// If selected tab was removed focus tab to the right or
342		// in case the last tab was removed the tab to the left.
343		if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
344			this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
345		
346		o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
347			function(n, i) { return n >= index ? --n : n });
348		
349		this._tabify();
350		
351		// callback
352		this._trigger('remove', null, this.ui($li.find('a')[0], $panel[0]));
353	},
354	enable: function(index) {
355		var o = this.options;
356		if ($.inArray(index, o.disabled) == -1)
357			return;
358		
359		var $li = this.$lis.eq(index).removeClass(o.disabledClass);
360		if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
361			$li.css('display', 'inline-block');
362			setTimeout(function() {
363				$li.css('display', 'block');
364			}, 0);
365		}
366		
367		o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
368		
369		// callback
370		this._trigger('enable', null, this.ui(this.$tabs[index], this.$panels[index]));
371	},
372	disable: function(index) {
373		var self = this, o = this.options;
374		if (index != o.selected) { // cannot disable already selected tab
375			this.$lis.eq(index).addClass(o.disabledClass);
376			
377			o.disabled.push(index);
378			o.disabled.sort();
379			
380			// callback
381			this._trigger('disable', null, this.ui(this.$tabs[index], this.$panels[index]));
382		}
383	},
384	select: function(index) {
385		// TODO make null as argument work
386		if (typeof index == 'string')
387			index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
388		this.$tabs.eq(index).trigger(this.options.event + '.tabs');
389	},
390	load: function(index, callback) { // callback is for internal usage only
391		
392		var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
393				bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
394		
395		callback = callback || function() {};
396		
397		// no remote or from cache - just finish with callback
398		if (!url || !bypassCache && $.data(a, 'cache.tabs')) {
399			callback();
400			return;
401		}
402		
403		// load remote from here on
404		
405		var inner = function(parent) {
406			var $parent = $(parent), $inner = $parent.find('*:last');
407			return $inner.length && $inner.is(':not(img)') && $inner || $parent;
408		};
409		var cleanup = function() {
410			self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass)
411					.each(function() {
412						if (o.spinner)
413							inner(this).parent().html(inner(this).data('label.tabs'));
414					});
415			self.xhr = null;
416		};
417		
418		if (o.spinner) {
419			var label = inner(a).html();
420			inner(a).wrapInner('<em></em>')
421				.find('em').data('label.tabs', label).html(o.spinner);
422		}
423		
424		var ajaxOptions = $.extend({}, o.ajaxOptions, {
425			url: url,
426			success: function(r, s) {
427				$(self._sanitizeSelector(a.hash)).html(r);
428				cleanup();
429				
430				if (o.cache)
431					$.data(a, 'cache.tabs', true); // if loaded once do not load them again
432				
433				// callbacks
434				self._trigger('load', null, self.ui(self.$tabs[index], self.$panels[index]));
435				try {
436					o.ajaxOptions.success(r, s);
437				}
438				catch (e) {}
439				
440				// This callback is required because the switch has to take
441				// place after loading has completed. Call last in order to 
442				// fire load before show callback...
443				callback();
444			}
445		});
446		if (this.xhr) {
447			// terminate pending requests from other tabs and restore tab label
448			this.xhr.abort();
449			cleanup();
450		}
451		$a.addClass(o.loadingClass);
452		self.xhr = $.ajax(ajaxOptions);
453	},
454	url: function(index, url) {
455		this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
456	},
457	destroy: function() {
458		var o = this.options;
459		this.element.unbind('.tabs')
460			.removeClass(o.navClass).removeData('tabs');
461		this.$tabs.each(function() {
462			var href = $.data(this, 'href.tabs');
463			if (href)
464				this.href = href;
465			var $this = $(this).unbind('.tabs');
466			$.each(['href', 'load', 'cache'], function(i, prefix) {
467				$this.removeData(prefix + '.tabs');
468			});
469		});
470		this.$lis.add(this.$panels).each(function() {
471			if ($.data(this, 'destroy.tabs'))
472				$(this).remove();
473			else
474				$(this).removeClass([o.selectedClass, o.deselectableClass,
475					o.disabledClass, o.panelClass, o.hideClass].join(' '));
476		});
477		if (o.cookie)
478			this._cookie(null, o.cookie);
479	}
480});
481
482$.extend($.ui.tabs, {
483	version: '@VERSION',
484	getter: 'length',
485	defaults: {
486		// basic setup
487		deselectable: false,
488		event: 'click',
489		disabled: [],
490		cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
491		// Ajax
492		spinner: 'Loading&#8230;',
493		cache: false,
494		idPrefix: 'ui-tabs-',
495		ajaxOptions: null,
496		// animations
497		fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
498		// templates
499		tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
500		panelTemplate: '<div></div>',
501		// CSS class names
502		navClass: 'ui-tabs-nav',
503		selectedClass: 'ui-tabs-selected',
504		deselectableClass: 'ui-tabs-deselectable',
505		disabledClass: 'ui-tabs-disabled',
506		panelClass: 'ui-tabs-panel',
507		hideClass: 'ui-tabs-hide',
508		loadingClass: 'ui-tabs-loading'
509	}
510});
511
512/*
513 * Tabs Extensions
514 */
515
516/*
517 * Rotate
518 */
519$.extend($.ui.tabs.prototype, {
520	rotation: null,
521	rotate: function(ms, continuing) {
522		
523		continuing = continuing || false;
524		
525		var self = this, t = this.options.selected;
526		
527		function start() {
528			self.rotation = setInterval(function() {
529				t = ++t < self.$tabs.length ? t : 0;
530				self.select(t);
531			}, ms);
532		}
533		
534		function stop(e) {
535			if (!e || e.clientX) { // only in case of a true click
536				clearInterval(self.rotation);
537			}
538		}
539		
540		// start interval
541		if (ms) {
542			start();
543			if (!continuing)
544				this.$tabs.bind(this.options.event + '.tabs', stop);
545			else
546				this.$tabs.bind(this.options.event + '.tabs', function() {
547					stop();
548					t = self.options.selected;
549					start();
550				});
551		}
552		// stop interval
553		else {
554			stop();
555			this.$tabs.unbind(this.options.event + '.tabs', stop);
556		}
557	}
558});
559
560})(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.