From 03ef2fb4525dc57cd397bfebf7b1f97e696ca3ff Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 12:04:14 -0400 Subject: Tabs: Split out event handler, showtab, hidetab, resetStyle to their own methods --- ui/jquery.ui.tabs.js | 227 ++++++++++++++++++++++++++------------------------- 1 file changed, 116 insertions(+), 111 deletions(-) diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index fcdf22c0e..f12383d08 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -258,147 +258,152 @@ $.widget( "ui.tabs", { this._hoverable( this.lis ); // set up animations - var hideFx, showFx; if ( o.fx ) { if ( $.isArray( o.fx ) ) { - hideFx = o.fx[ 0 ]; - showFx = o.fx[ 1 ]; + this.hideFx = o.fx[ 0 ]; + this.showFx = o.fx[ 1 ]; } else { - hideFx = showFx = o.fx; + this.hideFx = this.showFx = o.fx; } } - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle( $el, fx ) { - $el.css( "display", "" ); - if ( !$.support.opacity && fx.opacity ) { - $el[ 0 ].style.removeAttribute( "filter" ); - } + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.anchors.bind( o.event + ".tabs", $.proxy( this, "_eventHandler" )); + + // disable click in any case + this.anchors.bind( "click.tabs", function( event ){ + event.preventDefault(); + }); + }, + + // Reset certain styles left over from animation + // and prevent IE's ClearType bug... + _resetStyle: function ( $el, fx ) { + $el.css( "display", "" ); + if ( !$.support.opacity && fx.opacity ) { + $el[ 0 ].style.removeAttribute( "filter" ); } + }, - // Show a tab... - var showTab = showFx - ? function( clicked, $show, event ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way - .animate( showFx, showFx.duration || "normal", function() { - resetStyle( $show, showFx ); - self._trigger( "show", event, self._ui( clicked, $show[ 0 ] ) ); - }); - } - : function( clicked, $show, event ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.removeClass( "ui-tabs-hide" ); - self._trigger( "show", event, self._ui( clicked, $show[ 0 ] ) ); - }; - - // Hide a tab, $show is optional... - var hideTab = hideFx - ? function( clicked, $hide ) { - $hide.animate( hideFx, hideFx.duration || "normal", function() { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - resetStyle( $hide, hideFx ); - self.element.dequeue( "tabs" ); + _showTab: function( clicked, show, event ) { + var self = this; + + $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); + + if ( this.showFx ) { + show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way + .animate( showFx, showFx.duration || "normal", function() { + self._resetStyle( show, showFx ); + self._trigger( "show", event, self._ui( clicked, show[ 0 ] ) ); }); - } - : function( clicked, $hide, $show ) { + } else { + show.removeClass( "ui-tabs-hide" ); + self._trigger( "show", event, self._ui( clicked, show[ 0 ] ) ); + } + }, + + _hideTab: function( clicked, $hide ) { + var self = this; + + if ( this.hideFx ) { + $hide.animate( hideFx, hideFx.duration || "normal", function() { self.lis.removeClass( "ui-tabs-selected ui-state-active" ); $hide.addClass( "ui-tabs-hide" ); + self._resetStyle( $hide, hideFx ); self.element.dequeue( "tabs" ); - }; + }); + } else { + self.lis.removeClass( "ui-tabs-selected ui-state-active" ); + $hide.addClass( "ui-tabs-hide" ); + self.element.dequeue( "tabs" ); + } + }, - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.anchors.bind( o.event + ".tabs", function( event ) { - event.preventDefault(); - var el = this, - $li = $(el).closest( "li" ), - $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), - $show = self.element.find( self._sanitizeSelector( el.hash ) ); - - // If tab is already selected and not collapsible or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || - $li.hasClass( "ui-state-disabled" ) || - $li.hasClass( "ui-state-processing" ) || - self.panels.filter( ":animated" ).length || - self._trigger( "select", event, self._ui( this, $show[ 0 ] ) ) === false ) { - this.blur(); - return; - } + _eventHandler: function( event ) { + event.preventDefault(); + var self = this, + o = this.options, + el = event.currentTarget, + $li = $(el).closest( "li" ), + $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), + $show = self.element.find( self._sanitizeSelector( el.hash ) ); + + // If tab is already selected and not collapsible or tab disabled or + // or is already loading or click callback returns false stop here. + // Check if click handler returns false last so that it is not executed + // for a disabled or loading tab! + if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || + $li.hasClass( "ui-state-disabled" ) || + $li.hasClass( "ui-state-processing" ) || + self.panels.filter( ":animated" ).length || + self._trigger( "select", event, self._ui( el, $show[ 0 ] ) ) === false ) { + el.blur(); + return; + } - o.selected = self.anchors.index( this ); + o.selected = self.anchors.index( el ); - self.abort(); + self.abort(); - // if tab may be closed - if ( o.collapsible ) { - if ( $li.hasClass( "ui-tabs-selected" ) ) { - o.selected = -1; + // if tab may be closed + if ( o.collapsible ) { + if ( $li.hasClass( "ui-tabs-selected" ) ) { + o.selected = -1; - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } + if ( o.cookie ) { + self._cookie( o.selected, o.cookie ); + } - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }).dequeue( "tabs" ); + self.element.queue( "tabs", function() { + self._hideTab( el, $hide ); + }).dequeue( "tabs" ); - this.blur(); - return; - } else if ( !$hide.length ) { - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } + el.blur(); + return; + } else if ( !$hide.length ) { + if ( o.cookie ) { + self._cookie( o.selected, o.cookie ); + } - self.element.queue( "tabs", function() { - showTab( el, $show, event ); - }); + self.element.queue( "tabs", function() { + self._showTab( el, $show, event ); + }); - // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 - self.load( self.anchors.index( this ) ); + // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 + self.load( self.anchors.index( el ) ); - this.blur(); - return; - } + el.blur(); + return; } + } - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } + if ( o.cookie ) { + self._cookie( o.selected, o.cookie ); + } - // show new tab - if ( $show.length ) { - if ( $hide.length ) { - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }); - } + // show new tab + if ( $show.length ) { + if ( $hide.length ) { self.element.queue( "tabs", function() { - showTab( el, $show, event ); + self._hideTab( el, $hide ); }); - - self.load( self.anchors.index( this ) ); - } else { - throw "jQuery UI Tabs: Mismatching fragment identifier."; } + self.element.queue( "tabs", function() { + self._showTab( el, $show, event ); + }); - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability - if ( $.browser.msie ) { - this.blur(); - } - }); + self.load( self.anchors.index( el ) ); + } else { + throw "jQuery UI Tabs: Mismatching fragment identifier."; + } - // disable click in any case - this.anchors.bind( "click.tabs", function( event ){ - event.preventDefault(); - }); + // Prevent IE from keeping other link focussed when using the back button + // and remove dotted border from clicked link. This is controlled via CSS + // in modern browsers; blur() removes focus from address bar in Firefox + // which can become a usability + if ( $.browser.msie ) { + el.blur(); + } }, _getIndex: function( index ) { -- cgit v1.2.3 From aeaaf93ebb51ab6ff61a42d365edfd3872ae2ebd Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 15:00:39 -0400 Subject: Tabs: Add beforeload event; deprecate ajaxOptions and cache options. Fixes #7131 Tabs: Add beforeload event; deprecate ajaxOptions and cache options --- tests/unit/tabs/tabs.html | 3 + tests/unit/tabs/tabs_defaults.js | 3 +- tests/unit/tabs/tabs_defaults_deprecated.js | 28 ++++++ tests/unit/tabs/tabs_deprecated.html | 122 ++++++++++++++++++++++ tests/unit/tabs/tabs_deprecated.js | 13 +++ tests/unit/tabs/tabs_events.js | 19 ++++ tests/unit/tabs/tabs_options.js | 8 -- ui/jquery.ui.tabs.js | 150 +++++++++++++++++++--------- 8 files changed, 287 insertions(+), 59 deletions(-) create mode 100644 tests/unit/tabs/tabs_defaults_deprecated.js create mode 100644 tests/unit/tabs/tabs_deprecated.html create mode 100644 tests/unit/tabs/tabs_deprecated.js diff --git a/tests/unit/tabs/tabs.html b/tests/unit/tabs/tabs.html index 74855ca9a..02fbfe3bb 100644 --- a/tests/unit/tabs/tabs.html +++ b/tests/unit/tabs/tabs.html @@ -7,6 +7,9 @@ + diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index ef93c69ee..4f663fbf2 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -4,8 +4,7 @@ var tabs_defaults = { add: null, - ajaxOptions: null, - cache: false, + beforeload: null, collapsible: false, cookie: null, disable: null, diff --git a/tests/unit/tabs/tabs_defaults_deprecated.js b/tests/unit/tabs/tabs_defaults_deprecated.js new file mode 100644 index 000000000..73e9ffede --- /dev/null +++ b/tests/unit/tabs/tabs_defaults_deprecated.js @@ -0,0 +1,28 @@ +/* + * tabs_defaults.js + */ + +var tabs_defaults = { + add: null, + ajaxOptions: null, + beforeload: null, + cache: false, + collapsible: false, + cookie: null, + disable: null, + disabled: false, + enable: null, + event: "click", + fx: null, + idPrefix: "ui-tabs-", + load: null, + panelTemplate: "
", + remove: null, + select: null, + show: null, + spinner: "Loading…", + tabTemplate: "
  • #{label}
  • " +}; + +// FAIL: falsy values break the cookie option +commonWidgetTests( "tabs", { defaults: tabs_defaults } ); diff --git a/tests/unit/tabs/tabs_deprecated.html b/tests/unit/tabs/tabs_deprecated.html new file mode 100644 index 000000000..3b927675c --- /dev/null +++ b/tests/unit/tabs/tabs_deprecated.html @@ -0,0 +1,122 @@ + + + + + jQuery UI Tabs Test Suite + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    jQuery UI Tabs Test Suite (deprecated)

    +

    +
    +

    +
      +
    + +
    + +
    +
      +
    • 1
    • +
    • 2
    • +
    • 3
    • +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
      +
    • 1
    • +
    +
    +
    +
    +
      +
    • 1
    • +
    +
      +
    1. 1
    2. +
    +
    +
    +
      +
    1. 1
    2. +
    +
      +
    • 1
    • +
    +
    +
    +
    +
      +
      +
      +
      +
        +
      • 1 +
          +
        • 3
        • +
        • 4
        • +
        +
      • +
      • 2
      • +
      +
      +
      +
      +
      +
        +
      • 1
      • +
      • 2
      • +
      +
      +
      +
      +
      + + diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js new file mode 100644 index 000000000..72034c083 --- /dev/null +++ b/tests/unit/tabs/tabs_deprecated.js @@ -0,0 +1,13 @@ +(function( $ ) { + +module("tabs (deprecated): cache and ajaxoptions"); + +test('ajaxOptions', function() { + ok(false, "missing test - untested code is broken code."); +}); + +test('cache', function() { + ok(false, "missing test - untested code is broken code."); +}); + +}( jQuery ) ); diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index 24fb62f9b..26ea76fb4 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -26,6 +26,25 @@ test('select', function() { equals( evenObj.originalEvent.type, "click", "select triggered by click" ); }); +test('beforeload', function() { + expect( 5 ); + + el = $('#tabs2'); + + el.tabs({ + selected: 2, + beforeload: function( event, ui ) { + ok( $.isFunction( ui.jqXHR.promise ), 'contain jqXHR object'); + equals( ui.settings.url, "data/test.html", 'contain ajax settings url'); + equals( ui.tab, el.find('a')[ 2 ], 'contain tab as DOM anchor element'); + equals( ui.panel, el.find('div')[ 2 ], 'contain panel as DOM div element'); + equals( ui.index, 2, 'contain index'); + event.preventDefault(); + } + }); + +}); + test('load', function() { ok(false, "missing test - untested code is broken code."); }); diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index 1c621ac28..cf50bd970 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -5,14 +5,6 @@ module("tabs: options"); -test('ajaxOptions', function() { - ok(false, "missing test - untested code is broken code."); -}); - -test('cache', function() { - ok(false, "missing test - untested code is broken code."); -}); - test('collapsible', function() { expect(4); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index f12383d08..39f1b537b 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -27,8 +27,7 @@ function getNextListId() { $.widget( "ui.tabs", { options: { add: null, - ajaxOptions: null, - cache: false, + beforeload: null, cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } collapsible: false, disable: null, @@ -246,11 +245,6 @@ $.widget( "ui.tabs", { $( li ).toggleClass( "ui-state-disabled", $.inArray( i, o.disabled ) != -1 ); } - // reset cache if switching from cached to not cached - if ( o.cache === false ) { - this.anchors.removeData( "cache.tabs" ); - } - // remove all handlers before, tabify may run on existing tabs after add or option change this.lis.add( this.anchors ).unbind( ".tabs" ); @@ -431,7 +425,7 @@ $.widget( "ui.tabs", { this.href = href; } var $this = $( this ).unbind( ".tabs" ); - $.each( [ "href", "load", "cache" ], function( i, prefix ) { + $.each( [ "href", "load" ], function( i, prefix ) { $this.removeData( prefix + ".tabs" ); }); }); @@ -607,57 +601,45 @@ $.widget( "ui.tabs", { var self = this, o = this.options, a = this.anchors.eq( index )[ 0 ], - url = $.data( a, "load.tabs" ); + url = $.data( a, "load.tabs" ), + eventData = self._ui( self.anchors[ index ], self.panels[ index ] ); this.abort(); - // not remote or from cache - if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { + // not remote + if ( !url ) { this.element.dequeue( "tabs" ); return; } - // load remote from here on - this.lis.eq( index ).addClass( "ui-state-processing" ); - - if ( o.spinner ) { - var span = $( "span", a ); - span.data( "label.tabs", span.html() ).html( o.spinner ); - } - - this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { + this.xhr = $.ajax({ url: url, - success: function( r, s ) { - self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); - - // take care of tab labels - self._cleanup(); + beforeSend: function( jqXHR, settings ) { + return self._trigger( "beforeload", null, + $.extend( { jqXHR: jqXHR, settings: settings }, eventData ) ); + } + }); - if ( o.cache ) { - $.data( a, "cache.tabs", true ); - } + if ( this.xhr ) { + // load remote from here on + this.lis.eq( index ).addClass( "ui-state-processing" ); - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - o.ajaxOptions.success( r, s ); - } - catch ( e ) {} - }, - error: function( xhr, s, e ) { - // take care of tab labels - self._cleanup(); - - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - o.ajaxOptions.error( xhr, s, index, a ); - } - catch ( e ) {} + if ( o.spinner ) { + var span = $( "span", a ); + span.data( "label.tabs", span.html() ).html( o.spinner ); } - } ) ); + + this.xhr + .success( function( response ) { + self.element.find( self._sanitizeSelector( a.hash ) ).html( response ); + }) + .complete( function( jqXHR, status ) { + // take care of tab labels + self._cleanup(); + + self._trigger( "load", null, eventData ); + }); + } // last, so that load event is fired before show... self.element.dequeue( "tabs" ); @@ -686,7 +668,7 @@ $.widget( "ui.tabs", { }, url: function( index, url ) { - this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); + this.anchors.eq( index ).data( "load.tabs", url ); return this; }, @@ -699,4 +681,74 @@ $.extend( $.ui.tabs, { version: "@VERSION" }); +// DEPRECATED +if ( $.uiBackCompat !== false ) { + + // ajaxOptions and cache options + (function( $, prototype ) { + $.extend( prototype.options, { + ajaxOptions: null, + cache: false + }); + + var _create = prototype._create, + _setOption = prototype._setOption, + _destroy = prototype._destroy, + oldurl = prototype._url; + + $.extend( prototype, { + _create: function() { + _create.call( this ); + + var self = this; + + this.element.bind( "tabsbeforeload", function( event, ui ) { + // tab is already cached + if ( $.data( ui.tab, "cache.tabs" ) ) { + event.preventDefault(); + return; + } + + $.extend( ui.settings, self.options.ajaxOptions, { + error: function( xhr, s, e ) { + try { + // Passing index avoid a race condition when this method is + // called after the user has selected another tab. + // Pass the anchor that initiated this request allows + // loadError to manipulate the tab content panel via $(a.hash) + self.options.ajaxOptions.error( xhr, s, ui.index, ui.tab ); + } + catch ( e ) {} + } + }); + + ui.jqXHR.success( function() { + if ( self.options.cache ) { + $.data( ui.tab, "cache.tabs", true ); + } + }); + }); + }, + + _setOption: function( key, value ) { + // reset cache if switching from cached to not cached + if ( key === "cache" && value === false ) { + this.anchors.removeData( "cache.tabs" ); + } + _setOption.apply( this, arguments ); + }, + + _destroy: function() { + this.anchors.removeData( "cache.tabs" ); + _destroy.call( this ); + }, + + url: function( index, url ){ + this.anchors.eq( index ).removeData( "cache.tabs" ); + oldurl.apply( this, arguments ); + } + }); + }( jQuery, jQuery.ui.tabs.prototype ) ); +} + })( jQuery ); -- cgit v1.2.3 From 3d612445264ba1a5f76917aee78217b92b04543b Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 15:23:08 -0400 Subject: Tabs: Deprecate abort method. Fixes #7133 Tabs: Deprecate abort method --- ui/jquery.ui.tabs.js | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 39f1b537b..617e84848 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -337,7 +337,9 @@ $.widget( "ui.tabs", { o.selected = self.anchors.index( el ); - self.abort(); + if ( self.xhr ) { + self.xhr.abort(); + } // if tab may be closed if ( o.collapsible ) { @@ -413,7 +415,9 @@ $.widget( "ui.tabs", { _destroy: function() { var o = this.options; - this.abort(); + if ( this.xhr ) { + this.xhr.abort(); + } this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); @@ -604,7 +608,9 @@ $.widget( "ui.tabs", { url = $.data( a, "load.tabs" ), eventData = self._ui( self.anchors[ index ], self.panels[ index ] ); - this.abort(); + if ( this.xhr ) { + this.xhr.abort(); + } // not remote if ( !url ) { @@ -634,6 +640,17 @@ $.widget( "ui.tabs", { self.element.find( self._sanitizeSelector( a.hash ) ).html( response ); }) .complete( function( jqXHR, status ) { + if ( status === "abort" ) { + // stop possibly running animations + self.element.queue( [] ); + self.panels.stop( false, true ); + + // "tabs" queue must not contain more than two elements, + // which are the callbacks for the latest clicked tab... + self.element.queue( "tabs", self.element.queue( "tabs" ).splice( -2, 2 ) ); + + delete this.xhr; + } // take care of tab labels self._cleanup(); @@ -647,26 +664,6 @@ $.widget( "ui.tabs", { return this; }, - abort: function() { - // stop possibly running animations - this.element.queue( [] ); - this.panels.stop( false, true ); - - // "tabs" queue must not contain more than two elements, - // which are the callbacks for the latest clicked tab... - this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); - - // terminate pending requests from other tabs - if ( this.xhr ) { - this.xhr.abort(); - delete this.xhr; - } - - // take care of tab labels - this._cleanup(); - return this; - }, - url: function( index, url ) { this.anchors.eq( index ).data( "load.tabs", url ); return this; @@ -749,6 +746,15 @@ if ( $.uiBackCompat !== false ) { } }); }( jQuery, jQuery.ui.tabs.prototype ) ); + + // abort method + (function( $, prototype ) { + prototype.abort = function() { + if ( this.xhr ) { + this.xhr.abort(); + } + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From e7971c9077ce1f8e4f9afb123118349544bf1acb Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 15:48:53 -0400 Subject: Tabs: Deprecate spinner option. Fixes #7134 Tabs: Deprecate spinner option --- tests/unit/tabs/tabs_core.js | 30 ---------------------- tests/unit/tabs/tabs_defaults.js | 1 - tests/unit/tabs/tabs_deprecated.js | 31 +++++++++++++++++++++++ tests/unit/tabs/tabs_options.js | 4 --- ui/jquery.ui.tabs.js | 51 ++++++++++++++++++++++++-------------- 5 files changed, 63 insertions(+), 54 deletions(-) diff --git a/tests/unit/tabs/tabs_core.js b/tests/unit/tabs/tabs_core.js index 652788bba..7d9074819 100644 --- a/tests/unit/tabs/tabs_core.js +++ b/tests/unit/tabs/tabs_core.js @@ -25,34 +25,4 @@ test('navigation markup', function() { el.tabs('destroy'); }); -test('ajax', function() { - expect(4); - stop(); - - el = $('#tabs2'); - - el.tabs({ - selected: 2, - load: function() { - // spinner: default spinner - setTimeout(function() { - equals($('li:eq(2) > a > span', el).length, 1, "should restore tab markup after spinner is removed"); - equals($('li:eq(2) > a > span', el).html(), '3', "should restore tab label after spinner is removed"); - el.tabs('destroy'); - el.tabs({ - selected: 2, - spinner: '', - load: function() { - // spinner: image - equals($('li:eq(2) > a > span', el).length, 1, "should restore tab markup after spinner is removed"); - equals($('li:eq(2) > a > span', el).html(), '3', "should restore tab label after spinner is removed"); - start(); - } - }); - }, 1); - } - }); - -}); - })(jQuery); diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index 4f663fbf2..397d81ce6 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -18,7 +18,6 @@ var tabs_defaults = { remove: null, select: null, show: null, - spinner: "Loading…", tabTemplate: "
    • #{label}
    • " }; diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 72034c083..cec689808 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -10,4 +10,35 @@ test('cache', function() { ok(false, "missing test - untested code is broken code."); }); +module("tabs (deprecated): spinner"); + +test('spinner', function() { + expect(4); + stop(); + + el = $('#tabs2'); + + el.tabs({ + selected: 2, + load: function() { + // spinner: default spinner + setTimeout(function() { + equals($('li:eq(2) > a > span', el).length, 1, "should restore tab markup after spinner is removed"); + equals($('li:eq(2) > a > span', el).html(), '3', "should restore tab label after spinner is removed"); + el.tabs('destroy'); + el.tabs({ + selected: 2, + spinner: '', + load: function() { + // spinner: image + equals($('li:eq(2) > a > span', el).length, 1, "should restore tab markup after spinner is removed"); + equals($('li:eq(2) > a > span', el).html(), '3', "should restore tab label after spinner is removed"); + start(); + } + }); + }, 1); + } + }); +}); + }( jQuery ) ); diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index cf50bd970..45fba8f32 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -117,10 +117,6 @@ test('selected', function() { equals(el.tabs('option', 'selected'), 0, 'should not collapse tab if value is same as selected'); }); -test('spinner', function() { - ok(false, "missing test - untested code is broken code."); -}); - test('tabTemplate', function() { ok(false, "missing test - untested code is broken code."); }); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 617e84848..f54b166c9 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -41,7 +41,6 @@ $.widget( "ui.tabs", { remove: null, select: null, show: null, - spinner: "Loading…", tabTemplate: "
    • #{label}
    • " }, @@ -85,17 +84,6 @@ $.widget( "ui.tabs", { }; }, - _cleanup: function() { - // restore all former loading tabs labels - this.lis.filter( ".ui-state-processing" ) - .removeClass( "ui-state-processing" ) - .find( "span:data(label.tabs)" ) - .each(function() { - var el = $( this ); - el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); - }); - }, - _tabify: function( init ) { var self = this, o = this.options, @@ -630,11 +618,6 @@ $.widget( "ui.tabs", { // load remote from here on this.lis.eq( index ).addClass( "ui-state-processing" ); - if ( o.spinner ) { - var span = $( "span", a ); - span.data( "label.tabs", span.html() ).html( o.spinner ); - } - this.xhr .success( function( response ) { self.element.find( self._sanitizeSelector( a.hash ) ).html( response ); @@ -651,8 +634,8 @@ $.widget( "ui.tabs", { delete this.xhr; } - // take care of tab labels - self._cleanup(); + + self.lis.eq( index ).removeClass( "ui-state-processing" ); self._trigger( "load", null, eventData ); }); @@ -755,6 +738,36 @@ if ( $.uiBackCompat !== false ) { } }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // spinner + (function( $, prototype ) { + $.extend( prototype.options, { + spinner: "Loading…" + }); + + var _create = prototype._create; + prototype._create = function() { + _create.call( this ); + var self = this; + + this.element.bind( "tabsbeforeload", function( event, ui ) { + if ( self.options.spinner ) { + var span = $( "span", ui.tab ); + if ( span.length ) { + span.data( "label.tabs", span.html() ).html( self.options.spinner ); + } + } + ui.jqXHR.complete( function() { + if ( self.options.spinner ) { + var span = $( "span", ui.tab ); + if ( span.length ) { + span.html( span.data( "label.tabs" ) ).removeData( "label.tabs" ); + } + } + }); + }); + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From e5f081bc1c16c051665eafc22c9a7af3fba456c8 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 16:12:05 -0400 Subject: Tabs: Deprecate enable and disable events. Fixes #7142 Tabs: Deprecate enable and disable events --- tests/unit/tabs/tabs_defaults.js | 2 -- tests/unit/tabs/tabs_deprecated.js | 35 +++++++++++++++++++++++++++++ tests/unit/tabs/tabs_events.js | 33 ---------------------------- ui/jquery.ui.tabs.js | 45 ++++++++++++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 39 deletions(-) diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index 397d81ce6..5a6bc065e 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -7,9 +7,7 @@ var tabs_defaults = { beforeload: null, collapsible: false, cookie: null, - disable: null, disabled: false, - enable: null, event: "click", fx: null, idPrefix: "ui-tabs-", diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index cec689808..ee2dbdc74 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -41,4 +41,39 @@ test('spinner', function() { }); }); +module("tabs (deprecated): enable/disable events"); + +test('enable', function() { + expect(4); + + var uiObj; + el = $('#tabs1').tabs({ + disabled: [ 0, 1 ], + enable: function (event, ui) { + uiObj = ui; + } + }); + el.tabs('enable', 1); + ok(uiObj !== undefined, 'trigger callback'); + equals(uiObj.tab, $('a', el)[1], 'contain tab as DOM anchor element'); + equals(uiObj.panel, $('div', el)[1], 'contain panel as DOM div element'); + equals(uiObj.index, 1, 'contain index'); +}); + +test('disable', function() { + expect(4); + + var uiObj; + el = $('#tabs1').tabs({ + disable: function (event, ui) { + uiObj = ui; + } + }); + el.tabs('disable', 1); + ok(uiObj !== undefined, 'trigger callback'); + equals(uiObj.tab, $('a', el)[1], 'contain tab as DOM anchor element'); + equals(uiObj.panel, $('div', el)[1], 'contain panel as DOM div element'); + equals(uiObj.index, 1, 'contain index'); +}); + }( jQuery ) ); diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index 26ea76fb4..56c1360ee 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -88,37 +88,4 @@ test('remove', function() { ok(false, "missing test - untested code is broken code."); }); -test('enable', function() { - expect(4); - - var uiObj; - el = $('#tabs1').tabs({ - disabled: [ 0, 1 ], - enable: function (event, ui) { - uiObj = ui; - } - }); - el.tabs('enable', 1); - ok(uiObj !== undefined, 'trigger callback'); - equals(uiObj.tab, $('a', el)[1], 'contain tab as DOM anchor element'); - equals(uiObj.panel, $('div', el)[1], 'contain panel as DOM div element'); - equals(uiObj.index, 1, 'contain index'); -}); - -test('disable', function() { - expect(4); - - var uiObj; - el = $('#tabs1').tabs({ - disable: function (event, ui) { - uiObj = ui; - } - }); - el.tabs('disable', 1); - ok(uiObj !== undefined, 'trigger callback'); - equals(uiObj.tab, $('a', el)[1], 'contain tab as DOM anchor element'); - equals(uiObj.panel, $('div', el)[1], 'contain panel as DOM div element'); - equals(uiObj.index, 1, 'contain index'); -}); - })(jQuery); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index f54b166c9..b7a270fb6 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -30,9 +30,7 @@ $.widget( "ui.tabs", { beforeload: null, cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } collapsible: false, - disable: null, disabled: false, - enable: null, event: "click", fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } idPrefix: "ui-tabs-", @@ -545,7 +543,6 @@ $.widget( "ui.tabs", { o.disabled = false; } - this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); return this; }, @@ -569,7 +566,6 @@ $.widget( "ui.tabs", { o.disabled = true; } - this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); } return this; @@ -768,6 +764,47 @@ if ( $.uiBackCompat !== false ) { }); }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // enable/disable events + (function( $, prototype ) { + $.extend( prototype.options, { + enable: null, + disable: null + }); + + var enable = prototype.enable, + disable = prototype.disable; + + prototype.enable = function( index ) { + var o = this.options, + trigger; + + if ( index && o.disabled || ($.isArray( o.disabled ) && $.inArray( index, o.disabled ) !== -1 ) ) { + trigger = true; + } + + enable.apply( this, arguments ); + + if ( trigger ) { + this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + } + }; + + prototype.disable = function( index ) { + var o = this.options, + trigger; + + if ( index && !o.disabled || ($.isArray( o.disabled ) && $.inArray( index, o.disabled ) == -1 ) ) { + trigger = true; + } + + disable.apply( this, arguments ); + + if ( trigger ) { + this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + } + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From e378876918361182e6cb6321159393828848b2c9 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 16:29:57 -0400 Subject: Tabs: Deprecate add and remove methods Fixes #7141 Tabs: Deprecate add and remove methods --- tests/unit/tabs/tabs_defaults.js | 2 - tests/unit/tabs/tabs_deprecated.js | 74 ++++++++++++++++- tests/unit/tabs/tabs_events.js | 19 ----- tests/unit/tabs/tabs_methods.js | 36 -------- tests/unit/tabs/tabs_tickets.js | 11 --- ui/jquery.ui.tabs.js | 163 +++++++++++++++++++------------------ 6 files changed, 155 insertions(+), 150 deletions(-) diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index 5a6bc065e..f7307b458 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -3,7 +3,6 @@ */ var tabs_defaults = { - add: null, beforeload: null, collapsible: false, cookie: null, @@ -13,7 +12,6 @@ var tabs_defaults = { idPrefix: "ui-tabs-", load: null, panelTemplate: "
      ", - remove: null, select: null, show: null, tabTemplate: "
    • #{label}
    • " diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index ee2dbdc74..b385a33c2 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -1,6 +1,6 @@ (function( $ ) { -module("tabs (deprecated): cache and ajaxoptions"); +module("tabs (deprecated): options"); test('ajaxOptions', function() { ok(false, "missing test - untested code is broken code."); @@ -10,8 +10,6 @@ test('cache', function() { ok(false, "missing test - untested code is broken code."); }); -module("tabs (deprecated): spinner"); - test('spinner', function() { expect(4); stop(); @@ -41,7 +39,7 @@ test('spinner', function() { }); }); -module("tabs (deprecated): enable/disable events"); +module("tabs (deprecated): events"); test('enable', function() { expect(4); @@ -76,4 +74,72 @@ test('disable', function() { equals(uiObj.index, 1, 'contain index'); }); +test('add', function() { + + // TODO move to methods, not at all event related... + + var el = $('
        ').tabs(); + equals(el.tabs('option', 'selected'), -1, 'Initially empty, no selected tab'); + + el.tabs('add', '#test1', 'Test 1'); + equals(el.tabs('option', 'selected'), 0, 'First tab added should be auto selected'); + + el.tabs('add', '#test2', 'Test 2'); + equals(el.tabs('option', 'selected'), 0, 'Second tab added should not be auto selected'); + +}); + +test('remove', function() { + ok(false, "missing test - untested code is broken code."); +}); + +module("tabs (deprecated): methods"); + +test('add', function() { + expect(4); + + el = $('#tabs1').tabs(); + el.tabs('add', '#new', 'New'); + + var added = $('li:last', el).simulate('mouseover'); + ok(added.is('.ui-state-hover'), 'should add mouseover handler to added tab'); + added.simulate('mouseout'); + var other = $('li:first', el).simulate('mouseover'); + ok(other.is('.ui-state-hover'), 'should not remove mouseover handler from existing tab'); + other.simulate('mouseout'); + + equals($('a', added).attr('href'), '#new', 'should not expand href to full url of current page'); + + ok(false, "missing test - untested code is broken code."); +}); + +test('remove', function() { + expect(4); + + el = $('#tabs1').tabs(); + + el.tabs('remove', 0); + equals(el.tabs('length'), 2, 'remove tab'); + equals($('li a[href$="fragment-1"]', el).length, 0, 'remove associated list item'); + equals($('#fragment-1').length, 0, 'remove associated panel'); + + // TODO delete tab -> focus tab to right + // TODO delete last tab -> focus tab to left + + el.tabs('select', 1); + el.tabs('remove', 1); + equals(el.tabs('option', 'selected'), 0, 'update selected property'); +}); + +test('#5069 - ui.tabs.add creates two tab panels when using a full URL', function() { + // http://dev.jqueryui.com/ticket/5069 + expect(2); + + el = $('#tabs2').tabs(); + equals(el.children('div').length, el.find('> ul > li').length, 'After creation, number of panels should be equal to number of tabs'); + el.tabs('add', '/ajax_html_echo', 'Test'); + equals(el.children('div').length, el.find('> ul > li').length, 'After add, number of panels should be equal to number of tabs'); + +}); + }( jQuery ) ); diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index 56c1360ee..b3f8653a2 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -69,23 +69,4 @@ test('show', function() { }); -test('add', function() { - - // TODO move to methods, not at all event related... - - var el = $('
          ').tabs(); - equals(el.tabs('option', 'selected'), -1, 'Initially empty, no selected tab'); - - el.tabs('add', '#test1', 'Test 1'); - equals(el.tabs('option', 'selected'), 0, 'First tab added should be auto selected'); - - el.tabs('add', '#test2', 'Test 2'); - equals(el.tabs('option', 'selected'), 0, 'Second tab added should not be auto selected'); - -}); - -test('remove', function() { - ok(false, "missing test - untested code is broken code."); -}); - })(jQuery); diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index 0209af697..ac0747df9 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -130,42 +130,6 @@ test('disable', function() { same(el.tabs('option', 'disabled'), true, 'set to true'); }); -test('add', function() { - expect(4); - - el = $('#tabs1').tabs(); - el.tabs('add', '#new', 'New'); - - var added = $('li:last', el).simulate('mouseover'); - ok(added.is('.ui-state-hover'), 'should add mouseover handler to added tab'); - added.simulate('mouseout'); - var other = $('li:first', el).simulate('mouseover'); - ok(other.is('.ui-state-hover'), 'should not remove mouseover handler from existing tab'); - other.simulate('mouseout'); - - equals($('a', added).attr('href'), '#new', 'should not expand href to full url of current page'); - - ok(false, "missing test - untested code is broken code."); -}); - -test('remove', function() { - expect(4); - - el = $('#tabs1').tabs(); - - el.tabs('remove', 0); - equals(el.tabs('length'), 2, 'remove tab'); - equals($('li a[href$="fragment-1"]', el).length, 0, 'remove associated list item'); - equals($('#fragment-1').length, 0, 'remove associated panel'); - - // TODO delete tab -> focus tab to right - // TODO delete last tab -> focus tab to left - - el.tabs('select', 1); - el.tabs('remove', 1); - equals(el.tabs('option', 'selected'), 0, 'update selected property'); -}); - test('select', function() { expect(6); diff --git a/tests/unit/tabs/tabs_tickets.js b/tests/unit/tabs/tabs_tickets.js index 4a09d59e4..5da799730 100644 --- a/tests/unit/tabs/tabs_tickets.js +++ b/tests/unit/tabs/tabs_tickets.js @@ -59,17 +59,6 @@ test('#4033 - IE expands hash to full url and misinterprets tab as ajax', functi }); -test('#5069 - ui.tabs.add creates two tab panels when using a full URL', function() { - // http://dev.jqueryui.com/ticket/5069 - expect(2); - - el = $('#tabs2').tabs(); - equals(el.children('div').length, el.find('> ul > li').length, 'After creation, number of panels should be equal to number of tabs'); - el.tabs('add', '/ajax_html_echo', 'Test'); - equals(el.children('div').length, el.find('> ul > li').length, 'After add, number of panels should be equal to number of tabs'); - -}); - test('#5893 - Sublist in the tab list are considered as tab', function() { // http://dev.jqueryui.com/ticket/5893 expect(1); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index b7a270fb6..03f085ea2 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -26,7 +26,6 @@ function getNextListId() { $.widget( "ui.tabs", { options: { - add: null, beforeload: null, cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } collapsible: false, @@ -36,7 +35,6 @@ $.widget( "ui.tabs", { idPrefix: "ui-tabs-", load: null, panelTemplate: "
          ", - remove: null, select: null, show: null, tabTemplate: "
        • #{label}
        • " @@ -445,82 +443,6 @@ $.widget( "ui.tabs", { return this; }, - add: function( url, label, index ) { - if ( index === undefined ) { - index = this.anchors.length; - } - - var self = this, - o = this.options, - $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), - id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); - - $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); - - // try to find an existing element before creating a new one - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .data( "destroy.tabs", true ); - } - $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); - - if ( index >= this.lis.length ) { - $li.appendTo( this.list ); - $panel.appendTo( this.list[ 0 ].parentNode ); - } else { - $li.insertBefore( this.lis[ index ] ); - $panel.insertBefore( this.panels[ index ] ); - } - - o.disabled = $.map( o.disabled, function( n, i ) { - return n >= index ? ++n : n; - }); - - this._tabify(); - - if ( this.anchors.length == 1 ) { - o.selected = 0; - $li.addClass( "ui-tabs-selected ui-state-active" ); - $panel.removeClass( "ui-tabs-hide" ); - this.element.queue( "tabs", function() { - self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); - }); - - this.load( 0 ); - } - - this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - remove: function( index ) { - index = this._getIndex( index ); - var o = this.options, - $li = this.lis.eq( index ).remove(), - $panel = this.panels.eq( index ).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { - this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); - } - - o.disabled = $.map( - $.grep( o.disabled, function(n, i) { - return n != index; - }), - function( n, i ) { - return n >= index ? --n : n; - }); - - this._tabify(); - - this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); - return this; - }, - enable: function( index ) { if ( index === undefined ) { for ( var i = 0, len = this.lis.length; i < len; i++ ) { @@ -805,6 +727,91 @@ if ( $.uiBackCompat !== false ) { } }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // add/remove methods and events + (function( $, prototype ) { + $.extend( prototype.options, { + add: null, + remove: null + }); + + prototype.add = function( url, label, index ) { + if ( index === undefined ) { + index = this.anchors.length; + } + + var self = this, + o = this.options, + $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), + id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); + + $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); + + // try to find an existing element before creating a new one + var $panel = self.element.find( "#" + id ); + if ( !$panel.length ) { + $panel = $( o.panelTemplate ) + .attr( "id", id ) + .data( "destroy.tabs", true ); + } + $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); + + if ( index >= this.lis.length ) { + $li.appendTo( this.list ); + $panel.appendTo( this.list[ 0 ].parentNode ); + } else { + $li.insertBefore( this.lis[ index ] ); + $panel.insertBefore( this.panels[ index ] ); + } + + o.disabled = $.map( o.disabled, function( n, i ) { + return n >= index ? ++n : n; + }); + + this._tabify(); + + if ( this.anchors.length == 1 ) { + o.selected = 0; + $li.addClass( "ui-tabs-selected ui-state-active" ); + $panel.removeClass( "ui-tabs-hide" ); + this.element.queue( "tabs", function() { + self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); + }); + + this.load( 0 ); + } + + this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); + return this; + }; + + prototype.remove = function( index ) { + index = this._getIndex( index ); + var o = this.options, + $li = this.lis.eq( index ).remove(), + $panel = this.panels.eq( index ).remove(); + + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { + this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); + } + + o.disabled = $.map( + $.grep( o.disabled, function(n, i) { + return n != index; + }), + function( n, i ) { + return n >= index ? --n : n; + }); + + this._tabify(); + + this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); + return this; + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); + } })( jQuery ); -- cgit v1.2.3 From 03eb54b37902db771accd3a53bad1b927c058bc7 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 16:49:14 -0400 Subject: Tabs: Deprecate the length method. Fixes #7143 Tabs: Deprecate the length method --- tests/unit/tabs/tabs_deprecated.js | 6 ++++++ tests/unit/tabs/tabs_methods.js | 7 ------- tests/unit/tabs/tabs_tickets.js | 4 ++-- ui/jquery.ui.tabs.js | 10 ++++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index b385a33c2..880ea075e 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -139,7 +139,13 @@ test('#5069 - ui.tabs.add creates two tab panels when using a full URL', functio equals(el.children('div').length, el.find('> ul > li').length, 'After creation, number of panels should be equal to number of tabs'); el.tabs('add', '/ajax_html_echo', 'Test'); equals(el.children('div').length, el.find('> ul > li').length, 'After add, number of panels should be equal to number of tabs'); +}); + +test('length', function() { + expect(1); + el = $('#tabs1').tabs(); + equals(el.tabs('length'), $('ul a', el).length, ' should return length'); }); }( jQuery ) ); diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index ac0747df9..44c91d492 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -167,11 +167,4 @@ test('url', function() { ok(false, "missing test - untested code is broken code."); }); -test('length', function() { - expect(1); - - el = $('#tabs1').tabs(); - equals(el.tabs('length'), $('ul a', el).length, ' should return length'); -}); - })(jQuery); diff --git a/tests/unit/tabs/tabs_tickets.js b/tests/unit/tabs/tabs_tickets.js index 5da799730..c301e9eb0 100644 --- a/tests/unit/tabs/tabs_tickets.js +++ b/tests/unit/tabs/tabs_tickets.js @@ -54,7 +54,7 @@ test('#4033 - IE expands hash to full url and misinterprets tab as ajax', functi el = $('') .appendTo('#main').tabs(); - + equals($('a', el).data('load.tabs'), undefined, 'should not create ajax tab'); }); @@ -64,7 +64,7 @@ test('#5893 - Sublist in the tab list are considered as tab', function() { expect(1); el = $('#tabs6').tabs(); - equals(el.tabs( "length" ), 2, 'should contain 2 tab'); + equals(el.data("tabs").anchors.length, 2, 'should contain 2 tab'); }); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 03f085ea2..c026858ee 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -568,10 +568,6 @@ $.widget( "ui.tabs", { url: function( index, url ) { this.anchors.eq( index ).data( "load.tabs", url ); return this; - }, - - length: function() { - return this.anchors.length; } }); @@ -812,6 +808,12 @@ if ( $.uiBackCompat !== false ) { }; }( jQuery, jQuery.ui.tabs.prototype ) ); + // length method + (function( $, prototype ) { + prototype.length = function() { + return this.anchors.length; + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From 8b89febbbb4d2f13c67bc8ec406b68ff29da3a5a Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 20:37:26 -0400 Subject: Tabs: split up _tabify, create refresh method. Fixes #7140 Tabs: Add refresh method --- tests/unit/tabs/tabs_methods.js | 28 ++++ ui/jquery.ui.tabs.js | 278 +++++++++++++++++++++++----------------- 2 files changed, 187 insertions(+), 119 deletions(-) diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index 44c91d492..50b8abd27 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -159,6 +159,34 @@ test('select', function() { equals(el.tabs('option', 'selected'), 1, 'should select tab by id'); }); +test('refresh', function() { + expect(5); + + var el = $('
            ').tabs(), + ul = el.find('ul'); + + equals(el.tabs('option', 'selected'), -1, 'Initially empty, no selected tab'); + + ul.append('
          • Test 1
          • '); + el.tabs('refresh'); + equals( el.find('.ui-tabs-panel').length, 1, 'Panel created after refresh'); + + ul.find('li').remove(); + el.tabs('refresh'); + equals( el.find('.ui-tabs-panel').length, 0, 'Panel removed after refresh'); + + ul.append('
          • Test 1
          • '); + $('
            Test Panel 1
            ').insertAfter( ul ); + el.tabs('refresh'); + el.tabs('select', 0); + equals( el.tabs('option', 'selected'), 0, 'First tab added should be auto selected'); + + ul.append('
          • Test 2
          • '); + $('
            Test Panel 2
            ').insertAfter( ul ); + el.tabs('refresh'); + equals( el.tabs('option', 'selected'), 0, 'Second tab added should not be auto selected'); +}); + test('load', function() { ok(false, "missing test - untested code is broken code."); }); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index c026858ee..14c74b110 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -41,7 +41,81 @@ $.widget( "ui.tabs", { }, _create: function() { - this._tabify( true ); + var self = this, + o = this.options; + + this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); + + this._processTabs(); + + // Selected tab + // use "selected" option or try to retrieve: + // 1. from fragment identifier in url + // 2. from cookie + // 3. from selected class attribute on
          • + if ( o.selected === undefined ) { + if ( location.hash ) { + this.anchors.each(function( i, a ) { + if ( a.hash == location.hash ) { + o.selected = i; + return false; + } + }); + } + if ( typeof o.selected !== "number" && o.cookie ) { + o.selected = parseInt( self._cookie(), 10 ); + } + if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { + o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); + } + o.selected = o.selected || ( this.lis.length ? 0 : -1 ); + } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release + o.selected = -1; + } + + // sanity check - default to first tab... + o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) + ? o.selected + : 0; + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( $.isArray( o.disabled ) ) { + o.disabled = $.unique( o.disabled.concat( + $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { + return self.lis.index( n ); + }) + ) ).sort(); + } + + this._setupFx( o.fx ); + + this._refresh(); + + // highlight selected tab + this.panels.addClass( "ui-tabs-hide" ); + this.lis.removeClass( "ui-tabs-selected ui-state-active" ); + // check for length avoids error when initializing empty list + if ( o.selected >= 0 && this.anchors.length ) { + var temp = self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ) + .removeClass( "ui-tabs-hide" ); + + this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); + + // seems to be expected behavior that the show callback is fired + self.element.queue( "tabs", function() { + self._trigger( "show", null, + self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); + }); + + this.load( o.selected ); + } + + // clean up to avoid memory leaks in certain versions of IE 6 + $( window ).bind( "unload.tabs", function() { + self.lis.add( self.anchors ).unbind( ".tabs" ); + self.lis = self.anchors = self.panels = null; + }); }, _setOption: function( key, value ) { @@ -52,7 +126,7 @@ $.widget( "ui.tabs", { this.select( value ); } else { this.options[ key ] = value; - this._tabify(); + this.refresh(); } }, @@ -80,9 +154,64 @@ $.widget( "ui.tabs", { }; }, - _tabify: function( init ) { + refresh: function() { + var self = this; + + this._processTabs(); + + this._refresh(); + + // Remove panels that we created that are missing their tab + this.element.find(".ui-tabs-panel:data(destroy.tabs)").each( function( index, panel ) { + var anchor = self.anchors.filter( "[href$='#" + panel.id + "']"); + if ( !anchor.length ) { + $( panel ).remove(); + } + }); + }, + + _refresh: function() { + var self = this, + o = this.options; + + this.element + .toggleClass( "ui-tabs-collapsible", o.collapsible ); + + this.list + .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); + + this.lis + .addClass( "ui-state-default ui-corner-top" ); + + this.panels + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); + + if ( !o.disabled.length ) { + o.disabled = false; + } + + // set or update cookie after init and add/remove respectively + if ( o.cookie ) { + this._cookie( o.selected, o.cookie ); + } + + // disable tabs + for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { + $( li ).toggleClass( "ui-state-disabled", $.inArray( i, o.disabled ) != -1 ); + } + + this._setupEvents( o.event ); + + // remove all handlers, may run on existing tabs + this.lis.unbind( ".tabs" ); + + + this._focusable( this.lis ); + this._hoverable( this.lis ); + }, + + _processTabs: function() { var self = this, - o = this.options, fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash this.list = this.element.find( "ol,ul" ).eq( 0 ); @@ -124,7 +253,7 @@ $.widget( "ui.tabs", { a.href = "#" + id; var $panel = self.element.find( "#" + id ); if ( !$panel.length ) { - $panel = $( o.panelTemplate ) + $panel = $( self.options.panelTemplate ) .attr( "id", id ) .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) .insertAfter( self.panels[ i - 1 ] || self.list ); @@ -133,125 +262,21 @@ $.widget( "ui.tabs", { self.panels = self.panels.add( $panel ); // invalid tab href } else { - o.disabled.push( i ); + self.options.disabled.push( i ); } }); + }, - // initialization from scratch - if ( init ) { - // attach necessary classes for styling - this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); - this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); - this.lis.addClass( "ui-state-default ui-corner-top" ); - this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
          • - if ( o.selected === undefined ) { - if ( location.hash ) { - this.anchors.each(function( i, a ) { - if ( a.hash == location.hash ) { - o.selected = i; - return false; - } - }); - } - if ( typeof o.selected !== "number" && o.cookie ) { - o.selected = parseInt( self._cookie(), 10 ); - } - if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } - o.selected = o.selected || ( this.lis.length ? 0 : -1 ); - } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release - o.selected = -1; - } - - // sanity check - default to first tab... - o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) - ? o.selected - : 0; - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - if ( $.isArray( o.disabled ) ) { - o.disabled = $.unique( o.disabled.concat( - $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { - return self.lis.index( n ); - }) - ) ).sort(); - } - - // highlight selected tab - this.panels.addClass( "ui-tabs-hide" ); - this.lis.removeClass( "ui-tabs-selected ui-state-active" ); - // check for length avoids error when initializing empty list - if ( o.selected >= 0 && this.anchors.length ) { - self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); - this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); - - // seems to be expected behavior that the show callback is fired - self.element.queue( "tabs", function() { - self._trigger( "show", null, - self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); - }); - - this.load( o.selected ); - } - - // clean up to avoid memory leaks in certain versions of IE 6 - // TODO: namespace this event - $( window ).bind( "unload", function() { - self.lis.add( self.anchors ).unbind( ".tabs" ); - self.lis = self.anchors = self.panels = null; - }); - // update selected after add/remove - } else { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } - - if ( !o.disabled.length ) { - o.disabled = false; - } - - this.element.toggleClass( "ui-tabs-collapsible", o.collapsible ); - - // set or update cookie after init and add/remove respectively - if ( o.cookie ) { - this._cookie( o.selected, o.cookie ); - } - - // disable tabs - for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { - $( li ).toggleClass( "ui-state-disabled", $.inArray( i, o.disabled ) != -1 ); - } - - // remove all handlers before, tabify may run on existing tabs after add or option change - this.lis.add( this.anchors ).unbind( ".tabs" ); - - this._focusable( this.lis ); - this._hoverable( this.lis ); - + _setupFx: function( fx ) { // set up animations - if ( o.fx ) { - if ( $.isArray( o.fx ) ) { - this.hideFx = o.fx[ 0 ]; - this.showFx = o.fx[ 1 ]; + if ( fx ) { + if ( $.isArray( fx ) ) { + this.hideFx = fx[ 0 ]; + this.showFx = fx[ 1 ]; } else { - this.hideFx = this.showFx = o.fx; + this.hideFx = this.showFx = fx; } } - - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.anchors.bind( o.event + ".tabs", $.proxy( this, "_eventHandler" )); - - // disable click in any case - this.anchors.bind( "click.tabs", function( event ){ - event.preventDefault(); - }); }, // Reset certain styles left over from animation @@ -297,6 +322,21 @@ $.widget( "ui.tabs", { } }, + _setupEvents: function( event ) { + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.anchors.unbind( ".tabs" ); + + if ( event ) { + this.anchors.bind( event.split( " " ).join( ".tabs " ) + ".tabs", + $.proxy( this, "_eventHandler" ) ); + } + + // disable click in any case + this.anchors.bind( "click.tabs", function( event ){ + event.preventDefault(); + }); + }, + _eventHandler: function( event ) { event.preventDefault(); var self = this, @@ -764,7 +804,7 @@ if ( $.uiBackCompat !== false ) { return n >= index ? ++n : n; }); - this._tabify(); + this.refresh(); if ( this.anchors.length == 1 ) { o.selected = 0; @@ -801,7 +841,7 @@ if ( $.uiBackCompat !== false ) { return n >= index ? --n : n; }); - this._tabify(); + this.refresh(); this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); return this; -- cgit v1.2.3 From f6e7b6c9f6b49e4c7ab648bd617fe724ce0fb417 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 20:49:59 -0400 Subject: Use this.running to know if we are still in process of showing/hidding a tab --- ui/jquery.ui.tabs.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 14c74b110..0157a3329 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -44,6 +44,8 @@ $.widget( "ui.tabs", { var self = this, o = this.options; + this.running = false; + this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); this._processTabs(); @@ -294,9 +296,11 @@ $.widget( "ui.tabs", { $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); if ( this.showFx ) { + self.running = true; show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way .animate( showFx, showFx.duration || "normal", function() { self._resetStyle( show, showFx ); + self.running = false; self._trigger( "show", event, self._ui( clicked, show[ 0 ] ) ); }); } else { @@ -309,7 +313,9 @@ $.widget( "ui.tabs", { var self = this; if ( this.hideFx ) { + self.running = true; $hide.animate( hideFx, hideFx.duration || "normal", function() { + self.running = false; self.lis.removeClass( "ui-tabs-selected ui-state-active" ); $hide.addClass( "ui-tabs-hide" ); self._resetStyle( $hide, hideFx ); @@ -346,14 +352,15 @@ $.widget( "ui.tabs", { $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), $show = self.element.find( self._sanitizeSelector( el.hash ) ); - // If tab is already selected and not collapsible or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || + // tab is already selected, but not collapsible + if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible ) || + // can't switch durning an animation + self.running || + // tab is disabled $li.hasClass( "ui-state-disabled" ) || + // tab is already loading $li.hasClass( "ui-state-processing" ) || - self.panels.filter( ":animated" ).length || + // allow canceling by select event self._trigger( "select", event, self._ui( el, $show[ 0 ] ) ) === false ) { el.blur(); return; -- cgit v1.2.3 From 1e2d3145fff7cdeca61e62f95eb1e30c37e664c5 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sat, 26 Mar 2011 22:14:17 -0400 Subject: Tabs: Deprecate url method; use aria-controls instead of title to specify panels. Fixes #7132 Tabs: Deprecate url method; use aria-controls instead of title to specify panels --- demos/tabs/ajax.html | 3 +- tests/unit/tabs/tabs_deprecated.js | 24 +++++++++++ tests/unit/tabs/tabs_methods.js | 4 -- tests/unit/tabs/tabs_tickets.js | 37 +++++++--------- ui/jquery.ui.tabs.js | 87 ++++++++++++++++++++++---------------- 5 files changed, 92 insertions(+), 63 deletions(-) diff --git a/demos/tabs/ajax.html b/demos/tabs/ajax.html index c62625791..284de57f9 100644 --- a/demos/tabs/ajax.html +++ b/demos/tabs/ajax.html @@ -14,7 +14,8 @@ $( "#tabs" ).tabs({ ajaxOptions: { error: function( xhr, status, index, anchor ) { - $( anchor.hash ).html( + var selector = $( anchor ).attr( "aria-controls" ); + $( selector ).html( "Couldn't load this tab. We'll try to fix this as soon as possible. " + "If this wouldn't be a demo." ); } diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 880ea075e..ef03d84cb 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -1,5 +1,19 @@ (function( $ ) { +module("tabs (deprecated): core"); + +test( "#4581 - title attribute for remote tabs does not support foreign languages", function() { + expect( 1 ); + + $( "#tabs2" ).tabs({ + selected: 3, + beforeload: function( event, ui ) { + event.preventDefault(); + equal( ui.panel.id, "∫ßáö_Սե", "proper title" ); + } + }); +}); + module("tabs (deprecated): options"); test('ajaxOptions', function() { @@ -148,4 +162,14 @@ test('length', function() { equals(el.tabs('length'), $('ul a', el).length, ' should return length'); }); +test('url', function() { + el = $('#tabs2').tabs(); + var tab = el.find('a:eq(3)'), + url = tab.attr('href'); + + el.tabs('url', 3, "data/test2.html"); + equals(tab.attr('href'), 'data/test2.html', 'Url was updated'); + tab.attr('href', url ); +}); + }( jQuery ) ); diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index 50b8abd27..e00a95a3e 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -191,8 +191,4 @@ test('load', function() { ok(false, "missing test - untested code is broken code."); }); -test('url', function() { - ok(false, "missing test - untested code is broken code."); -}); - })(jQuery); diff --git a/tests/unit/tabs/tabs_tickets.js b/tests/unit/tabs/tabs_tickets.js index c301e9eb0..9df72a6f7 100644 --- a/tests/unit/tabs/tabs_tickets.js +++ b/tests/unit/tabs/tabs_tickets.js @@ -42,21 +42,29 @@ test('#3627 - Ajax tab with url containing a fragment identifier fails to load', // http://dev.jqueryui.com/ticket/3627 expect(1); - el = $('#tabs2').tabs(); - - ok(/test.html$/.test( $('a:eq(2)', el).data('load.tabs') ), 'should ignore fragment identifier'); - + el = $('#tabs2').tabs({ + selected: 2, + beforeload: function( event, ui ) { + event.preventDefault(); + ok(/test.html$/.test( ui.settings.url ), 'should ignore fragment identifier'); + } + }); }); test('#4033 - IE expands hash to full url and misinterprets tab as ajax', function() { // http://dev.jqueryui.com/ticket/4033 expect(1); - el = $('') - .appendTo('#main').tabs(); + el = $(''); + el.appendTo('#main'); + el.tabs({ + beforeload: function( event, ui ) { + event.preventDefault(); + ok( false, 'should not be an ajax tab'); + } + }); - equals($('a', el).data('load.tabs'), undefined, 'should not create ajax tab'); - + equals($('a', el).attr('aria-controls'), '#tab', 'aria-contorls attribute is correct'); }); test('#5893 - Sublist in the tab list are considered as tab', function() { @@ -68,19 +76,6 @@ test('#5893 - Sublist in the tab list are considered as tab', function() { }); -asyncTest( "#4581 - title attribute for remote tabs does not support foreign languages", function() { - expect( 1 ); - - $( "#tabs2" ).tabs({ - selected: 3, - load: function( event, ui ) { - equal( ui.panel.id, "∫ßáö_Սե", "proper title" ); - start(); - } - }); -}); - - test('#6710 - selectors are global', function() { // http://bugs.jqueryui.com/ticket/6710 expect(1); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 0157a3329..f3741f0a6 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -99,15 +99,16 @@ $.widget( "ui.tabs", { this.lis.removeClass( "ui-tabs-selected ui-state-active" ); // check for length avoids error when initializing empty list if ( o.selected >= 0 && this.anchors.length ) { - var temp = self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ) - .removeClass( "ui-tabs-hide" ); + var tab = self.anchors[ o.selected ], + panel = self.element.find( self._sanitizeSelector( $( tab ).attr( "aria-controls" ) ) ); + + panel.removeClass( "ui-tabs-hide" ); this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); // seems to be expected behavior that the show callback is fired self.element.queue( "tabs", function() { - self._trigger( "show", null, - self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); + self._trigger( "show", null, self._ui( tab, panel[ 0 ] ) ); }); this.load( o.selected ); @@ -133,7 +134,7 @@ $.widget( "ui.tabs", { }, _tabId: function( a ) { - return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || + return ( $( a ).attr( "aria-controls" ) || "" ).replace( /^#/ , "" ) || this.options.idPrefix + getNextTabId(); }, @@ -165,7 +166,7 @@ $.widget( "ui.tabs", { // Remove panels that we created that are missing their tab this.element.find(".ui-tabs-panel:data(destroy.tabs)").each( function( index, panel ) { - var anchor = self.anchors.filter( "[href$='#" + panel.id + "']"); + var anchor = self.anchors.filter( "[aria-controls='#" + panel.id + "']"); if ( !anchor.length ) { $( panel ).remove(); } @@ -224,14 +225,17 @@ $.widget( "ui.tabs", { this.panels = $( [] ); this.anchors.each(function( i, a ) { - var href = $( a ).attr( "href" ); + var href = $( a ).attr( "href" ), + hrefBase = href.split( "#" )[ 0 ], + selector, + panel, + baseEl; + // For dynamically created HTML that contains a hash as href IE < 8 expands // such href to the full page url with hash and then misinterprets tab as ajax. // Same consideration applies for an added tab with a fragment identifier // since a[href=#fragment-identifier] does unexpectedly not match. // Thus normalize href attribute... - var hrefBase = href.split( "#" )[ 0 ], - baseEl; if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { href = a.hash; @@ -240,32 +244,30 @@ $.widget( "ui.tabs", { // inline tab if ( fragmentId.test( href ) ) { - self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); + selector = href; + panel = self.element.find( self._sanitizeSelector( selector ) ); // remote tab // prevent loading the page itself if href is just "#" } else if ( href && href !== "#" ) { - // required for restore on destroy - $.data( a, "href.tabs", href ); - - // TODO until #3808 is fixed strip fragment identifier from url - // (IE fails to load from such url) - $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); - var id = self._tabId( a ); - a.href = "#" + id; - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( self.options.panelTemplate ) + selector = "#" + id; + panel = self.element.find( selector ); + if ( !panel.length ) { + panel = $( self.options.panelTemplate ) .attr( "id", id ) .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "destroy.tabs", true ) .insertAfter( self.panels[ i - 1 ] || self.list ); - $panel.data( "destroy.tabs", true ); } - self.panels = self.panels.add( $panel ); // invalid tab href } else { self.options.disabled.push( i ); } + + if ( panel.length) { + self.panels = self.panels.add( panel ); + } + $( a ).attr( "aria-controls", selector ); }); }, @@ -348,9 +350,9 @@ $.widget( "ui.tabs", { var self = this, o = this.options, el = event.currentTarget, - $li = $(el).closest( "li" ), + $li = $( el ).closest( "li" ), $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), - $show = self.element.find( self._sanitizeSelector( el.hash ) ); + $show = self.element.find( self._sanitizeSelector( $( el ).attr( "aria-controls" ) ) ); // tab is already selected, but not collapsible if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible ) || @@ -455,10 +457,6 @@ $.widget( "ui.tabs", { this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); this.anchors.each(function() { - var href = $.data( this, "href.tabs" ); - if ( href ) { - this.href = href; - } var $this = $( this ).unbind( ".tabs" ); $.each( [ "href", "load" ], function( i, prefix ) { $this.removeData( prefix + ".tabs" ); @@ -558,8 +556,11 @@ $.widget( "ui.tabs", { var self = this, o = this.options, a = this.anchors.eq( index )[ 0 ], - url = $.data( a, "load.tabs" ), - eventData = self._ui( self.anchors[ index ], self.panels[ index ] ); + panel = self.element.find( self._sanitizeSelector( $( a ).attr( "aria-controls" ) ) ), + // TODO until #3808 is fixed strip fragment identifier from url + // (IE fails to load from such url) + url = $( a ).attr( "href" ).replace( /#.*$/, "" ), + eventData = self._ui( a, panel[ 0 ] ); if ( this.xhr ) { this.xhr.abort(); @@ -585,7 +586,7 @@ $.widget( "ui.tabs", { this.xhr .success( function( response ) { - self.element.find( self._sanitizeSelector( a.hash ) ).html( response ); + panel.html( response ); }) .complete( function( jqXHR, status ) { if ( status === "abort" ) { @@ -609,13 +610,9 @@ $.widget( "ui.tabs", { // last, so that load event is fired before show... self.element.dequeue( "tabs" ); - return this; - }, - - url: function( index, url ) { - this.anchors.eq( index ).data( "load.tabs", url ); return this; } + }); $.extend( $.ui.tabs, { @@ -861,6 +858,22 @@ if ( $.uiBackCompat !== false ) { return this.anchors.length; }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // url method + (function( $, prototype ) { + prototype.url = function( index, url ) { + this.anchors.eq( index ).attr( "href", url ); + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); + + // _tabId method + (function( $, prototype ) { + var _tabId = prototype._tabId; + prototype._tabId = function( a ) { + return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || + _tabId.apply( this, arguments ); + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From c363019590da9c38754fb7c60e5f44e25ca48e21 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sun, 27 Mar 2011 15:12:53 -0400 Subject: Tabs: Deprecate templating (idPrefix, tabTemplate, panelTemplate options) Fixes #7139 Tabs: Deprecate templating (idPrefix, tabTemplate, panelTemplate options) --- tests/unit/tabs/tabs_defaults.js | 5 +--- tests/unit/tabs/tabs_deprecated.js | 12 +++++++++ tests/unit/tabs/tabs_options.js | 12 --------- ui/jquery.ui.tabs.js | 52 ++++++++++++++++++++++++++------------ 4 files changed, 49 insertions(+), 32 deletions(-) diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index f7307b458..98cb99fb5 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -9,12 +9,9 @@ var tabs_defaults = { disabled: false, event: "click", fx: null, - idPrefix: "ui-tabs-", load: null, - panelTemplate: "
            ", select: null, - show: null, - tabTemplate: "
          • #{label}
          • " + show: null }; // FAIL: falsy values break the cookie option diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index ef03d84cb..7e4816793 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -24,6 +24,18 @@ test('cache', function() { ok(false, "missing test - untested code is broken code."); }); +test('idPrefix', function() { + ok(false, "missing test - untested code is broken code."); +}); + +test('tabTemplate', function() { + ok(false, "missing test - untested code is broken code."); +}); + +test('panelTemplate', function() { + ok(false, "missing test - untested code is broken code."); +}); + test('spinner', function() { expect(4); stop(); diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index 45fba8f32..de6d7e74e 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -79,14 +79,6 @@ test('fx', function() { ok(false, "missing test - untested code is broken code."); }); -test('idPrefix', function() { - ok(false, "missing test - untested code is broken code."); -}); - -test('panelTemplate', function() { - ok(false, "missing test - untested code is broken code."); -}); - test('selected', function() { expect(8); @@ -117,8 +109,4 @@ test('selected', function() { equals(el.tabs('option', 'selected'), 0, 'should not collapse tab if value is same as selected'); }); -test('tabTemplate', function() { - ok(false, "missing test - untested code is broken code."); -}); - })(jQuery); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index f3741f0a6..4a7ae3981 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -32,12 +32,9 @@ $.widget( "ui.tabs", { disabled: false, event: "click", fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - idPrefix: "ui-tabs-", load: null, - panelTemplate: "
            ", select: null, - show: null, - tabTemplate: "
          • #{label}
          • " + show: null }, _create: function() { @@ -135,7 +132,7 @@ $.widget( "ui.tabs", { _tabId: function( a ) { return ( $( a ).attr( "aria-controls" ) || "" ).replace( /^#/ , "" ) || - this.options.idPrefix + getNextTabId(); + "ui-tabs-" + getNextTabId(); }, _sanitizeSelector: function( hash ) { @@ -253,11 +250,8 @@ $.widget( "ui.tabs", { selector = "#" + id; panel = self.element.find( selector ); if ( !panel.length ) { - panel = $( self.options.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "destroy.tabs", true ) - .insertAfter( self.panels[ i - 1 ] || self.list ); + panel = self._createPanel( id ); + panel.insertAfter( self.panels[ i - 1 ] || self.list ); } // invalid tab href } else { @@ -271,6 +265,13 @@ $.widget( "ui.tabs", { }); }, + _createPanel: function( id ) { + return $( "
            " ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "destroy.tabs", true ); + }, + _setupFx: function( fx ) { // set up animations if ( fx ) { @@ -772,7 +773,8 @@ if ( $.uiBackCompat !== false ) { (function( $, prototype ) { $.extend( prototype.options, { add: null, - remove: null + remove: null, + tabTemplate: "
          • #{label}
          • " }); prototype.add = function( url, label, index ) { @@ -790,9 +792,7 @@ if ( $.uiBackCompat !== false ) { // try to find an existing element before creating a new one var $panel = self.element.find( "#" + id ); if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .data( "destroy.tabs", true ); + $panel = self._createPanel( id ); } $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); @@ -868,10 +868,30 @@ if ( $.uiBackCompat !== false ) { // _tabId method (function( $, prototype ) { + $.extend( prototype.options, { + idPrefix: "ui-tabs-" + }); + var _tabId = prototype._tabId; prototype._tabId = function( a ) { - return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || - _tabId.apply( this, arguments ); + return ( $( a ).attr( "aria-controls" ) || "" ).replace( /^#/ , "" ) || + a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || + this.options.idPrefix + getNextTabId(); + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); + + // _tabId method + (function( $, prototype ) { + $.extend( prototype.options, { + panelTemplate: "
            " + }); + + var _createPanel = prototype._createPanel; + prototype._createPanel = function( id ) { + return $( this.options.panelTemplate ) + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "destroy.tabs", true ); }; }( jQuery, jQuery.ui.tabs.prototype ) ); } -- cgit v1.2.3 From 9a00fd4c5ef637f29afc6debda4db136f1fcb3fb Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sun, 27 Mar 2011 16:37:43 -0400 Subject: Tabs: Rename selected option to active. Fixes #7135 Tabs: Rename selected option to active --- tests/unit/tabs/tabs_deprecated.js | 49 ++++++++++++++++++++++ tests/unit/tabs/tabs_events.js | 2 +- tests/unit/tabs/tabs_methods.js | 24 +++++------ tests/unit/tabs/tabs_options.js | 30 +++++++------- tests/unit/tabs/tabs_tickets.js | 2 +- ui/jquery.ui.tabs.js | 84 ++++++++++++++++++++++++++------------ 6 files changed, 136 insertions(+), 55 deletions(-) diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 7e4816793..8b6b50d7e 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -65,6 +65,55 @@ test('spinner', function() { }); }); +test('selected', function() { + expect(11); + + el = $('#tabs1').tabs(); + equals(el.tabs('option', 'selected'), 0, 'should be 0 by default'); + + el.tabs('destroy'); + //set a hash in the url + location.hash = '#fragment-2'; + //selection of tab with divs ordered differently than list + el = $('#tabs1').tabs(); + equals(el.tabs('option', 'selected'), 1, 'second tab should be selected'); + + el.tabs('destroy'); + //set a hash in the url + location.hash = '#tabs7-2'; + //selection of tab with divs ordered differently than list + el = $('#tabs7').tabs(); + equals(el.tabs('option', 'selected'), 1, 'second tab should be selected'); + + el.tabs('destroy'); + el = $('#tabs1').tabs({ selected: -1 }); + equals(el.tabs('option', 'selected'), -1, 'should be -1 for all tabs unselected'); + equals( $('li.ui-tabs-selected', el).length, 0, 'no tab should be selected' ); + equals( $('div.ui-tabs-hide', '#tabs1').length, 3, 'all panels should be hidden' ); + + el.tabs('destroy'); + el.tabs({ selected: null }); + equals(el.tabs('option', 'selected'), -1, 'should be -1 for all tabs unselected with value null (deprecated)'); + + el.tabs('destroy'); + el.tabs({ selected: 1 }); + equals(el.tabs('option', 'selected'), 1, 'should be specified tab'); + + el.tabs('destroy'); + el.tabs({ selected: 99 }); + equals(el.tabs('option', 'selected'), 0, 'selected should default to zero if given value is out of index'); + + el.tabs('destroy'); + el.tabs({ collapsible: true }); + el.tabs('option', 'selected', 0); + equals(el.tabs('option', 'selected'), 0, 'should not collapse tab if value is same as selected'); + + el.tabs('destroy'); + el = $('#tabs1').tabs(); + el.tabs('select', 1); + equals(el.tabs('option', 'selected'), 1, 'should select tab'); +}); + module("tabs (deprecated): events"); test('enable', function() { diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index b3f8653a2..04f282157 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -32,7 +32,7 @@ test('beforeload', function() { el = $('#tabs2'); el.tabs({ - selected: 2, + active: 2, beforeload: function( event, ui ) { ok( $.isFunction( ui.jqXHR.promise ), 'contain jqXHR object'); equals( ui.settings.url, "data/test.html", 'contain ajax settings url'); diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index e00a95a3e..dbb5c2d15 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -16,7 +16,7 @@ test('init', function() { ok( $('div:eq(0)', el).is('.ui-tabs-panel.ui-widget-content.ui-corner-bottom'), 'attach classes to panel' ); ok( $('li:eq(0)', el).is('.ui-tabs-selected.ui-state-active.ui-corner-top'), 'attach classes to active li'); ok( $('li:eq(1)', el).is('.ui-state-default.ui-corner-top'), 'attach classes to inactive li'); - equals( el.tabs('option', 'selected'), 0, 'selected option set' ); + equals( el.tabs('option', 'active'), 0, 'active option set' ); equals( $('li', el).index( $('li.ui-tabs-selected', el) ), 0, 'second tab active'); equals( $('div', el).index( $('div.ui-tabs-hide', '#tabs1') ), 1, 'second panel should be hidden' ); }); @@ -30,7 +30,7 @@ test('init with hash', function() { //selection of tab with divs ordered differently than list el = $('#tabs1').tabs(); - equals(el.tabs('option', 'selected'), 1, 'second tab should be selected'); + equals(el.tabs('option', 'active'), 1, 'second tab should be active'); ok(!$('#tabs1 ul li:eq(0)').is('.ui-tabs-selected.ui-state-active'), 'first tab should not be selected nor active'); ok($('#tabs1 div:eq(0)').is('.ui-tabs-hide'), 'first div for first tab should be hidden'); @@ -48,7 +48,7 @@ test('init mismatched order with hash', function() { //selection of tab with divs ordered differently than list el = $('#tabs7').tabs(); - equals(el.tabs('option', 'selected'), 1, 'second tab should be selected'); + equals(el.tabs('option', 'active'), 1, 'second tab should be active'); ok(!$('#tabs7-list li:eq(0)').is('.ui-tabs-selected.ui-state-active'), 'first tab should not be selected nor active'); ok($('#tabs7 div:eq(1)').is('.ui-tabs-hide'), 'second div for first tab should be hidden'); @@ -136,27 +136,27 @@ test('select', function() { el = $('#tabs1').tabs(); el.tabs('select', 1); - equals(el.tabs('option', 'selected'), 1, 'should select tab'); + equals(el.tabs('option', 'active'), 1, 'should select tab'); el.tabs('destroy'); el.tabs({ collapsible: true }); el.tabs('select', 0); - equals(el.tabs('option', 'selected'), -1, 'should collapse tab passing in the already selected tab'); + equals(el.tabs('option', 'active'), -1, 'should collapse tab passing in the already active tab'); el.tabs('destroy'); el.tabs({ collapsible: true }); el.tabs('select', -1); - equals(el.tabs('option', 'selected'), -1, 'should collapse tab passing in -1'); + equals(el.tabs('option', 'active'), -1, 'should collapse tab passing in -1'); el.tabs('destroy'); el.tabs(); el.tabs('select', 0); - equals(el.tabs('option', 'selected'), 0, 'should not collapse tab if collapsible is not set to true'); + equals(el.tabs('option', 'active'), 0, 'should not collapse tab if collapsible is not set to true'); el.tabs('select', -1); - equals(el.tabs('option', 'selected'), 0, 'should not collapse tab if collapsible is not set to true'); + equals(el.tabs('option', 'active'), 0, 'should not collapse tab if collapsible is not set to true'); el.tabs('select', '#fragment-2'); - equals(el.tabs('option', 'selected'), 1, 'should select tab by id'); + equals(el.tabs('option', 'active'), 1, 'should select tab by id'); }); test('refresh', function() { @@ -165,7 +165,7 @@ test('refresh', function() { var el = $('
              ').tabs(), ul = el.find('ul'); - equals(el.tabs('option', 'selected'), -1, 'Initially empty, no selected tab'); + equals(el.tabs('option', 'active'), -1, 'Initially empty, no active tab'); ul.append('
            • Test 1
            • '); el.tabs('refresh'); @@ -179,12 +179,12 @@ test('refresh', function() { $('
              Test Panel 1
              ').insertAfter( ul ); el.tabs('refresh'); el.tabs('select', 0); - equals( el.tabs('option', 'selected'), 0, 'First tab added should be auto selected'); + equals( el.tabs('option', 'active'), 0, 'First tab added should be auto active'); ul.append('
            • Test 2
            • '); $('
              Test Panel 2
              ').insertAfter( ul ); el.tabs('refresh'); - equals( el.tabs('option', 'selected'), 0, 'Second tab added should not be auto selected'); + equals( el.tabs('option', 'active'), 0, 'Second tab added should not be auto active'); }); test('load', function() { diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index de6d7e74e..b1a7a5e78 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -34,8 +34,8 @@ test('cookie', function() { equals(cookie(), 0, 'initial cookie value'); el.tabs('destroy'); - el.tabs({ selected: 1, cookie: cookieObj }); - equals(cookie(), 1, 'initial cookie value, from selected property'); + el.tabs({ active: 1, cookie: cookieObj }); + equals(cookie(), 1, 'initial cookie value, from active property'); el.tabs('select', 2); equals(cookie(), 2, 'cookie value updated after select'); @@ -79,34 +79,34 @@ test('fx', function() { ok(false, "missing test - untested code is broken code."); }); -test('selected', function() { +test('active', function() { expect(8); el = $('#tabs1').tabs(); - equals(el.tabs('option', 'selected'), 0, 'should be 0 by default'); + equals(el.tabs('option', 'active'), 0, 'should be 0 by default'); el.tabs('destroy'); - el.tabs({ selected: -1 }); - equals(el.tabs('option', 'selected'), -1, 'should be -1 for all tabs unselected'); - equals( $('li.ui-tabs-selected', el).length, 0, 'no tab should be selected' ); + el.tabs({ active: -1 }); + equals(el.tabs('option', 'active'), -1, 'should be -1 for all tabs deactive'); + equals( $('li.ui-tabs-selected', el).length, 0, 'no tab should be active' ); equals( $('div.ui-tabs-hide', '#tabs1').length, 3, 'all panels should be hidden' ); el.tabs('destroy'); - el.tabs({ selected: null }); - equals(el.tabs('option', 'selected'), -1, 'should be -1 for all tabs unselected with value null (deprecated)'); + el.tabs({ active: null }); + equals(el.tabs('option', 'active'), -1, 'should be -1 for all tabs deactive with value null (deprecated)'); el.tabs('destroy'); - el.tabs({ selected: 1 }); - equals(el.tabs('option', 'selected'), 1, 'should be specified tab'); + el.tabs({ active: 1 }); + equals(el.tabs('option', 'active'), 1, 'should be specified tab'); el.tabs('destroy'); - el.tabs({ selected: 99 }); - equals(el.tabs('option', 'selected'), 0, 'selected should default to zero if given value is out of index'); + el.tabs({ active: 99 }); + equals(el.tabs('option', 'active'), 0, 'active should default to zero if given value is out of index'); el.tabs('destroy'); el.tabs({ collapsible: true }); - el.tabs('option', 'selected', 0); - equals(el.tabs('option', 'selected'), 0, 'should not collapse tab if value is same as selected'); + el.tabs('option', 'active', 0); + equals(el.tabs('option', 'active'), 0, 'should not collapse tab if value is same as active'); }); })(jQuery); diff --git a/tests/unit/tabs/tabs_tickets.js b/tests/unit/tabs/tabs_tickets.js index 9df72a6f7..486d3b6d2 100644 --- a/tests/unit/tabs/tabs_tickets.js +++ b/tests/unit/tabs/tabs_tickets.js @@ -43,7 +43,7 @@ test('#3627 - Ajax tab with url containing a fragment identifier fails to load', expect(1); el = $('#tabs2').tabs({ - selected: 2, + active: 2, beforeload: function( event, ui ) { event.preventDefault(); ok(/test.html$/.test( ui.settings.url ), 'should ignore fragment identifier'); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 4a7ae3981..d76565a2a 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -52,29 +52,29 @@ $.widget( "ui.tabs", { // 1. from fragment identifier in url // 2. from cookie // 3. from selected class attribute on
            • - if ( o.selected === undefined ) { + if ( o.active === undefined ) { if ( location.hash ) { this.anchors.each(function( i, a ) { if ( a.hash == location.hash ) { - o.selected = i; + o.active = i; return false; } }); } - if ( typeof o.selected !== "number" && o.cookie ) { - o.selected = parseInt( self._cookie(), 10 ); + if ( typeof o.active !== "number" && o.cookie ) { + o.active = parseInt( self._cookie(), 10 ); } - if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); + if ( typeof o.active !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { + o.active = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); } - o.selected = o.selected || ( this.lis.length ? 0 : -1 ); - } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release - o.selected = -1; + o.active = o.active || ( this.lis.length ? 0 : -1 ); + } else if ( o.active === null ) { // usage of null is deprecated, TODO remove in next release + o.active = -1; } // sanity check - default to first tab... - o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) - ? o.selected + o.active = ( ( o.active >= 0 && this.anchors[ o.active ] ) || o.active < 0 ) + ? o.active : 0; // Take disabling tabs via class attribute from HTML @@ -95,20 +95,20 @@ $.widget( "ui.tabs", { this.panels.addClass( "ui-tabs-hide" ); this.lis.removeClass( "ui-tabs-selected ui-state-active" ); // check for length avoids error when initializing empty list - if ( o.selected >= 0 && this.anchors.length ) { - var tab = self.anchors[ o.selected ], + if ( o.active >= 0 && this.anchors.length ) { + var tab = self.anchors[ o.active ], panel = self.element.find( self._sanitizeSelector( $( tab ).attr( "aria-controls" ) ) ); panel.removeClass( "ui-tabs-hide" ); - this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); + this.lis.eq( o.active ).addClass( "ui-tabs-selected ui-state-active" ); // seems to be expected behavior that the show callback is fired self.element.queue( "tabs", function() { self._trigger( "show", null, self._ui( tab, panel[ 0 ] ) ); }); - this.load( o.selected ); + this.load( o.active ); } // clean up to avoid memory leaks in certain versions of IE 6 @@ -119,8 +119,8 @@ $.widget( "ui.tabs", { }, _setOption: function( key, value ) { - if ( key == "selected" ) { - if (this.options.collapsible && value == this.options.selected ) { + if ( key == "active" ) { + if (this.options.collapsible && value == this.options.active ) { return; } this.select( value ); @@ -192,7 +192,7 @@ $.widget( "ui.tabs", { // set or update cookie after init and add/remove respectively if ( o.cookie ) { - this._cookie( o.selected, o.cookie ); + this._cookie( o.active, o.cookie ); } // disable tabs @@ -369,7 +369,7 @@ $.widget( "ui.tabs", { return; } - o.selected = self.anchors.index( el ); + o.active = self.anchors.index( el ); if ( self.xhr ) { self.xhr.abort(); @@ -378,10 +378,10 @@ $.widget( "ui.tabs", { // if tab may be closed if ( o.collapsible ) { if ( $li.hasClass( "ui-tabs-selected" ) ) { - o.selected = -1; + o.active = -1; if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); + self._cookie( o.active, o.cookie ); } self.element.queue( "tabs", function() { @@ -392,7 +392,7 @@ $.widget( "ui.tabs", { return; } else if ( !$hide.length ) { if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); + self._cookie( o.active, o.cookie ); } self.element.queue( "tabs", function() { @@ -408,7 +408,7 @@ $.widget( "ui.tabs", { } if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); + self._cookie( o.active, o.cookie ); } // show new tab @@ -542,8 +542,8 @@ $.widget( "ui.tabs", { select: function( index ) { index = this._getIndex( index ); if ( index == -1 ) { - if ( this.options.collapsible && this.options.selected != -1 ) { - index = this.options.selected; + if ( this.options.collapsible && this.options.active != -1 ) { + index = this.options.active; } else { return this; } @@ -811,7 +811,7 @@ if ( $.uiBackCompat !== false ) { this.refresh(); if ( this.anchors.length == 1 ) { - o.selected = 0; + o.active = o.selected = 0; $li.addClass( "ui-tabs-selected ui-state-active" ); $panel.removeClass( "ui-tabs-hide" ); this.element.queue( "tabs", function() { @@ -894,6 +894,38 @@ if ( $.uiBackCompat !== false ) { .data( "destroy.tabs", true ); }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // selected option + (function( $, prototype ) { + var _create = prototype._create, + _setOption = prototype._setOption, + _eventHandler = prototype._eventHandler; + + prototype._create = function() { + var options = this.options; + if ( options.active === undefined && options.selected !== undefined ) { + options.active = options.selected; + } + _create.call( this ); + options.selected = options.active; + }; + + prototype._setOption = function( key, value ) { + var options = this.options; + if ( key === "selected" ) { + key = "active"; + } + _setOption.apply( this, arguments ); + if ( key === "active" ) { + options.selected = options.active ; + } + }; + + prototype._eventHandler = function( event ) { + _eventHandler.apply( this, arguments ); + this.options.selected = this.options.active ; + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From 787efd307aff11ad3c51a72f520c58b8158ae973 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sun, 27 Mar 2011 16:55:05 -0400 Subject: Tabs: Rename show event to activate. Fixes #7137 Tabs: Rename show event to activate --- tests/unit/tabs/tabs_defaults.js | 4 ++-- tests/unit/tabs/tabs_defaults_deprecated.js | 1 + tests/unit/tabs/tabs_deprecated.js | 20 ++++++++++++++++++ tests/unit/tabs/tabs_events.js | 4 ++-- ui/jquery.ui.tabs.js | 32 ++++++++++++++++++++++------- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index 98cb99fb5..e155a3dac 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -3,6 +3,7 @@ */ var tabs_defaults = { + activate: null, beforeload: null, collapsible: false, cookie: null, @@ -10,8 +11,7 @@ var tabs_defaults = { event: "click", fx: null, load: null, - select: null, - show: null + select: null }; // FAIL: falsy values break the cookie option diff --git a/tests/unit/tabs/tabs_defaults_deprecated.js b/tests/unit/tabs/tabs_defaults_deprecated.js index 73e9ffede..47fd75d8f 100644 --- a/tests/unit/tabs/tabs_defaults_deprecated.js +++ b/tests/unit/tabs/tabs_defaults_deprecated.js @@ -3,6 +3,7 @@ */ var tabs_defaults = { + activate: null, add: null, ajaxOptions: null, beforeload: null, diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 8b6b50d7e..ba1a778b0 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -168,6 +168,26 @@ test('remove', function() { ok(false, "missing test - untested code is broken code."); }); +test('show', function() { + expect(5); + + var uiObj, eventObj; + el = $('#tabs1').tabs({ + show: function(event, ui) { + uiObj = ui; + eventObj = event; + } + }); + ok(uiObj !== undefined, 'trigger callback after initialization'); + equals(uiObj.tab, $('a', el)[0], 'contain tab as DOM anchor element'); + equals(uiObj.panel, $('div', el)[0], 'contain panel as DOM div element'); + equals(uiObj.index, 0, 'contain index'); + + el.find( "li:eq(1) a" ).simulate( "click" ); + equals( eventObj.originalEvent.type, "click", "show triggered by click" ); + +}); + module("tabs (deprecated): methods"); test('add', function() { diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index 04f282157..60affd7ff 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -49,12 +49,12 @@ test('load', function() { ok(false, "missing test - untested code is broken code."); }); -test('show', function() { +test('activate', function() { expect(5); var uiObj, eventObj; el = $('#tabs1').tabs({ - show: function(event, ui) { + activate: function(event, ui) { uiObj = ui; eventObj = event; } diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index d76565a2a..d605b2d48 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -26,6 +26,7 @@ function getNextListId() { $.widget( "ui.tabs", { options: { + activate: null, beforeload: null, cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } collapsible: false, @@ -33,8 +34,7 @@ $.widget( "ui.tabs", { event: "click", fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } load: null, - select: null, - show: null + select: null }, _create: function() { @@ -103,9 +103,9 @@ $.widget( "ui.tabs", { this.lis.eq( o.active ).addClass( "ui-tabs-selected ui-state-active" ); - // seems to be expected behavior that the show callback is fired + // seems to be expected behavior that the activate callback is fired self.element.queue( "tabs", function() { - self._trigger( "show", null, self._ui( tab, panel[ 0 ] ) ); + self._trigger( "activate", null, self._ui( tab, panel[ 0 ] ) ); }); this.load( o.active ); @@ -304,11 +304,11 @@ $.widget( "ui.tabs", { .animate( showFx, showFx.duration || "normal", function() { self._resetStyle( show, showFx ); self.running = false; - self._trigger( "show", event, self._ui( clicked, show[ 0 ] ) ); + self._trigger( "activate", event, self._ui( clicked, show[ 0 ] ) ); }); } else { show.removeClass( "ui-tabs-hide" ); - self._trigger( "show", event, self._ui( clicked, show[ 0 ] ) ); + self._trigger( "activate", event, self._ui( clicked, show[ 0 ] ) ); } }, @@ -815,7 +815,7 @@ if ( $.uiBackCompat !== false ) { $li.addClass( "ui-tabs-selected ui-state-active" ); $panel.removeClass( "ui-tabs-hide" ); this.element.queue( "tabs", function() { - self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); + self._trigger( "activate", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); }); this.load( 0 ); @@ -926,6 +926,24 @@ if ( $.uiBackCompat !== false ) { this.options.selected = this.options.active ; }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // show event + (function( $, prototype ) { + $.extend( prototype.options, { + show: null + }); + var _trigger = prototype._trigger; + + prototype._trigger = function( type, event, data ) { + var ret = _trigger.apply( this, arguments ); + if ( !ret ) { + return false; + } + if ( type === "activate" ) { + ret = _trigger.call( this, "show", event, data ); + } + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From 8b0c3618bdebddd98d4c09e77d14c50c4f4d3190 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Sun, 27 Mar 2011 17:02:58 -0400 Subject: Tabs: Rename select event to beforeActivate. Fixes #7136 Tabs: Rename select event to beforeActivate --- tests/unit/tabs/tabs_defaults.js | 4 ++-- tests/unit/tabs/tabs_defaults_deprecated.js | 1 + tests/unit/tabs/tabs_deprecated.js | 21 +++++++++++++++++++++ tests/unit/tabs/tabs_events.js | 10 +++++----- ui/jquery.ui.tabs.js | 17 ++++++++++------- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index e155a3dac..194d2b76c 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -5,13 +5,13 @@ var tabs_defaults = { activate: null, beforeload: null, + beforeActivate: null, collapsible: false, cookie: null, disabled: false, event: "click", fx: null, - load: null, - select: null + load: null }; // FAIL: falsy values break the cookie option diff --git a/tests/unit/tabs/tabs_defaults_deprecated.js b/tests/unit/tabs/tabs_defaults_deprecated.js index 47fd75d8f..03ee13d3d 100644 --- a/tests/unit/tabs/tabs_defaults_deprecated.js +++ b/tests/unit/tabs/tabs_defaults_deprecated.js @@ -7,6 +7,7 @@ var tabs_defaults = { add: null, ajaxOptions: null, beforeload: null, + beforeActivate: null, cache: false, collapsible: false, cookie: null, diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index ba1a778b0..38fa6db71 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -188,6 +188,27 @@ test('show', function() { }); +test('select', function() { + expect(7); + + var eventObj; + el = $('#tabs1').tabs({ + select: function(event, ui) { + ok(true, 'select triggered after initialization'); + equals(this, el[0], "context of callback"); + equals(event.type, 'tabsselect', 'event type in callback'); + equals(ui.tab, el.find('a')[1], 'contain tab as DOM anchor element'); + equals(ui.panel, el.find('div')[1], 'contain panel as DOM div element'); + equals(ui.index, 1, 'contain index'); + evenObj = event; + } + }); + el.tabs('select', 1); + + el.find( "li:eq(1) a" ).simulate( "click" ); + equals( evenObj.originalEvent.type, "click", "select triggered by click" ); +}); + module("tabs (deprecated): methods"); test('add', function() { diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index 60affd7ff..4fedde842 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -5,15 +5,15 @@ module("tabs: events"); -test('select', function() { +test('beforeActivate', function() { expect(7); var eventObj; el = $('#tabs1').tabs({ - select: function(event, ui) { - ok(true, 'select triggered after initialization'); + beforeActivate: function(event, ui) { + ok(true, 'beforeActivate triggered after initialization'); equals(this, el[0], "context of callback"); - equals(event.type, 'tabsselect', 'event type in callback'); + equals(event.type, 'tabsbeforeactivate', 'event type in callback'); equals(ui.tab, el.find('a')[1], 'contain tab as DOM anchor element'); equals(ui.panel, el.find('div')[1], 'contain panel as DOM div element'); equals(ui.index, 1, 'contain index'); @@ -23,7 +23,7 @@ test('select', function() { el.tabs('select', 1); el.find( "li:eq(1) a" ).simulate( "click" ); - equals( evenObj.originalEvent.type, "click", "select triggered by click" ); + equals( evenObj.originalEvent.type, "click", "beforeActivate triggered by click" ); }); test('beforeload', function() { diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index d605b2d48..8508f0adb 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -28,13 +28,13 @@ $.widget( "ui.tabs", { options: { activate: null, beforeload: null, + beforeActivate: null, cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } collapsible: false, disabled: false, event: "click", fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - load: null, - select: null + load: null }, _create: function() { @@ -363,8 +363,8 @@ $.widget( "ui.tabs", { $li.hasClass( "ui-state-disabled" ) || // tab is already loading $li.hasClass( "ui-state-processing" ) || - // allow canceling by select event - self._trigger( "select", event, self._ui( el, $show[ 0 ] ) ) === false ) { + // allow canceling by beforeActivate event + self._trigger( "beforeActivate", event, self._ui( el, $show[ 0 ] ) ) === false ) { el.blur(); return; } @@ -927,10 +927,11 @@ if ( $.uiBackCompat !== false ) { }; }( jQuery, jQuery.ui.tabs.prototype ) ); - // show event + // show and select event (function( $, prototype ) { $.extend( prototype.options, { - show: null + show: null, + select: null }); var _trigger = prototype._trigger; @@ -939,7 +940,9 @@ if ( $.uiBackCompat !== false ) { if ( !ret ) { return false; } - if ( type === "activate" ) { + if ( type === "beforeActivate" ) { + ret = _trigger.call( this, "select", event, data ); + } else if ( type === "activate" ) { ret = _trigger.call( this, "show", event, data ); } }; -- cgit v1.2.3 From c6a6ef5ee6ed026ed47a96030a341a8b08a201cf Mon Sep 17 00:00:00 2001 From: David Petersen Date: Mon, 28 Mar 2011 22:28:59 -0400 Subject: Tabs: Deprecate select method. Fixes #7138 Tabs: Deprecate select method --- tests/unit/tabs/tabs_deprecated.js | 30 ++++++++++++ tests/unit/tabs/tabs_events.js | 11 +++-- tests/unit/tabs/tabs_methods.js | 31 +----------- tests/unit/tabs/tabs_options.js | 10 ++-- tests/unit/tabs/tabs_tickets.js | 6 +-- ui/jquery.ui.tabs.js | 99 ++++++++++++++++++++++++-------------- 6 files changed, 110 insertions(+), 77 deletions(-) diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 38fa6db71..1abaa0b04 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -247,6 +247,36 @@ test('remove', function() { equals(el.tabs('option', 'selected'), 0, 'update selected property'); }); +test('select', function() { + expect(6); + + el = $('#tabs1').tabs(); + + el.tabs('select', 1); + equals(el.tabs('option', 'active'), 1, 'should select tab'); + + el.tabs('destroy'); + el.tabs({ collapsible: true }); + el.tabs('select', 0); + equals(el.tabs('option', 'active'), -1, 'should collapse tab passing in the already active tab'); + + el.tabs('destroy'); + el.tabs({ collapsible: true }); + el.tabs('select', -1); + equals(el.tabs('option', 'active'), -1, 'should collapse tab passing in -1'); + + el.tabs('destroy'); + el.tabs(); + el.tabs('select', 0); + equals(el.tabs('option', 'active'), 0, 'should not collapse tab if collapsible is not set to true'); + el.tabs('select', -1); + equals(el.tabs('option', 'active'), 0, 'should not collapse tab if collapsible is not set to true'); + + el.tabs('select', '#fragment-2'); + equals(el.tabs('option', 'active'), 1, 'should select tab by id'); +}); + + test('#5069 - ui.tabs.add creates two tab panels when using a full URL', function() { // http://dev.jqueryui.com/ticket/5069 expect(2); diff --git a/tests/unit/tabs/tabs_events.js b/tests/unit/tabs/tabs_events.js index 4fedde842..381326533 100644 --- a/tests/unit/tabs/tabs_events.js +++ b/tests/unit/tabs/tabs_events.js @@ -8,7 +8,6 @@ module("tabs: events"); test('beforeActivate', function() { expect(7); - var eventObj; el = $('#tabs1').tabs({ beforeActivate: function(event, ui) { ok(true, 'beforeActivate triggered after initialization'); @@ -17,13 +16,17 @@ test('beforeActivate', function() { equals(ui.tab, el.find('a')[1], 'contain tab as DOM anchor element'); equals(ui.panel, el.find('div')[1], 'contain panel as DOM div element'); equals(ui.index, 1, 'contain index'); - evenObj = event; } }); - el.tabs('select', 1); + el.tabs('option', 'active', 1); + el.tabs('destroy'); + el.tabs({ + beforeActivate: function(event, ui) { + equals( event.originalEvent.type, "click", "beforeActivate triggered by click" ); + } + }); el.find( "li:eq(1) a" ).simulate( "click" ); - equals( evenObj.originalEvent.type, "click", "beforeActivate triggered by click" ); }); test('beforeload', function() { diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index dbb5c2d15..69dcc872e 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -130,35 +130,6 @@ test('disable', function() { same(el.tabs('option', 'disabled'), true, 'set to true'); }); -test('select', function() { - expect(6); - - el = $('#tabs1').tabs(); - - el.tabs('select', 1); - equals(el.tabs('option', 'active'), 1, 'should select tab'); - - el.tabs('destroy'); - el.tabs({ collapsible: true }); - el.tabs('select', 0); - equals(el.tabs('option', 'active'), -1, 'should collapse tab passing in the already active tab'); - - el.tabs('destroy'); - el.tabs({ collapsible: true }); - el.tabs('select', -1); - equals(el.tabs('option', 'active'), -1, 'should collapse tab passing in -1'); - - el.tabs('destroy'); - el.tabs(); - el.tabs('select', 0); - equals(el.tabs('option', 'active'), 0, 'should not collapse tab if collapsible is not set to true'); - el.tabs('select', -1); - equals(el.tabs('option', 'active'), 0, 'should not collapse tab if collapsible is not set to true'); - - el.tabs('select', '#fragment-2'); - equals(el.tabs('option', 'active'), 1, 'should select tab by id'); -}); - test('refresh', function() { expect(5); @@ -178,7 +149,7 @@ test('refresh', function() { ul.append('
            • Test 1
            • '); $('
              Test Panel 1
              ').insertAfter( ul ); el.tabs('refresh'); - el.tabs('select', 0); + el.tabs('option', 'active', 0); equals( el.tabs('option', 'active'), 0, 'First tab added should be auto active'); ul.append('
            • Test 2
            • '); diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index b1a7a5e78..1352a68e5 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -13,8 +13,10 @@ test('collapsible', function() { el.tabs({ collapsible: true }); equals(el.tabs('option', 'collapsible'), true, 'option set'); ok(el.is('.ui-tabs-collapsible'), 'extra class "ui-tabs-collapsible" attached'); - el.tabs('select', 0); + + el.tabs('option', 'active', false); equals($('div.ui-tabs-hide', '#tabs1').length, 3, 'all panels should be hidden'); + el.tabs('option', 'collapsible', false); ok(el.is(':not(.ui-tabs-collapsible)'), 'extra class "ui-tabs-collapsible" not attached'); @@ -37,8 +39,8 @@ test('cookie', function() { el.tabs({ active: 1, cookie: cookieObj }); equals(cookie(), 1, 'initial cookie value, from active property'); - el.tabs('select', 2); - equals(cookie(), 2, 'cookie value updated after select'); + el.tabs('option', 'active', 2); + equals(cookie(), 2, 'cookie value updated after activating'); el.tabs('destroy'); $.cookie(cookieName, 1); @@ -47,7 +49,7 @@ test('cookie', function() { el.tabs('destroy'); el.tabs({ cookie: cookieObj, collapsible: true }); - el.tabs('select', 0); + el.tabs('option', 'active', false); equals(cookie(), -1, 'cookie value for all tabs unselected'); el.tabs('destroy'); diff --git a/tests/unit/tabs/tabs_tickets.js b/tests/unit/tabs/tabs_tickets.js index 486d3b6d2..9ff4d6f92 100644 --- a/tests/unit/tabs/tabs_tickets.js +++ b/tests/unit/tabs/tabs_tickets.js @@ -13,7 +13,7 @@ test('#2715 - id containing colon', function() { ok( $('div.ui-tabs-panel:eq(0)', '#tabs2').is(':visible'), 'first panel should be visible' ); ok( $('div.ui-tabs-panel:eq(1)', '#tabs2').is(':hidden'), 'second panel should be hidden' ); - el.tabs('select', 1).tabs('select', 0); + el.tabs('option', 'active', 1).tabs('option', 'active', 0); ok( $('div.ui-tabs-panel:eq(0)', '#tabs2').is(':visible'), 'first panel should be visible' ); ok( $('div.ui-tabs-panel:eq(1)', '#tabs2').is(':hidden'), 'second panel should be hidden' ); @@ -30,10 +30,10 @@ test('#???? - panel containing inline style', function() { el = $('#tabs2').tabs(); equals(inlineStyle('height'), expected, 'init should not remove inline style'); - el.tabs('select', 1); + el.tabs('option', 'active', 1); equals(inlineStyle('height'), expected, 'show tab should not remove inline style'); - el.tabs('select', 0); + el.tabs('option', 'active', 0); equals(inlineStyle('height'), expected, 'hide tab should not remove inline style'); }); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 8508f0adb..b35a91e51 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -96,8 +96,8 @@ $.widget( "ui.tabs", { this.lis.removeClass( "ui-tabs-selected ui-state-active" ); // check for length avoids error when initializing empty list if ( o.active >= 0 && this.anchors.length ) { - var tab = self.anchors[ o.active ], - panel = self.element.find( self._sanitizeSelector( $( tab ).attr( "aria-controls" ) ) ); + this.active = this._findActive( o.active ); + var panel = self.element.find( self._sanitizeSelector( this.active.attr( "aria-controls" ) ) ); panel.removeClass( "ui-tabs-hide" ); @@ -105,7 +105,7 @@ $.widget( "ui.tabs", { // seems to be expected behavior that the activate callback is fired self.element.queue( "tabs", function() { - self._trigger( "activate", null, self._ui( tab, panel[ 0 ] ) ); + self._trigger( "activate", null, self._ui( self.active[ 0 ], panel[ 0 ] ) ); }); this.load( o.active ); @@ -120,10 +120,9 @@ $.widget( "ui.tabs", { _setOption: function( key, value ) { if ( key == "active" ) { - if (this.options.collapsible && value == this.options.active ) { - return; - } - this.select( value ); + // _activate() will handle invalid values and update this.option + this._activate( value ); + return } else { this.options[ key ] = value; this.refresh(); @@ -350,10 +349,10 @@ $.widget( "ui.tabs", { event.preventDefault(); var self = this, o = this.options, - el = event.currentTarget, - $li = $( el ).closest( "li" ), + clicked = $( event.currentTarget ), + $li = clicked.closest( "li" ), $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), - $show = self.element.find( self._sanitizeSelector( $( el ).attr( "aria-controls" ) ) ); + $show = self.element.find( self._sanitizeSelector( clicked.attr( "aria-controls" ) ) ); // tab is already selected, but not collapsible if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible ) || @@ -364,12 +363,14 @@ $.widget( "ui.tabs", { // tab is already loading $li.hasClass( "ui-state-processing" ) || // allow canceling by beforeActivate event - self._trigger( "beforeActivate", event, self._ui( el, $show[ 0 ] ) ) === false ) { - el.blur(); + self._trigger( "beforeActivate", event, self._ui( clicked[ 0 ], $show[ 0 ] ) ) === false ) { + clicked[ 0 ].blur(); return; } - o.active = self.anchors.index( el ); + o.active = self.anchors.index( clicked ); + + self.active = clicked; if ( self.xhr ) { self.xhr.abort(); @@ -379,16 +380,17 @@ $.widget( "ui.tabs", { if ( o.collapsible ) { if ( $li.hasClass( "ui-tabs-selected" ) ) { o.active = -1; + self.active = null; if ( o.cookie ) { self._cookie( o.active, o.cookie ); } self.element.queue( "tabs", function() { - self._hideTab( el, $hide ); + self._hideTab( clicked, $hide ); }).dequeue( "tabs" ); - el.blur(); + clicked[ 0 ].blur(); return; } else if ( !$hide.length ) { if ( o.cookie ) { @@ -396,13 +398,13 @@ $.widget( "ui.tabs", { } self.element.queue( "tabs", function() { - self._showTab( el, $show, event ); + self._showTab( clicked, $show, event ); }); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 - self.load( self.anchors.index( el ) ); + self.load( self.anchors.index( clicked ) ); - el.blur(); + clicked[ 0 ].blur(); return; } } @@ -415,14 +417,14 @@ $.widget( "ui.tabs", { if ( $show.length ) { if ( $hide.length ) { self.element.queue( "tabs", function() { - self._hideTab( el, $hide ); + self._hideTab( clicked, $hide ); }); } self.element.queue( "tabs", function() { - self._showTab( el, $show, event ); + self._showTab( clicked, $show, event ); }); - self.load( self.anchors.index( el ) ); + self.load( self.anchors.index( clicked ) ); } else { throw "jQuery UI Tabs: Mismatching fragment identifier."; } @@ -432,8 +434,31 @@ $.widget( "ui.tabs", { // in modern browsers; blur() removes focus from address bar in Firefox // which can become a usability if ( $.browser.msie ) { - el.blur(); + clicked[ 0 ].blur(); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( this.active && active === this.active[ 0 ] ) { + return; } + + // trying to collapse, simulate a click on the current active header + active = active || this.active; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.anchors.eq( selector ) : + typeof selector === "string" ? this.anchors.filter( "[href$='" + selector + "']" ) : $(); }, _getIndex: function( index ) { @@ -539,19 +564,6 @@ $.widget( "ui.tabs", { return this; }, - select: function( index ) { - index = this._getIndex( index ); - if ( index == -1 ) { - if ( this.options.collapsible && this.options.active != -1 ) { - index = this.options.active; - } else { - return this; - } - } - this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); - return this; - }, - load: function( index ) { index = this._getIndex( index ); var self = this, @@ -834,7 +846,7 @@ if ( $.uiBackCompat !== false ) { // If selected tab was removed focus tab to the right or // in case the last tab was removed the tab to the left. if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { - this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); + this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); } o.disabled = $.map( @@ -947,6 +959,21 @@ if ( $.uiBackCompat !== false ) { } }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // select method + (function( $, prototype ) { + prototype.select = function( index ) { + index = this._getIndex( index ); + if ( index == -1 ) { + if ( this.options.collapsible && this.options.selected != -1 ) { + index = this.options.selected; + } else { + return; + } + } + this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From cb0588f2dd80b5bcc6ff8ddf313366ab1f4c53b1 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Mon, 28 Mar 2011 22:46:31 -0400 Subject: Tabs: Deprecate cookie option. Fixes #7144 Tabs: Deprecate cookie option --- tests/unit/tabs/tabs_defaults.js | 1 - tests/unit/tabs/tabs_deprecated.js | 36 ++++++++++++++++ tests/unit/tabs/tabs_options.js | 35 --------------- ui/jquery.ui.tabs.js | 87 +++++++++++++++++++++++--------------- 4 files changed, 90 insertions(+), 69 deletions(-) diff --git a/tests/unit/tabs/tabs_defaults.js b/tests/unit/tabs/tabs_defaults.js index 194d2b76c..0f33cc28c 100644 --- a/tests/unit/tabs/tabs_defaults.js +++ b/tests/unit/tabs/tabs_defaults.js @@ -7,7 +7,6 @@ var tabs_defaults = { beforeload: null, beforeActivate: null, collapsible: false, - cookie: null, disabled: false, event: "click", fx: null, diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 1abaa0b04..9885ff6a0 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -36,6 +36,42 @@ test('panelTemplate', function() { ok(false, "missing test - untested code is broken code."); }); +test('cookie', function() { + expect(6); + + el = $('#tabs1'); + var cookieName = 'tabs_test', cookieObj = { name: cookieName }; + $.cookie(cookieName, null); // blank state + var cookie = function() { + return parseInt($.cookie(cookieName), 10); + }; + + el.tabs({ cookie: cookieObj }); + equals(cookie(), 0, 'initial cookie value'); + + el.tabs('destroy'); + el.tabs({ active: 1, cookie: cookieObj }); + equals(cookie(), 1, 'initial cookie value, from active property'); + + el.tabs('option', 'active', 2); + equals(cookie(), 2, 'cookie value updated after activating'); + + el.tabs('destroy'); + $.cookie(cookieName, 1); + el.tabs({ cookie: cookieObj }); + equals(cookie(), 1, 'initial cookie value, from existing cookie'); + + el.tabs('destroy'); + el.tabs({ cookie: cookieObj, collapsible: true }); + el.tabs('option', 'active', false); + equals(cookie(), -1, 'cookie value for all tabs unselected'); + + el.tabs('destroy'); + ok($.cookie(cookieName) === null, 'erase cookie after destroy'); + +}); + + test('spinner', function() { expect(4); stop(); diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index 1352a68e5..5196ec9bb 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -22,41 +22,6 @@ test('collapsible', function() { }); -test('cookie', function() { - expect(6); - - el = $('#tabs1'); - var cookieName = 'tabs_test', cookieObj = { name: cookieName }; - $.cookie(cookieName, null); // blank state - var cookie = function() { - return parseInt($.cookie(cookieName), 10); - }; - - el.tabs({ cookie: cookieObj }); - equals(cookie(), 0, 'initial cookie value'); - - el.tabs('destroy'); - el.tabs({ active: 1, cookie: cookieObj }); - equals(cookie(), 1, 'initial cookie value, from active property'); - - el.tabs('option', 'active', 2); - equals(cookie(), 2, 'cookie value updated after activating'); - - el.tabs('destroy'); - $.cookie(cookieName, 1); - el.tabs({ cookie: cookieObj }); - equals(cookie(), 1, 'initial cookie value, from existing cookie'); - - el.tabs('destroy'); - el.tabs({ cookie: cookieObj, collapsible: true }); - el.tabs('option', 'active', false); - equals(cookie(), -1, 'cookie value for all tabs unselected'); - - el.tabs('destroy'); - ok($.cookie(cookieName) === null, 'erase cookie after destroy'); - -}); - test('disabled', function() { expect(4); diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index b35a91e51..066bd5299 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -29,7 +29,6 @@ $.widget( "ui.tabs", { activate: null, beforeload: null, beforeActivate: null, - cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } collapsible: false, disabled: false, event: "click", @@ -50,8 +49,7 @@ $.widget( "ui.tabs", { // Selected tab // use "selected" option or try to retrieve: // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
            • + // 2. from selected class attribute on
            • if ( o.active === undefined ) { if ( location.hash ) { this.anchors.each(function( i, a ) { @@ -61,9 +59,6 @@ $.widget( "ui.tabs", { } }); } - if ( typeof o.active !== "number" && o.cookie ) { - o.active = parseInt( self._cookie(), 10 ); - } if ( typeof o.active !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { o.active = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); } @@ -139,12 +134,6 @@ $.widget( "ui.tabs", { return hash.replace( /:/g, "\\:" ); }, - _cookie: function() { - var cookie = this.cookie || - ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); - return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); - }, - _ui: function( tab, panel ) { return { tab: tab, @@ -189,11 +178,6 @@ $.widget( "ui.tabs", { o.disabled = false; } - // set or update cookie after init and add/remove respectively - if ( o.cookie ) { - this._cookie( o.active, o.cookie ); - } - // disable tabs for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { $( li ).toggleClass( "ui-state-disabled", $.inArray( i, o.disabled ) != -1 ); @@ -382,10 +366,6 @@ $.widget( "ui.tabs", { o.active = -1; self.active = null; - if ( o.cookie ) { - self._cookie( o.active, o.cookie ); - } - self.element.queue( "tabs", function() { self._hideTab( clicked, $hide ); }).dequeue( "tabs" ); @@ -393,10 +373,6 @@ $.widget( "ui.tabs", { clicked[ 0 ].blur(); return; } else if ( !$hide.length ) { - if ( o.cookie ) { - self._cookie( o.active, o.cookie ); - } - self.element.queue( "tabs", function() { self._showTab( clicked, $show, event ); }); @@ -409,10 +385,6 @@ $.widget( "ui.tabs", { } } - if ( o.cookie ) { - self._cookie( o.active, o.cookie ); - } - // show new tab if ( $show.length ) { if ( $hide.length ) { @@ -507,10 +479,6 @@ $.widget( "ui.tabs", { } }); - if ( o.cookie ) { - this._cookie( null, o.cookie ); - } - return this; }, @@ -974,6 +942,59 @@ if ( $.uiBackCompat !== false ) { this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); }; }( jQuery, jQuery.ui.tabs.prototype ) ); + + // cookie option + (function( $, prototype ) { + $.extend( prototype.options, { + cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + }); + + var _create = prototype._create, + _refresh = prototype._refresh, + _eventHandler = prototype._eventHandler, + _destroy = prototype._destroy; + + prototype._create = function() { + var o = this.options; + if ( o.active === undefined ) { + if ( typeof o.active !== "number" && o.cookie ) { + o.active = parseInt( this._cookie(), 10 ); + } + } + _create.call( this ); + }; + + prototype._cookie = function() { + var cookie = this.cookie || + ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); + return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); + }; + + prototype._refresh = function() { + _refresh.call( this ); + + // set or update cookie after init and add/remove respectively + if ( this.options.cookie ) { + this._cookie( this.options.active, this.options.cookie ); + } + }; + + prototype._eventHandler = function( event ) { + _eventHandler.apply( this, arguments ); + + if ( this.options.cookie ) { + this._cookie( this.options.active, this.options.cookie ); + } + }; + + prototype._destroy = function() { + _destroy.call( this ); + + if ( this.options.cookie ) { + this._cookie( null, this.options.cookie ); + } + }; + }( jQuery, jQuery.ui.tabs.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From e9ae04a394e63e5b012f28fc40a04e71c4f935d9 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Tue, 29 Mar 2011 07:44:01 -0400 Subject: Tabs: CSS Consistency Updates. Fixes #7146 Tabs: CSS Consistency Updates --- tests/unit/tabs/tabs_deprecated.js | 2 +- tests/unit/tabs/tabs_methods.js | 26 +++++++++---------- tests/unit/tabs/tabs_options.js | 4 +-- tests/unit/tabs/tabs_tickets.js | 2 +- themes/base/jquery.ui.tabs.css | 7 +++-- ui/jquery.ui.tabs.js | 52 ++++++++++++++++++-------------------- 6 files changed, 45 insertions(+), 48 deletions(-) diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 9885ff6a0..b784c724e 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -125,7 +125,7 @@ test('selected', function() { el = $('#tabs1').tabs({ selected: -1 }); equals(el.tabs('option', 'selected'), -1, 'should be -1 for all tabs unselected'); equals( $('li.ui-tabs-selected', el).length, 0, 'no tab should be selected' ); - equals( $('div.ui-tabs-hide', '#tabs1').length, 3, 'all panels should be hidden' ); + equals( $('div:hidden', '#tabs1').length, 3, 'all panels should be hidden' ); el.tabs('destroy'); el.tabs({ selected: null }); diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js index 69dcc872e..c33bebe65 100644 --- a/tests/unit/tabs/tabs_methods.js +++ b/tests/unit/tabs/tabs_methods.js @@ -14,11 +14,11 @@ test('init', function() { ok( el.is('.ui-tabs.ui-widget.ui-widget-content.ui-corner-all'), 'attach classes to container'); ok( $('ul', el).is('.ui-tabs-nav.ui-helper-reset.ui-helper-clearfix.ui-widget-header.ui-corner-all'), 'attach classes to list' ); ok( $('div:eq(0)', el).is('.ui-tabs-panel.ui-widget-content.ui-corner-bottom'), 'attach classes to panel' ); - ok( $('li:eq(0)', el).is('.ui-tabs-selected.ui-state-active.ui-corner-top'), 'attach classes to active li'); + ok( $('li:eq(0)', el).is('.ui-tabs-active.ui-state-active.ui-corner-top'), 'attach classes to active li'); ok( $('li:eq(1)', el).is('.ui-state-default.ui-corner-top'), 'attach classes to inactive li'); equals( el.tabs('option', 'active'), 0, 'active option set' ); - equals( $('li', el).index( $('li.ui-tabs-selected', el) ), 0, 'second tab active'); - equals( $('div', el).index( $('div.ui-tabs-hide', '#tabs1') ), 1, 'second panel should be hidden' ); + equals( $('li', el).index( $('li.ui-tabs-active', el) ), 0, 'second tab active'); + equals( $('div', el).index( $('div:hidden', '#tabs1') ), 1, 'second panel should be hidden' ); }); test('init with hash', function() { @@ -32,11 +32,11 @@ test('init with hash', function() { equals(el.tabs('option', 'active'), 1, 'second tab should be active'); - ok(!$('#tabs1 ul li:eq(0)').is('.ui-tabs-selected.ui-state-active'), 'first tab should not be selected nor active'); - ok($('#tabs1 div:eq(0)').is('.ui-tabs-hide'), 'first div for first tab should be hidden'); + ok(!$('#tabs1 ul li:eq(0)').is('.ui-tabs-active.ui-state-active'), 'first tab should not be selected nor active'); + ok($('#tabs1 div:eq(0)').is(':hidden'), 'first div for first tab should be hidden'); - ok($('#tabs1 ul li:eq(1)').is('.ui-tabs-selected.ui-state-active'), 'second tab should be selected and active'); - ok(!$('#tabs1 div:eq(1)').is('.ui-tabs-hide'), 'second div for second tab should not be hidden'); + ok($('#tabs1 ul li:eq(1)').is('.ui-tabs-active.ui-state-active'), 'second tab should be selected and active'); + ok(!$('#tabs1 div:eq(1)').is(':hidden'), 'second div for second tab should not be hidden'); }); test('init mismatched order with hash', function() { @@ -50,11 +50,11 @@ test('init mismatched order with hash', function() { equals(el.tabs('option', 'active'), 1, 'second tab should be active'); - ok(!$('#tabs7-list li:eq(0)').is('.ui-tabs-selected.ui-state-active'), 'first tab should not be selected nor active'); - ok($('#tabs7 div:eq(1)').is('.ui-tabs-hide'), 'second div for first tab should be hidden'); + ok(!$('#tabs7-list li:eq(0)').is('.ui-tabs-active.ui-state-active'), 'first tab should not be selected nor active'); + ok($('#tabs7 div:eq(1)').is(':hidden'), 'second div for first tab should be hidden'); - ok($('#tabs7-list li:eq(1)').is('.ui-tabs-selected.ui-state-active'), 'second tab should be selected and active'); - ok(!$('#tabs7 div:eq(0)').is('.ui-tabs-hide'), 'first div for second tab should not be hidden'); + ok($('#tabs7-list li:eq(1)').is('.ui-tabs-active.ui-state-active'), 'second tab should be selected and active'); + ok(!$('#tabs7 div:eq(0)').is(':hidden'), 'first div for second tab should not be hidden'); }); test('destroy', function() { @@ -66,8 +66,8 @@ test('destroy', function() { ok( el.is(':not(.ui-tabs, .ui-widget, .ui-widget-content, .ui-corner-all, .ui-tabs-collapsible)'), 'remove classes from container'); ok( $('ul', el).is(':not(.ui-tabs-nav, .ui-helper-reset, .ui-helper-clearfix, .ui-widget-header, .ui-corner-all)'), 'remove classes from list' ); - ok( $('div:eq(1)', el).is(':not(.ui-tabs-panel, .ui-widget-content, .ui-corner-bottom, .ui-tabs-hide)'), 'remove classes to panel' ); - ok( $('li:eq(0)', el).is(':not(.ui-tabs-selected, .ui-state-active, .ui-corner-top)'), 'remove classes from active li'); + ok( $('div:eq(1)', el).is(':not(.ui-tabs-panel, .ui-widget-content, .ui-corner-bottom)'), 'remove classes to panel' ); + ok( $('li:eq(0)', el).is(':not(.ui-tabs-active, .ui-state-active, .ui-corner-top)'), 'remove classes from active li'); ok( $('li:eq(1)', el).is(':not(.ui-state-default, .ui-corner-top)'), 'remove classes from inactive li'); ok( $('li:eq(2)', el).is(':not(.ui-state-hover, .ui-state-focus)'), 'remove classes from mouseovered or focused li'); }); diff --git a/tests/unit/tabs/tabs_options.js b/tests/unit/tabs/tabs_options.js index 5196ec9bb..98cd3b4ca 100644 --- a/tests/unit/tabs/tabs_options.js +++ b/tests/unit/tabs/tabs_options.js @@ -15,7 +15,7 @@ test('collapsible', function() { ok(el.is('.ui-tabs-collapsible'), 'extra class "ui-tabs-collapsible" attached'); el.tabs('option', 'active', false); - equals($('div.ui-tabs-hide', '#tabs1').length, 3, 'all panels should be hidden'); + equals($('div:hidden', '#tabs1').length, 3, 'all panels should be hidden'); el.tabs('option', 'collapsible', false); ok(el.is(':not(.ui-tabs-collapsible)'), 'extra class "ui-tabs-collapsible" not attached'); @@ -56,7 +56,7 @@ test('active', function() { el.tabs({ active: -1 }); equals(el.tabs('option', 'active'), -1, 'should be -1 for all tabs deactive'); equals( $('li.ui-tabs-selected', el).length, 0, 'no tab should be active' ); - equals( $('div.ui-tabs-hide', '#tabs1').length, 3, 'all panels should be hidden' ); + equals( $('div:hidden', '#tabs1').length, 3, 'all panels should be hidden' ); el.tabs('destroy'); el.tabs({ active: null }); diff --git a/tests/unit/tabs/tabs_tickets.js b/tests/unit/tabs/tabs_tickets.js index 9ff4d6f92..36ddd6e84 100644 --- a/tests/unit/tabs/tabs_tickets.js +++ b/tests/unit/tabs/tabs_tickets.js @@ -92,7 +92,7 @@ test('#6710 - selectors are global', function() { \ '); container.find('#tabs_6710').tabs(); - ok( container.find('#tabs-2_6710').hasClass('ui-tabs-hide'), 'should find panels and add corresponding classes' ); + ok( container.find('#tabs-2_6710').is(':hidden'), 'should find panels and add corresponding classes' ); }); diff --git a/themes/base/jquery.ui.tabs.css b/themes/base/jquery.ui.tabs.css index 12666facd..d4c039f30 100644 --- a/themes/base/jquery.ui.tabs.css +++ b/themes/base/jquery.ui.tabs.css @@ -11,8 +11,7 @@ .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 066bd5299..f9926ebef 100755 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -59,8 +59,8 @@ $.widget( "ui.tabs", { } }); } - if ( typeof o.active !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { - o.active = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); + if ( typeof o.active !== "number" && this.lis.filter( ".ui-tabs-active" ).length ) { + o.active = this.lis.index( this.lis.filter( ".ui-tabs-active" ) ); } o.active = o.active || ( this.lis.length ? 0 : -1 ); } else if ( o.active === null ) { // usage of null is deprecated, TODO remove in next release @@ -87,16 +87,16 @@ $.widget( "ui.tabs", { this._refresh(); // highlight selected tab - this.panels.addClass( "ui-tabs-hide" ); - this.lis.removeClass( "ui-tabs-selected ui-state-active" ); + this.panels.hide(); + this.lis.removeClass( "ui-tabs-active ui-state-active" ); // check for length avoids error when initializing empty list if ( o.active >= 0 && this.anchors.length ) { this.active = this._findActive( o.active ); var panel = self.element.find( self._sanitizeSelector( this.active.attr( "aria-controls" ) ) ); - panel.removeClass( "ui-tabs-hide" ); + panel.show(); - this.lis.eq( o.active ).addClass( "ui-tabs-selected ui-state-active" ); + this.lis.eq( o.active ).addClass( "ui-tabs-active ui-state-active" ); // seems to be expected behavior that the activate callback is fired self.element.queue( "tabs", function() { @@ -131,7 +131,7 @@ $.widget( "ui.tabs", { _sanitizeSelector: function( hash ) { // we need this because an id may contain a ":" - return hash.replace( /:/g, "\\:" ); + return hash ? hash.replace( /:/g, "\\:" ) : ""; }, _ui: function( tab, panel ) { @@ -279,18 +279,18 @@ $.widget( "ui.tabs", { _showTab: function( clicked, show, event ) { var self = this; - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); + $( clicked ).closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); if ( this.showFx ) { self.running = true; - show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way + show.hide() .animate( showFx, showFx.duration || "normal", function() { self._resetStyle( show, showFx ); self.running = false; self._trigger( "activate", event, self._ui( clicked, show[ 0 ] ) ); }); } else { - show.removeClass( "ui-tabs-hide" ); + show.show(); self._trigger( "activate", event, self._ui( clicked, show[ 0 ] ) ); } }, @@ -302,14 +302,13 @@ $.widget( "ui.tabs", { self.running = true; $hide.animate( hideFx, hideFx.duration || "normal", function() { self.running = false; - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); + self.lis.removeClass( "ui-tabs-active ui-state-active" ); self._resetStyle( $hide, hideFx ); self.element.dequeue( "tabs" ); }); } else { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); + self.lis.removeClass( "ui-tabs-active ui-state-active" ); + $hide.hide(); self.element.dequeue( "tabs" ); } }, @@ -335,17 +334,17 @@ $.widget( "ui.tabs", { o = this.options, clicked = $( event.currentTarget ), $li = clicked.closest( "li" ), - $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), + $hide = self.element.find( self._sanitizeSelector( $( this.active ).attr( "aria-controls" ) ) ), $show = self.element.find( self._sanitizeSelector( clicked.attr( "aria-controls" ) ) ); // tab is already selected, but not collapsible - if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible ) || + if ( ( $li.hasClass( "ui-tabs-active" ) && !o.collapsible ) || // can't switch durning an animation self.running || // tab is disabled $li.hasClass( "ui-state-disabled" ) || // tab is already loading - $li.hasClass( "ui-state-processing" ) || + $li.hasClass( "ui-tabs-loading" ) || // allow canceling by beforeActivate event self._trigger( "beforeActivate", event, self._ui( clicked[ 0 ], $show[ 0 ] ) ) === false ) { clicked[ 0 ].blur(); @@ -362,7 +361,7 @@ $.widget( "ui.tabs", { // if tab may be closed if ( o.collapsible ) { - if ( $li.hasClass( "ui-tabs-selected" ) ) { + if ( $li.hasClass( "ui-tabs-active" ) ) { o.active = -1; self.active = null; @@ -468,13 +467,12 @@ $.widget( "ui.tabs", { $( this ).removeClass([ "ui-state-default", "ui-corner-top", - "ui-tabs-selected", + "ui-tabs-active", "ui-state-active", "ui-state-disabled", "ui-tabs-panel", "ui-widget-content", - "ui-corner-bottom", - "ui-tabs-hide" + "ui-corner-bottom" ].join( " " ) ); } }); @@ -563,7 +561,7 @@ $.widget( "ui.tabs", { if ( this.xhr ) { // load remote from here on - this.lis.eq( index ).addClass( "ui-state-processing" ); + this.lis.eq( index ).addClass( "ui-tabs-loading" ); this.xhr .success( function( response ) { @@ -582,7 +580,7 @@ $.widget( "ui.tabs", { delete this.xhr; } - self.lis.eq( index ).removeClass( "ui-state-processing" ); + self.lis.eq( index ).removeClass( "ui-tabs-loading" ); self._trigger( "load", null, eventData ); }); @@ -774,7 +772,7 @@ if ( $.uiBackCompat !== false ) { if ( !$panel.length ) { $panel = self._createPanel( id ); } - $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); + $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide(); if ( index >= this.lis.length ) { $li.appendTo( this.list ); @@ -792,8 +790,8 @@ if ( $.uiBackCompat !== false ) { if ( this.anchors.length == 1 ) { o.active = o.selected = 0; - $li.addClass( "ui-tabs-selected ui-state-active" ); - $panel.removeClass( "ui-tabs-hide" ); + $li.addClass( "ui-tabs-active ui-state-active" ); + $panel.show(); this.element.queue( "tabs", function() { self._trigger( "activate", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); }); @@ -813,7 +811,7 @@ if ( $.uiBackCompat !== false ) { // If selected tab was removed focus tab to the right or // in case the last tab was removed the tab to the left. - if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { + if ( $li.hasClass( "ui-tabs-active" ) && this.anchors.length > 1) { this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); } -- cgit v1.2.3