diff --git a/tests/unit/spinner/spinner_events.js b/tests/unit/spinner/spinner_events.js index 133a8d5a2..72b185528 100644 --- a/tests/unit/spinner/spinner_events.js +++ b/tests/unit/spinner/spinner_events.js @@ -121,7 +121,7 @@ test( "stop", function() { element.spinner( "value", 999 ); }); -test( "change", function() { +asyncTest( "change", function() { expect( 14 ); var element = $( "#spin" ).spinner(); @@ -174,50 +174,56 @@ test( "change", function() { shouldChange( false, "button up, before blur" ); element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup(); shouldChange( true, "blur after button up" ); - element.blur(); + setTimeout(function() { + element.blur(); - shouldChange( false, "button down, before blur" ); - element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup(); - shouldChange( true, "blur after button down" ); - element.blur(); + shouldChange( false, "button down, before blur" ); + element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup(); + shouldChange( true, "blur after button down" ); + setTimeout(function() { + element.blur(); - shouldChange( false, "many buttons, same final value, before blur" ); - element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup(); - element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup(); - element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup(); - element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup(); - shouldChange( false, "blur after many buttons, same final value" ); - element.blur(); + shouldChange( false, "many buttons, same final value, before blur" ); + element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup(); + element.spinner( "widget" ).find( ".ui-spinner-up" ).mousedown().mouseup(); + element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup(); + element.spinner( "widget" ).find( ".ui-spinner-down" ).mousedown().mouseup(); + shouldChange( false, "blur after many buttons, same final value" ); + element.blur(); + setTimeout(function() { + shouldChange( true, "stepUp" ); + element.spinner( "stepUp" ); - shouldChange( true, "stepUp" ); - element.spinner( "stepUp" ); + shouldChange( true, "stepDown" ); + element.spinner( "stepDown" ); - shouldChange( true, "stepDown" ); - element.spinner( "stepDown" ); + shouldChange( true, "pageUp" ); + element.spinner( "pageUp" ); - shouldChange( true, "pageUp" ); - element.spinner( "pageUp" ); + shouldChange( true, "pageDown" ); + element.spinner( "pageDown" ); - shouldChange( true, "pageDown" ); - element.spinner( "pageDown" ); + shouldChange( true, "value" ); + element.spinner( "value", 999 ); - shouldChange( true, "value" ); - element.spinner( "value", 999 ); + shouldChange( false, "value, same value" ); + element.spinner( "value", 999 ); - shouldChange( false, "value, same value" ); - element.spinner( "value", 999 ); + shouldChange( true, "max, value changed" ); + element.spinner( "option", "max", 900 ); - shouldChange( true, "max, value changed" ); - element.spinner( "option", "max", 900 ); + shouldChange( false, "max, value not changed" ); + element.spinner( "option", "max", 1000 ); - shouldChange( false, "max, value not changed" ); - element.spinner( "option", "max", 1000 ); + shouldChange( true, "min, value changed" ); + element.spinner( "option", "min", 950 ); - shouldChange( true, "min, value changed" ); - element.spinner( "option", "min", 950 ); - - shouldChange( false, "min, value not changed" ); - element.spinner( "option", "min", 200 ); + shouldChange( false, "min, value not changed" ); + element.spinner( "option", "min", 200 ); + start(); + }); + }); + }); }); })( jQuery ); diff --git a/ui/jquery.ui.spinner.js b/ui/jquery.ui.spinner.js index bd55a09ea..1e4204a0c 100644 --- a/ui/jquery.ui.spinner.js +++ b/ui/jquery.ui.spinner.js @@ -93,6 +93,11 @@ $.widget( "ui.spinner", { this.previous = this.element.val(); }, blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + this._refresh(); this.uiSpinner.removeClass( "ui-state-active" ); if ( this.previous !== this.element.val() ) { @@ -117,11 +122,42 @@ $.widget( "ui.spinner", { event.preventDefault(); }, "mousedown .ui-spinner-button": function( event ) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[0] === this.document[0].activeElement ? + this.previous : this.element.val(); + function checkFocus() { + var isActive = this.element[0] === this.document[0].activeElement; + if ( !isActive ) { + this.element.focus(); + this.previous = previous; + // support: IE + // IE sets focus asynchronously, so we need to check if focus + // moved off of the input because the user clicked on the button. + this._delay(function() { + this.previous = previous; + }); + } + } + // ensure focus is on (or stays on) the text field event.preventDefault(); - if ( this.document[0].activeElement !== this.element[ 0 ] ) { - this.element.focus(); - } + checkFocus.call( this ); + + // support: IE + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + // and check (again) if focus moved off of the input. + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + checkFocus.call( this ); + }); if ( this._start( event ) === false ) { return;