Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion tests/unit/datepicker/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ QUnit.test( "initialization - Reinitialization after body had been emptied.", fu
QUnit.test( "widget method - empty collection", function( assert ) {
assert.expect( 1 );
$( "#nonExist" ).datepicker(); // Should create nothing
assert.ok( !$( "#ui-datepicker-div" ).length, "Non init on empty collection" );
assert.strictEqual( $( "#ui-datepicker-div" ).length, 0, "Non init on empty collection" );
} );

QUnit.test( "widget method", function( assert ) {
Expand Down Expand Up @@ -540,4 +540,40 @@ QUnit.test( "mouse", function( assert ) {
"Mouse click inline - next" );
} );

QUnit.test( "initialized on focus is immediately shown (gh-2385)", function( assert ) {
assert.expect( 2 );

var dp, dp2, inp, inp2, parent;

try {
inp = $( "#inp" );
parent = inp.parent();
parent.on( "focus", "#inp:not(.hasDatepicker)", function() {
testHelper.init( "#inp" );
dp = $( "#ui-datepicker-div" );
} );
inp.trigger( "focus" );
assert.equal( dp.css( "display" ), "block",
"Datepicker - visible (delegated focus)" );
} finally {
inp.datepicker( "destroy" );
}

try {
inp2 = $( "#inp2" );
inp2.on( "focus", function() {
if ( $( this ).hasClass( "hasDatepicker" ) ) {
return;
}
testHelper.init( "#inp2" );
dp2 = $( "#ui-datepicker-div" );
} );
inp2.trigger( "focus" );
assert.equal( dp2.css( "display" ), "block",
"Datepicker - visible (regular focus)" );
} finally {
inp2.datepicker( "destroy" );
}
} );

} );
23 changes: 23 additions & 0 deletions ui/widgets/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,22 @@ $.extend( Datepicker.prototype, {
if ( inst.settings.disabled ) {
this._disableDatepicker( target );
}

// Support: jQuery 4.0.0+
// jQuery 4.0+ follows native focus events order, meaning that `focusin`
// is fired after `focus`. As delegated `focus` is implemented in jQuery
// via `focusin`, `focus` handlers attached during a delegated `focus`
// handler will not fire until the second time the field receives focus.
// This is what the `_attachments` method does. To account for that, show
// the datepicker if input is already focused. `_showDatepicker` checks
// if the datepicker is already open, so it's not a problem that it
// fires again as a `focus` handler in jQuery <4.
//
// Note that the fact such an initialization worked inside of delegated
// focus handlers was a result of an implementation detail in jQuery. If
// a regular `focus` handler was used to initialize the datepicker, neither
// jQuery 4.0 nor 3.x would show the datepicker without the call below.
this._showDatepickerIfFocused( input );
},

/* Make attachments based on settings. */
Expand Down Expand Up @@ -594,6 +610,7 @@ $.extend( Datepicker.prototype, {
this._setDate( inst, date );
this._updateAlternate( inst );
this._updateDatepicker( inst );
this._showDatepickerIfFocused( target );
}
},

Expand Down Expand Up @@ -862,6 +879,12 @@ $.extend( Datepicker.prototype, {
}
},

_showDatepickerIfFocused: function( input ) {
if ( input.length && input.is( ":focus" ) ) {
this._showDatepicker( input[ 0 ] );
}
},

/* Generate the date picker content. */
_updateDatepicker: function( inst ) {
this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
Expand Down