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