From 42337dd959c1e302c5656d5b25ceb42e99df6215 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Scott=20Gonz=C3=A1lez?= Date: Wed, 14 Sep 2011 08:54:29 -0400 Subject: [PATCH] Spinner: Fix step mismatches whenever stepping, paging or using the value setter. Thanks Nate Ferrero --- tests/unit/spinner/spinner_core.js | 11 +++--- tests/unit/spinner/spinner_methods.js | 26 +++++++------ tests/unit/spinner/spinner_options.js | 5 ++- ui/jquery.ui.spinner.js | 55 ++++++++++++++++++--------- 4 files changed, 58 insertions(+), 39 deletions(-) diff --git a/tests/unit/spinner/spinner_core.js b/tests/unit/spinner/spinner_core.js index 34a79bb16..e12d1af2f 100644 --- a/tests/unit/spinner/spinner_core.js +++ b/tests/unit/spinner/spinner_core.js @@ -109,14 +109,12 @@ test( "mouse click on up button, increases value not greater than max", function }); test( "mousewheel on input", function() { - expect( 5 ); + expect( 4 ); - var element = $( "#spin" ).spinner({ + var element = $( "#spin" ).val( 0 ).spinner({ step: 2 }); - equal( element.val(), 0 ); - element.trigger( "mousewheel" ); equal( element.val(), 0, "mousewheel event without delta does not change value" ); @@ -198,10 +196,11 @@ test( "precision", function() { equal( element.val(), "0.0501", "precision from step" ); element.val( 1.05 ).spinner( "option", { - step: 1 + step: 1, + min: -9.95 }); element.spinner( "stepDown" ); - equal( element.val(), "0.05", "precision from value" ); + equal( element.val(), "0.05", "precision from min" ); }); })( jQuery ); diff --git a/tests/unit/spinner/spinner_methods.js b/tests/unit/spinner/spinner_methods.js index fbfcf1bb3..a9fd6c889 100644 --- a/tests/unit/spinner/spinner_methods.js +++ b/tests/unit/spinner/spinner_methods.js @@ -54,7 +54,7 @@ test( "disable", function() { test( "enable", function() { expect( 5 ); - var element = $( "#spin" ).spinner({ disabled: true }) + var element = $( "#spin" ).val( 1 ).spinner({ disabled: true }) wrapper = element.spinner( "widget" ); ok( wrapper.hasClass( "ui-spinner-disabled" ), "before: wrapper has ui-spinner-disabled class" ); @@ -66,7 +66,7 @@ test( "enable", function() { ok( !element.is( ":disabled" ), "after: input does not have disabled attribute" ); spinner_simulateKeyDownUp( element, $.ui.keyCode.UP ); - equals( 1, element.val(), "keyboard - value does not change on key UP" ); + equals( 2, element.val(), "keyboard - value changes on key UP" ); }); test( "pageDown", function() { @@ -117,23 +117,23 @@ test( "stepDown", function() { }); element.spinner( "stepDown" ); - equals( element.val(), -2, "stepDown 1 step" ); + equals( element.val(), "-1", "stepDown 1 step" ); element.spinner( "stepDown", 5 ); - equals( element.val(), -12, "stepDown 5 steps" ); + equals( element.val(), "-11", "stepDown 5 steps" ); element.spinner( "stepDown", 4 ); - equals( element.val(), -15, "close to min and stepDown 4 steps" ); + equals( element.val(), "-15", "close to min and stepDown 4 steps" ); element.spinner( "stepDown" ); - equals( element.val(), -15, "at min and stepDown 1 step" ); + equals( element.val(), "-15", "at min and stepDown 1 step" ); }); test( "stepUp", function() { expect( 4 ); var element = $( "#spin" ).val( 0 ).spinner({ step: 2, - max: 15 + max: 16 }); element.spinner( "stepUp" ); @@ -143,20 +143,22 @@ test( "stepUp", function() { equals( element.val(), 12, "stepUp 5 steps" ); element.spinner( "stepUp", 4 ); - equals( element.val(), 15, "close to min and stepUp 4 steps" ); + equals( element.val(), 16, "close to min and stepUp 4 steps" ); element.spinner( "stepUp" ); - equals( element.val(), 15, "at max and stepUp 1 step" ); + equals( element.val(), 16, "at max and stepUp 1 step" ); }); test( "value", function() { expect( 2 ); - var element = $( "#spin" ).val( 0 ).spinner(); + var element = $( "#spin" ).val( 0 ).spinner({ + step: 3 + }); element.spinner( "value", 10 ); - equals( element.val(), 10, "change value via value method" ); + equals( element.val(), 9, "change value via value method" ); - equals( element.spinner( "value" ), 10, "get value via value method" ); + equals( element.spinner( "value" ), 9, "get value via value method" ); }); })( jQuery ); diff --git a/tests/unit/spinner/spinner_options.js b/tests/unit/spinner/spinner_options.js index 48bdf96a9..2b557cb69 100644 --- a/tests/unit/spinner/spinner_options.js +++ b/tests/unit/spinner/spinner_options.js @@ -123,10 +123,11 @@ test( "step, 2", function() { equals( element.val(), "2", "stepUp" ); element.spinner( "value", "10.5" ); - equals( element.val(), "10.5", "value reset to 10.5" ); + equals( element.val(), "10", "value reset to 10" ); + element.val( "4.5" ); element.spinner( "stepUp" ); - equals( element.val(), "12.5", "stepUp" ); + equals( element.val(), "6", "stepUp" ); }); test( "step, 0.7", function() { diff --git a/ui/jquery.ui.spinner.js b/ui/jquery.ui.spinner.js index d58665265..1fb715b1b 100644 --- a/ui/jquery.ui.spinner.js +++ b/ui/jquery.ui.spinner.js @@ -213,20 +213,16 @@ $.widget( "ui.spinner", { }, _spin: function( step, event ) { + var value = this.value() || 0; + if ( !this.counter ) { this.counter = 1; } - var value = this.value(), - newVal = value + step * this._increment( this.counter ), - // fix precision from bad JS floating point math - precision = Math.max( this._precision( value ), - this._precision( this.options.step ) ); - // clamp the new value - newVal = this._trimValue( newVal.toFixed( precision ) ); + value = this._adjustValue( value + step * this._increment( this.counter ) ); - if ( !this.spinning || this._trigger( "spin", event, { value: newVal } ) !== false) { - this._value( newVal ); + if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { + this._value( value ); this.counter++; } }, @@ -244,19 +240,40 @@ $.widget( "ui.spinner", { }, _precision: function( num ) { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); + } + return precision; + }, + + _precisionOf: function( num ) { var str = num.toString(), decimal = str.indexOf( "." ); return decimal === -1 ? 0 : str.length - decimal - 1; }, - _trimValue: function( value ) { - var options = this.options; + _adjustValue: function( value ) { + var base, aboveMin, + options = this.options; - if ( options.max != null && value > options.max) { + // make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value - base; + // - round to the nearest step + aboveMin = Math.round(aboveMin / options.step) * options.step; + // - rounding is based on 0, so adjust back to our base + value = base + aboveMin; + + // fix precision from bad JS floating point math + value = parseFloat( value.toFixed( this._precision() ) ); + + // clamp the value + if ( options.max !== null && value > options.max) { return options.max; } - - if ( options.min != null && value < options.min ) { + if ( options.min !== null && value < options.min ) { return options.min; } @@ -295,10 +312,10 @@ $.widget( "ui.spinner", { }), _parse: function( val ) { - if ( typeof val === "string" ) { + if ( typeof val === "string" && val !== "" ) { val = window.Globalize && this.options.numberFormat ? Globalize.parseFloat( val ) : +val; } - return isNaN( val ) ? null : val; + return val === "" || isNaN( val ) ? null : val; }, _format: function( value ) { @@ -320,13 +337,13 @@ $.widget( "ui.spinner", { }, // update the value without triggering change - _value: function( value, ignoreRange ) { + _value: function( value, allowAny ) { var parsed; if ( value !== "" ) { parsed = this._parse( value ); if ( parsed !== null ) { - if ( !ignoreRange ) { - parsed = this._trimValue( parsed ); + if ( !allowAny ) { + parsed = this._adjustValue( parsed ); } value = this._format( parsed ); } -- 2.39.5