[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/jquery_ui/jquery.ui/ui/ -> ui.tabs.js (source)

   1  /*

   2   * jQuery UI Tabs 1.7.2

   3   *

   4   * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.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          if (this.options.deselectable !== undefined) {
  19              this.options.collapsible = this.options.deselectable;
  20          }
  21          this._tabify(true);
  22      },
  23  
  24      _setData: function(key, value) {
  25          if (key == 'selected') {
  26              if (this.options.collapsible && value == this.options.selected) {
  27                  return;
  28              }
  29              this.select(value);
  30          }
  31          else {
  32              this.options[key] = value;
  33              if (key == 'deselectable') {
  34                  this.options.collapsible = value;
  35              }
  36              this._tabify();
  37          }
  38      },
  39  
  40      _tabId: function(a) {
  41          return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
  42              this.options.idPrefix + $.data(a);
  43      },
  44  
  45      _sanitizeSelector: function(hash) {
  46          return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"

  47      },
  48  
  49      _cookie: function() {
  50          var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0]));
  51          return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
  52      },
  53  
  54      _ui: function(tab, panel) {
  55          return {
  56              tab: tab,
  57              panel: panel,
  58              index: this.anchors.index(tab)
  59          };
  60      },
  61  
  62      _cleanup: function() {
  63          // restore all former loading tabs labels

  64          this.lis.filter('.ui-state-processing').removeClass('ui-state-processing')
  65                  .find('span:data(label.tabs)')
  66                  .each(function() {
  67                      var el = $(this);
  68                      el.html(el.data('label.tabs')).removeData('label.tabs');
  69                  });
  70      },
  71  
  72      _tabify: function(init) {
  73  
  74          this.list = this.element.children('ul:first');
  75          this.lis = $('li:has(a[href])', this.list);
  76          this.anchors = this.lis.map(function() { return $('a', this)[0]; });
  77          this.panels = $([]);
  78  
  79          var self = this, o = this.options;
  80  
  81          var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash

  82          this.anchors.each(function(i, a) {
  83              var href = $(a).attr('href');
  84  
  85              // For dynamically created HTML that contains a hash as href IE < 8 expands

  86              // such href to the full page url with hash and then misinterprets tab as ajax.

  87              // Same consideration applies for an added tab with a fragment identifier

  88              // since a[href=#fragment-identifier] does unexpectedly not match.

  89              // Thus normalize href attribute...

  90              var hrefBase = href.split('#')[0], baseEl;
  91              if (hrefBase && (hrefBase === location.toString().split('#')[0] ||
  92                      (baseEl = $('base')[0]) && hrefBase === baseEl.href)) {
  93                  href = a.hash;
  94                  a.href = href;
  95              }
  96  
  97              // inline tab

  98              if (fragmentId.test(href)) {
  99                  self.panels = self.panels.add(self._sanitizeSelector(href));
 100              }
 101  
 102              // remote tab

 103              else if (href != '#') { // prevent loading the page itself if href is just "#"
 104                  $.data(a, 'href.tabs', href); // required for restore on destroy

 105  
 106                  // TODO until #3808 is fixed strip fragment identifier from url

 107                  // (IE fails to load from such url)

 108                  $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data

 109  
 110                  var id = self._tabId(a);
 111                  a.href = '#' + id;
 112                  var $panel = $('#' + id);
 113                  if (!$panel.length) {
 114                      $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom')
 115                          .insertAfter(self.panels[i - 1] || self.list);
 116                      $panel.data('destroy.tabs', true);
 117                  }
 118                  self.panels = self.panels.add($panel);
 119              }
 120  
 121              // invalid tab href

 122              else {
 123                  o.disabled.push(i);
 124              }
 125          });
 126  
 127          // initialization from scratch

 128          if (init) {
 129  
 130              // attach necessary classes for styling

 131              this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all');
 132              this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
 133              this.lis.addClass('ui-state-default ui-corner-top');
 134              this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom');
 135  
 136              // Selected tab

 137              // use "selected" option or try to retrieve:

 138              // 1. from fragment identifier in url

 139              // 2. from cookie

 140              // 3. from selected class attribute on <li>

 141              if (o.selected === undefined) {
 142                  if (location.hash) {
 143                      this.anchors.each(function(i, a) {
 144                          if (a.hash == location.hash) {
 145                              o.selected = i;
 146                              return false; // break

 147                          }
 148                      });
 149                  }
 150                  if (typeof o.selected != 'number' && o.cookie) {
 151                      o.selected = parseInt(self._cookie(), 10);
 152                  }
 153                  if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) {
 154                      o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
 155                  }
 156                  o.selected = o.selected || 0;
 157              }
 158              else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release
 159                  o.selected = -1;
 160              }
 161  
 162              // sanity check - default to first tab...

 163              o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0;
 164  
 165              // Take disabling tabs via class attribute from HTML

 166              // into account and update option properly.

 167              // A selected tab cannot become disabled.

 168              o.disabled = $.unique(o.disabled.concat(
 169                  $.map(this.lis.filter('.ui-state-disabled'),
 170                      function(n, i) { return self.lis.index(n); } )
 171              )).sort();
 172  
 173              if ($.inArray(o.selected, o.disabled) != -1) {
 174                  o.disabled.splice($.inArray(o.selected, o.disabled), 1);
 175              }
 176  
 177              // highlight selected tab

 178              this.panels.addClass('ui-tabs-hide');
 179              this.lis.removeClass('ui-tabs-selected ui-state-active');
 180              if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list
 181                  this.panels.eq(o.selected).removeClass('ui-tabs-hide');
 182                  this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active');
 183  
 184                  // seems to be expected behavior that the show callback is fired

 185                  self.element.queue("tabs", function() {
 186                      self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected]));
 187                  });
 188                  
 189                  this.load(o.selected);
 190              }
 191  
 192              // clean up to avoid memory leaks in certain versions of IE 6

 193              $(window).bind('unload', function() {
 194                  self.lis.add(self.anchors).unbind('.tabs');
 195                  self.lis = self.anchors = self.panels = null;
 196              });
 197  
 198          }
 199          // update selected after add/remove

 200          else {
 201              o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
 202          }
 203  
 204          // update collapsible

 205          this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible');
 206  
 207          // set or update cookie after init and add/remove respectively

 208          if (o.cookie) {
 209              this._cookie(o.selected, o.cookie);
 210          }
 211  
 212          // disable tabs

 213          for (var i = 0, li; (li = this.lis[i]); i++) {
 214              $(li)[$.inArray(i, o.disabled) != -1 &&
 215                  !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled');
 216          }
 217  
 218          // reset cache if switching from cached to not cached

 219          if (o.cache === false) {
 220              this.anchors.removeData('cache.tabs');
 221          }
 222  
 223          // remove all handlers before, tabify may run on existing tabs after add or option change

 224          this.lis.add(this.anchors).unbind('.tabs');
 225  
 226          if (o.event != 'mouseover') {
 227              var addState = function(state, el) {
 228                  if (el.is(':not(.ui-state-disabled)')) {
 229                      el.addClass('ui-state-' + state);
 230                  }
 231              };
 232              var removeState = function(state, el) {
 233                  el.removeClass('ui-state-' + state);
 234              };
 235              this.lis.bind('mouseover.tabs', function() {
 236                  addState('hover', $(this));
 237              });
 238              this.lis.bind('mouseout.tabs', function() {
 239                  removeState('hover', $(this));
 240              });
 241              this.anchors.bind('focus.tabs', function() {
 242                  addState('focus', $(this).closest('li'));
 243              });
 244              this.anchors.bind('blur.tabs', function() {
 245                  removeState('focus', $(this).closest('li'));
 246              });
 247          }
 248  
 249          // set up animations

 250          var hideFx, showFx;
 251          if (o.fx) {
 252              if ($.isArray(o.fx)) {
 253                  hideFx = o.fx[0];
 254                  showFx = o.fx[1];
 255              }
 256              else {
 257                  hideFx = showFx = o.fx;
 258              }
 259          }
 260  
 261          // Reset certain styles left over from animation

 262          // and prevent IE's ClearType bug...

 263  		function resetStyle($el, fx) {
 264              $el.css({ display: '' });
 265              if ($.browser.msie && fx.opacity) {
 266                  $el[0].style.removeAttribute('filter');
 267              }
 268          }
 269  
 270          // Show a tab...

 271          var showTab = showFx ?
 272              function(clicked, $show) {
 273                  $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');
 274                  $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way
 275                      .animate(showFx, showFx.duration || 'normal', function() {
 276                          resetStyle($show, showFx);
 277                          self._trigger('show', null, self._ui(clicked, $show[0]));
 278                      });
 279              } :
 280              function(clicked, $show) {
 281                  $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');
 282                  $show.removeClass('ui-tabs-hide');
 283                  self._trigger('show', null, self._ui(clicked, $show[0]));
 284              };
 285  
 286          // Hide a tab, $show is optional...

 287          var hideTab = hideFx ?
 288              function(clicked, $hide) {
 289                  $hide.animate(hideFx, hideFx.duration || 'normal', function() {
 290                      self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');
 291                      $hide.addClass('ui-tabs-hide');
 292                      resetStyle($hide, hideFx);
 293                      self.element.dequeue("tabs");
 294                  });
 295              } :
 296              function(clicked, $hide, $show) {
 297                  self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');
 298                  $hide.addClass('ui-tabs-hide');
 299                  self.element.dequeue("tabs");
 300              };
 301  
 302          // attach tab event handler, unbind to avoid duplicates from former tabifying...

 303          this.anchors.bind(o.event + '.tabs', function() {
 304              var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'),
 305                      $show = $(self._sanitizeSelector(this.hash));
 306  
 307              // If tab is already selected and not collapsible or tab disabled or

 308              // or is already loading or click callback returns false stop here.

 309              // Check if click handler returns false last so that it is not executed

 310              // for a disabled or loading tab!

 311              if (($li.hasClass('ui-tabs-selected') && !o.collapsible) ||
 312                  $li.hasClass('ui-state-disabled') ||
 313                  $li.hasClass('ui-state-processing') ||
 314                  self._trigger('select', null, self._ui(this, $show[0])) === false) {
 315                  this.blur();
 316                  return false;
 317              }
 318  
 319              o.selected = self.anchors.index(this);
 320  
 321              self.abort();
 322  
 323              // if tab may be closed

 324              if (o.collapsible) {
 325                  if ($li.hasClass('ui-tabs-selected')) {
 326                      o.selected = -1;
 327  
 328                      if (o.cookie) {
 329                          self._cookie(o.selected, o.cookie);
 330                      }
 331  
 332                      self.element.queue("tabs", function() {
 333                          hideTab(el, $hide);
 334                      }).dequeue("tabs");
 335                      
 336                      this.blur();
 337                      return false;
 338                  }
 339                  else if (!$hide.length) {
 340                      if (o.cookie) {
 341                          self._cookie(o.selected, o.cookie);
 342                      }
 343                      
 344                      self.element.queue("tabs", function() {
 345                          showTab(el, $show);
 346                      });
 347  
 348                      self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171

 349                      
 350                      this.blur();
 351                      return false;
 352                  }
 353              }
 354  
 355              if (o.cookie) {
 356                  self._cookie(o.selected, o.cookie);
 357              }
 358  
 359              // show new tab

 360              if ($show.length) {
 361                  if ($hide.length) {
 362                      self.element.queue("tabs", function() {
 363                          hideTab(el, $hide);
 364                      });
 365                  }
 366                  self.element.queue("tabs", function() {
 367                      showTab(el, $show);
 368                  });
 369                  
 370                  self.load(self.anchors.index(this));
 371              }
 372              else {
 373                  throw 'jQuery UI Tabs: Mismatching fragment identifier.';
 374              }
 375  
 376              // Prevent IE from keeping other link focussed when using the back button

 377              // and remove dotted border from clicked link. This is controlled via CSS

 378              // in modern browsers; blur() removes focus from address bar in Firefox

 379              // which can become a usability and annoying problem with tabs('rotate').

 380              if ($.browser.msie) {
 381                  this.blur();
 382              }
 383  
 384          });
 385  
 386          // disable click in any case

 387          this.anchors.bind('click.tabs', function(){return false;});
 388  
 389      },
 390  
 391      destroy: function() {
 392          var o = this.options;
 393  
 394          this.abort();
 395          
 396          this.element.unbind('.tabs')
 397              .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible')
 398              .removeData('tabs');
 399  
 400          this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');
 401  
 402          this.anchors.each(function() {
 403              var href = $.data(this, 'href.tabs');
 404              if (href) {
 405                  this.href = href;
 406              }
 407              var $this = $(this).unbind('.tabs');
 408              $.each(['href', 'load', 'cache'], function(i, prefix) {
 409                  $this.removeData(prefix + '.tabs');
 410              });
 411          });
 412  
 413          this.lis.unbind('.tabs').add(this.panels).each(function() {
 414              if ($.data(this, 'destroy.tabs')) {
 415                  $(this).remove();
 416              }
 417              else {
 418                  $(this).removeClass([
 419                      'ui-state-default',
 420                      'ui-corner-top',
 421                      'ui-tabs-selected',
 422                      'ui-state-active',
 423                      'ui-state-hover',
 424                      'ui-state-focus',
 425                      'ui-state-disabled',
 426                      'ui-tabs-panel',
 427                      'ui-widget-content',
 428                      'ui-corner-bottom',
 429                      'ui-tabs-hide'
 430                  ].join(' '));
 431              }
 432          });
 433  
 434          if (o.cookie) {
 435              this._cookie(null, o.cookie);
 436          }
 437      },
 438  
 439      add: function(url, label, index) {
 440          if (index === undefined) {
 441              index = this.anchors.length; // append by default

 442          }
 443  
 444          var self = this, o = this.options,
 445              $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)),
 446              id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]);
 447  
 448          $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true);
 449  
 450          // try to find an existing element before creating a new one

 451          var $panel = $('#' + id);
 452          if (!$panel.length) {
 453              $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true);
 454          }
 455          $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide');
 456  
 457          if (index >= this.lis.length) {
 458              $li.appendTo(this.list);
 459              $panel.appendTo(this.list[0].parentNode);
 460          }
 461          else {
 462              $li.insertBefore(this.lis[index]);
 463              $panel.insertBefore(this.panels[index]);
 464          }
 465  
 466          o.disabled = $.map(o.disabled,
 467              function(n, i) { return n >= index ? ++n : n; });
 468  
 469          this._tabify();
 470  
 471          if (this.anchors.length == 1) { // after tabify
 472              $li.addClass('ui-tabs-selected ui-state-active');
 473              $panel.removeClass('ui-tabs-hide');
 474              this.element.queue("tabs", function() {
 475                  self._trigger('show', null, self._ui(self.anchors[0], self.panels[0]));
 476              });
 477                  
 478              this.load(0);
 479          }
 480  
 481          // callback

 482          this._trigger('add', null, this._ui(this.anchors[index], this.panels[index]));
 483      },
 484  
 485      remove: function(index) {
 486          var o = this.options, $li = this.lis.eq(index).remove(),
 487              $panel = this.panels.eq(index).remove();
 488  
 489          // If selected tab was removed focus tab to the right or

 490          // in case the last tab was removed the tab to the left.

 491          if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) {
 492              this.select(index + (index + 1 < this.anchors.length ? 1 : -1));
 493          }
 494  
 495          o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
 496              function(n, i) { return n >= index ? --n : n; });
 497  
 498          this._tabify();
 499  
 500          // callback

 501          this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0]));
 502      },
 503  
 504      enable: function(index) {
 505          var o = this.options;
 506          if ($.inArray(index, o.disabled) == -1) {
 507              return;
 508          }
 509  
 510          this.lis.eq(index).removeClass('ui-state-disabled');
 511          o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
 512  
 513          // callback

 514          this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index]));
 515      },
 516  
 517      disable: function(index) {
 518          var self = this, o = this.options;
 519          if (index != o.selected) { // cannot disable already selected tab
 520              this.lis.eq(index).addClass('ui-state-disabled');
 521  
 522              o.disabled.push(index);
 523              o.disabled.sort();
 524  
 525              // callback

 526              this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index]));
 527          }
 528      },
 529  
 530      select: function(index) {
 531          if (typeof index == 'string') {
 532              index = this.anchors.index(this.anchors.filter('[href$=' + index + ']'));
 533          }
 534          else if (index === null) { // usage of null is deprecated, TODO remove in next release
 535              index = -1;
 536          }
 537          if (index == -1 && this.options.collapsible) {
 538              index = this.options.selected;
 539          }
 540  
 541          this.anchors.eq(index).trigger(this.options.event + '.tabs');
 542      },
 543  
 544      load: function(index) {
 545          var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs');
 546  
 547          this.abort();
 548  
 549          // not remote or from cache

 550          if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) {
 551              this.element.dequeue("tabs");
 552              return;
 553          }
 554  
 555          // load remote from here on

 556          this.lis.eq(index).addClass('ui-state-processing');
 557  
 558          if (o.spinner) {
 559              var span = $('span', a);
 560              span.data('label.tabs', span.html()).html(o.spinner);
 561          }
 562  
 563          this.xhr = $.ajax($.extend({}, o.ajaxOptions, {
 564              url: url,
 565              success: function(r, s) {
 566                  $(self._sanitizeSelector(a.hash)).html(r);
 567  
 568                  // take care of tab labels

 569                  self._cleanup();
 570  
 571                  if (o.cache) {
 572                      $.data(a, 'cache.tabs', true); // if loaded once do not load them again

 573                  }
 574  
 575                  // callbacks

 576                  self._trigger('load', null, self._ui(self.anchors[index], self.panels[index]));
 577                  try {
 578                      o.ajaxOptions.success(r, s);
 579                  }
 580                  catch (e) {}
 581  
 582                  // last, so that load event is fired before show...

 583                  self.element.dequeue("tabs");
 584              }
 585          }));
 586      },
 587  
 588      abort: function() {
 589          // stop possibly running animations

 590          this.element.queue([]);
 591          this.panels.stop(false, true);
 592  
 593          // terminate pending requests from other tabs

 594          if (this.xhr) {
 595              this.xhr.abort();
 596              delete this.xhr;
 597          }
 598  
 599          // take care of tab labels

 600          this._cleanup();
 601  
 602      },
 603  
 604      url: function(index, url) {
 605          this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url);
 606      },
 607  
 608      length: function() {
 609          return this.anchors.length;
 610      }
 611  
 612  });
 613  
 614  $.extend($.ui.tabs, {
 615      version: '1.7.2',
 616      getter: 'length',
 617      defaults: {
 618          ajaxOptions: null,
 619          cache: false,
 620          cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
 621          collapsible: false,
 622          disabled: [],
 623          event: 'click',
 624          fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
 625          idPrefix: 'ui-tabs-',
 626          panelTemplate: '<div></div>',
 627          spinner: '<em>Loading&#8230;</em>',
 628          tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
 629      }
 630  });
 631  
 632  /*

 633   * Tabs Extensions

 634   */
 635  
 636  /*

 637   * Rotate

 638   */
 639  $.extend($.ui.tabs.prototype, {
 640      rotation: null,
 641      rotate: function(ms, continuing) {
 642  
 643          var self = this, o = this.options;
 644          
 645          var rotate = self._rotate || (self._rotate = function(e) {
 646              clearTimeout(self.rotation);
 647              self.rotation = setTimeout(function() {
 648                  var t = o.selected;
 649                  self.select( ++t < self.anchors.length ? t : 0 );
 650              }, ms);
 651              
 652              if (e) {
 653                  e.stopPropagation();
 654              }
 655          });
 656          
 657          var stop = self._unrotate || (self._unrotate = !continuing ?
 658              function(e) {
 659                  if (e.clientX) { // in case of a true click
 660                      self.rotate(null);
 661                  }
 662              } :
 663              function(e) {
 664                  t = o.selected;
 665                  rotate();
 666              });
 667  
 668          // start rotation

 669          if (ms) {
 670              this.element.bind('tabsshow', rotate);
 671              this.anchors.bind(o.event + '.tabs', stop);
 672              rotate();
 673          }
 674          // stop rotation

 675          else {
 676              clearTimeout(self.rotation);
 677              this.element.unbind('tabsshow', rotate);
 678              this.anchors.unbind(o.event + '.tabs', stop);
 679              delete this._rotate;
 680              delete this._unrotate;
 681          }
 682      }
 683  });
 684  
 685  })(jQuery);


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7