[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

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

   1  /*

   2   * jQuery UI Tabs 1.7.3

   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  var tabId = 0,
  16      listId = 0;
  17  
  18  $.widget("ui.tabs", {
  19  
  20      _init: function() {
  21          if (this.options.deselectable !== undefined) {
  22              this.options.collapsible = this.options.deselectable;
  23          }
  24          this._tabify(true);
  25      },
  26  
  27      _setData: function(key, value) {
  28          if (key == 'selected') {
  29              if (this.options.collapsible && value == this.options.selected) {
  30                  return;
  31              }
  32              this.select(value);
  33          }
  34          else {
  35              this.options[key] = value;
  36              if (key == 'deselectable') {
  37                  this.options.collapsible = value;
  38              }
  39              this._tabify();
  40          }
  41      },
  42  
  43      _tabId: function(a) {
  44          return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') ||
  45              this.options.idPrefix + (++tabId);
  46      },
  47  
  48      _sanitizeSelector: function(hash) {
  49          return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"

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

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

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

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

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

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

  92              // Thus normalize href attribute...

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

 101              if (fragmentId.test(href)) {
 102                  self.panels = self.panels.add(self._sanitizeSelector(href));
 103              }
 104  
 105              // remote tab

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

 108  
 109                  // TODO until #3808 is fixed strip fragment identifier from url

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

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

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

 125              else {
 126                  o.disabled.push(i);
 127              }
 128          });
 129  
 130          // initialization from scratch

 131          if (init) {
 132  
 133              // attach necessary classes for styling

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

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

 141              // 1. from fragment identifier in url

 142              // 2. from cookie

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

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

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

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

 169              // into account and update option properly.

 170              // A selected tab cannot become disabled.

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

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

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

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

 203          else {
 204              o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected'));
 205          }
 206  
 207          // update collapsible

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

 211          if (o.cookie) {
 212              this._cookie(o.selected, o.cookie);
 213          }
 214  
 215          // disable tabs

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

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

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

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

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

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

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

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

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

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

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

 313              // for a disabled or loading tab!

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

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

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

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

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

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

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

 383              if ($.browser.msie) {
 384                  this.blur();
 385              }
 386  
 387          });
 388  
 389          // disable click in any case

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

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

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

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

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

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

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

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

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

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

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

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

 576                  }
 577  
 578                  // callbacks

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

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

 593          this.element.queue([]);
 594          this.panels.stop(false, true);
 595  
 596          // terminate pending requests from other tabs

 597          if (this.xhr) {
 598              this.xhr.abort();
 599              delete this.xhr;
 600          }
 601  
 602          // take care of tab labels

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

 636   * Tabs Extensions

 637   */
 638  
 639  /*

 640   * Rotate

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

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

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


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7