Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add 'step' as a configuration attribute in Slider #1500

Closed
wants to merge 1 commit into from

2 participants

@customcommander

Hi,

This is an attempt to implement #1449 (provided that I correctly understood the requirement).

Pinging owner @lsmith

Cheers,

@lsmith lsmith commented on the diff
src/slider/js/value-range.js
@@ -376,6 +376,20 @@ Y.SliderValueRange = Y.mix( SliderValueRange, {
},
/**
+ * Amount to increment/decrement the Slider value.
+ *
+ * @attribute step
+ * @type {Number}
+ * @default 1
+ */
+ step: {
+ value: 1,
+ validator: function (value) {
+ return Y.Lang.isNumber(value) && value > 0 && value <= this.get('max');
@lsmith
lsmith added a note

min can be greater than max for value-reversed Sliders.

Ouch, I didn't know those existed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith lsmith commented on the diff
src/slider/js/value-range.js
@@ -396,7 +414,11 @@ Y.SliderValueRange = Y.mix( SliderValueRange, {
* @default 10
*/
majorStep : {
- value: 10
+ value: 10,
+ getter: function (value) {
+ var step = this.get('step');
+ return (step==1) ? value : step+value;
@lsmith
lsmith added a note

This kind of hard coding isn't very library friendly. Why the special casing of 1? Also, == should be === unless coercion is needed.

Which hard coding? value: 10 was there before. Or is the getter the offending code?

About the special casing of 1, I wanted to avoid (given minor and major steps are both set to 1 and 10):

value after minor inc after major inc
1 3 14

Which was failing the existing tests. As opposed to:

value after minor inc after major inc
1 2 12

Which I thought was the expected behavior.

I didn't bother to === check again since I made sure that step is a number through its validator function. But I don't mind changing this.

@lsmith
lsmith added a note

value: 10 is configurable, but having 1 hard coded in the logic of the getter is what makes it difficult for implementers to customize. It's easier to customize by configuration than to override, and harder still to override attribute getter (or any function). In general, it's preferable to use string values as getter/setter/validator/valueFn configurations because they use late binding to resolve the method, so is easier for subclassing or class extension overrides. FYI.

Ah yeah that makes sense

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith

I'm not sure I understand the purpose of this PR. Slider already supports minorStep and majorStep for keyboard interaction, and I don't see any change to the parts of the code that deal with mouse events. What does this add?

@customcommander

As mentioned above I wasn't sure if I had fully understood the requirement.

My attempt was simply to modify the behavior of minor and major steps as I assumed these were picked up internally to increment/decrement the value of the Slider.

So I just assumed that it would work out of the box seeing that the keyboard automation was passing. I did forget about the mouse indeed.

Obviously this PR has failed at so many levels so quite happy to abandon it.

Thanks

@lsmith

If you do want to dedicate the time to add support for value ticks (e.g. 0, 10, 20,...), it would make a lot of people happy! :)

@lsmith lsmith closed this
@customcommander customcommander deleted the customcommander:slider-step branch
@customcommander

Sorry but I'm a bit confused as to what the difference is between the two features: step and tick? I'd like to give it another shot but I could use a bit of clarification to be honest.

@lsmith

Sorry for the confusion. Ticks are discrete values that the slider thumb would jump between as the user interacted with the slider either by keyboard or mouse. If you look at the "Slider with Steps and Snapping" example of this Slider (randomly googled) http://code.ovidiu.ch/slider/, hopefully you'll see what I mean.

Rather than minorStep and majorStep which operate only via keyboard and don't limit the available values--only increment or decrement the value by the step amount--ticks disallow all but a whitelisted set of values.

@customcommander

I think I got it now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 15, 2013
  1. @customcommander
This page is out of date. Refresh to see the latest.
View
5 src/slider/docs/index.mustache
@@ -135,6 +135,11 @@
<td>0</td>
</tr>
<tr>
+ <td><code>step</code></td>
+ <td>The amount to increment or decrement the value</td>
+ <td>1</td>
+ </tr>
+ <tr>
<td><code>length</code></td>
<td>Height of vertical Slider rail; width of horizontal Slider rail</td>
<td>150px</td>
View
26 src/slider/js/value-range.js
@@ -376,6 +376,20 @@ Y.SliderValueRange = Y.mix( SliderValueRange, {
},
/**
+ * Amount to increment/decrement the Slider value.
+ *
+ * @attribute step
+ * @type {Number}
+ * @default 1
+ */
+ step: {
+ value: 1,
+ validator: function (value) {
+ return Y.Lang.isNumber(value) && value > 0 && value <= this.get('max');
@lsmith
lsmith added a note

min can be greater than max for value-reversed Sliders.

Ouch, I didn't know those existed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ }
+ },
+
+ /**
* amount to increment/decrement the Slider value
* when the arrow up/down/left/right keys are pressed
*
@@ -384,7 +398,11 @@ Y.SliderValueRange = Y.mix( SliderValueRange, {
* @default 1
*/
minorStep : {
- value: 1
+ value: 1,
+ getter: function (value) {
+ var step = this.get('step');
+ return (step==1) ? value : step+value;
+ }
},
/**
@@ -396,7 +414,11 @@ Y.SliderValueRange = Y.mix( SliderValueRange, {
* @default 10
*/
majorStep : {
- value: 10
+ value: 10,
+ getter: function (value) {
+ var step = this.get('step');
+ return (step==1) ? value : step+value;
@lsmith
lsmith added a note

This kind of hard coding isn't very library friendly. Why the special casing of 1? Also, == should be === unless coercion is needed.

Which hard coding? value: 10 was there before. Or is the getter the offending code?

About the special casing of 1, I wanted to avoid (given minor and major steps are both set to 1 and 10):

value after minor inc after major inc
1 3 14

Which was failing the existing tests. As opposed to:

value after minor inc after major inc
1 2 12

Which I thought was the expected behavior.

I didn't bother to === check again since I made sure that step is a number through its validator function. But I don't mind changing this.

@lsmith
lsmith added a note

value: 10 is configurable, but having 1 hard coded in the logic of the getter is what makes it difficult for implementers to customize. It's easier to customize by configuration than to override, and harder still to override attribute getter (or any function). In general, it's preferable to use string values as getter/setter/validator/valueFn configurations because they use late binding to resolve the method, so is easier for subclassing or class extension overrides. FYI.

Ah yeah that makes sense

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ }
},
/**
View
65 src/slider/tests/unit/assets/slider-tests.js
@@ -684,6 +684,26 @@ suite.add( new Y.Test.Case({
Y.Assert.areEqual(50, thumb.getAttribute('aria-valuetext'));
slider.destroy();
+ },
+
+ "step should default to 1": function () {
+ var slider = new Y.Slider();
+ Y.Assert.areSame(1, slider.get('step'));
+ },
+
+ "step should always be a number": function () {
+ var slider = new Y.Slider({ step: "wat" });
+ Y.Assert.isNumber(slider.get('step'));
+ },
+
+ "step cannot be lesser than 1": function () {
+ var slider = new Y.Slider({ step: 0 });
+ Y.Assert.isTrue(slider.get('step')>0);
+ },
+
+ "step cannot be greater than max": function () {
+ var slider = new Y.Slider({ max: 100, step: 101 });
+ Y.Assert.isTrue(slider.get('step')<slider.get('max'));
}
}));
@@ -879,6 +899,51 @@ suite.add( new Y.Test.Case({
}
}));
+suite.add(new Y.Test.Case({
+
+ name: "Slider with steps",
+
+ init: function () {
+ Y.one('body').append('<div id="slider_test"></div>');
+ },
+
+ destroy: function () {
+ Y.one('#slider_test').remove();
+ },
+
+ setUp: function () {
+ this.slider = new Y.Slider({ step: 10, value: 50 });
+ this.prevValue = this.slider.getValue();
+ this.minorStep = this.slider.get('minorStep');
+ this.majorStep = this.slider.get('majorStep');
+ this.slider.render('#slider_test');
+ },
+
+ tearDown: function () {
+ this.slider.destroy();
+ },
+
+ "test: a minor increment": function () {
+ this.slider.thumb.key(39); // arrow right
+ Y.Assert.areSame(this.prevValue + this.minorStep, this.slider.getValue());
+ },
+
+ "test: a minor decrement": function () {
+ this.slider.thumb.key(37); // arrow left
+ Y.Assert.areSame(this.prevValue - this.minorStep, this.slider.getValue());
+ },
+
+ "test: major increment": function () {
+ this.slider.thumb.key(33); // page up
+ Y.Assert.areSame(this.prevValue + this.majorStep, this.slider.getValue());
+ },
+
+ "test: major decrement": function () {
+ this.slider.thumb.key(34); // page down
+ Y.Assert.areSame(this.prevValue - this.majorStep, this.slider.getValue());
+ }
+}));
+
Y.Test.Runner.add( suite );
Something went wrong with that request. Please try again.