From 2879b3ac253fb1faf94a815552982a0f6a485a58 Mon Sep 17 00:00:00 2001 From: Mike Sherov Date: Sun, 7 Apr 2013 14:16:31 -0400 Subject: [PATCH] Datepicker Tests: Fix IE tests by accounting for async nature of focus/blur and by correctly not double focusing a programmatically focused date picker. A partial fix was implemented to resolve #6694, and this commit completes the fix so we can programmatically focus a date picker without focus being fired twice.(cherry picked from commit 1c1b64fcf017471970c3903a2bc89cc7d108aaa3) --- tests/unit/datepicker/datepicker_options.js | 146 +++++++++--------- .../datepicker/datepicker_test_helpers.js | 7 + ui/jquery.ui.datepicker.js | 15 +- 3 files changed, 89 insertions(+), 79 deletions(-) diff --git a/tests/unit/datepicker/datepicker_options.js b/tests/unit/datepicker/datepicker_options.js index 1efd854a9..c1dcfb2b7 100644 --- a/tests/unit/datepicker/datepicker_options.js +++ b/tests/unit/datepicker/datepicker_options.js @@ -87,56 +87,53 @@ test("change", function() { equal($.datepicker._defaults.showOn, "focus", "Retain default showOn"); }); -asyncTest("invocation", function() { +asyncTest( "invocation", function() { expect( 29 ); var button, image, - inp = TestHelpers.datepicker.init("#inp"), - dp = $("#ui-datepicker-div"), - body = $("body"); + inp = TestHelpers.datepicker.init( "#inp" ), + dp = $( "#ui-datepicker-div" ), + body = $( "body" ); function step1() { // On focus - button = inp.siblings("button"); - ok(button.length === 0, "Focus - button absent"); - image = inp.siblings("img"); - ok(image.length === 0, "Focus - image absent"); - inp[0].focus(); - setTimeout(function() { - ok(dp.is(":visible"), "Focus - rendered on focus"); - inp.simulate("keydown", {keyCode: $.ui.keyCode.ESCAPE}); - ok(!dp.is(":visible"), "Focus - hidden on exit"); - inp[0].blur(); - setTimeout(function() { - inp[0].focus(); - setTimeout(function() { - ok(dp.is(":visible"), "Focus - rendered on focus"); - body.simulate("mousedown", {}); - ok(!dp.is(":visible"), "Focus - hidden on external click"); - inp.datepicker("hide").datepicker("destroy"); + button = inp.siblings( "button" ); + ok( button.length === 0, "Focus - button absent" ); + image = inp.siblings( "img" ); + ok( image.length === 0, "Focus - image absent" ); - step2(); - }); + inp.one( "focus", function() { + ok( dp.is( ":visible" ), "Focus - rendered on focus" ); + inp.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + ok( !dp.is( ":visible" ), "Focus - hidden on exit" ); + + TestHelpers.datepicker.onBlurThenFocus( inp, function() { + ok( dp.is( ":visible" ), "Focus - rendered on focus" ); + body.simulate( "mousedown", {} ); + ok( !dp.is( ":visible" ), "Focus - hidden on external click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + step2(); }); - }); + })[ 0 ].focus(); } function step2() { // On button - inp = TestHelpers.datepicker.init("#inp", {showOn: "button", buttonText: "Popup"}); - ok(!dp.is(":visible"), "Button - initially hidden"); - button = inp.siblings("button"); - image = inp.siblings("img"); - ok(button.length === 1, "Button - button present"); - ok(image.length === 0, "Button - image absent"); - equal(button.text(), "Popup", "Button - button text"); - inp[0].focus(); - setTimeout(function() { - ok(!dp.is(":visible"), "Button - not rendered on focus"); + inp = TestHelpers.datepicker.init( "#inp", { showOn: "button", buttonText: "Popup" } ); + ok( !dp.is( ":visible" ), "Button - initially hidden" ); + button = inp.siblings( "button" ); + image = inp.siblings( "img" ); + ok( button.length === 1, "Button - button present" ); + ok( image.length === 0, "Button - image absent" ); + equal( button.text(), "Popup", "Button - button text" ); + + TestHelpers.datepicker.onBlurThenFocus( inp, function() { + ok( !dp.is( ":visible" ), "Button - not rendered on focus" ); button.click(); - ok(dp.is(":visible"), "Button - rendered on button click"); + ok( dp.is( ":visible" ), "Button - rendered on button click" ); button.click(); - ok(!dp.is(":visible"), "Button - hidden on second button click"); - inp.datepicker("hide").datepicker("destroy"); + ok( !dp.is( ":visible" ), "Button - hidden on second button click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); step3(); }); @@ -144,23 +141,27 @@ asyncTest("invocation", function() { function step3() { // On image button - inp = TestHelpers.datepicker.init("#inp", {showOn: "button", buttonImageOnly: true, - buttonImage: "images/calendar.gif", buttonText: "Cal"}); - ok(!dp.is(":visible"), "Image button - initially hidden"); - button = inp.siblings("button"); - ok(button.length === 0, "Image button - button absent"); - image = inp.siblings("img"); - ok(image.length === 1, "Image button - image present"); - equal(image.attr("src"), "images/calendar.gif", "Image button - image source"); - equal(image.attr("title"), "Cal", "Image button - image text"); - inp[0].focus(); - setTimeout(function() { - ok(!dp.is(":visible"), "Image button - not rendered on focus"); + inp = TestHelpers.datepicker.init( "#inp", { + showOn: "button", + buttonImageOnly: true, + buttonImage: "images/calendar.gif", + buttonText: "Cal" + }); + ok( !dp.is( ":visible" ), "Image button - initially hidden" ); + button = inp.siblings( "button" ); + ok( button.length === 0, "Image button - button absent" ); + image = inp.siblings( "img" ); + ok( image.length === 1, "Image button - image present" ); + equal( image.attr( "src" ), "images/calendar.gif", "Image button - image source" ); + equal( image.attr( "title" ), "Cal", "Image button - image text" ); + + TestHelpers.datepicker.onBlurThenFocus( inp, function() { + ok( !dp.is( ":visible" ), "Image button - not rendered on focus" ); image.click(); - ok(dp.is(":visible"), "Image button - rendered on image click"); + ok( dp.is( ":visible" ), "Image button - rendered on image click" ); image.click(); - ok(!dp.is(":visible"), "Image button - hidden on second image click"); - inp.datepicker("hide").datepicker("destroy"); + ok( !dp.is( ":visible" ), "Image button - hidden on second image click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); step4(); }); @@ -168,29 +169,26 @@ asyncTest("invocation", function() { function step4() { // On both - inp = TestHelpers.datepicker.init("#inp", {showOn: "both", buttonImage: "images/calendar.gif"}); - ok(!dp.is(":visible"), "Both - initially hidden"); - button = inp.siblings("button"); - ok(button.length === 1, "Both - button present"); - image = inp.siblings("img"); - ok(image.length === 0, "Both - image absent"); - image = button.children("img"); - ok(image.length === 1, "Both - button image present"); - inp[0].blur(); - setTimeout(function() { - inp[0].focus(); - setTimeout(function() { - ok(dp.is(":visible"), "Both - rendered on focus"); - body.simulate("mousedown", {}); - ok(!dp.is(":visible"), "Both - hidden on external click"); - button.click(); - ok(dp.is(":visible"), "Both - rendered on button click"); - button.click(); - ok(!dp.is(":visible"), "Both - hidden on second button click"); - inp.datepicker("hide").datepicker("destroy"); + inp = TestHelpers.datepicker.init( "#inp", { showOn: "both", buttonImage: "images/calendar.gif"} ); + ok( !dp.is( ":visible" ), "Both - initially hidden" ); + button = inp.siblings( "button" ); + ok( button.length === 1, "Both - button present" ); + image = inp.siblings( "img" ); + ok( image.length === 0, "Both - image absent" ); + image = button.children( "img" ); + ok( image.length === 1, "Both - button image present" ); - start(); - }); + TestHelpers.datepicker.onBlurThenFocus( inp, function() { + ok( dp.is( ":visible" ), "Both - rendered on focus" ); + body.simulate( "mousedown", {} ); + ok( !dp.is( ":visible" ), "Both - hidden on external click" ); + button.click(); + ok( dp.is( ":visible" ), "Both - rendered on button click" ); + button.click(); + ok( !dp.is( ":visible" ), "Both - hidden on second button click" ); + inp.datepicker( "hide" ).datepicker( "destroy" ); + + start(); }); } diff --git a/tests/unit/datepicker/datepicker_test_helpers.js b/tests/unit/datepicker/datepicker_test_helpers.js index a9605edff..504bcc767 100644 --- a/tests/unit/datepicker/datepicker_test_helpers.js +++ b/tests/unit/datepicker/datepicker_test_helpers.js @@ -18,5 +18,12 @@ TestHelpers.datepicker = { $.datepicker.setDefaults($.datepicker.regional[""]); return $(id).datepicker($.extend({showAnim: ""}, options || {})); }, + onBlurThenFocus: function( element, callback ) { + element.one( "blur", function(){ + element.one( "focus", function(){ + callback(); + })[ 0 ].focus(); + })[ 0 ].blur(); + }, PROP_NAME: "datepicker" }; \ No newline at end of file diff --git a/ui/jquery.ui.datepicker.js b/ui/jquery.ui.datepicker.js index b545a77fd..1147dffb6 100644 --- a/ui/jquery.ui.datepicker.js +++ b/ui/jquery.ui.datepicker.js @@ -752,9 +752,10 @@ $.extend(Datepicker.prototype, { inst.dpDiv[showAnim || "show"](showAnim ? duration : null); } - if (inst.input.is(":visible") && !inst.input.is(":disabled")) { + if ( $.datepicker._shouldFocusInput( inst ) ) { inst.input.focus(); } + $.datepicker._curInst = inst; } }, @@ -781,10 +782,7 @@ $.extend(Datepicker.prototype, { inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + "Class"]("ui-datepicker-rtl"); - // #6694 - don't focus the input if it's already focused - // this breaks the change event in IE - if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && - inst.input.is(":visible") && !inst.input.is(":disabled") && inst.input[0] !== document.activeElement) { + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { inst.input.focus(); } @@ -801,6 +799,13 @@ $.extend(Datepicker.prototype, { } }, + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + // Support: IE and jQuery <1.9 + _shouldFocusInput: function( inst ) { + return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); + }, + /* Check positioning to remain on screen. */ _checkOffset: function(inst, offset, isFixed) { var dpWidth = inst.dpDiv.outerWidth(),