Skip to content

Commit 632e6c7

Browse files
committed
Tabs: Pass appropriate data for beforeActivate event. Fixes #7136 - Tabs: Rename select event to beforeActivate.
1 parent fdedf16 commit 632e6c7

File tree

4 files changed

+117
-63
lines changed

4 files changed

+117
-63
lines changed

tests/unit/tabs/tabs.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@
2626
<script src="tabs_options.js"></script>
2727
<script src="tabs_tickets.js"></script>
2828

29+
<script>
30+
function tabs_state( tabs ) {
31+
var expected = $.makeArray( arguments ).slice( 1 );
32+
var actual = tabs.find( ".ui-tabs-nav li" ).map(function() {
33+
return $( this ).hasClass( "ui-state-active" ) ? 1 : 0;
34+
}).get();
35+
same( actual, expected );
36+
}
37+
</script>
2938
<script>
3039
// disable this stale testsuite for testswarm only
3140
var url = window.location.search;

tests/unit/tabs/tabs_deprecated.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
<script src="tabs_tickets.js"></script>
2626
<script src="tabs_deprecated.js"></script>
2727

28+
<script>
29+
function tabs_state( tabs ) {
30+
var expected = $.makeArray( arguments ).slice( 1 );
31+
var actual = tabs.find( ".ui-tabs-nav li" ).map(function() {
32+
return $( this ).hasClass( "ui-state-active" ) ? 1 : 0;
33+
}).get();
34+
same( actual, expected );
35+
}
36+
</script>
2837
<script>
2938
// disable this stale testsuite for testswarm only
3039
var url = window.location.search;

tests/unit/tabs/tabs_events.js

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,55 @@
1-
/*
2-
* tabs_events.js
3-
*/
4-
(function($) {
1+
(function( $ ) {
52

6-
module("tabs: events");
3+
module( "tabs: events" );
74

8-
test('beforeActivate', function() {
9-
expect(7);
5+
test( "beforeActivate", function() {
6+
expect( 26 );
107

11-
el = $('#tabs1').tabs({
12-
beforeActivate: function(event, ui) {
13-
ok(true, 'beforeActivate triggered after initialization');
14-
equals(this, el[0], "context of callback");
15-
equals(event.type, 'tabsbeforeactivate', 'event type in callback');
16-
equals(ui.tab, el.find('a')[1], 'contain tab as DOM anchor element');
17-
equals(ui.panel, el.find('div')[1], 'contain panel as DOM div element');
18-
equals(ui.index, 1, 'contain index');
19-
}
8+
var element = $( "#tabs1" ).tabs({
9+
// TODO: should be false
10+
active: -1,
11+
collapsible: true
12+
}),
13+
tabs = element.find( ".ui-tabs-nav a" ),
14+
panels = element.find( ".ui-tabs-panel" );
15+
16+
element.one( "tabsbeforeactivate", function( event, ui ) {
17+
equals( ui.oldTab.size(), 0 );
18+
equals( ui.oldPanel.size(), 0 );
19+
equals( ui.newTab.size(), 1 );
20+
strictEqual( ui.newTab[ 0 ], tabs[ 0 ] );
21+
equals( ui.newPanel.size(), 1 );
22+
strictEqual( ui.newPanel[ 0 ], panels[ 0 ] );
23+
tabs_state( element, 0, 0, 0 );
2024
});
21-
el.tabs('option', 'active', 1);
25+
element.tabs( "option", "active", 0 );
26+
tabs_state( element, 1, 0, 0 );
2227

23-
el.tabs('destroy');
24-
el.tabs({
25-
beforeActivate: function(event, ui) {
26-
equals( event.originalEvent.type, "click", "beforeActivate triggered by click" );
27-
}
28+
element.one( "tabsbeforeactivate", function( event, ui ) {
29+
equals( ui.oldTab.size(), 1 );
30+
strictEqual( ui.oldTab[ 0 ], tabs[ 0 ] );
31+
equals( ui.oldPanel.size(), 1 );
32+
strictEqual( ui.oldPanel[ 0 ], panels[ 0 ] );
33+
equals( ui.newTab.size(), 1 );
34+
strictEqual( ui.newTab[ 0 ], tabs[ 1 ] );
35+
equals( ui.newPanel.size(), 1 );
36+
strictEqual( ui.newPanel[ 0 ], panels[ 1 ] );
37+
tabs_state( element, 1, 0, 0 );
2838
});
29-
el.find( "li:eq(1) a" ).simulate( "click" );
39+
element.tabs( "option", "active", 1 );
40+
tabs_state( element, 0, 1, 0 );
41+
42+
element.one( "tabsbeforeactivate", function( event, ui ) {
43+
equals( ui.oldTab.size(), 1 );
44+
strictEqual( ui.oldTab[ 0 ], tabs[ 1 ] );
45+
equals( ui.oldPanel.size(), 1 );
46+
strictEqual( ui.oldPanel[ 0 ], panels[ 1 ] );
47+
equals( ui.newTab.size(), 0 );
48+
equals( ui.newPanel.size(), 0 );
49+
tabs_state( element, 0, 1, 0 );
50+
});
51+
element.tabs( "option", "active", false );
52+
tabs_state( element, 0, 0, 0 );
3053
});
3154

3255
test('beforeload', function() {

ui/jquery.ui.tabs.js

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ $.widget( "ui.tabs", {
104104
});
105105

106106
this.load( o.active );
107+
} else {
108+
this.active = $();
107109
}
108110

109111
// clean up to avoid memory leaks in certain versions of IE 6
@@ -329,73 +331,80 @@ $.widget( "ui.tabs", {
329331
},
330332

331333
_eventHandler: function( event ) {
332-
event.preventDefault();
333-
var self = this,
334-
o = this.options,
334+
var that = this,
335+
options = that.options,
336+
active = that.active,
335337
clicked = $( event.currentTarget ),
336-
$li = clicked.closest( "li" ),
337-
$hide = self.element.find( self._sanitizeSelector( $( this.active ).attr( "aria-controls" ) ) ),
338-
$show = self.element.find( self._sanitizeSelector( clicked.attr( "aria-controls" ) ) );
339-
340-
// tab is already selected, but not collapsible
341-
if ( ( $li.hasClass( "ui-tabs-active" ) && !o.collapsible ) ||
342-
// can't switch durning an animation
343-
self.running ||
344-
// tab is disabled
345-
$li.hasClass( "ui-state-disabled" ) ||
346-
// tab is already loading
347-
$li.hasClass( "ui-tabs-loading" ) ||
348-
// allow canceling by beforeActivate event
349-
self._trigger( "beforeActivate", event, self._ui( clicked[ 0 ], $show[ 0 ] ) ) === false ) {
338+
clickedIsActive = clicked[ 0 ] === active[ 0 ],
339+
collapsing = clickedIsActive && options.collapsible,
340+
toShow = collapsing ? $() : that.element.find( that._sanitizeSelector( clicked.attr( "aria-controls" ) ) ),
341+
toHide = !active.length ? $() : that.element.find( that._sanitizeSelector( active.attr( "aria-controls" ) ) ),
342+
tab = clicked.closest( "li" ),
343+
eventData = {
344+
oldTab: active,
345+
oldPanel: toHide,
346+
newTab: collapsing ? $() : clicked,
347+
newPanel: toShow
348+
};
349+
350+
event.preventDefault();
351+
352+
if ( tab.hasClass( "ui-state-disabled" ) ||
353+
// tab is already loading
354+
tab.hasClass( "ui-tabs-loading" ) ||
355+
// can't switch durning an animation
356+
that.running ||
357+
// click on active header, but not collapsible
358+
( clickedIsActive && !options.collapsible ) ||
359+
// allow canceling activation
360+
( that._trigger( "beforeActivate", event, eventData ) === false ) ) {
350361
clicked[ 0 ].blur();
351362
return;
352363
}
353364

354-
o.active = self.anchors.index( clicked );
355-
356-
self.active = clicked;
365+
options.active = collapsing ? false : that.anchors.index( clicked );
357366

358-
if ( self.xhr ) {
359-
self.xhr.abort();
367+
that.active = clicked;
368+
if ( that.xhr ) {
369+
that.xhr.abort();
360370
}
361371

362372
// if tab may be closed
363-
if ( o.collapsible ) {
364-
if ( $li.hasClass( "ui-tabs-active" ) ) {
365-
o.active = -1;
366-
self.active = null;
373+
if ( options.collapsible ) {
374+
if ( collapsing ) {
375+
options.active = false;
367376

368-
self.element.queue( "tabs", function() {
369-
self._hideTab( clicked, $hide );
377+
that.element.queue( "tabs", function() {
378+
that._hideTab( clicked, toHide );
370379
}).dequeue( "tabs" );
371380

372381
clicked[ 0 ].blur();
373382
return;
374-
} else if ( !$hide.length ) {
375-
self.element.queue( "tabs", function() {
376-
self._showTab( clicked, $show, event );
383+
} else if ( !toHide.length ) {
384+
that.element.queue( "tabs", function() {
385+
that._showTab( clicked, toShow, event );
377386
});
378387

379388
// TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
380-
self.load( self.anchors.index( clicked ) );
389+
that.load( that.anchors.index( clicked ) );
381390

382391
clicked[ 0 ].blur();
383392
return;
384393
}
385394
}
386395

387396
// show new tab
388-
if ( $show.length ) {
389-
if ( $hide.length ) {
390-
self.element.queue( "tabs", function() {
391-
self._hideTab( clicked, $hide );
397+
if ( toShow.length ) {
398+
if ( toHide.length ) {
399+
that.element.queue( "tabs", function() {
400+
that._hideTab( clicked, toHide );
392401
});
393402
}
394-
self.element.queue( "tabs", function() {
395-
self._showTab( clicked, $show, event );
403+
that.element.queue( "tabs", function() {
404+
that._showTab( clicked, toShow, event );
396405
});
397406

398-
self.load( self.anchors.index( clicked ) );
407+
that.load( that.anchors.index( clicked ) );
399408
} else {
400409
throw "jQuery UI Tabs: Mismatching fragment identifier.";
401410
}
@@ -919,7 +928,11 @@ if ( $.uiBackCompat !== false ) {
919928
return false;
920929
}
921930
if ( type === "beforeActivate" ) {
922-
ret = _trigger.call( this, "select", event, data );
931+
ret = _trigger.call( this, "select", event, {
932+
tab: data.newTab[ 0],
933+
panel: data.newPanel[ 0 ],
934+
index: data.newTab.closest( "li" ).index()
935+
});
923936
} else if ( type === "activate" ) {
924937
ret = _trigger.call( this, "show", event, data );
925938
}

0 commit comments

Comments
 (0)