diff --git a/AUTHORS.txt b/AUTHORS.txt index 1521874ce45..bf1554481da 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -282,3 +282,15 @@ Will Holley Uri Gilad Richard Gibson Simen Bekkhus +Chen Eshchar +Bruno Pérel +Mohammed Alshehri +Anne-Gaelle Colom +Adam Foster +Luke Page +Marcus Warren +Patricia Juarez +Ben Mosher +Ablay Keldibek +Nils Heuermann +Marco Ziech diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d694c99cfc..8c1ceb034ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,68 +16,83 @@ This is the best way to contribute to jQuery UI. Please read through the full gu Every week (unless otherwise noted) the jQuery UI team has a meeting to discuss the progress of current work and to bring forward possible new blockers for discussion. The meeting is held on [IRC](http://irc.jquery.org) in the #jquery-meeting channel at [Noon EST](http://www.timeanddate.com/worldclock/fixedtime.html?month=1&day=17&year=2011&hour=12&min=0&sec=0&p1=43) on Wednesdays. Meeting notes are posted on http://meetings.jquery.org/category/ui/ after each meeting. -## Tips For Bug Patching +## Tips for Getting Started -### Environment: localhost w/ PHP, Node.js & Grunt +### Environment: Minimum Required -jQuery UI uses Node.js & Grunt to automate the building and validation of source code. +If you are contributing changes you will need a fork of jquery-ui (see [Getting the Source](#environment-getting-the-source)). If you just want the source code you could clone jquery-ui directly: -Some tests depend on PHP running locally, so make sure you have the following installed: - -* A web server with PHP support (any will do, such as [XAMPP](http://www.apachefriends.org/en/xampp.html) or [MAMP](http://www.mamp.info/en/index.html)) -* [Node.js](http://nodejs.org/) (includes NPM, necessary for the next step) -* Grunt (install with: `npm install -g grunt`) +```bash +git clone git://github.com/jquery/jquery-ui.git +cd jquery-ui +``` -### Build a Local Copy of jQuery UI +The tests can run in any local web server. Ideally you should test your patch in appropriate web browsers and if possible run `grunt` to lint the code and run automated tests (this will happen automatically when you create a pull request). See the [Recommended Setup](#environment-recommended-setup) for setting up Node.js so that the grunt command works. -Create a fork of the jQuery UI repo on GitHub at http://github.com/jquery/jquery-ui. +### Environment: Getting the Source -Change directory to your web root directory, whatever that might be: +* Create a fork of the jQuery UI repo on GitHub at http://github.com/jquery/jquery-ui. This will create a fork of jquery-ui in your Github account. +* You may want to clone jquery-ui under the path to your web server. If so, change to the required directory ```bash -$ cd /path/to/your/www/root/ +cd /path/to/your/www/root/ ``` -Clone your jQuery UI fork to work locally. - -*Note: be sure to replace `[USERNAME]` with your GitHub username.* +* Clone your jQuery UI git repo. ```bash -$ git clone git@github.com:[USERNAME]/jquery-ui.git +git clone git://github.com/[USERNAME]/jquery-ui.git +cd jquery-ui ``` -Change to the newly created directory. +*Note: be sure to replace `[USERNAME]` with your GitHub username.* + +* Add the official jQuery repository as a remote. We recommend naming it "upstream". ```bash -$ cd jquery-ui +git remote add upstream git://github.com/jquery/jquery-ui.git ``` -Add the official jQuery repository as a remote. We recommend naming it "upstream". +* Get in the habit of pulling in the "upstream" master to stay up to date as jQuery UI receives new commits. ```bash -$ git remote add upstream git://github.com/jquery/jquery-ui.git +git pull upstream master ``` -Get in the habit of pulling in the "upstream" master to stay up to date as jQuery UI receives new commits. +### Environment: Recommended Setup + +jQuery UI uses Node.js & Grunt to automate the building and validation of source code. Here is how to set that up: + +* Get [Node.js](http://nodejs.org/) (includes NPM, necessary for the next step) +* Install Grunt cli: ```bash -$ git pull upstream master +npm install -g grunt-cli ``` -Install the dependencies. +* Install local Node.js modules ```bash npm install ``` +The tests require a local web server and the samples contain some PHP, so a PHP web server may be useful. + +* Install a web server. Here are some you could use: + * Windows: [WAMP download](http://www.wampserver.com/en/) + * Mac: [MAMP download](http://www.mamp.info/en/index.html) + * Linux: [Setting up LAMP](https://www.linux.com/learn/tutorials/288158-easy-lamp-server-installation) + * [Mongoose (most platforms)](http://code.google.com/p/mongoose/) + * [http-server](https://www.npmjs.com/package/http-server) + +### Running the Tests + To lint the JavaScript, HTML, and CSS, as well as run a smoke test in PhantomJS, run grunt: ```bash -$ grunt +grunt ``` To run the tests for a specific plugin in your browser, open the appropriate file from the `/tests/unit/` directory, for example: `http://localhost/tests/unit/accordion/accordion.html`. The domain will be dependent on your local server configuration; if there is a port, be sure to include it. Ideally you would test in all of our [supported browsers](http://jqueryui.com/browser-support/), but if you don't have all of these browsers available, that's ok. - -Make sure to read our [commits and pull requests documentation](http://dev.contribute.jquery.org/commits-and-pull-requests/) for full details on working with branches and forks, as well as our commit guidelines. diff --git a/Gruntfile.js b/Gruntfile.js index 72236561f59..88919152a86 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -119,7 +119,7 @@ function createBanner( files ) { "<%= grunt.template.today('isoDate') %>\n" + "<%= pkg.homepage ? '* ' + pkg.homepage + '\\n' : '' %>" + (files ? "* Includes: " + fileNames.join(", ") + "\n" : "") + - "* Copyright <%= grunt.template.today('yyyy') %> <%= pkg.author.name %>;" + + "* Copyright <%= pkg.author.name %>;" + " Licensed <%= _.pluck(pkg.licenses, 'type').join(', ') %> */\n"; } @@ -302,7 +302,10 @@ grunt.initConfig({ "jquery-2.0.2/MIT-LICENSE.txt": "jquery-2.0.2/MIT-LICENSE.txt", "jquery-2.0.3/jquery.js": "jquery-2.0.3/jquery.js", - "jquery-2.0.3/MIT-LICENSE.txt": "jquery-2.0.3/MIT-LICENSE.txt" + "jquery-2.0.3/MIT-LICENSE.txt": "jquery-2.0.3/MIT-LICENSE.txt", + + "jquery-3.0.0/jquery.js": "jquery-3.0.0/dist/jquery.js", + "jquery-3.0.0/LICENSE.txt": "jquery-3.0.0/LICENSE.txt" } } } diff --git a/LICENSE.txt b/LICENSE.txt index 156f8d5caaf..4819e54213f 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,4 @@ -Copyright 2007, 2014 jQuery Foundation and other contributors, -https://jquery.org/ +Copyright jQuery Foundation and other contributors, https://jquery.org/ This software consists of voluntary contributions made by many individuals. For exact contribution history, see the revision history diff --git a/README.md b/README.md index edd49ab7baa..a09a065dd99 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ If you are interested in helping develop jQuery UI, you are in the right place. To discuss development with team members and the community, visit the [Developing jQuery UI Forum](http://forum.jquery.com/developing-jquery-ui) or [#jqueryui-dev on irc.freenode.net](http://irc.jquery.org/). -## For contributors +## For Contributors If you want to help and provide a patch for a bugfix or new feature, please take a few minutes and look at [our Getting Involved guide](http://wiki.jqueryui.com/w/page/35263114/Getting-Involved). @@ -21,35 +21,21 @@ In general, fork the project, create a branch for a specific change and send a pull request for that branch. Don't mix unrelated changes. You can use the commit message as the description for the pull request. +For more information, see the [contributing page](CONTRIBUTING.md). ## Running the Unit Tests -Run the unit tests with a local server that supports PHP. No database is required. Pre-configured php local servers are available for Windows and Mac. Here are some options: - -- Windows: [WAMP download](http://www.wampserver.com/en/) -- Mac: [MAMP download](http://www.mamp.info/en/index.html) -- Linux: [Setting up LAMP](https://www.linux.com/learn/tutorials/288158-easy-lamp-server-installation) -- [Mongoose (most platforms)](http://code.google.com/p/mongoose/) +Run the unit tests manually with appropriate browsers and any local web server. See our [environment setup](CONTRIBUTING.md#environment-minimum-required) and [information on running tests](CONTRIBUTING.md#running-the-tests). +You can also run the unit tests inside phantomjs by [setting up your environment](CONTRIBUTING.md#user-content-environment-recommended-setup). ## Building jQuery UI -jQuery UI uses the [Grunt](http://github.com/gruntjs/grunt) build system. +jQuery UI uses the [Grunt](http://gruntjs.com/) build system. -To build jQuery UI, you must have [node.js](http://nodejs.org/) installed and then run the following commands: +To build jQuery UI, [set up your environment](CONTRIBUTING.md#environment-minimum-required) and then run the following commands: ```sh - -# Install the Grunt CLI -npm install -g grunt-cli - -# Clone the jQuery UI git repo -git clone git://github.com/jquery/jquery-ui.git -cd jquery-ui - -# Install the node module dependencies -npm install - # Run the concat task to concatenate files grunt concat diff --git a/bower.json b/bower.json index 6067e9512f5..4c84426c262 100644 --- a/bower.json +++ b/bower.json @@ -37,6 +37,7 @@ "jquery-2.0.0": "jquery#2.0.0", "jquery-2.0.1": "jquery#2.0.1", "jquery-2.0.2": "jquery#2.0.2", - "jquery-2.0.3": "jquery#2.0.3" + "jquery-2.0.3": "jquery#2.0.3", + "jquery-3.0.0": "jquery#3.0.0" } } diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index aa1c52abc53..32d93756cb0 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -4,7 +4,7 @@ module.exports = function( grunt ) { var versions = { "git": "git", - "1.10": "1.10.0 1.10.1 1.10.2", + "1.10": "1.10.0 1.10.2", "1.9": "1.9.0 1.9.1", "1.8": "1.8.0 1.8.1 1.8.2 1.8.3", "1.7": "1.7.0 1.7.1 1.7.2", @@ -61,7 +61,7 @@ function submit( commit, runs, configFile, extra, done ) { name: "Commit " + commit.substr( 0, 10 ) + "" + extra, runs: runs, runMax: config.runMax, - browserSets: [ "popular-ui" ], + browserSets: config.browserSets, timeout: 1000 * 60 * 30 }, function( error, passed ) { if ( error ) { diff --git a/demos/autocomplete/search.php b/demos/autocomplete/search.php index 835772deea8..04bda422423 100644 --- a/demos/autocomplete/search.php +++ b/demos/autocomplete/search.php @@ -368,7 +368,6 @@ "Glossy Ibis"=>"Plegadis falcinellus", "Spanish Imperial Eagle"=>"Aquila adalberti", "Lesser Kestrel"=>"Falco naumanni", -"Houbara Bustard"=>"Chlamydotis undulata", "Crab-Plover"=>"Dromas ardeola", "Cream-coloured Courser"=>"Cursorius cursor", "Collared Pratincole"=>"Glareola pratincola", diff --git a/demos/effect/easing.html b/demos/effect/easing.html index aa5bccbc6f5..c70786d7309 100644 --- a/demos/effect/easing.html +++ b/demos/effect/easing.html @@ -96,7 +96,7 @@
-

All easings provided by jQuery UI are drawn above, using a HTML canvas element. Click a diagram to see the easing in action.

+

All easings provided by jQuery UI are drawn above, using an HTML canvas element. Click a diagram to see the easing in action.

diff --git a/demos/sortable/empty-lists.html b/demos/sortable/empty-lists.html index 6d8f6565b2d..1925446195a 100644 --- a/demos/sortable/empty-lists.html +++ b/demos/sortable/empty-lists.html @@ -11,7 +11,7 @@ @@ -134,6 +138,19 @@

Drums

+
+
+

Header

+
+

+ The calculated height of this accordion should be the same + regardless of whether the accordion was collapsed or not + when the height was calculated. +

+
+
+
+ diff --git a/tests/unit/accordion/accordion_core.js b/tests/unit/accordion/accordion_core.js index 8e0175aeb93..721d1548751 100644 --- a/tests/unit/accordion/accordion_core.js +++ b/tests/unit/accordion/accordion_core.js @@ -28,9 +28,10 @@ test( "handle click on header-descendant", function() { }); test( "accessibility", function () { - expect( 37 ); + expect( 61 ); var element = $( "#list1" ).accordion({ - active: 1 + active: 1, + collapsible: true }), headers = element.find( ".ui-accordion-header" ); @@ -45,31 +46,60 @@ test( "accessibility", function () { }); equal( headers.eq( 1 ).attr( "tabindex" ), 0, "active header has tabindex=0" ); - equal( headers.eq( 1 ).attr( "aria-selected" ), "true", "active tab has aria-selected=true" ); - equal( headers.eq( 1 ).attr( "aria-expanded" ), "true", "active tab has aria-expanded=true" ); - equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "false", "active tabpanel has aria-hidden=false" ); - equal( headers.eq( 0 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" ); - equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" ); - equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" ); - equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" ); - equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" ); - equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" ); - equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" ); - equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" ); + equal( headers.eq( 1 ).attr( "aria-selected" ), "true", "active tab (1) has aria-selected=true" ); + equal( headers.eq( 1 ).attr( "aria-expanded" ), "true", "active tab (1) has aria-expanded=true" ); + equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "false", "active tabpanel (1) has aria-hidden=false" ); + equal( headers.eq( 0 ).attr( "tabindex" ), -1, "inactive header (0) has tabindex=-1" ); + equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab (0) has aria-selected=false" ); + equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab (0) has aria-expanded=false" ); + equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (0) has aria-hidden=true" ); + equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); element.accordion( "option", "active", 0 ); - equal( headers.eq( 0 ).attr( "tabindex" ), 0, "active header has tabindex=0" ); - equal( headers.eq( 0 ).attr( "aria-selected" ), "true", "active tab has aria-selected=true" ); - equal( headers.eq( 0 ).attr( "aria-expanded" ), "true", "active tab has aria-expanded=true" ); - equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "false", "active tabpanel has aria-hidden=false" ); - equal( headers.eq( 1 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" ); - equal( headers.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" ); - equal( headers.eq( 1 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" ); - equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" ); - equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header has tabindex=-1" ); - equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab has aria-selected=false" ); - equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab has aria-expanded=false" ); - equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel has aria-hidden=true" ); + equal( headers.eq( 0 ).attr( "tabindex" ), 0, "active header (0) has tabindex=0" ); + equal( headers.eq( 0 ).attr( "aria-selected" ), "true", "active tab (0) has aria-selected=true" ); + equal( headers.eq( 0 ).attr( "aria-expanded" ), "true", "active tab (0) has aria-expanded=true" ); + equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "false", "active tabpanel (0) has aria-hidden=false" ); + equal( headers.eq( 1 ).attr( "tabindex" ), -1, "inactive header (1) has tabindex=-1" ); + equal( headers.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab (1) has aria-selected=false" ); + equal( headers.eq( 1 ).attr( "aria-expanded" ), "false", "inactive tab (1) has aria-expanded=false" ); + equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (1) has aria-hidden=true" ); + equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + + element.accordion( "option", "active", false ); + equal( headers.eq( 0 ).attr( "tabindex" ), 0, "previously active header (0) has tabindex=0" ); + equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab (0) has aria-selected=false" ); + equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab (0) has aria-expanded=false" ); + equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (0) has aria-hidden=true" ); + equal( headers.eq( 1 ).attr( "tabindex" ), -1, "inactive header (1) has tabindex=-1" ); + equal( headers.eq( 1 ).attr( "aria-selected" ), "false", "inactive tab (1) has aria-selected=false" ); + equal( headers.eq( 1 ).attr( "aria-expanded" ), "false", "inactive tab (1) has aria-expanded=false" ); + equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (1) has aria-hidden=true" ); + equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + + element.accordion( "option", "active", 1 ); + equal( headers.eq( 1 ).attr( "tabindex" ), 0, "active header has tabindex=0" ); + equal( headers.eq( 1 ).attr( "aria-selected" ), "true", "active tab (1) has aria-selected=true" ); + equal( headers.eq( 1 ).attr( "aria-expanded" ), "true", "active tab (1) has aria-expanded=true" ); + equal( headers.eq( 1 ).next().attr( "aria-hidden" ), "false", "active tabpanel (1) has aria-hidden=false" ); + equal( headers.eq( 0 ).attr( "tabindex" ), -1, "inactive header (0) has tabindex=-1" ); + equal( headers.eq( 0 ).attr( "aria-selected" ), "false", "inactive tab (0) has aria-selected=false" ); + equal( headers.eq( 0 ).attr( "aria-expanded" ), "false", "inactive tab (0) has aria-expanded=false" ); + equal( headers.eq( 0 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (0) has aria-hidden=true" ); + equal( headers.eq( 2 ).attr( "tabindex" ), -1, "inactive header (2) has tabindex=-1" ); + equal( headers.eq( 2 ).attr( "aria-selected" ), "false", "inactive tab (2) has aria-selected=false" ); + equal( headers.eq( 2 ).attr( "aria-expanded" ), "false", "inactive tab (2) has aria-expanded=false" ); + equal( headers.eq( 2 ).next().attr( "aria-hidden" ), "true", "inactive tabpanel (2) has aria-hidden=true" ); + }); asyncTest( "keyboard support", function() { @@ -80,38 +110,81 @@ asyncTest( "keyboard support", function() { keyCode = $.ui.keyCode; equal( headers.filter( ".ui-state-focus" ).length, 0, "no headers focused on init" ); headers.eq( 0 ).simulate( "focus" ); - setTimeout(function() { + setTimeout( step1 ); + + function step1() { ok( headers.eq( 0 ).is( ".ui-state-focus" ), "first header has focus" ); headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN } ); + setTimeout( step2 ); + } + + // Support: IE 11 with jQuery 1.7 - 1.8 only + // All of the setTimeouts() from keydowns aren't necessary with newer jQuery. + // Only the explicit focus simulations require them. + function step2() { ok( headers.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next header" ); headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT } ); + setTimeout( step3 ); + } + + function step3() { ok( headers.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next header" ); headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN } ); - ok( headers.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first header" ); + setTimeout( step4 ); + } + function step4() { + ok( headers.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first header" ); headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP } ); + setTimeout( step5 ); + } + + function step5() { ok( headers.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last header" ); headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT } ); - ok( headers.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous header" ); + setTimeout( step6 ); + } + function step6() { + ok( headers.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous header" ); headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME } ); + setTimeout( step7 ); + } + + function step7() { ok( headers.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first header" ); headers.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END } ); - ok( headers.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last header" ); + setTimeout( step8 ); + } + function step8() { + ok( headers.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last header" ); headers.eq( 2 ).simulate( "keydown", { keyCode: keyCode.ENTER } ); + setTimeout( step9 ); + } + + function step9() { equal( element.accordion( "option", "active" ) , 2, "ENTER activates panel" ); headers.eq( 1 ).simulate( "keydown", { keyCode: keyCode.SPACE } ); - equal( element.accordion( "option", "active" ), 1, "SPACE activates panel" ); + setTimeout( step10 ); + } + function step10() { + equal( element.accordion( "option", "active" ), 1, "SPACE activates panel" ); anchor.simulate( "focus" ); - setTimeout(function() { - ok( !headers.eq( 1 ).is( ".ui-state-focus" ), "header loses focus when focusing inside the panel" ); - anchor.simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } ); - ok( headers.eq( 1 ).is( ".ui-state-focus" ), "CTRL+UP moves focus to header" ); - start(); - }, 1 ); - }, 1 ); + setTimeout( step11 ); + } + + function step11() { + ok( !headers.eq( 1 ).is( ".ui-state-focus" ), "header loses focus when focusing inside the panel" ); + anchor.simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } ); + setTimeout( step12 ); + } + + function step12() { + ok( headers.eq( 1 ).is( ".ui-state-focus" ), "CTRL+UP moves focus to header" ); + start(); + } }); }( jQuery ) ); diff --git a/tests/unit/accordion/accordion_options.js b/tests/unit/accordion/accordion_options.js index 214753e40bf..dc50317fb58 100644 --- a/tests/unit/accordion/accordion_options.js +++ b/tests/unit/accordion/accordion_options.js @@ -44,6 +44,22 @@ test( "{ active: false }", function() { strictEqual( element.accordion( "option", "active" ), 0 ); }); +// http://bugs.jqueryui.com/ticket/11938 +test( "{ active: false, collapsible: true }", function() { + expect( 1 ); + var element = $( "#collapsible" ).accordion(), + height = element.outerHeight(); + + element + .accordion( "destroy" ) + .accordion( { + active: false, + collapsible: true + } ) + .accordion( "option", "active", 0 ); + equal( element.outerHeight(), height ); +} ); + test( "{ active: Number }", function() { expect( 8 ); var element = $( "#list1" ).accordion({ diff --git a/tests/unit/datepicker/datepicker_options.js b/tests/unit/datepicker/datepicker_options.js index 12da290bb29..5c60ed431f7 100644 --- a/tests/unit/datepicker/datepicker_options.js +++ b/tests/unit/datepicker/datepicker_options.js @@ -504,21 +504,21 @@ test("minMax", function() { inp.datepicker("setDate", "12/30/" + new Date().getFullYear()); ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled at 12/30/maxYear"); - inp.datepicker("option", { + inp.val( "" ).datepicker("option", { minDate: new Date(1900, 0, 1), - maxDate: "-6Y", - yearRange: "1900:-6" - }).val( "" ); - ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled"); - ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - prev button enabled"); + maxDate: "-7Y", + yearRange: "1900:-7" + }); + ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - relative - next button disabled"); + ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - relative - prev button enabled"); - inp.datepicker("option", { + inp.val( "" ).datepicker("option", { minDate: new Date(1900, 0, 1), maxDate: "1/25/2007", yearRange: "1900:2007" - }).val( "" ); - ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - next button disabled"); - ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - prev button enabled"); + }); + ok(dp.find(".ui-datepicker-next").hasClass("ui-state-disabled"), "Year Range Test - absolute - next button disabled"); + ok(!dp.find(".ui-datepicker-prev").hasClass("ui-state-disabled"), "Year Range Test - absolute - prev button enabled"); }); test("setDate", function() { diff --git a/tests/unit/dialog/dialog.html b/tests/unit/dialog/dialog.html index 936316a3632..6f39f7b8afd 100644 --- a/tests/unit/dialog/dialog.html +++ b/tests/unit/dialog/dialog.html @@ -5,9 +5,6 @@ jQuery UI Dialog Test Suite - diff --git a/tests/unit/dialog/dialog_core.js b/tests/unit/dialog/dialog_core.js index d72fef7b5bf..56f1e3da8e7 100644 --- a/tests/unit/dialog/dialog_core.js +++ b/tests/unit/dialog/dialog_core.js @@ -59,90 +59,94 @@ asyncTest( "focus tabbable", function() { element = $( markup ).dialog( options ); setTimeout(function() { - testFn(); - element.remove(); - setTimeout( next ); + testFn(function done() { + element.remove(); + setTimeout( next ); + }); }); } function step1() { - element = $( "
" ).dialog( options ); - setTimeout(function() { + checkFocus( "
", options, function( done ) { var input = element.find( "input:last" ).focus().blur(); element.dialog( "instance" )._focusTabbable(); setTimeout(function() { equal( document.activeElement, input[ 0 ], "1. an element that was focused previously." ); - element.remove(); - setTimeout( step2 ); + done(); }); - }); + }, step2 ); } function step2() { - checkFocus( "
", options, function() { + checkFocus( "
", options, function( done ) { equal( document.activeElement, element.find( "input" )[ 1 ], "2. first element inside the dialog matching [autofocus]" ); + done(); }, step3 ); } function step3() { - checkFocus( "
", options, function() { + checkFocus( "
", options, function( done ) { equal( document.activeElement, element.find( "input" )[ 0 ], "3. tabbable element inside the content element" ); + done(); }, step4 ); } function step4() { - checkFocus( "
text
", options, function() { + checkFocus( "
text
", options, function( done ) { equal( document.activeElement, element.dialog( "widget" ).find( ".ui-dialog-buttonpane button" )[ 0 ], "4. tabbable element inside the buttonpane" ); + done(); }, step5 ); } function step5() { - checkFocus( "
text
", {}, function() { + checkFocus( "
text
", {}, function( done ) { equal( document.activeElement, element.dialog( "widget" ).find( ".ui-dialog-titlebar .ui-dialog-titlebar-close" )[ 0 ], "5. the close button" ); + done(); }, step6 ); } function step6() { - element = $( "
text
" ).dialog({ - autoOpen: false - }); - element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide(); - element.dialog( "open" ); - setTimeout(function() { - equal( document.activeElement, element.parent()[ 0 ], "6. the dialog itself" ); - element.remove(); - setTimeout( step7 ); - }); + checkFocus( "
text
", { autoOpen: false }, function( done ) { + element.dialog( "widget" ).find( ".ui-dialog-titlebar-close" ).hide(); + element.dialog( "open" ); + setTimeout(function() { + equal( document.activeElement, element.parent()[ 0 ], "6. the dialog itself" ); + done(); + }); + }, step7 ); } function step7() { - element = $( "
" ).dialog({ - open: function() { - var inputs = $( this ).find( "input" ); - inputs.last().keydown(function( event ) { - event.preventDefault(); - inputs.first().focus(); - }); - } - }); - setTimeout(function() { - var inputs = element.find( "input" ); - equal( document.activeElement, inputs[ 1 ], "Focus starts on second input" ); - inputs.last().simulate( "keydown", { keyCode: $.ui.keyCode.TAB }); - setTimeout(function() { - equal( document.activeElement, inputs[ 0 ], - "Honor preventDefault, allowing custom focus management" ); - element.remove(); - start(); - }, 50 ); - }); + checkFocus( + "
", + { + open: function() { + var inputs = $( this ).find( "input" ); + inputs.last().keydown(function( event ) { + event.preventDefault(); + inputs.first().focus(); + }); + } + }, + function( done ) { + var inputs = element.find( "input" ); + equal( document.activeElement, inputs[ 1 ], "Focus starts on second input" ); + inputs.last().simulate( "keydown", { keyCode: $.ui.keyCode.TAB }); + setTimeout(function() { + equal( document.activeElement, inputs[ 0 ], + "Honor preventDefault, allowing custom focus management" ); + done(); + }, 50 ); + }, + start + ); } step1(); diff --git a/tests/unit/draggable/draggable_options.js b/tests/unit/draggable/draggable_options.js index e54ae1df46d..d8bbedc9163 100644 --- a/tests/unit/draggable/draggable_options.js +++ b/tests/unit/draggable/draggable_options.js @@ -405,6 +405,29 @@ test( "connectToSortable, dragging through one sortable to a second", function() element.simulate( "drag", dragParams ); }); +test( "connectToSortable, dragging through a sortable", function() { + expect( 1 ); + + var draggable = $( "#draggableSortable" ).draggable({ + scroll: false, + connectToSortable: "#sortable2" + }), + sortable = $( "#sortable2" ).sortable(), + sortableOffset = sortable.offset(); + + // http://bugs.jqueryui.com/ticket/10669 + // Draggable: Position issue with connectToSortable + draggable.one( "dragstop", function() { + equal( draggable.parent().attr( "id" ), "sortable", "restored draggable to original parent" ); + }); + + draggable.simulate( "drag", { + x: sortableOffset.left + 25, + y: sortableOffset.top + sortable.outerHeight() + 400, + moves: 20 + }); +}); + test( "{ containment: Element }", function() { expect( 1 ); diff --git a/tests/unit/index.html b/tests/unit/index.html index bd48590ec37..418cfd34cc6 100644 --- a/tests/unit/index.html +++ b/tests/unit/index.html @@ -7,7 +7,7 @@ - + diff --git a/tests/unit/position/position.html b/tests/unit/position/position.html index 0cad7d322a7..334fbbb7826 100644 --- a/tests/unit/position/position.html +++ b/tests/unit/position/position.html @@ -47,6 +47,9 @@
+ +
+
diff --git a/tests/unit/position/position_core.js b/tests/unit/position/position_core.js index 5b1872af983..7176e37e147 100644 --- a/tests/unit/position/position_core.js +++ b/tests/unit/position/position_core.js @@ -726,4 +726,41 @@ test( "bug #5280: consistent results (avoid fractional values)", function() { deepEqual( offset1, offset2 ); }); +test( "bug #8710: flip if flipped position fits more", function() { + expect( 3 ); + + // Positions a 10px tall element within 99px height at top 90px. + collisionTest({ + within: "#bug-8710-within-smaller", + of: "#parentx", + collision: "flip", + at: "right bottom+30" + }, { + top: 0, + left: 60 + }, "flip - top fits all" ); + + // Positions a 10px tall element within 99px height at top 92px. + collisionTest({ + within: "#bug-8710-within-smaller", + of: "#parentx", + collision: "flip", + at: "right bottom+32" + }, { + top: -2, + left: 60 + }, "flip - top fits more" ); + + // Positions a 10px tall element within 101px height at top 92px. + collisionTest({ + within: "#bug-8710-within-bigger", + of: "#parentx", + collision: "flip", + at: "right bottom+32" + }, { + top: 92, + left: 60 + }, "no flip - top fits less" ); +}); + }( jQuery ) ); diff --git a/tests/unit/resizable/resizable.html b/tests/unit/resizable/resizable.html index 5668c909a22..a44346e7cba 100644 --- a/tests/unit/resizable/resizable.html +++ b/tests/unit/resizable/resizable.html @@ -69,6 +69,7 @@
I'm a resizable.
+
diff --git a/tests/unit/resizable/resizable_options.js b/tests/unit/resizable/resizable_options.js index c46801bc54d..7fd409cecb2 100644 --- a/tests/unit/resizable/resizable_options.js +++ b/tests/unit/resizable/resizable_options.js @@ -237,7 +237,7 @@ test( "containment - immediate parent", function() { test("grid", function() { expect(4); - var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ handles: "all", grid: [0, 20] }); + var handle = ".ui-resizable-se", target = $("#resizable1").resizable({ handles: "all", grid: [ 0, 20 ] }); TestHelpers.resizable.drag(handle, 3, 9); equal( target.width(), 103, "compare width"); @@ -265,7 +265,7 @@ test("grid (min/max dimensions)", function() { test("grid (wrapped)", function() { expect(4); - var handle = ".ui-resizable-se", target = $("#resizable2").resizable({ handles: "all", grid: [0, 20] }); + var handle = ".ui-resizable-se", target = $("#resizable2").resizable({ handles: "all", grid: [ 0, 20 ] }); TestHelpers.resizable.drag(handle, 3, 9); equal( target.width(), 103, "compare width"); @@ -311,12 +311,12 @@ test( "grid - maintains grid with padding and border when approaching no dimensi height: 80 }).resizable({ handles: "all", - grid: 50 + grid: [ 50, 12 ] }); TestHelpers.resizable.drag( handle, 50, 50 ); equal( target.outerWidth(), 50, "compare width" ); - equal( target.outerHeight(), 50, "compare height" ); + equal( target.outerHeight(), 52, "compare height" ); }); test("ui-resizable-se { handles: 'all', minWidth: 60, minHeight: 60, maxWidth: 100, maxHeight: 100 }", function() { @@ -375,6 +375,35 @@ test("ui-resizable-nw { handles: 'all', minWidth: 60, minHeight: 60, maxWidth: 1 equal( target.height(), 100, "compare maxHeight" ); }); + +test( "custom handles { handles: { 's': $('#resizer1'), containment: 'parent' }", function () { + expect( 2 ); + + var handle = "#resizer1", + target = $( "#resizable1" ).resizable({ handles: { "s": $( "#resizer1" ) }, containment: "parent" }); + + TestHelpers.resizable.drag( handle, 0, 70 ); + equal( target.height(), 170, "compare height" ); + + TestHelpers.resizable.drag( handle, 0, -70 ); + equal( target.height(), 100, "compare height" ); +}); + + +test( "custom handles { handles: { 's': $('#resizer1')[0], containment: 'parent' }", function () { + expect( 2 ); + + var handle = "#resizer1", + target = $( "#resizable1" ).resizable({ handles: { "s": $( "#resizer1" )[ 0 ] }, containment: "parent" }); + + TestHelpers.resizable.drag( handle, 0, 70 ); + equal( target.height(), 170, "compare height" ); + + TestHelpers.resizable.drag( handle, 0, -70 ); + equal( target.height(), 100, "compare height" ); +}); + + test("zIndex, applied to all handles", function() { expect(8); @@ -404,4 +433,34 @@ test( "alsoResize + containment", function() { equal( other.height(), 150, "alsoResize constrained height at containment edge" ); }); +test( "alsoResize + multiple selection", function() { + expect( 6 ); + var other1 = $( "
" ) + .addClass( "other" ) + .css({ + width: 50, + height: 50 + }) + .appendTo( "body" ), + other2 = $( "
" ) + .addClass( "other" ) + .css({ + width: 50, + height: 50 + }) + .appendTo( "body"), + element = $( "#resizable1" ).resizable({ + alsoResize: other1.add( other2 ), + containment: "#container" + }); + + TestHelpers.resizable.drag( ".ui-resizable-se", 400, 400 ); + equal( element.width(), 300, "resizable constrained width at containment edge" ); + equal( element.height(), 200, "resizable constrained height at containment edge" ); + equal( other1.width(), 250, "alsoResize o1 constrained width at containment edge" ); + equal( other1.height(), 150, "alsoResize o1 constrained height at containment edge" ); + equal( other2.width(), 250, "alsoResize o2 constrained width at containment edge" ); + equal( other2.height(), 150, "alsoResize o2 constrained height at containment edge" ); +}); + })(jQuery); diff --git a/tests/unit/slider/slider_events.js b/tests/unit/slider/slider_events.js index ec93a056536..6de3a65cdef 100644 --- a/tests/unit/slider/slider_events.js +++ b/tests/unit/slider/slider_events.js @@ -99,7 +99,7 @@ test( "programmatic event triggers", function() { }); test( "mouse based interaction part two: when handles overlap", function() { - expect( 4 ); + expect( 6 ); var element = $( "#slider1" ) .slider({ @@ -147,6 +147,22 @@ test( "mouse based interaction part two: when handles overlap", function() { }); handles.eq( 0 ).simulate( "drag", { dx: 10 } ); + element = $( "#slider1" ) + .slider({ + range: true, + min: 0, + max: 100, + values: [ 0, 50 ] + }), + handles = element.find( ".ui-slider-handle" ); + + element.slider( "option", { values: [ 100, 100 ] } ); + handles.eq( 0 ).simulate( "drag", { dx: -10 } ); + equal( element.slider( "values" )[ 0 ], 99, "setting both values of range slider to the maximum doesn't lock slider" ); + + element.slider( "option", { values: [ 0, 0 ] } ); + handles.eq( 1 ).simulate( "drag", { dx: 10 } ); + equal( element.slider( "values" )[ 1 ], 1, "setting both values of range slider to the minimum doesn't lock slider" ); }); })( jQuery ); diff --git a/tests/unit/slider/slider_methods.js b/tests/unit/slider/slider_methods.js index c5c7e1254aa..74a9aebf2b5 100644 --- a/tests/unit/slider/slider_methods.js +++ b/tests/unit/slider/slider_methods.js @@ -62,7 +62,7 @@ test( "disable", function() { }); test( "value", function() { - expect( 17 ); + expect( 19 ); $( [ false, "min", "max" ] ).each(function() { var element = $( "
" ).slider({ range: this, @@ -88,10 +88,76 @@ test( "value", function() { equal( element.slider( "value" ), 1, "value method get respects max" ); equal( element.slider( "value", 2 ), element, "value method is chainable" ); equal( element.slider( "option", "value" ), 1, "value method set respects max" ); + + // set max value with step 0.01 + element.slider( "option", { + min: 2, + value: 2, + max: 2.4, + step: 0.01 + }); + element.slider( "option", "value", 2.4 ); + equal( element.slider( "value" ), 2.4, "value is set to max with 0.01 step" ); + + element = $( "
" ).slider({ + value: 100, + min: 10, + max: 500, + step: 50 + }); + + element.slider( "option", "value", 510 ); + equal( element.slider( "value" ), 460, "value is restricted to maximum valid step" ); }); -//test( "values", function() { -// ok(false, "missing test - untested code is broken code." ); -//}); +test( "values, single step", function() { + expect( 8 ); + + var element = $( "
" ).slider( { + range: false, + min: 10, + max: 100, + step: 1, + values: [ 20 ] + } ); + + deepEqual( element.slider( "values" ), [ 20 ], "range: false, values - get value for handle" ); + equal( element.slider( "values", 0 ), 20, "values (index) - get value of handle" ); + + element.slider( "values", 0, 5 ); + equal( element.slider( "values", 0 ), 10, "values (index) - restrict against min" ); + + element.slider( "values", 0, 110 ); + equal( element.slider( "values", 0 ), 100, "values (index) - restrict against max" ); + + element.slider( "option", "range", true ); + element.slider( "values", [ 20, 90 ] ); + + deepEqual( element.slider( "values" ), [ 20, 90 ], "range: true, values - get value for all handles" ); + equal( element.slider( "values", 0 ), 20, "values (index) - 1st handle" ); + equal( element.slider( "values", 1 ), 90, "values (index) - 2nd handle" ); + + element.slider( "values", [ 5, 110 ] ); + deepEqual( element.slider( "values" ), [ 10, 100 ], "values - restricted against min and max" ); + element.slider( "destroy" ); +} ); + +test( "values, multi step", function() { + expect( 2 ); + + var element = $( "
" ).slider( { + range: false, + min: 9, + max: 20, + step: 3, + values: [ 9, 12 ] + } ); + deepEqual( element.slider( "values" ), [ 9, 12 ], "values - evenly divisible by step" ); + + element.slider( "values", [ 10, 20 ] ); + deepEqual( element.slider( "values" ), [ 9, 18 ], "values - not evenly divisible by step" ); + + element.slider( "destroy" ); +} ); })( jQuery ); diff --git a/tests/unit/slider/slider_options.js b/tests/unit/slider/slider_options.js index defb6f3b0fb..7f65916842e 100644 --- a/tests/unit/slider/slider_options.js +++ b/tests/unit/slider/slider_options.js @@ -40,7 +40,7 @@ test( "disabled", function(){ }); test( "max", function() { - expect( 4 ); + expect( 7 ); element = $( "
" ); options = { @@ -54,7 +54,7 @@ test( "max", function() { element.slider( options ); ok( element.slider( "option", "value" ) === options.value, "value option is not contained by max" ); ok( element.slider( "value" ) === options.max, "value method is contained by max" ); - + options = { max: 9, min: 1, @@ -65,14 +65,43 @@ test( "max", function() { element.slider( options ); ok( element.slider( "value" ) === 7, "value method is within max, edge Case" ); - + options.step = 2; element.slider( options ); ok( element.slider( "value" ) === options.max, "value method will max, step is changed" ); element.slider( "destroy" ); -}); + options = { + max: 60, + min: 50, + orientation: "horizontal", + step: 0.1, + value: 60 + }; + + element.slider( options ); + ok( element.slider( "value" ) === options.max, "value method will max, step is changed and step is float" ); + element.slider( "destroy" ); + + options = { + max: 10.75, + min: 1.22, + orientation: "horizontal", + step: 0.01, + value: 10.75 + }; + + element.slider( options ); + ok( element.slider( "value" ) === options.max, "value method will max, step is changed, step is float and max is float" ); + element.slider( "destroy" ); + + options.max = 10.749999999; + + element.slider( options ); + ok( element.slider( "value" ) === 10.74, "value method will max, step is changed, step is float, max is float and not divisible" ); + element.slider( "destroy" ); +} ); test( "min", function() { expect( 2 ); diff --git a/tests/unit/sortable/sortable.html b/tests/unit/sortable/sortable.html index 3edc999b76e..f13b895b8db 100644 --- a/tests/unit/sortable/sortable.html +++ b/tests/unit/sortable/sortable.html @@ -74,20 +74,56 @@ - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
121.11.2
341.31.4
561.51.6
781.71.8
2.12.2
2.32.4
2.52.6
2.72.8
3.13.2
3.33.4
3.53.6
3.73.8
diff --git a/tests/unit/sortable/sortable_methods.js b/tests/unit/sortable/sortable_methods.js index f3fe240e701..9c0a86a359b 100644 --- a/tests/unit/sortable/sortable_methods.js +++ b/tests/unit/sortable/sortable_methods.js @@ -90,4 +90,39 @@ test( "disable", function() { equal( chainable, element, "disable is chainable" ); }); +test( "refresh() should update the positions of initially empty lists (see #7498)", function() { + expect( 1 ); + + var changeCount = 0, + element = $( "#qunit-fixture" ).html( "
    " ).find( "ul" ); + + element + .css({ + "float": "left", + width: "100px" + }) + .sortable({ + change: function() { + changeCount++; + } + }) + .append( "
  • a
  • a
  • " ) + .find( "li" ) + .css({ + "float": "left", + width: "50px", + height: "50px" + }); + + element.sortable( "refresh" ); + + // Switch the order of the two li elements + element.find( "li" ).eq( 0 ).simulate( "drag", { + dx: 55, + moves: 15 + }); + + equal( changeCount, 1 ); +}); + })(jQuery); diff --git a/tests/unit/sortable/sortable_options.js b/tests/unit/sortable/sortable_options.js index f2beb4dbcd6..235dec9c604 100644 --- a/tests/unit/sortable/sortable_options.js +++ b/tests/unit/sortable/sortable_options.js @@ -87,7 +87,6 @@ asyncTest( "#7415: Incorrect revert animation with axis: 'y'", function() { element = $( "#sortable" ).sortable({ axis: "y", revert: true, - stop: start, sort: function() { expectedLeft = item.css( "left" ); } @@ -103,6 +102,7 @@ asyncTest( "#7415: Incorrect revert animation with axis: 'y'", function() { var top = parseFloat( item.css( "top" ) ); equal( item.css( "left" ), expectedLeft, "left not animated" ); ok( top > 0 && top < 300, "top is animated" ); + start(); }, 100 ); }); @@ -388,6 +388,42 @@ test( "{ placholder: String } tr", function() { }); }); +test( "{ placholder: String } tbody", function() { + expect( 6 ); + + var originalWidths, + element = $( "#sortable-table" ).sortable({ + placeholder: "test", + start: function( event, ui ) { + var currentWidths = otherBody.children().map(function() { + return $( this ).width(); + }).get(); + ok( ui.placeholder.hasClass( "test" ), "placeholder has class" ); + deepEqual( currentWidths, originalWidths, "table cells maintain size" ); + equal( ui.placeholder.children().length, 1, + "placeholder has one child" ); + equal( ui.placeholder.children( "tr" ).length, 1, + "placeholder's child is tr" ); + equal( ui.placeholder.find( "> tr" ).children().length, + dragBody.find( "> tr:first" ).children().length, + "placeholder's tr has correct number of cells" ); + equal( ui.placeholder.find( "> tr" ).children().html(), + $( " " ).html(), + "placeholder td has content for forced dimensions" ); + } + }), + bodies = element.children( "tbody" ), + dragBody = bodies.eq( 0 ), + otherBody = bodies.eq( 1 ); + + originalWidths = otherBody.children().map(function() { + return $( this ).width(); + }).get(); + dragBody.simulate( "drag", { + dy: 1 + }); +}); + /* test("{ revert: false }, default", function() { ok(false, "missing test - untested code is broken code."); diff --git a/tests/unit/tabs/tabs_core.js b/tests/unit/tabs/tabs_core.js index 2e094e11b0a..2d18a6f1ab7 100644 --- a/tests/unit/tabs/tabs_core.js +++ b/tests/unit/tabs/tabs_core.js @@ -299,197 +299,224 @@ asyncTest( "keyboard support - LEFT, RIGHT, UP, DOWN, HOME, END, SPACE, ENTER", setTimeout( step1, 1 ); }); -asyncTest( "keyboard support - CTRL navigation", function() { - expect( 115 ); - var element = $( "#tabs1" ).tabs(), - tabs = element.find( ".ui-tabs-nav li" ), - panels = element.find( ".ui-tabs-panel" ), - keyCode = $.ui.keyCode; - - element.tabs( "instance" ).delay = 50; - - equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" ); - tabs.eq( 0 ).simulate( "focus" ); - - // down - function step1() { - ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab has focus" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - - tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.DOWN, ctrlKey: true } ); - ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next tab" ); - ok( !tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab is no longer focused" ); - equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); - equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); - equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - - setTimeout( step2, 100 ); - } - - // right - function step2() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" ); - equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); - equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); - - tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.RIGHT, ctrlKey: true } ); - ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next tab" ); - equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - - setTimeout( step3, 100 ); - } - - // down (wrap) - function step3() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); - - tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.DOWN, ctrlKey: true } ); - ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first tab" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - - setTimeout( step4, 100 ); - } - - // up (wrap) - function step4() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - - tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.UP, ctrlKey: true } ); - ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last tab" ); - equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - - setTimeout( step5, 100 ); - } - - // left - function step5() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); - - tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.LEFT, ctrlKey: true } ); - ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous tab" ); - equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); - equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); - equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - - setTimeout( step6, 100 ); - } - - // home - function step6() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" ); - equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); - equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); - - tabs.eq( 1 ).simulate( "keydown", { keyCode: keyCode.HOME, ctrlKey: true } ); - ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first tab" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" ); - ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); - equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); - equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); +// Navigation with CTRL and COMMAND (both behave the same) +$.each({ + ctrl: "CTRL", + meta: "COMMAND" +}, function( modifier, label ) { + asyncTest( "keyboard support - " + label + " navigation", function() { + expect( 115 ); + var element = $( "#tabs1" ).tabs(), + tabs = element.find( ".ui-tabs-nav li" ), + panels = element.find( ".ui-tabs-panel" ), + keyCode = $.ui.keyCode; + + element.tabs( "instance" ).delay = 50; + + equal( tabs.filter( ".ui-state-focus" ).length, 0, "no tabs focused on init" ); + tabs.eq( 0 ).simulate( "focus" ); + + // down + function step1() { + var eventProperties = { keyCode: keyCode.DOWN }; + eventProperties[ modifier + "Key" ] = true; + + ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab has focus" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + + tabs.eq( 0 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "DOWN moves focus to next tab" ); + ok( !tabs.eq( 0 ).is( ".ui-state-focus" ), "first tab is no longer focused" ); + equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); + equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); + equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step2, 100 ); + } - setTimeout( step7, 100 ); - } + // right + function step2() { + var eventProperties = { keyCode: keyCode.RIGHT }; + eventProperties[ modifier + "Key" ] = true; + + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" ); + equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); + equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); + + tabs.eq( 1 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "RIGHT moves focus to next tab" ); + equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step3, 100 ); + } - // end - function step7() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + // down (wrap) + function step3() { + var eventProperties = { keyCode: keyCode.DOWN }; + eventProperties[ modifier + "Key" ] = true; + + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + + tabs.eq( 2 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "DOWN wraps focus to first tab" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step4, 100 ); + } - tabs.eq( 0 ).simulate( "keydown", { keyCode: keyCode.END, ctrlKey: true } ); - ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last tab" ); - equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + // up (wrap) + function step4() { + var eventProperties = { keyCode: keyCode.UP }; + eventProperties[ modifier + "Key" ] = true; + + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + tabs.eq( 0 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "UP wraps focus to last tab" ); + equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step5, 100 ); + } - setTimeout( step8, 100 ); - } + // left + function step5() { + var eventProperties = { keyCode: keyCode.LEFT }; + eventProperties[ modifier + "Key" ] = true; + + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + + tabs.eq( 2 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 1 ).is( ".ui-state-focus" ), "LEFT moves focus to previous tab" ); + equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); + equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); + equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step6, 100 ); + } - // space - function step8() { - equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); - ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); - ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + // home + function step6() { + var eventProperties = { keyCode: keyCode.HOME }; + eventProperties[ modifier + "Key" ] = true; + + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + ok( panels.eq( 1 ).is( ":hidden" ), "second panel is hidden" ); + equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); + equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); + + tabs.eq( 1 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 0 ).is( ".ui-state-focus" ), "HOME moves focus to first tab" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + equal( tabs.eq( 1 ).attr( "aria-selected" ), "false", "second tab has aria-selected=false" ); + ok( panels.eq( 1 ).is( ":hidden" ), "second panel is still hidden" ); + equal( tabs.eq( 1 ).attr( "aria-expanded" ), "false", "second tab has aria-expanded=false" ); + equal( panels.eq( 1 ).attr( "aria-hidden" ), "true", "second panel has aria-hidden=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step7, 100 ); + } - tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.SPACE } ); - equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" ); - equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" ); - ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" ); - equal( tabs.eq( 2 ).attr( "aria-expanded" ), "true", "third tab has aria-expanded=true" ); - equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" ); - ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" ); - equal( tabs.eq( 0 ).attr( "aria-expanded" ), "false", "first tab has aria-expanded=false" ); - equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" ); + // end + function step7() { + var eventProperties = { keyCode: keyCode.END }; + eventProperties[ modifier + "Key" ] = true; + + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + tabs.eq( 0 ).simulate( "keydown", eventProperties ); + ok( tabs.eq( 2 ).is( ".ui-state-focus" ), "END moves focus to last tab" ); + equal( tabs.eq( 2 ).attr( "aria-selected" ), "false", "third tab has aria-selected=false" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 2 ).is( ":hidden" ), "third panel is still hidden" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is still visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + + setTimeout( step8, 100 ); + } - setTimeout( start, 1 ); - } + // space + function step8() { + equal( tabs.eq( 0 ).attr( "aria-selected" ), "true", "first tab has aria-selected=true" ); + ok( panels.eq( 0 ).is( ":visible" ), "first panel is visible" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "true", "first tab has aria-expanded=true" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "false", "first panel has aria-hidden=false" ); + ok( panels.eq( 2 ).is( ":hidden" ), "third panel is hidden" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "false", "third tab has aria-expanded=false" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "true", "third panel has aria-hidden=true" ); + + tabs.eq( 2 ).simulate( "keydown", { keyCode: keyCode.SPACE } ); + equal( tabs.eq( 2 ).attr( "aria-selected" ), "true", "third tab has aria-selected=true" ); + equal( tabs.eq( 0 ).attr( "aria-selected" ), "false", "first tab has aria-selected=false" ); + ok( panels.eq( 2 ).is( ":visible" ), "third panel is visible" ); + equal( tabs.eq( 2 ).attr( "aria-expanded" ), "true", "third tab has aria-expanded=true" ); + equal( panels.eq( 2 ).attr( "aria-hidden" ), "false", "third panel has aria-hidden=false" ); + ok( panels.eq( 0 ).is( ":hidden" ), "first panel is hidden" ); + equal( tabs.eq( 0 ).attr( "aria-expanded" ), "false", "first tab has aria-expanded=false" ); + equal( panels.eq( 0 ).attr( "aria-hidden" ), "true", "first panel has aria-hidden=true" ); + + setTimeout( start, 1 ); + } - setTimeout( step1, 1 ); + setTimeout( step1, 1 ); + }); }); asyncTest( "keyboard support - CTRL+UP, ALT+PAGE_DOWN, ALT+PAGE_UP", function() { diff --git a/tests/unit/tabs/tabs_test_helpers.js b/tests/unit/tabs/tabs_test_helpers.js index 0c930918615..74170c2630c 100644 --- a/tests/unit/tabs/tabs_test_helpers.js +++ b/tests/unit/tabs/tabs_test_helpers.js @@ -40,7 +40,10 @@ TestHelpers.tabs = { equalHeight: function( tabs, height ) { tabs.find( ".ui-tabs-panel" ).each(function() { - equal( $( this ).outerHeight(), height ); + + // Handle overly-precise values + var actualHeight = parseFloat( $( this ).outerHeight().toFixed( 1 ) ); + equal( actualHeight, height ); }); }, diff --git a/tests/unit/testsuite.js b/tests/unit/testsuite.js index 18353c702df..fe0595c75b5 100644 --- a/tests/unit/testsuite.js +++ b/tests/unit/testsuite.js @@ -64,9 +64,9 @@ QUnit.config.urlConfig.push({ id: "jquery", label: "jQuery version", value: [ - "1.6", "1.6.1", "1.6.2", "1.6.3", "1.6.4", "1.7", "1.7.1", "1.7.2", + "1.6.0", "1.6.1", "1.6.2", "1.6.3", "1.6.4", "1.7.0", "1.7.1", "1.7.2", "1.8.0", "1.8.1", "1.8.2", "1.8.3", "1.9.0", "1.9.1", "1.10.0", - "1.10.1", "1.10.2", "2.0.0", "2.0.1", "2.0.2", "2.0.3", "git" + "1.10.1", "1.10.2", "2.0.0", "2.0.1", "2.0.2", "2.0.3", "3.0.0", "git" ], tooltip: "Which jQuery Core version to test against" }); @@ -301,11 +301,11 @@ window.domEqual = function( selector, modifier, message ) { result = {}; $.each( properties, function( index, attr ) { var value = elem.prop( attr ); - result[ attr ] = value !== undefined ? value : ""; + result[ attr ] = value != null ? value : ""; }); $.each( attributes, function( index, attr ) { var value = elem.attr( attr ); - result[ attr ] = value !== undefined ? value : ""; + result[ attr ] = value != null ? value : ""; }); result.style = getElementStyles( elem[ 0 ] ); result.events = $._data( elem[ 0 ], "events" ); diff --git a/tests/unit/tooltip/tooltip_options.js b/tests/unit/tooltip/tooltip_options.js index 17f0a423775..a07f65199ab 100644 --- a/tests/unit/tooltip/tooltip_options.js +++ b/tests/unit/tooltip/tooltip_options.js @@ -71,6 +71,28 @@ asyncTest( "content: sync + async callback", function() { }).tooltip( "open" ); }); +// http://bugs.jqueryui.com/ticket/8740 +asyncTest( "content: async callback loses focus before load", function() { + expect( 1 ); + + var element = $( "#tooltipped1" ).tooltip({ + content: function( response ) { + setTimeout(function() { + element.trigger( "mouseleave" ); + setTimeout(function() { + response( "sometext" ); + setTimeout(function() { + ok( !$( "#" + element.data( "ui-tooltip-id" ) ).is( ":visible" ), + "Tooltip should not display" ); + start(); + }); + }); + }); + } + }); + element.trigger( "mouseover" ); +}); + test( "content: change while open", function() { expect( 2 ) ; var element = $( "#tooltipped1" ).tooltip({ diff --git a/tests/unit/widget/widget_core.js b/tests/unit/widget/widget_core.js index feafca9428c..2b88e39ef22 100644 --- a/tests/unit/widget/widget_core.js +++ b/tests/unit/widget/widget_core.js @@ -50,21 +50,21 @@ test( "element normalization", function() { $.ui.testWidget.prototype.defaultElement = ""; $.ui.testWidget.prototype._create = function() { ok( this.element.is( "span[data-test=pass]" ), "generated span with properties" ); - deepEqual( this.element.testWidget( "instance" ), this, "instace stored in .data()" ); + deepEqual( this.element.testWidget( "instance" ), this, "instance stored in .data()" ); }; $.ui.testWidget(); elem = $( "" ); $.ui.testWidget.prototype._create = function() { deepEqual( this.element[ 0 ], elem[ 0 ], "from element" ); - deepEqual( elem.testWidget( "instance" ), this, "instace stored in .data()" ); + deepEqual( elem.testWidget( "instance" ), this, "instance stored in .data()" ); }; $.ui.testWidget( {}, elem[ 0 ] ); elem = $( "
    " ); $.ui.testWidget.prototype._create = function() { deepEqual( this.element[ 0 ], elem[ 0 ], "from jQuery object" ); - deepEqual( elem.testWidget( "instance" ), this, "instace stored in .data()" ); + deepEqual( elem.testWidget( "instance" ), this, "instance stored in .data()" ); }; $.ui.testWidget( {}, elem ); @@ -72,7 +72,7 @@ test( "element normalization", function() { .appendTo( "#qunit-fixture" ); $.ui.testWidget.prototype._create = function() { deepEqual( this.element[ 0 ], elem[ 0 ], "from selector" ); - deepEqual( elem.testWidget( "instance" ), this, "instace stored in .data()" ); + deepEqual( elem.testWidget( "instance" ), this, "instance stored in .data()" ); }; $.ui.testWidget( {}, "#element-normalization-selector" ); diff --git a/tests/visual/compound/datepicker_dialog.html b/tests/visual/compound/datepicker_dialog.html index e6a25a2e8df..52c91a0835b 100644 --- a/tests/visual/compound/datepicker_dialog.html +++ b/tests/visual/compound/datepicker_dialog.html @@ -12,6 +12,7 @@ + + + + + + + +
    +

    Range Slider

    +

    When set both values of range slider to the maximum, slider should not lock

    +
    +
    + + +
    + + + + diff --git a/themes/base/accordion.css b/themes/base/accordion.css index 43560be03d1..23114b16432 100644 --- a/themes/base/accordion.css +++ b/themes/base/accordion.css @@ -2,7 +2,7 @@ * jQuery UI Accordion @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/all.css b/themes/base/all.css index 614a133d946..b31adc80f1d 100644 --- a/themes/base/all.css +++ b/themes/base/all.css @@ -2,7 +2,7 @@ * jQuery UI CSS Framework @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/autocomplete.css b/themes/base/autocomplete.css index 4ddbfeef8e2..7fcb2829ef4 100644 --- a/themes/base/autocomplete.css +++ b/themes/base/autocomplete.css @@ -2,7 +2,7 @@ * jQuery UI Autocomplete @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/base.css b/themes/base/base.css index 479c3279d9b..3ed02661f5e 100644 --- a/themes/base/base.css +++ b/themes/base/base.css @@ -2,7 +2,7 @@ * jQuery UI CSS Framework @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/button.css b/themes/base/button.css index 43ff15cfe43..70caf10ed42 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -2,7 +2,7 @@ * jQuery UI Button @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/core.css b/themes/base/core.css index e66fcf32a3b..387d5dd3706 100644 --- a/themes/base/core.css +++ b/themes/base/core.css @@ -2,7 +2,7 @@ * jQuery UI CSS Framework @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/datepicker.css b/themes/base/datepicker.css index 164a3458330..a77eab7b2ab 100644 --- a/themes/base/datepicker.css +++ b/themes/base/datepicker.css @@ -2,7 +2,7 @@ * jQuery UI Datepicker @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/dialog.css b/themes/base/dialog.css index df092111d01..10c89d0b8ac 100644 --- a/themes/base/dialog.css +++ b/themes/base/dialog.css @@ -2,7 +2,7 @@ * jQuery UI Dialog @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/draggable.css b/themes/base/draggable.css index 8583330403a..f2000c45656 100644 --- a/themes/base/draggable.css +++ b/themes/base/draggable.css @@ -2,7 +2,7 @@ * jQuery UI Draggable @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ diff --git a/themes/base/menu.css b/themes/base/menu.css index 2be35870fb7..489923055f1 100644 --- a/themes/base/menu.css +++ b/themes/base/menu.css @@ -2,7 +2,7 @@ * jQuery UI Menu @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/progressbar.css b/themes/base/progressbar.css index b38d0441614..ede7e1f92ca 100644 --- a/themes/base/progressbar.css +++ b/themes/base/progressbar.css @@ -2,7 +2,7 @@ * jQuery UI Progressbar @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/resizable.css b/themes/base/resizable.css index efc05dd113d..318c6ebddaf 100644 --- a/themes/base/resizable.css +++ b/themes/base/resizable.css @@ -2,7 +2,7 @@ * jQuery UI Resizable @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ diff --git a/themes/base/selectable.css b/themes/base/selectable.css index 8badbb6ab12..f0790f47113 100644 --- a/themes/base/selectable.css +++ b/themes/base/selectable.css @@ -2,7 +2,7 @@ * jQuery UI Selectable @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ diff --git a/themes/base/selectmenu.css b/themes/base/selectmenu.css index b362956a6df..18f36aa9b70 100644 --- a/themes/base/selectmenu.css +++ b/themes/base/selectmenu.css @@ -2,7 +2,7 @@ * jQuery UI Selectmenu @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/slider.css b/themes/base/slider.css index c64d9500a15..cffdc96919d 100644 --- a/themes/base/slider.css +++ b/themes/base/slider.css @@ -2,7 +2,7 @@ * jQuery UI Slider @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/sortable.css b/themes/base/sortable.css index a89d8531afa..7931b451e54 100644 --- a/themes/base/sortable.css +++ b/themes/base/sortable.css @@ -2,7 +2,7 @@ * jQuery UI Sortable @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ diff --git a/themes/base/spinner.css b/themes/base/spinner.css index 4f6e59d9b4d..a7563e6b943 100644 --- a/themes/base/spinner.css +++ b/themes/base/spinner.css @@ -2,7 +2,7 @@ * jQuery UI Spinner @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/tabs.css b/themes/base/tabs.css index 58ef66ccc64..06ae1a8b200 100644 --- a/themes/base/tabs.css +++ b/themes/base/tabs.css @@ -2,7 +2,7 @@ * jQuery UI Tabs @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/theme.css b/themes/base/theme.css index 510d6fc5b33..84cdedf9797 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -2,7 +2,7 @@ * jQuery UI CSS Framework @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/themes/base/tooltip.css b/themes/base/tooltip.css index 7214429c2da..f8f7bc84118 100644 --- a/themes/base/tooltip.css +++ b/themes/base/tooltip.css @@ -2,7 +2,7 @@ * jQuery UI Tooltip @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/ui/accordion.js b/ui/accordion.js index 94643719731..483de50107d 100644 --- a/ui/accordion.js +++ b/ui/accordion.js @@ -2,7 +2,7 @@ * jQuery UI Accordion @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * @@ -360,9 +360,16 @@ return $.widget( "ui.accordion", { } else if ( heightStyle === "auto" ) { maxHeight = 0; this.headers.next() - .each(function() { + .each( function() { + var isVisible = $( this ).is( ":visible" ); + if ( !isVisible ) { + $( this ).show(); + } maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); - }) + if ( !isVisible ) { + $( this ).hide(); + } + } ) .height( maxHeight ); } }, @@ -483,7 +490,10 @@ return $.widget( "ui.accordion", { toHide.attr({ "aria-hidden": "true" }); - toHide.prev().attr( "aria-selected", "false" ); + toHide.prev().attr({ + "aria-selected": "false", + "aria-expanded": "false" + }); // if we're switching panels, remove the old header from the tab order // if we're opening from collapsed state, remove the previous header from the tab order // if we're collapsing, then keep the collapsing header in the tab order @@ -494,7 +504,7 @@ return $.widget( "ui.accordion", { }); } else if ( toShow.length ) { this.headers.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; + return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; }) .attr( "tabIndex", -1 ); } @@ -504,8 +514,8 @@ return $.widget( "ui.accordion", { .prev() .attr({ "aria-selected": "true", - tabIndex: 0, - "aria-expanded": "true" + "aria-expanded": "true", + tabIndex: 0 }); }, @@ -513,6 +523,7 @@ return $.widget( "ui.accordion", { var total, easing, duration, that = this, adjust = 0, + boxSizing = toShow.css( "box-sizing" ), down = toShow.length && ( !toHide.length || ( toShow.index() < toHide.index() ) ), animate = this.options.animate || {}, @@ -555,7 +566,9 @@ return $.widget( "ui.accordion", { step: function( now, fx ) { fx.now = Math.round( now ); if ( fx.prop !== "height" ) { - adjust += fx.now; + if ( boxSizing === "content-box" ) { + adjust += fx.now; + } } else if ( that.options.heightStyle !== "content" ) { fx.now = Math.round( total - toHide.outerHeight() - adjust ); adjust = 0; diff --git a/ui/autocomplete.js b/ui/autocomplete.js index 0132ed7f3a2..fe14726bec0 100644 --- a/ui/autocomplete.js +++ b/ui/autocomplete.js @@ -2,7 +2,7 @@ * jQuery UI Autocomplete @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * @@ -67,14 +67,11 @@ $.widget( "ui.autocomplete", { isTextarea = nodeName === "textarea", isInput = nodeName === "input"; - this.isMultiLine = - // Textareas are always multi-line - isTextarea ? true : - // Inputs are always single-line, even if inside a contentEditable element - // IE also treats inputs as contentEditable - isInput ? false : - // All other element types are determined by whether or not they're contentEditable - this.element.prop( "isContentEditable" ); + // Textareas are always multi-line + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + // All other element types are determined by whether or not they're contentEditable + this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element ); this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; this.isNewMenu = true; @@ -221,6 +218,16 @@ $.widget( "ui.autocomplete", { this.cancelBlur = true; this._delay(function() { delete this.cancelBlur; + + // Support: IE 8 only + // Right clicking a menu item or selecting text from the menu items will + // result in focus moving out of the input. However, we've already received + // and ignored the blur event because of the cancelBlur flag set above. So + // we restore focus to ensure that the menu closes properly based on the user's + // next actions. + if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { + this.element.focus(); + } }); // clicking on the scrollbar causes focus to shift to the body @@ -278,7 +285,7 @@ $.widget( "ui.autocomplete", { previous = this.previous; // only trigger when focus was lost (click on menu) - if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { + if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { this.element.focus(); this.previous = previous; // #6109 - IE triggers two focus events and the second @@ -302,7 +309,7 @@ $.widget( "ui.autocomplete", { } }); - this.liveRegion = $( "", { + this.liveRegion = $( "
    ", { role: "status", "aria-live": "assertive", "aria-relevant": "additions" @@ -352,7 +359,7 @@ $.widget( "ui.autocomplete", { } if ( !element || !element[ 0 ] ) { - element = this.element.closest( ".ui-front" ); + element = this.element.closest( ".ui-front, dialog" ); } if ( !element.length ) { @@ -578,6 +585,24 @@ $.widget( "ui.autocomplete", { // prevents moving cursor to beginning/end of the text field in some browsers event.preventDefault(); } + }, + + // Support: Chrome <=50 + // We should be able to just use this.element.prop( "isContentEditable" ) + // but hidden elements always report false in Chrome. + // https://code.google.com/p/chromium/issues/detail?id=313082 + _isContentEditable: function( element ) { + if ( !element.length ) { + return false; + } + + var editable = element.prop( "contentEditable" ); + + if ( editable === "inherit" ) { + return this._isContentEditable( element.parent() ); + } + + return editable === "true"; } }); diff --git a/ui/button.js b/ui/button.js index 5d502ad51ea..3269e85ca96 100644 --- a/ui/button.js +++ b/ui/button.js @@ -2,7 +2,7 @@ * jQuery UI Button @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * diff --git a/ui/core.js b/ui/core.js index 0bcb46aa7df..e712bcebb06 100644 --- a/ui/core.js +++ b/ui/core.js @@ -2,7 +2,7 @@ * jQuery UI Core @VERSION * http://jqueryui.com * - * Copyright 2014 jQuery Foundation and other contributors + * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * @@ -43,6 +43,45 @@ $.extend( $.ui, { SPACE: 32, TAB: 9, UP: 38 + }, + + // Internal use only + safeActiveElement: function( document ) { + var activeElement; + + // Support: IE 9 only + // IE9 throws an "Unspecified error" accessing document.activeElement from an