| | 1 | /* |
| | 2 | * Tabs 3 - New Wave Tabs |
| | 3 | * |
| | 4 | * Copyright (c) 2007 Klaus Hartl (stilbuero.de) |
| | 5 | * Dual licensed under the MIT (MIT-LICENSE.txt) |
| | 6 | * and GPL (GPL-LICENSE.txt) licenses. |
| | 7 | */ |
| | 8 | |
| | 9 | (function($) { |
| | 10 | |
| | 11 | // if the UI scope is not availalable, add it |
| | 12 | $.ui = $.ui || {}; |
| | 13 | |
| | 14 | // tabs initialization |
| | 15 | $.fn.tabs = function(initial, options) { |
| | 16 | if (initial && initial.constructor == Object) { // shift arguments |
| | 17 | options = initial; |
| | 18 | initial = null; |
| | 19 | } |
| | 20 | options = options || {}; |
| | 21 | |
| | 22 | initial = initial && initial.constructor == Number && --initial || 0; |
| | 23 | |
| | 24 | return this.each(function() { |
| | 25 | new $.ui.tabs(this, $.extend(options, { initial: initial })); |
| | 26 | }); |
| | 27 | }; |
| | 28 | |
| | 29 | // other chainable tabs methods |
| | 30 | $.each(['Add', 'Remove', 'Enable', 'Disable', 'Click', 'Load', 'Href'], function(i, method) { |
| | 31 | $.fn['tabs' + method] = function() { |
| | 32 | var args = arguments; |
| | 33 | return this.each(function() { |
| | 34 | var instance = $.ui.tabs.getInstance(this); |
| | 35 | instance[method.toLowerCase()].apply(instance, args); |
| | 36 | }); |
| | 37 | }; |
| | 38 | }); |
| | 39 | $.fn.tabsSelected = function() { |
| | 40 | var selected = -1; |
| | 41 | if (this[0]) { |
| | 42 | var instance = $.ui.tabs.getInstance(this[0]), |
| | 43 | $lis = $('li', this); |
| | 44 | selected = $lis.index( $lis.filter('.' + instance.options.selectedClass)[0] ); |
| | 45 | } |
| | 46 | return selected >= 0 ? ++selected : -1; |
| | 47 | }; |
| | 48 | |
| | 49 | // tabs class |
| | 50 | $.ui.tabs = function(el, options) { |
| | 51 | |
| | 52 | this.source = el; |
| | 53 | |
| | 54 | this.options = $.extend({ |
| | 55 | |
| | 56 | // basic setup |
| | 57 | initial: 0, |
| | 58 | event: 'click', |
| | 59 | disabled: [], |
| | 60 | cookie: null, // pass options object as expected by cookie plugin: { expires: 7, path: '/', domain: 'jquery.com', secure: true } |
| | 61 | // TODO bookmarkable: $.ajaxHistory ? true : false, |
| | 62 | unselected: false, |
| | 63 | unselect: options.unselected ? true : false, |
| | 64 | |
| | 65 | // Ajax |
| | 66 | spinner: 'Loading…', |
| | 67 | cache: false, |
| | 68 | idPrefix: 'ui-tabs-', |
| | 69 | ajaxOptions: {}, |
| | 70 | |
| | 71 | // animations |
| | 72 | /*fxFade: null, |
| | 73 | fxSlide: null, |
| | 74 | fxShow: null, |
| | 75 | fxHide: null,*/ |
| | 76 | fxSpeed: 'normal', |
| | 77 | /*fxShowSpeed: null, |
| | 78 | fxHideSpeed: null,*/ |
| | 79 | |
| | 80 | // callbacks |
| | 81 | add: function() {}, |
| | 82 | remove: function() {}, |
| | 83 | enable: function() {}, |
| | 84 | disable: function() {}, |
| | 85 | click: function() {}, |
| | 86 | hide: function() {}, |
| | 87 | show: function() {}, |
| | 88 | load: function() {}, |
| | 89 | |
| | 90 | // templates |
| | 91 | tabTemplate: '<li><a href="#{href}"><span>#{text}</span></a></li>', |
| | 92 | panelTemplate: '<div></div>', |
| | 93 | |
| | 94 | // CSS classes |
| | 95 | navClass: 'ui-tabs-nav', |
| | 96 | selectedClass: 'ui-tabs-selected', |
| | 97 | unselectClass: 'ui-tabs-unselect', |
| | 98 | disabledClass: 'ui-tabs-disabled', |
| | 99 | panelClass: 'ui-tabs-panel', |
| | 100 | hideClass: 'ui-tabs-hide', |
| | 101 | loadingClass: 'ui-tabs-loading' |
| | 102 | |
| | 103 | }, options); |
| | 104 | |
| | 105 | this.options.event += '.ui-tabs'; // namespace event |
| | 106 | this.options.cookie = $.cookie && $.cookie.constructor == Function && this.options.cookie; |
| | 107 | |
| | 108 | // save instance for later |
| | 109 | $.data(el, $.ui.tabs.INSTANCE_KEY, this); |
| | 110 | |
| | 111 | // create tabs |
| | 112 | this.tabify(true); |
| | 113 | }; |
| | 114 | |
| | 115 | // static |
| | 116 | $.ui.tabs.INSTANCE_KEY = 'ui_tabs_instance'; |
| | 117 | $.ui.tabs.getInstance = function(el) { |
| | 118 | return $.data(el, $.ui.tabs.INSTANCE_KEY); |
| | 119 | }; |
| | 120 | |
| | 121 | // instance methods |
| | 122 | $.extend($.ui.tabs.prototype, { |
| | 123 | tabId: function(a) { |
| | 124 | return a.title ? a.title.replace(/\s/g, '_') |
| | 125 | : this.options.idPrefix + $.data(a); |
| | 126 | }, |
| | 127 | tabify: function(init) { |
| | 128 | |
| | 129 | this.$lis = $('li:has(a[href])', this.source); |
| | 130 | this.$tabs = this.$lis.map(function() { return $('a', this)[0] }); |
| | 131 | this.$panels = $([]); |
| | 132 | |
| | 133 | var self = this, o = this.options; |
| | 134 | |
| | 135 | this.$tabs.each(function(i, a) { |
| | 136 | // inline tab |
| | 137 | if (a.hash && a.hash.replace('#', '')) { // Safari 2 reports '#' for an empty hash |
| | 138 | self.$panels = self.$panels.add(a.hash); |
| | 139 | } |
| | 140 | // remote tab |
| | 141 | else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#" |
| | 142 | $.data(a, 'href', a.href); |
| | 143 | var id = self.tabId(a); |
| | 144 | a.href = '#' + id; |
| | 145 | self.$panels = self.$panels.add( |
| | 146 | $('#' + id)[0] || $(o.panelTemplate).attr('id', id).addClass(o.panelClass) |
| | 147 | .insertAfter( self.$panels[i - 1] || self.source ) |
| | 148 | ); |
| | 149 | } |
| | 150 | // invalid tab href |
| | 151 | else { |
| | 152 | o.disabled.push(i + 1); |
| | 153 | } |
| | 154 | }); |
| | 155 | |
| | 156 | if (init) { |
| | 157 | |
| | 158 | // attach necessary classes for styling if not present |
| | 159 | $(this.source).hasClass(o.navClass) || $(this.source).addClass(o.navClass); |
| | 160 | this.$panels.each(function() { |
| | 161 | var $this = $(this); |
| | 162 | $this.hasClass(o.panelClass) || $this.addClass(o.panelClass); |
| | 163 | }); |
| | 164 | |
| | 165 | // disabled tabs |
| | 166 | for (var i = 0, position; position = o.disabled[i]; i++) { |
| | 167 | this.disable(position); |
| | 168 | } |
| | 169 | |
| | 170 | // Try to retrieve initial tab: |
| | 171 | // 1. from fragment identifier in url if present |
| | 172 | // 2. from cookie |
| | 173 | // 3. from selected class attribute on <li> |
| | 174 | // 4. otherwise use given initial argument |
| | 175 | // 5. check if tab is disabled |
| | 176 | this.$tabs.each(function(i, a) { |
| | 177 | if (location.hash) { |
| | 178 | if (a.hash == location.hash) { |
| | 179 | o.initial = i; |
| | 180 | // prevent page scroll to fragment |
| | 181 | //if (($.browser.msie || $.browser.opera) && !o.remote) { |
| | 182 | if ($.browser.msie || $.browser.opera) { |
| | 183 | var $toShow = $(location.hash), toShowId = $toShow.attr('id'); |
| | 184 | $toShow.attr('id', ''); |
| | 185 | setTimeout(function() { |
| | 186 | $toShow.attr('id', toShowId); // restore id |
| | 187 | }, 500); |
| | 188 | } |
| | 189 | scrollTo(0, 0); |
| | 190 | return false; // break |
| | 191 | } |
| | 192 | } else if (o.cookie) { |
| | 193 | o.initial = parseInt($.cookie( $.ui.tabs.INSTANCE_KEY + $.data(self.source) )) || 0; |
| | 194 | return false; // break |
| | 195 | } else if ( self.$lis.eq(i).hasClass(o.selectedClass) ) { |
| | 196 | o.initial = i; |
| | 197 | return false; // break |
| | 198 | } |
| | 199 | }); |
| | 200 | var n = this.$lis.length; |
| | 201 | while (this.$lis.eq(o.initial).hasClass(o.disabledClass) && n) { |
| | 202 | o.initial = ++o.initial < this.$lis.length ? o.initial : 0; |
| | 203 | n--; |
| | 204 | } |
| | 205 | if (!n) { // all tabs disabled, set option unselected to true |
| | 206 | o.unselected = o.unselect = true; |
| | 207 | } |
| | 208 | |
| | 209 | // highlight selected tab |
| | 210 | this.$panels.addClass(o.hideClass); |
| | 211 | this.$lis.removeClass(o.selectedClass); |
| | 212 | if (!o.unselected) { |
| | 213 | this.$panels.eq(o.initial).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before |
| | 214 | this.$lis.eq(o.initial).addClass(o.selectedClass); |
| | 215 | } |
| | 216 | |
| | 217 | // load if remote tab |
| | 218 | var href = !o.unselected && $.data(this.$tabs[o.initial], 'href'); |
| | 219 | if (href) { |
| | 220 | this.load(o.initial + 1, href); |
| | 221 | } |
| | 222 | |
| | 223 | // disable click if event is configured to something else |
| | 224 | if (!/^click/.test(o.event)) { |
| | 225 | this.$tabs.bind('click', function(e) { e.preventDefault(); }); |
| | 226 | } |
| | 227 | |
| | 228 | } |
| | 229 | |
| | 230 | // setup animations |
| | 231 | var showAnim = {}, showSpeed = o.fxShowSpeed || o.fxSpeed, |
| | 232 | hideAnim = {}, hideSpeed = o.fxHideSpeed || o.fxSpeed; |
| | 233 | if (o.fxSlide || o.fxFade) { |
| | 234 | if (o.fxSlide) { |
| | 235 | showAnim['height'] = 'show'; |
| | 236 | hideAnim['height'] = 'hide'; |
| | 237 | } |
| | 238 | if (o.fxFade) { |
| | 239 | showAnim['opacity'] = 'show'; |
| | 240 | hideAnim['opacity'] = 'hide'; |
| | 241 | } |
| | 242 | } else { |
| | 243 | if (o.fxShow) { |
| | 244 | showAnim = o.fxShow; |
| | 245 | } else { // use some kind of animation to prevent browser scrolling to the tab |
| | 246 | showAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox |
| | 247 | showSpeed = 1; // as little as 1 is sufficient |
| | 248 | } |
| | 249 | if (o.fxHide) { |
| | 250 | hideAnim = o.fxHide; |
| | 251 | } else { // use some kind of animation to prevent browser scrolling to the tab |
| | 252 | hideAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox |
| | 253 | hideSpeed = 1; // as little as 1 is sufficient |
| | 254 | } |
| | 255 | } |
| | 256 | |
| | 257 | // reset some styles to maintain print style sheets etc. |
| | 258 | var resetCSS = { display: '', overflow: '', height: '' }; |
| | 259 | if (!$.browser.msie) { // not in IE to prevent ClearType font issue |
| | 260 | resetCSS['opacity'] = ''; |
| | 261 | } |
| | 262 | |
| | 263 | // Hide a tab, animation prevents browser scrolling to fragment, |
| | 264 | // $show is optional. |
| | 265 | function hideTab(clicked, $hide, $show) { |
| | 266 | $hide.animate(hideAnim, hideSpeed, function() { // |
| | 267 | $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. |
| | 268 | if ($.browser.msie && hideAnim['opacity']) { |
| | 269 | $hide[0].style.filter = ''; |
| | 270 | } |
| | 271 | o.hide(clicked, $hide[0], $show && $show[0] || null); |
| | 272 | if ($show) { |
| | 273 | showTab(clicked, $show, $hide); |
| | 274 | } |
| | 275 | }); |
| | 276 | } |
| | 277 | |
| | 278 | // Show a tab, animation prevents browser scrolling to fragment, |
| | 279 | // $hide is optional |
| | 280 | function showTab(clicked, $show, $hide) { |
| | 281 | if (!(o.fxSlide || o.fxFade || o.fxShow)) { |
| | 282 | $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels |
| | 283 | } |
| | 284 | $show.animate(showAnim, showSpeed, function() { |
| | 285 | $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. |
| | 286 | if ($.browser.msie && showAnim['opacity']) { |
| | 287 | $show[0].style.filter = ''; |
| | 288 | } |
| | 289 | o.show(clicked, $show[0], $hide && $hide[0] || null); |
| | 290 | }); |
| | 291 | } |
| | 292 | |
| | 293 | // switch a tab |
| | 294 | function switchTab(clicked, $li, $hide, $show) { |
| | 295 | /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click |
| | 296 | $.ajaxHistory.update(clicked.hash); |
| | 297 | }*/ |
| | 298 | $li.addClass(o.selectedClass) |
| | 299 | .siblings().removeClass(o.selectedClass); |
| | 300 | hideTab(clicked, $hide, $show); |
| | 301 | } |
| | 302 | |
| | 303 | // attach tab event handler, unbind to avoid duplicates from former tabifying... |
| | 304 | this.$tabs.unbind(o.event).bind(o.event, function() { |
| | 305 | |
| | 306 | //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click |
| | 307 | var $li = $(this).parents('li:eq(0)'), |
| | 308 | $hide = self.$panels.filter(':visible'), |
| | 309 | $show = $(this.hash); |
| | 310 | |
| | 311 | // If tab is already selected and not unselectable or tab disabled or click callback returns false stop here. |
| | 312 | // Check if click handler returns false last so that it is not executed for a disabled tab! |
| | 313 | if (($li.hasClass(o.selectedClass) && !o.unselect) || $li.hasClass(o.disabledClass) |
| | 314 | || o.click(this, $show[0], $hide[0]) === false) { |
| | 315 | this.blur(); |
| | 316 | return false; |
| | 317 | } |
| | 318 | |
| | 319 | if (o.cookie) { |
| | 320 | $.cookie($.ui.tabs.INSTANCE_KEY + $.data(self.source), self.$tabs.index(this), o.cookie); |
| | 321 | } |
| | 322 | |
| | 323 | // if tab may be closed |
| | 324 | if (o.unselect) { |
| | 325 | if ($li.hasClass(o.selectedClass)) { |
| | 326 | $li.removeClass(o.selectedClass); |
| | 327 | self.$panels.stop(); |
| | 328 | hideTab(this, $hide); |
| | 329 | this.blur(); |
| | 330 | return false; |
| | 331 | } else if (!$hide.length) { |
| | 332 | self.$panels.stop(); |
| | 333 | if ($.data(this, 'href')) { // remote tab |
| | 334 | var a = this; |
| | 335 | self.load(self.$tabs.index(this) + 1, $.data(this, 'href'), function() { |
| | 336 | $li.addClass(o.selectedClass).addClass(o.unselectClass); |
| | 337 | showTab(a, $show); |
| | 338 | }); |
| | 339 | } else { |
| | 340 | $li.addClass(o.selectedClass).addClass(o.unselectClass); |
| | 341 | showTab(this, $show); |
| | 342 | } |
| | 343 | this.blur(); |
| | 344 | return false; |
| | 345 | } |
| | 346 | } |
| | 347 | |
| | 348 | // stop possibly running animations |
| | 349 | self.$panels.stop(); |
| | 350 | |
| | 351 | // show new tab |
| | 352 | if ($show.length) { |
| | 353 | |
| | 354 | // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled |
| | 355 | /*if ($.browser.msie && o.bookmarkable) { |
| | 356 | var showId = this.hash.replace('#', ''); |
| | 357 | $show.attr('id', ''); |
| | 358 | setTimeout(function() { |
| | 359 | $show.attr('id', showId); // restore id |
| | 360 | }, 0); |
| | 361 | }*/ |
| | 362 | |
| | 363 | if ($.data(this, 'href')) { // remote tab |
| | 364 | var a = this; |
| | 365 | self.load(self.$tabs.index(this) + 1, $.data(this, 'href'), function() { |
| | 366 | switchTab(a, $li, $hide, $show); |
| | 367 | }); |
| | 368 | } else { |
| | 369 | switchTab(this, $li, $hide, $show); |
| | 370 | } |
| | 371 | |
| | 372 | // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash |
| | 373 | /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0; |
| | 374 | var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0; |
| | 375 | setTimeout(function() { |
| | 376 | scrollTo(scrollX, scrollY); |
| | 377 | }, 0);*/ |
| | 378 | |
| | 379 | } else { |
| | 380 | throw 'jQuery UI Tabs: Mismatching fragment identifier.'; |
| | 381 | } |
| | 382 | |
| | 383 | // Prevent IE from keeping other link focussed when using the back button |
| | 384 | // and remove dotted border from clicked link. This is controlled in modern |
| | 385 | // browsers via CSS, also blur removes focus from address bar in Firefox |
| | 386 | // which can become a usability and annoying problem with tabsRotate. |
| | 387 | if ($.browser.msie) { |
| | 388 | this.blur(); |
| | 389 | } |
| | 390 | |
| | 391 | //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE |
| | 392 | return false; |
| | 393 | |
| | 394 | }); |
| | 395 | |
| | 396 | }, |
| | 397 | add: function(url, text, position) { |
| | 398 | if (url && text) { |
| | 399 | position = position || this.$tabs.length; // append by default |
| | 400 | |
| | 401 | var o = this.options, |
| | 402 | $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{text\}/, text)); |
| | 403 | |
| | 404 | var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] ); |
| | 405 | |
| | 406 | // try to find an existing element before creating a new one |
| | 407 | var $panel = $('#' + id); |
| | 408 | $panel = $panel.length && $panel |
| | 409 | || $(o.panelTemplate).attr('id', id).addClass(o.panelClass).addClass(o.hideClass); |
| | 410 | if (position >= this.$lis.length) { |
| | 411 | $li.appendTo(this.source); |
| | 412 | $panel.appendTo(this.source.parentNode); |
| | 413 | } else { |
| | 414 | $li.insertBefore(this.$lis[position - 1]); |
| | 415 | $panel.insertBefore(this.$panels[position - 1]); |
| | 416 | } |
| | 417 | |
| | 418 | this.tabify(); |
| | 419 | |
| | 420 | if (this.$tabs.length == 1) { |
| | 421 | $li.addClass(o.selectedClass); |
| | 422 | $panel.removeClass(o.hideClass); |
| | 423 | var href = $.data(this.$tabs[0], 'href'); |
| | 424 | if (href) { |
| | 425 | this.load(position + 1, href); |
| | 426 | } |
| | 427 | } |
| | 428 | o.add(this.$tabs[position], this.$panels[position]); // callback |
| | 429 | } else { |
| | 430 | throw 'jQuery UI Tabs: Not enough arguments to add tab.'; |
| | 431 | } |
| | 432 | }, |
| | 433 | remove: function(position) { |
| | 434 | if (position && position.constructor == Number) { |
| | 435 | var o = this.options, $li = this.$lis.eq(position - 1).remove(), |
| | 436 | $panel = this.$panels.eq(position - 1).remove(); |
| | 437 | |
| | 438 | // If selected tab was removed focus tab to the right or |
| | 439 | // tab to the left if last tab was removed. |
| | 440 | if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) { |
| | 441 | this.click(position + (position < this.$tabs.length ? 1 : -1)); |
| | 442 | } |
| | 443 | this.tabify(); |
| | 444 | o.remove($li.end()[0], $panel[0]); // callback |
| | 445 | } |
| | 446 | }, |
| | 447 | enable: function(position) { |
| | 448 | var o = this.options, $li = this.$lis.eq(position - 1); |
| | 449 | $li.removeClass(o.disabledClass); |
| | 450 | if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2... |
| | 451 | $li.css('display', 'inline-block'); |
| | 452 | setTimeout(function() { |
| | 453 | $li.css('display', 'block') |
| | 454 | }, 0) |
| | 455 | } |
| | 456 | o.enable(this.$tabs[position - 1], this.$panels[position - 1]); // callback |
| | 457 | }, |
| | 458 | disable: function(position) { |
| | 459 | var o = this.options; |
| | 460 | this.$lis.eq(position - 1).addClass(o.disabledClass); |
| | 461 | o.disable(this.$tabs[position - 1], this.$panels[position - 1]); // callback |
| | 462 | }, |
| | 463 | click: function(position) { |
| | 464 | this.$tabs.eq(position - 1).trigger(this.options.event); |
| | 465 | }, |
| | 466 | load: function(position, url, callback) { |
| | 467 | var self = this, o = this.options, |
| | 468 | $a = this.$tabs.eq(position - 1), a = $a[0], $span = $('span', a); |
| | 469 | |
| | 470 | // shift arguments |
| | 471 | if (url && url.constructor == Function) { |
| | 472 | callback = url; |
| | 473 | url = null; |
| | 474 | } |
| | 475 | |
| | 476 | // set new URL or get existing |
| | 477 | if (url) { |
| | 478 | $.data(a, 'href', url); |
| | 479 | } else { |
| | 480 | url = $.data(a, 'href'); |
| | 481 | } |
| | 482 | |
| | 483 | // load |
| | 484 | if (o.spinner) { |
| | 485 | $.data(a, 'title', $span.html()); |
| | 486 | $span.html('<em>' + o.spinner + '</em>'); |
| | 487 | } |
| | 488 | var finish = function() { |
| | 489 | self.$tabs.filter('.' + o.loadingClass).each(function() { |
| | 490 | $(this).removeClass(o.loadingClass); |
| | 491 | if (o.spinner) { |
| | 492 | $('span', this).html( $.data(this, 'title') ); |
| | 493 | } |
| | 494 | }); |
| | 495 | self.xhr = null; |
| | 496 | }; |
| | 497 | var ajaxOptions = $.extend(o.ajaxOptions, { |
| | 498 | url: url, |
| | 499 | success: function(r) { |
| | 500 | $(a.hash).html(r); |
| | 501 | finish(); |
| | 502 | // This callback is required because the switch has to take |
| | 503 | // place after loading has completed. |
| | 504 | if (callback && callback.constructor == Function) { |
| | 505 | callback(); |
| | 506 | } |
| | 507 | if (o.cache) { |
| | 508 | $.removeData(a, 'href'); // if loaded once do not load them again |
| | 509 | } |
| | 510 | o.load(self.$tabs[position - 1], self.$panels[position - 1]); // callback |
| | 511 | } |
| | 512 | }); |
| | 513 | if (this.xhr) { |
| | 514 | // terminate pending requests from other tabs and restore title |
| | 515 | this.xhr.abort(); |
| | 516 | finish(); |
| | 517 | } |
| | 518 | $a.addClass(o.loadingClass); |
| | 519 | setTimeout(function() { // timeout is again required in IE, "wait" for id being restored |
| | 520 | self.xhr = $.ajax(ajaxOptions); |
| | 521 | }, 0); |
| | 522 | |
| | 523 | }, |
| | 524 | href: function(position, href) { |
| | 525 | $.data(this.$tabs.eq(position - 1)[0], 'href', href); |
| | 526 | } |
| | 527 | }); |
| | 528 | |
| | 529 | })(jQuery); |