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