]> source.dussan.org Git - jquery-ui.git/commitdiff
Spinner: Handle async focus events in IE. Fixes incorrect detection of changes.
authorScott González <scott.gonzalez@gmail.com>
Thu, 10 May 2012 21:59:55 +0000 (17:59 -0400)
committerScott González <scott.gonzalez@gmail.com>
Thu, 10 May 2012 21:59:55 +0000 (17:59 -0400)
tests/unit/spinner/spinner_events.js
ui/jquery.ui.spinner.js

index 133a8d5a226e17d4cde5b874c9faecfb33d1ac74..72b185528dbea015d81cb024f086a4e16134bd14 100644 (file)
@@ -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();
-
-       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, "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( true, "stepUp" );
-       element.spinner( "stepUp" );
-
-       shouldChange( true, "stepDown" );
-       element.spinner( "stepDown" );
-
-       shouldChange( true, "pageUp" );
-       element.spinner( "pageUp" );
-
-       shouldChange( true, "pageDown" );
-       element.spinner( "pageDown" );
-
-       shouldChange( true, "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( false, "max, value not changed" );
-       element.spinner( "option", "max", 1000 );
-
-       shouldChange( true, "min, value changed" );
-       element.spinner( "option", "min", 950 );
-
-       shouldChange( false, "min, value not changed" );
-       element.spinner( "option", "min", 200 );
+       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" );
+               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();
+                       setTimeout(function() {
+                               shouldChange( true, "stepUp" );
+                               element.spinner( "stepUp" );
+
+                               shouldChange( true, "stepDown" );
+                               element.spinner( "stepDown" );
+
+                               shouldChange( true, "pageUp" );
+                               element.spinner( "pageUp" );
+
+                               shouldChange( true, "pageDown" );
+                               element.spinner( "pageDown" );
+
+                               shouldChange( true, "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( false, "max, value not changed" );
+                               element.spinner( "option", "max", 1000 );
+
+                               shouldChange( true, "min, value changed" );
+                               element.spinner( "option", "min", 950 );
+
+                               shouldChange( false, "min, value not changed" );
+                               element.spinner( "option", "min", 200 );
+                               start();
+                       });
+               });
+       });
 });
 
 })( jQuery );
index bd55a09ea200f23c15d082269606273492844283..1e4204a0c3aca42c2f812ae012b6ca58255ff214 100644 (file)
@@ -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;