Add tomcat ROOT apps for VMs
[jabaws.git] / VMrootpage / 2.1.0 / ROOT / js / ui.tabs.js
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); // 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);