aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/tabs/sortable.html8
-rw-r--r--demos/tooltip/custom-animation.html17
-rw-r--r--demos/tooltip/index.html2
-rw-r--r--demos/tooltip/video-player.html101
-rw-r--r--tests/unit/menu/menu_core.js11
-rw-r--r--tests/unit/tabs/tabs.html37
-rw-r--r--tests/unit/tabs/tabs_deprecated.html37
-rw-r--r--tests/unit/tabs/tabs_deprecated.js150
-rw-r--r--tests/unit/tabs/tabs_methods.js203
-rw-r--r--tests/unit/testsuite.js4
-rw-r--r--tests/unit/tooltip/tooltip.html2
-rw-r--r--tests/unit/tooltip/tooltip_defaults.js6
-rw-r--r--tests/unit/tooltip/tooltip_events.js6
-rw-r--r--tests/unit/tooltip/tooltip_methods.js5
-rw-r--r--tests/unit/tooltip/tooltip_options.js14
-rw-r--r--tests/visual/tooltip/animations.html72
-rw-r--r--themes/base/jquery.ui.resizable.css2
-rw-r--r--ui/jquery.ui.core.js46
-rw-r--r--ui/jquery.ui.datepicker.js47
-rwxr-xr-xui/jquery.ui.tabs.js214
-rw-r--r--ui/jquery.ui.tooltip.js12
-rw-r--r--ui/jquery.ui.widget.js26
22 files changed, 717 insertions, 305 deletions
diff --git a/demos/tabs/sortable.html b/demos/tabs/sortable.html
index ba8196d71..c3e882791 100644
--- a/demos/tabs/sortable.html
+++ b/demos/tabs/sortable.html
@@ -13,7 +13,13 @@
<link rel="stylesheet" href="../demos.css">
<script>
$(function() {
- $( "#tabs" ).tabs().find( ".ui-tabs-nav" ).sortable({ axis: "x" });
+ var tabs = $( "#tabs" ).tabs();
+ tabs.find( ".ui-tabs-nav" ).sortable({
+ axis: "x",
+ stop: function() {
+ tabs.tabs( "refresh" );
+ }
+ });
});
</script>
</head>
diff --git a/demos/tooltip/custom-animation.html b/demos/tooltip/custom-animation.html
index a9745a062..ef8857979 100644
--- a/demos/tooltip/custom-animation.html
+++ b/demos/tooltip/custom-animation.html
@@ -11,15 +11,14 @@
<link type="text/css" href="../demos.css" rel="stylesheet" />
<script type="text/javascript">
$(function() {
- // TODO overhaul this with custom animation API
$(".demo").tooltip({
- open: function() {
- $(".ui-tooltip").stop(false, true).hide().slideDown();
+ show: {
+ effect: "slideDown",
+ delay: 250
},
- close: function() {
- $(".ui-tooltip").stop(false, false).show().slideUp(function() {
- $(this).remove();
- });
+ hide: {
+ effect: "hide",
+ delay: 250
}
});
});
@@ -48,7 +47,9 @@
<div class="demo-description">
-<p>Here the tooltips are positioned relative to the mouse, and follow the mouse while it moves above the element.</p>
+<p>This demo shows how to customize animations. The tooltip is shown, after a
+delay of 250ms, using a slide down animation, and hidden, after another delay,
+without an animation.</p>
</div><!-- End demo-description -->
diff --git a/demos/tooltip/index.html b/demos/tooltip/index.html
index 3563350c5..4ad189ed2 100644
--- a/demos/tooltip/index.html
+++ b/demos/tooltip/index.html
@@ -14,7 +14,7 @@
<li><a href="tracking.html">Track the mouse</a></li>
<li><a href="custom-animation.html">Custom animation</a></li>
<li><a href="delegation-mixbag.html">Delegation Mixbag</a></li>
- <li><a href="lots.html">Lots</a></li>
+ <li><a href="video-player.html">Video Player</a></li>
</ul>
</div>
diff --git a/demos/tooltip/video-player.html b/demos/tooltip/video-player.html
new file mode 100644
index 000000000..c890c76b4
--- /dev/null
+++ b/demos/tooltip/video-player.html
@@ -0,0 +1,101 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <title>jQuery UI Tooltip - Video Player demo</title>
+ <link type="text/css" href="../../themes/base/jquery.ui.all.css" rel="stylesheet" />
+ <script type="text/javascript" src="../../jquery-1.5.1.js"></script>
+ <script type="text/javascript" src="../../ui/jquery.ui.core.js"></script>
+ <script type="text/javascript" src="../../ui/jquery.ui.widget.js"></script>
+ <script type="text/javascript" src="../../ui/jquery.ui.position.js"></script>
+ <script type="text/javascript" src="../../ui/jquery.ui.tooltip.js"></script>
+ <script type="text/javascript" src="../../ui/jquery.ui.button.js"></script>
+ <script type="text/javascript" src="../../ui/jquery.ui.menu.js"></script>
+ <script type="text/javascript" src="../../tests/visual/menu/popup.js"></script>
+ <link type="text/css" href="../demos.css" rel="stylesheet" />
+ <script type="text/javascript">
+ $(function() {
+ $("button").each(function() {
+ $(this).button({
+ icons: {
+ primary: $(this).data("icon")
+ },
+ text: !!$(this).attr("title")
+ });
+ });
+ $(".set").buttonset();
+
+ // TODO hide the tooltip when clicking the button
+ $("ul").menu().popup({
+ trigger: $(".menu")
+ });
+
+ $(".demo").tooltip({
+ position: {
+ my: "center top",
+ at: "center bottom+5",
+ },
+ show: {
+ duration: "fast"
+ },
+ hide: {
+ effect: "hide"
+ }
+ });
+ });
+ </script>
+ <style>
+ .player { width: 500px; height: 300px; border: 2px groove gray; background: rgb(200, 200, 200); text-align: center; line-height: 300px; }
+ /* TODO load from jquery.ui.popup.css */
+ .ui-popup { position: absolute; z-index: 5000; }
+
+ .ui-tooltip {
+ border: 1px solid white;
+ background: rgba(20, 20, 20, 1);
+ color: white;
+ }
+ </style>
+</head>
+<body>
+
+<div class="demo">
+
+ <div class="player">Here Be Video (HTML5?)</div>
+ <div class="tools">
+ <span class="set">
+ <button data-icon="ui-icon-circle-arrow-n" title="I like this">Like</button>
+ <button data-icon="ui-icon-circle-arrow-s">I dislike this</button>
+ </span>
+ <span class="set">
+ <button data-icon="ui-icon-circle-plus" title="Add to Watch Later">Add to</button>
+ <button class="menu" data-icon="ui-icon-triangle-1-s">Add to favorites or playlist</button>
+ </span>
+ <button title="Share this video">Share</button>
+ <button data-icon="ui-icon-alert">Flag as inappropiate</button>
+ <ul>
+ <li>
+ <a href="#">Favorites</a>
+ </li>
+ <li>
+ <a href="#">Watch Later</a>
+ </li>
+ <li>
+ <a href="#">New Playlist...</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+</div><!-- End demo -->
+
+
+
+<div class="demo-description">
+
+<p>A fake video player with like/share/stats button, each with a custom-styled tooltip.</p>
+
+</div><!-- End demo-description -->
+
+
+
+</body>
+</html>
diff --git a/tests/unit/menu/menu_core.js b/tests/unit/menu/menu_core.js
index 5b00e17e8..c0feae75c 100644
--- a/tests/unit/menu/menu_core.js
+++ b/tests/unit/menu/menu_core.js
@@ -13,23 +13,26 @@ test("accessibility", function () {
var item0 = $("li:eq(0) a");
ok( ac.hasClass("ui-menu ui-widget ui-widget-content ui-corner-all"), "menu class");
- equals( ac.attr("role"), "listbox", "main role");
+ equals( ac.attr("role"), "menu", "main role");
ok( !ac.attr("aria-activedescendant"), "aria attribute not yet active");
+
var item = ac.find( "li:first" ).find( "a" ).attr( "id", "xid" ).end();
ac.menu( "focus", $.Event(), item );
equals( ac.attr("aria-activedescendant"), "xid", "aria attribute, id from dom");
+
var item = ac.find( "li:last" );
ac.menu( "focus", $.Event(), item );
- equals( ac.attr("aria-activedescendant"), "menu1-activedescendant", "aria attribute, generated id");
+ equals( ac.attr("aria-activedescendant"), "menu1-4", "aria attribute, generated id");
});
test("items class and role", function () {
var ac = $('#menu1').menu();
- expect(1 + 4 * $("li",ac).length);
+ expect(1 + 5 * $("li",ac).length);
ok( ($("li",ac).length > 0 ), "number of menu items");
$("li",ac).each(function(item) {
ok( $(this).hasClass("ui-menu-item"), "menu item ("+ item + ") class for item");
- equals( $(this).attr("role"), "menuitem", "menu item ("+ item + ") role");
+ equals( $(this).attr("role"), "presentation", "menu item ("+ item + ") role");
+ equals( $("a", this).attr("role"), "menuitem", "menu item ("+ item + ") role");
ok( $("a",this).hasClass("ui-corner-all"), "a element class for menu item ("+ item + ") ");
equals( $("a",this).attr("tabindex"), "-1", "a element tabindex for menu item ("+ item + ") ");
});
diff --git a/tests/unit/tabs/tabs.html b/tests/unit/tabs/tabs.html
index bba0e8a58..565a0b427 100644
--- a/tests/unit/tabs/tabs.html
+++ b/tests/unit/tabs/tabs.html
@@ -34,7 +34,7 @@
panel = $( $.ui.tabs.prototype._sanitizeSelector(
"#" + tab.find( "a" ).attr( "aria-controls" ) ) ),
tabIsActive = tab.hasClass( "ui-state-active" ),
- panelIsActive = panel.is( ":visible" );
+ panelIsActive = panel.css( "display" ) !== "none";
if ( tabIsActive && panelIsActive ) {
return 1;
@@ -46,6 +46,41 @@
}).get();
same( actual, expected );
}
+
+ function tabs_disabled( tabs, state ) {
+ var expected = $.map( new Array( tabs.find ( ".ui-tabs-nav li" ).length ), function( _, index ) {
+ if ( typeof state === "boolean" ) {
+ return state ? 1 : 0;
+ } else {
+ return $.inArray( index, state ) !== -1 ? 1 : 0;
+ }
+ });
+
+ var internalState = tabs.tabs( "option", "disabled" );
+ if ( internalState === false ) {
+ internalState = [];
+ }
+ if ( internalState === true ) {
+ internalState = $.map( new Array( tabs.find( ".ui-tabs-nav li" ).length ), function( _, index ) {
+ return index;
+ });
+ }
+
+ var actual = tabs.find( ".ui-tabs-nav li" ).map(function( index ) {
+ var tab = $( this ),
+ tabIsDisabled = tab.hasClass( "ui-state-disabled" );
+
+ if ( tabIsDisabled && $.inArray( index, internalState ) !== -1 ) {
+ return 1;
+ }
+ if ( !tabIsDisabled && $.inArray( index, internalState ) === -1 ) {
+ return 0;
+ }
+ return -1; // mixed state - invalid
+ }).get();
+ same( tabs.tabs( "option", "disabled" ), state );
+ same( actual, expected );
+ }
</script>
<script>
// disable this stale testsuite for testswarm only
diff --git a/tests/unit/tabs/tabs_deprecated.html b/tests/unit/tabs/tabs_deprecated.html
index 1fb50352b..e71fea3d4 100644
--- a/tests/unit/tabs/tabs_deprecated.html
+++ b/tests/unit/tabs/tabs_deprecated.html
@@ -33,7 +33,7 @@
panel = $( $.ui.tabs.prototype._sanitizeSelector(
"#" + tab.find( "a" ).attr( "aria-controls" ) ) ),
tabIsActive = tab.hasClass( "ui-state-active" ),
- panelIsActive = panel.is( ":visible" );
+ panelIsActive = panel.css( "display" ) !== "none";
if ( tabIsActive && panelIsActive ) {
return 1;
@@ -45,6 +45,41 @@
}).get();
same( actual, expected );
}
+
+ function tabs_disabled( tabs, state ) {
+ var expected = $.map( new Array( tabs.find ( ".ui-tabs-nav li" ).length ), function( _, index ) {
+ if ( typeof state === "boolean" ) {
+ return state ? 1 : 0;
+ } else {
+ return $.inArray( index, state ) !== -1 ? 1 : 0;
+ }
+ });
+
+ var internalState = tabs.tabs( "option", "disabled" );
+ if ( internalState === false ) {
+ internalState = [];
+ }
+ if ( internalState === true ) {
+ internalState = $.map( new Array( tabs.find( ".ui-tabs-nav li" ).length ), function( _, index ) {
+ return index;
+ });
+ }
+
+ var actual = tabs.find( ".ui-tabs-nav li" ).map(function( index ) {
+ var tab = $( this ),
+ tabIsDisabled = tab.hasClass( "ui-state-disabled" );
+
+ if ( tabIsDisabled && $.inArray( index, internalState ) !== -1 ) {
+ return 1;
+ }
+ if ( !tabIsDisabled && $.inArray( index, internalState ) === -1 ) {
+ return 0;
+ }
+ return -1; // mixed state - invalid
+ }).get();
+ same( tabs.tabs( "option", "disabled" ), state );
+ same( actual, expected );
+ }
</script>
<script>
// disable this stale testsuite for testswarm only
diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js
index c221868fc..25877e69c 100644
--- a/tests/unit/tabs/tabs_deprecated.js
+++ b/tests/unit/tabs/tabs_deprecated.js
@@ -187,25 +187,6 @@ test('disable', function() {
equals(uiObj.index, 1, 'contain index');
});
-test('add', function() {
-
- // TODO move to methods, not at all event related...
-
- var el = $('<div id="tabs"><ul></ul></div>').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.");
-});
-
test('show', function() {
expect(5);
@@ -247,42 +228,108 @@ test('select', function() {
equals( evenObj.originalEvent.type, "click", "select triggered by click" );
});
-module("tabs (deprecated): methods");
-
-test('add', function() {
- expect(4);
-
- el = $('#tabs1').tabs();
- el.tabs('add', '#new', 'New');
+module( "tabs (deprecated): methods" );
- 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');
+test( "add", function() {
+ expect( 27 );
- equals($('a', added).attr('href'), '#new', 'should not expand href to full url of current page');
+ var element = $( "#tabs1" ).tabs();
+ tabs_state( element, 1, 0, 0 );
- ok(false, "missing test - untested code is broken code.");
+ // add without index
+ element.one( "tabsadd", function( event, ui ) {
+ equal( ui.index, 3, "ui.index" );
+ equal( $( ui.tab ).text(), "New", "ui.tab" );
+ equal( ui.panel.id, "new", "ui.panel" );
+ });
+ element.tabs( "add", "#new", "New" );
+ tabs_state( element, 1, 0, 0, 0 );
+ var tab = element.find( ".ui-tabs-nav li" ).last(),
+ anchor = tab.find( "a" );
+ equals( tab.text(), "New", "label" );
+ equals( anchor.attr( "href" ), "#new", "href" );
+ equals( anchor.attr( "aria-controls" ), "new", "aria-controls" );
+ ok( !tab.hasClass( "ui-state-hover" ), "not hovered" );
+ anchor.simulate( "mouseover" );
+ ok( tab.hasClass( "ui-state-hover" ), "hovered" );
+ anchor.simulate( "click" );
+ tabs_state( element, 0, 0, 0, 1 );
+
+ // add remote tab with index
+ element.one( "tabsadd", function( event, ui ) {
+ equal( ui.index, 1, "ui.index" );
+ equal( $( ui.tab ).text(), "New Remote", "ui.tab" );
+ equal( ui.panel.id, $( ui.tab ).attr( "aria-controls" ), "ui.panel" );
+ });
+ element.tabs( "add", "data/test.html", "New Remote", 1 );
+ tabs_state( element, 0, 0, 0, 0, 1 );
+ tab = element.find( ".ui-tabs-nav li" ).eq( 1 );
+ anchor = tab.find( "a" );
+ equals( tab.text(), "New Remote", "label" );
+ equals( anchor.attr( "href" ), "data/test.html", "href" );
+ ok( /^ui-tabs-\d+$/.test( anchor.attr( "aria-controls" ) ), "aria controls" );
+ ok( !tab.hasClass( "ui-state-hover" ), "not hovered" );
+ anchor.simulate( "mouseover" );
+ ok( tab.hasClass( "ui-state-hover" ), "hovered" );
+ anchor.simulate( "click" );
+ tabs_state( element, 0, 1, 0, 0, 0 );
+
+ // add to empty tab set
+ element = $( "<div><ul></ul></div>" ).tabs();
+ equals( element.tabs( "option", "active" ), false, "active: false on init" );
+ element.one( "tabsadd", function( event, ui ) {
+ equal( ui.index, 0, "ui.index" );
+ equal( $( ui.tab ).text(), "First", "ui.tab" );
+ equal( ui.panel.id, "first", "ui.panel" );
+ });
+ element.tabs( "add", "#first", "First" );
+ tabs_state( element, 1 );
+ equals( element.tabs( "option", "active" ), 0, "active: 0 after add" );
});
-test('remove', function() {
- expect(4);
+test( "#5069 - ui.tabs.add creates two tab panels when using a full URL", function() {
+ expect( 2 );
- el = $('#tabs1').tabs();
+ var element = $( "#tabs2" ).tabs();
+ equals( element.children( "div" ).length, element.find( ".ui-tabs-nav li" ).length );
+ element.tabs( "add", "/new", "New" );
+ equals( element.children( "div" ).length, element.find( ".ui-tabs-nav li" ).length );
+});
- 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');
+test( "remove", function() {
+ expect( 17 );
- // TODO delete tab -> focus tab to right
- // TODO delete last tab -> focus tab to left
+ var element = $( "#tabs1" ).tabs({ active: 1 });
+ tabs_state( element, 0, 1, 0 );
- el.tabs('select', 1);
- el.tabs('remove', 1);
- equals(el.tabs('option', 'selected'), 0, 'update selected property');
+ element.one( "tabsremove", function( event, ui ) {
+ equal( ui.index, -1, "ui.index" );
+ equal( $( ui.tab ).text(), "2", "ui.tab" );
+ equal( ui.panel.id, "fragment-2", "ui.panel" );
+ });
+ element.tabs( "remove", 1 );
+ tabs_state( element, 0, 1 );
+ equals( element.tabs( "option", "active" ), 1 );
+ equals( element.find( ".ui-tabs-nav li a[href$='fragment-2']" ).length, 0,
+ "remove correct list item" );
+ equals( element.find( "#fragment-2" ).length, 0, "remove correct panel" );
+
+ element.one( "tabsremove", function( event, ui ) {
+ equal( ui.index, -1, "ui.index" );
+ equal( $( ui.tab ).text(), "3", "ui.tab" );
+ equal( ui.panel.id, "fragment-3", "ui.panel" );
+ });
+ element.tabs( "remove", 1 );
+ tabs_state( element, 1 );
+ equals( element.tabs( "option", "active"), 0 );
+
+ element.one( "tabsremove", function( event, ui ) {
+ equal( ui.index, -1, "ui.index" );
+ equal( $( ui.tab ).text(), "1", "ui.tab" );
+ equal( ui.panel.id, "fragment-1", "ui.panel" );
+ });
+ element.tabs( "remove", 0 );
+ equals( element.tabs( "option", "active" ), false );
});
test('select', function() {
@@ -314,17 +361,6 @@ test('select', function() {
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);
-
- 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( "length", function() {
expect( 2 );
diff --git a/tests/unit/tabs/tabs_methods.js b/tests/unit/tabs/tabs_methods.js
index 7c72cd26d..361ace45b 100644
--- a/tests/unit/tabs/tabs_methods.js
+++ b/tests/unit/tabs/tabs_methods.js
@@ -17,90 +17,141 @@ test('destroy', function() {
ok( $('li:eq(2)', el).is(':not(.ui-state-hover, .ui-state-focus)'), 'remove classes from mouseovered or focused li');
});
-test('enable', function() {
- expect(8);
-
- el = $('#tabs1').tabs({ disabled: [ 0, 1 ] });
- el.tabs("enable", 1);
- ok( $('li:eq(1)', el).is(':not(.ui-state-disabled)'), 'remove class from li');
- same(el.tabs('option', 'disabled'), [ 0 ], 'update property');
-
- // enable all tabs
- el.tabs({ disabled: [ 0, 1 ] });
- el.tabs("enable");
- ok( !$('li.ui-state-disabled', el).length, 'enable all');
- same(el.tabs('option', 'disabled'), false, 'update property');
-
- el.tabs('destroy');
- // enable all tabs one by one
- el.tabs({ disabled: [ 1, 2 ] });
- el.tabs("enable", 1);
- ok( $('li:eq(1)', el).is(':not(.ui-state-disabled)'), 'remove class from li');
- same(el.tabs('option', 'disabled'), [ 2 ], 'update property');
- el.tabs("enable", 2);
- ok( $('li:eq(2)', el).is(':not(.ui-state-disabled)'), 'remove class from li');
- same( el.tabs('option', 'disabled'), false, 'set to false');
+test( "enable", function() {
+ expect( 8 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: true });
+ tabs_disabled( element, true );
+ element.tabs( "enable" );
+ tabs_disabled( element, false );
+ element.tabs( "destroy" );
+
+ element.tabs({ disabled: [ 0, 1 ] });
+ tabs_disabled( element, [ 0, 1 ] );
+ element.tabs( "enable" );
+ tabs_disabled( element, false );
});
-test('disable', function() {
- expect(12);
-
- // normal
- el = $('#tabs1').tabs();
- el.tabs('disable', 1);
- ok( $('li:eq(1)', el).is('.ui-state-disabled'), 'add class to li');
- same(el.tabs('option', 'disabled'), [ 1 ], 'update disabled property');
-
- // disable selected
- el.tabs('disable', 0);
- ok( $('li:eq(0)', el).is('.ui-state-disabled'), 'add class to selected li');
- same(el.tabs('option', 'disabled'), [ 0, 1 ], 'update disabled property');
-
- // disable all tabs
- el.tabs('disable');
- same( $('li.ui-state-disabled', el).length, 3, 'disable all');
- same(el.tabs('option', 'disabled'), true, 'set to true');
-
- el.tabs("destroy");
- // disable all tabs one by one
- el.tabs();
- el.tabs('disable', 0);
- ok( $('li:eq(0)', el).is('.ui-state-disabled'), 'add class to li');
- same(el.tabs('option', 'disabled'), [ 0 ], 'update disabled property');
- el.tabs('disable', 1);
- ok( $('li:eq(1)', el).is('.ui-state-disabled'), 'add class to li');
- same(el.tabs('option', 'disabled'), [ 0, 1 ], 'update disabled property');
- el.tabs('disable', 2);
- ok( $('li:eq(2)', el).is('.ui-state-disabled'), 'add class to li');
- same(el.tabs('option', 'disabled'), true, 'set to true');
+test( "enable( index )", function() {
+ expect( 10 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: true });
+ tabs_disabled( element, true );
+ // fully disabled -> partially disabled
+ element.tabs( "enable", 1 );
+ tabs_disabled( element, [ 0, 2 ] );
+ // partially disabled -> partially disabled
+ element.tabs( "enable", 2 );
+ tabs_disabled( element, [ 0 ] );
+ // already enabled tab, no change
+ element.tabs( "enable", 2 );
+ tabs_disabled( element, [ 0 ] );
+ // partially disabled -> fully enabled
+ element.tabs( "enable", 0 );
+ tabs_disabled( element, false );
});
-test('refresh', function() {
- expect(5);
-
- var el = $('<div id="tabs"><ul></ul></div>').tabs(),
- ul = el.find('ul');
-
- equals(el.tabs('option', 'active'), false, 'Initially empty, no active tab');
+test( "disable", function() {
+ expect( 8 );
- ul.append('<li><a href="data/test.html">Test 1</a></li>');
- el.tabs('refresh');
- equals( el.find('.ui-tabs-panel').length, 1, 'Panel created after refresh');
+ var element = $( "#tabs1" ).tabs({ disabled: false });
+ tabs_disabled( element, false );
+ element.tabs( "disable" );
+ tabs_disabled( element, true );
+ element.tabs( "destroy" );
- ul.find('li').remove();
- el.tabs('refresh');
- equals( el.find('.ui-tabs-panel').length, 0, 'Panel removed after refresh');
+ element.tabs({ disabled: [ 0, 1 ] });
+ tabs_disabled( element, [ 0, 1 ] );
+ element.tabs( "disable" );
+ tabs_disabled( element, true );
+});
- ul.append('<li><a href="#test1">Test 1</a></li>');
- $('<div id="test1">Test Panel 1</div>').insertAfter( ul );
- el.tabs('refresh');
- el.tabs('option', 'active', 0);
- equals( el.tabs('option', 'active'), 0, 'First tab added should be auto active');
+test( "disable( index )", function() {
+ expect( 10 );
+
+ var element = $( "#tabs1" ).tabs({ disabled: false });
+ tabs_disabled( element, false );
+ // fully enabled -> partially disabled
+ element.tabs( "disable", 1 );
+ tabs_disabled( element, [ 1 ] );
+ // partially disabled -> partially disabled
+ element.tabs( "disable", 2 );
+ tabs_disabled( element, [ 1, 2 ] );
+ // already disabled tab, no change
+ element.tabs( "disable", 2 );
+ tabs_disabled( element, [ 1, 2 ] );
+ // partially disabled -> fully disabled
+ element.tabs( "disable", 0 );
+ tabs_disabled( element, true );
+});
- ul.append('<li><a href="#test2">Test 2</a></li>');
- $('<div id="test2">Test Panel 2</div>').insertAfter( ul );
- el.tabs('refresh');
- equals( el.tabs('option', 'active'), 0, 'Second tab added should not be auto active');
+test( "refersh", function() {
+ expect( 27 );
+
+ var element = $( "#tabs1" ).tabs();
+ tabs_state( element, 1, 0, 0 );
+ tabs_disabled( element, false );
+
+ // disable tab via markup
+ element.find( ".ui-tabs-nav li" ).eq( 1 ).addClass( "ui-state-disabled" );
+ element.tabs( "refresh" );
+ tabs_state( element, 1, 0, 0 );
+ tabs_disabled( element, [ 1 ] );
+
+ // add remote tab
+ element.find( ".ui-tabs-nav" ).append( "<li id='newTab'><a href='data/test.html'>new</a></li>" );
+ element.tabs( "refresh" );
+ tabs_state( element, 1, 0, 0, 0 );
+ tabs_disabled( element, [ 1 ] );
+ equals( element.find( "#" + $( "#newTab a" ).attr( "aria-controls" ) ).length, 1,
+ "panel added for remote tab" );
+
+ // remove all tabs
+ element.find( ".ui-tabs-nav li, .ui-tabs-panel" ).remove();
+ element.tabs( "refresh" );
+ tabs_state( element );
+ equals( element.tabs( "option", "active" ), false, "no active tab" );
+
+ // add tabs
+ element.find( ".ui-tabs-nav" )
+ .append( "<li class='ui-state-disabled'><a href='#newTab2'>new 2</a></li>" )
+ .append( "<li><a href='#newTab3'>new 3</a></li>" )
+ .append( "<li><a href='#newTab4'>new 4</a></li>" )
+ .append( "<li><a href='#newTab5'>new 5</a></li>" );
+ element
+ .append( "<div id='newTab2'>new 2</div>" )
+ .append( "<div id='newTab3'>new 3</div>" )
+ .append( "<div id='newTab4'>new 4</div>" )
+ .append( "<div id='newTab5'>new 5</div>" );
+ element.tabs( "refresh" );
+ tabs_state( element, 0, 0, 0, 0 );
+ tabs_disabled( element, [ 0 ] );
+
+ // activate third tab
+ element.tabs( "option", "active", 2 );
+ tabs_state( element, 0, 0, 1, 0 );
+ tabs_disabled( element, [ 0 ] );
+
+ // remove fourth tab, third tab should stay active
+ element.find( ".ui-tabs-nav li" ).eq( 3 ).remove();
+ element.find( ".ui-tabs-panel" ).eq( 3 ).remove();
+ element.tabs( "refresh" );
+ tabs_state( element, 0, 0, 1 );
+ tabs_disabled( element, [ 0 ] );
+
+ // remove third (active) tab, second tab should become active
+ element.find( ".ui-tabs-nav li" ).eq( 2 ).remove();
+ element.find( ".ui-tabs-panel" ).eq( 2 ).remove();
+ element.tabs( "refresh" );
+ tabs_state( element, 0, 1 );
+ tabs_disabled( element, [ 0 ] );
+
+ // remove first tab, previously active tab (now first) should stay active
+ element.find( ".ui-tabs-nav li" ).eq( 0 ).remove();
+ element.find( ".ui-tabs-panel" ).eq( 0 ).remove();
+ element.tabs( "refresh" );
+ tabs_state( element, 1 );
+ tabs_disabled( element, false );
});
test('load', function() {
diff --git a/tests/unit/testsuite.js b/tests/unit/testsuite.js
index 4b273ce78..c1f394ed9 100644
--- a/tests/unit/testsuite.js
+++ b/tests/unit/testsuite.js
@@ -75,6 +75,10 @@ window.domEqual = function( selector, modifier, message ) {
var attributes = ["class", "role", "id", "tabIndex", "aria-activedescendant"];
function extract(value) {
+ if (!value || !value.length) {
+ QUnit.push( false, actual, expected, "domEqual failed, can't extract " + selector + ", message was: " + message );
+ return;
+ }
var result = {};
result.nodeName = value[0].nodeName;
$.each(attributes, function(index, attr) {
diff --git a/tests/unit/tooltip/tooltip.html b/tests/unit/tooltip/tooltip.html
index ee4e92723..189c75261 100644
--- a/tests/unit/tooltip/tooltip.html
+++ b/tests/unit/tooltip/tooltip.html
@@ -39,7 +39,7 @@
<div>
<a id="tooltipped1" href="#" title="anchortitle">anchor</a>
<input title="inputtitle" />
- <span data-tooltip="text">span</span>
+ <span id="fixture-span" data-tooltip="text">span</span>
</div>
</div>
diff --git a/tests/unit/tooltip/tooltip_defaults.js b/tests/unit/tooltip/tooltip_defaults.js
index c1fc49f1a..5f304f497 100644
--- a/tests/unit/tooltip/tooltip_defaults.js
+++ b/tests/unit/tooltip/tooltip_defaults.js
@@ -4,10 +4,10 @@ commonWidgetTests( "tooltip", {
items: "[title]",
content: $.ui.tooltip.prototype.options.content,
position: {
- my: "left center",
- at: "right center",
- offset: "15 0"
+ my: "left+15 center",
+ at: "right center"
},
+ tooltipClass: null,
// callbacks
create: null
diff --git a/tests/unit/tooltip/tooltip_events.js b/tests/unit/tooltip/tooltip_events.js
index 35620df47..5c915ae30 100644
--- a/tests/unit/tooltip/tooltip_events.js
+++ b/tests/unit/tooltip/tooltip_events.js
@@ -28,10 +28,10 @@ test("mouse events", function() {
},
close: function(event, ui) {
same( event.type, "tooltipclose" );
- same( event.originalEvent.type, "mouseout" );
+ same( event.originalEvent.type, "mouseleave" );
}
});
- e.trigger("mouseover").trigger("mouseout");
+ e.trigger("mouseover").trigger("mouseleave");
e.tooltip("destroy");
});
@@ -40,7 +40,7 @@ test("focus events", function() {
var e = $("#tooltipped1").tooltip({
open: function(event, ui) {
same( event.type, "tooltipopen" );
- same( event.originalEvent.type, "focus" );
+ same( event.originalEvent.type, "focusin" );
},
close: function(event, ui) {
same( event.type, "tooltipclose" );
diff --git a/tests/unit/tooltip/tooltip_methods.js b/tests/unit/tooltip/tooltip_methods.js
index ace1a1288..496a5fdb7 100644
--- a/tests/unit/tooltip/tooltip_methods.js
+++ b/tests/unit/tooltip/tooltip_methods.js
@@ -14,17 +14,20 @@ test("destroy", function() {
test("open", function() {
var e = $("#tooltipped1").tooltip();
- ok( $(".ui-tooltip").is(":hidden") );
e.tooltip("open");
ok( $(".ui-tooltip").is(":visible") );
$(":ui-tooltip").tooltip("destroy");
});
+/*
+TODO currently tooltip doesn't override widget
+can't return anything useful if no element is kept around and there's no useful reference
test("widget", function() {
var tooltip = $("#tooltipped1").tooltip();
same(tooltip.tooltip("widget")[0], $(".ui-tooltip")[0]);
same(tooltip.tooltip("widget").end()[0], tooltip[0]);
});
+*/
})(jQuery);
diff --git a/tests/unit/tooltip/tooltip_options.js b/tests/unit/tooltip/tooltip_options.js
index ea4b14229..37a468489 100644
--- a/tests/unit/tooltip/tooltip_options.js
+++ b/tests/unit/tooltip/tooltip_options.js
@@ -19,12 +19,12 @@ test("option: items", function() {
return $(this).attr("data-tooltip");
}
}).tooltip("open", event);
- same( $(".ui-tooltip").text(), "text" );
+ same( $( "#" + $("#fixture-span").attr("aria-describedby") ).text(), "text" );
});
test("content: default", function() {
$("#tooltipped1").tooltip().tooltip("open");
- same( $(".ui-tooltip").text(), "anchortitle" );
+ same( $( "#" + $("#tooltipped1").attr("aria-describedby") ).text(), "anchortitle" );
});
test("content: return string", function() {
@@ -33,7 +33,7 @@ test("content: return string", function() {
return "customstring";
}
}).tooltip("open");
- same( $(".ui-tooltip").text(), "customstring" );
+ same( $( "#" + $("#tooltipped1").attr("aria-describedby") ).text(), "customstring" );
});
test("content: return jQuery", function() {
@@ -42,21 +42,25 @@ test("content: return jQuery", function() {
return $("<div></div>").html("cu<b>s</b>tomstring");
}
}).tooltip("open");
- same( $(".ui-tooltip").text(), "customstring" );
+ same( $( "#" + $("#tooltipped1").attr("aria-describedby") ).text(), "customstring" );
});
+/*
+TODO broken, probably related to async content
test("content: callback string", function() {
stop();
$("#tooltipped1").tooltip({
content: function(response) {
response("customstring2");
setTimeout(function() {
- same( $(".ui-tooltip").text(), "customstring2" );
+ //console.log($("#tooltipped1").attr("aria-describedby"))
+ same( $( "#" + $("#tooltipped1").attr("aria-describedby") ).text(), "customstring2" );
start();
}, 100)
}
}).tooltip("open");
});
+*/
})(jQuery);
diff --git a/tests/visual/tooltip/animations.html b/tests/visual/tooltip/animations.html
new file mode 100644
index 000000000..f0deac1d3
--- /dev/null
+++ b/tests/visual/tooltip/animations.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <title>Tooltip Visual Test: Default</title>
+ <link rel="stylesheet" href="../visual.css" type="text/css" />
+ <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css" type="text/css">
+ <script type="text/javascript" src="../../../jquery-1.5.1.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.ui.button.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.ui.tooltip.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.effects.core.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.effects.blind.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.effects.bounce.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.effects.drop.js"></script>
+ <script type="text/javascript" src="../../../ui/jquery.effects.explode.js"></script>
+ <!--
+ <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script>
+ -->
+ <script type="text/javascript">
+ $(function() {
+ var animations = [{}, {
+ show: {
+ effect: "slideDown"
+ },
+ hide: {
+ effect: "slideUp"
+ }
+ }, {
+ show: {
+ effect: "explode"
+ },
+ hide: {
+ effect: "explode"
+ }
+ }, {
+ show: {
+ effect: "bounce"
+ },
+ hide: {
+ effect: "blind"
+ }
+ },
+ {
+ show: {
+ effect: "drop",
+ direction: "right"
+ },
+ hide: {
+ effect: "drop",
+ direction: "right"
+ }
+ }];
+ $.each(animations, function(index, animation) {
+ var text = JSON.stringify(animation);
+ $("<span></span>").attr("title", text).text(text).tooltip({
+ show: animation.show,
+ hide: animation.hide
+ }).wrap("<li></li>").parent().appendTo("ul");
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div style="width:300px">
+ <ul class="ui-widget ui-widget-header">
+ </ul>
+</div>
+</body>
+</html>
diff --git a/themes/base/jquery.ui.resizable.css b/themes/base/jquery.ui.resizable.css
index 05f855a71..2c1de870e 100644
--- a/themes/base/jquery.ui.resizable.css
+++ b/themes/base/jquery.ui.resizable.css
@@ -12,7 +12,7 @@
/* http://bugs.jqueryui.com/ticket/7233
- Resizable: resizable handles fail to work in IE if transparent and content overlaps
*/
- background-image:url(data:);
+ background-image:url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=);
}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
diff --git a/ui/jquery.ui.core.js b/ui/jquery.ui.core.js
index 51f6b71d7..8bcc4c441 100644
--- a/ui/jquery.ui.core.js
+++ b/ui/jquery.ui.core.js
@@ -174,6 +174,27 @@ $.each( [ "Width", "Height" ], function( i, name ) {
});
// selectors
+function focusable( element, isTabIndexNotNaN ) {
+ var nodeName = element.nodeName.toLowerCase();
+ if ( "area" === nodeName ) {
+ var map = element.parentNode,
+ mapName = map.name,
+ img;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName )
+ ? !element.disabled
+ : "a" == nodeName
+ ? element.href || isTabIndexNotNaN
+ : isTabIndexNotNaN)
+ // the element and all of its ancestors must be visible
+ && visible( element );
+}
+
function visible( element ) {
return !$( element ).parents().andSelf().filter(function() {
return $.curCSS( this, "visibility" ) === "hidden" ||
@@ -187,30 +208,13 @@ $.extend( $.expr[ ":" ], {
},
focusable: function( element ) {
- var nodeName = element.nodeName.toLowerCase(),
- tabIndex = $.attr( element, "tabindex" );
- if ( "area" === nodeName ) {
- var map = element.parentNode,
- mapName = map.name,
- img;
- if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
- return false;
- }
- img = $( "img[usemap=#" + mapName + "]" )[0];
- return !!img && visible( img );
- }
- return ( /input|select|textarea|button|object/.test( nodeName )
- ? !element.disabled
- : "a" == nodeName
- ? element.href || !isNaN( tabIndex )
- : !isNaN( tabIndex ))
- // the element and all of its ancestors must be visible
- && visible( element );
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
},
tabbable: function( element ) {
- var tabIndex = $.attr( element, "tabindex" );
- return ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( ":focusable" );
+ var tabIndex = $.attr( element, "tabindex" ),
+ isTabIndexNaN = isNaN( tabIndex );
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
}
});
diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js
index cc27365d3..3437d0bda 100644
--- a/ui/jquery.ui.datepicker.js
+++ b/ui/jquery.ui.datepicker.js
@@ -16,6 +16,7 @@ $.extend($.ui, { datepicker: { version: "@VERSION" } });
var PROP_NAME = 'datepicker';
var dpuuid = new Date().getTime();
+var instActive;
/* Date picker manager.
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
@@ -107,7 +108,7 @@ function Datepicker() {
autoSize: false // True to size the input for the date format, false to leave as is
};
$.extend(this._defaults, this.regional['']);
- this.dpDiv = $('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>');
+ this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
}
$.extend(Datepicker.prototype, {
@@ -173,7 +174,7 @@ $.extend(Datepicker.prototype, {
drawMonth: 0, drawYear: 0, // month being drawn
inline: inline, // is datepicker inline or not
dpDiv: (!inline ? this.dpDiv : // presentation div
- $('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))};
+ bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))};
},
/* Attach the date picker to an input field. */
@@ -674,29 +675,13 @@ $.extend(Datepicker.prototype, {
_updateDatepicker: function(inst) {
var self = this;
var borders = $.datepicker._getBorders(inst.dpDiv);
+ instActive = inst; // for delegate hover events
inst.dpDiv.empty().append(this._generateHTML(inst));
var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
}
- inst.dpDiv.find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a')
- .bind('mouseout', function(){
- $(this).removeClass('ui-state-hover');
- if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
- if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
- })
- .bind('mouseover', function(){
- if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) {
- $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
- $(this).addClass('ui-state-hover');
- if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
- if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
- }
- })
- .end()
- .find('.' + this._dayOverClass + ' a')
- .trigger('mouseover')
- .end();
+ inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
var numMonths = this._getNumberOfMonths(inst);
var cols = numMonths[1];
var width = 17;
@@ -1719,6 +1704,28 @@ $.extend(Datepicker.prototype, {
}
});
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function bindHover(dpDiv) {
+ var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
+ return dpDiv.delegate(selector, 'mouseout', function() {
+ $(this).removeClass('ui-state-hover');
+ if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover');
+ if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover');
+ })
+ .delegate(selector, 'mouseover', function(){
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
+ $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
+ $(this).addClass('ui-state-hover');
+ if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover');
+ if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover');
+ }
+ });
+}
+
/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
$.extend(target, props);
diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js
index d4ee9984f..7946cc667 100755
--- a/ui/jquery.ui.tabs.js
+++ b/ui/jquery.ui.tabs.js
@@ -81,7 +81,7 @@ $.widget( "ui.tabs", {
options.active = active;
// don't allow collapsible: false and active: false
- if ( !options.collapsible && options.active === false ) {
+ if ( !options.collapsible && options.active === false && this.anchors.length ) {
options.active = 0;
}
@@ -130,13 +130,26 @@ $.widget( "ui.tabs", {
return;
}
+ if ( key === "disabled" ) {
+ // don't use the widget factory's disabled handling
+ this._setupDisabled( value );
+ return;
+ }
+
+ this._super( "_setOption", key, value);
+
// setting collapsible: false while collapsed; open first panel
if ( key === "collapsible" && !value && this.options.active === false ) {
this._activate( 0 );
}
- this.options[ key ] = value;
- this.refresh();
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "fx" ) {
+ this._setupFx( value );
+ }
},
_tabId: function( a ) {
@@ -157,39 +170,45 @@ $.widget( "ui.tabs", {
},
refresh: function() {
- var self = this;
+ var self = this,
+ options = this.options,
+ lis = this.list.children( ":has(a[href])" );
- this._processTabs();
+ // get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ });
+ this._processTabs();
this._refresh();
+ this.panels.not( this._getPanelForTab( this.active ) ).hide();
- // 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( "[aria-controls='" + panel.id + "']");
- if ( !anchor.length ) {
- $( panel ).remove();
- }
- });
+ // was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.list[ 0 ], this.active[ 0 ] ) ) {
+ // activate previous tab
+ var next = options.active - 1;
+ this._activate( next >= 0 ? next : 0 );
+ // was active, active tab still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.anchors.index( this.active );
+ }
},
_refresh: function() {
- var that = this,
- options = that.options;
+ var options = this.options;
this.element.toggleClass( "ui-tabs-collapsible", options.collapsible );
- this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header 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" );
- if ( !options.disabled.length ) {
- options.disabled = false;
- }
-
- // disable tabs
- for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
- $( li ).toggleClass( "ui-state-disabled", $.inArray( i, options.disabled ) !== -1 );
- }
-
+ this._setupDisabled( options.disabled );
this._setupEvents( options.event );
// remove all handlers, may run on existing tabs
@@ -260,6 +279,23 @@ $.widget( "ui.tabs", {
.data( "destroy.tabs", true );
},
+ _setupDisabled: function( disabled ) {
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // disable tabs
+ for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
+ $( li ).toggleClass( "ui-state-disabled", ( disabled === true || $.inArray( i, disabled ) !== -1 ) );
+ }
+
+ this.options.disabled = disabled;
+ },
+
_setupFx: function( fx ) {
// set up animations
if ( fx ) {
@@ -502,53 +538,48 @@ $.widget( "ui.tabs", {
},
enable: function( index ) {
- if ( index === undefined ) {
- for ( var i = 0, len = this.lis.length; i < len; i++ ) {
- this.enable( i );
- }
- return this;
- }
- index = this._getIndex( index );
- var o = this.options;
- if ( !o.disabled || ($.isArray( o.disabled ) && $.inArray( index, o.disabled ) == -1 ) ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
return;
}
- this.lis.eq( index ).removeClass( "ui-state-disabled" );
- o.disabled = this.lis.map( function( i ) {
- return $(this).is( ".ui-state-disabled" ) ? i : null;
- }).get();
-
- if ( !o.disabled.length ) {
- o.disabled = false;
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ });
+ } else {
+ disabled = $.map( this.lis, function( li, num ) {
+ return num !== index ? num : null;
+ });
+ }
}
-
- return this;
+ this._setupDisabled( disabled );
},
disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
if ( index === undefined ) {
- for ( var i = 0, len = this.lis.length; i < len; i++ ) {
- this.disable( i );
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
}
- return this;
- }
- index = this._getIndex( index );
- var o = this.options;
- if ( !o.disabled || ($.isArray( o.disabled ) && $.inArray( index, o.disabled ) == -1 ) ) {
- this.lis.eq( index ).addClass( "ui-state-disabled" );
-
- o.disabled = this.lis.map( function( i ) {
- return $(this).is( ".ui-state-disabled" ) ? i : null;
- }).get();
-
- if ( o.disabled.length === this.anchors.length ) {
- o.disabled = true;
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
}
-
}
-
- return this;
+ this._setupDisabled( disabled );
},
load: function( index, event ) {
@@ -795,43 +826,38 @@ if ( $.uiBackCompat !== false ) {
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 ] );
+ var options = this.options,
+ li = $( options.tabTemplate
+ .replace( /#\{href\}/g, url )
+ .replace( /#\{label\}/g, label ) ),
+ id = !url.indexOf( "#" ) ?
+ url.replace( "#", "" ) :
+ this._tabId( li.find( "a" )[ 0 ] );
- $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );
+ li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );
+ li.find( "a" ).attr( "aria-controls", id );
// try to find an existing element before creating a new one
- var $panel = self.element.find( "#" + id );
- if ( !$panel.length ) {
- $panel = self._createPanel( id );
+ var panel = this.element.find( "#" + id );
+ if ( !panel.length ) {
+ panel = this._createPanel( id );
}
- $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide();
+ panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide();
if ( index >= this.lis.length ) {
- $li.appendTo( this.list );
- $panel.appendTo( this.list[ 0 ].parentNode );
+ li.appendTo( this.list );
+ panel.appendTo( this.list[ 0 ].parentNode );
} else {
- $li.insertBefore( this.lis[ index ] );
- $panel.insertBefore( this.panels[ index ] );
+ li.insertBefore( this.lis[ index ] );
+ panel.insertBefore( this.panels[ index ] );
}
-
- o.disabled = $.map( o.disabled, function( n, i ) {
+ options.disabled = $.map( options.disabled, function( n ) {
return n >= index ? ++n : n;
});
this.refresh();
-
- if ( this.anchors.length == 1 ) {
- o.active = o.selected = 0;
- $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 ] ) );
- });
-
- this.load( 0 );
+ if ( this.lis.length === 1 && options.active === false ) {
+ this.option( "active", 0 );
}
this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
@@ -840,27 +866,27 @@ if ( $.uiBackCompat !== false ) {
prototype.remove = function( index ) {
index = this._getIndex( index );
- var o = this.options,
- $li = this.lis.eq( index ).remove(),
- $panel = this.panels.eq( index ).remove();
+ var options = this.options,
+ tab = 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-active" ) && this.anchors.length > 1) {
+ if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 1) {
this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
}
- o.disabled = $.map(
- $.grep( o.disabled, function(n, i) {
- return n != index;
+ options.disabled = $.map(
+ $.grep( options.disabled, function( n ) {
+ return n !== index;
}),
- function( n, i ) {
+ function( n ) {
return n >= index ? --n : n;
});
this.refresh();
- this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
+ this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) );
return this;
};
}( jQuery, jQuery.ui.tabs.prototype ) );
diff --git a/ui/jquery.ui.tooltip.js b/ui/jquery.ui.tooltip.js
index 534b3c947..20638cba5 100644
--- a/ui/jquery.ui.tooltip.js
+++ b/ui/jquery.ui.tooltip.js
@@ -24,9 +24,8 @@ $.widget("ui.tooltip", {
return $( this ).attr( "title" );
},
position: {
- my: "left center",
- at: "right center",
- offset: "15 0"
+ my: "left+15 center",
+ at: "right center"
}
},
_create: function() {
@@ -90,8 +89,8 @@ $.widget("ui.tooltip", {
of: target
}, this.options.position ) ).hide();
-
- tooltip.fadeIn();
+ tooltip.stop( true );
+ this._show( tooltip, this.options.show );
this._trigger( "open", event );
@@ -111,7 +110,8 @@ $.widget("ui.tooltip", {
var tooltip = this._find( target );
target.removeAttr( "aria-describedby" );
- tooltip.fadeOut( function() {
+ tooltip.stop( true );
+ this._hide( tooltip, this.options.hide, function() {
$( this ).remove();
});
diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js
index 55b9f7984..a74e6b77b 100644
--- a/ui/jquery.ui.widget.js
+++ b/ui/jquery.ui.widget.js
@@ -356,11 +356,35 @@ $.Widget.prototype = {
}
};
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ options = options || {};
+ var hasOptions = !$.isEmptyObject( options ),
+ effectName = options.effect || defaultEffect;
+ options.complete = callback;
+ if (options.delay) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue( function() {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ });
+ }
+ };
+});
+
// DEPRECATED
if ( $.uiBackCompat !== false ) {
$.Widget.prototype._getCreateOptions = function() {
return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
- }
+ };
}
})( jQuery );