2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('slider-value-range', function(Y) {
11 * Adds value support for Slider as a range of integers between a configured
12 * minimum and maximum value. For use with <code>Y.Base.build(..)</code> to
13 * add the plumbing to <code>Y.SliderBase</code>.
16 * @submodule slider-value-range
19 // Constants for compression or performance
27 * One class of value algorithm that can be built onto SliderBase. By default,
28 * values range between 0 and 100, but you can configure these on the
29 * built Slider class by setting the <code>min</code> and <code>max</code>
30 * configurations. Set the initial value (will cause the thumb to move to the
31 * appropriate location on the rail) in configuration as well if appropriate.
33 * @class SliderValueRange
35 function SliderValueRange() {
36 this._initSliderValueRange();
39 Y.SliderValueRange = Y.mix( SliderValueRange, {
41 // Prototype properties and methods that will be added onto host class
45 * Factor used to translate value -> position -> value.
54 * Stub for construction logic. Override if extending this class and
55 * you need to set something up during the initializer phase.
57 * @method _initSliderValueRange
60 _initSliderValueRange: function () {},
63 * Override of stub method in SliderBase that is called at the end of
64 * its bindUI stage of render(). Subscribes to internal events to
65 * trigger UI and related state updates.
67 * @method _bindValueLogic
70 _bindValueLogic: function () {
72 minChange : this._afterMinChange,
73 maxChange : this._afterMaxChange,
74 valueChange: this._afterValueChange
79 * Move the thumb to appropriate position if necessary. Also resets
80 * the cached offsets and recalculates the conversion factor to
81 * translate position to value.
83 * @method _syncThumbPosition
86 _syncThumbPosition: function () {
87 this._calculateFactor();
89 this._setPosition( this.get( VALUE ) );
93 * Calculates and caches
94 * (range between max and min) / (rail length)
95 * for fast runtime calculation of position -> value.
97 * @method _calculateFactor
100 _calculateFactor: function () {
101 var length = this.get( 'length' ),
102 thumbSize = this.thumb.getStyle( this._key.dim ),
103 min = this.get( MIN ),
104 max = this.get( MAX );
106 // The default thumb width is based on Sam skin's thumb dimension.
107 // This attempts to allow for rendering off-DOM, then attaching
108 // without the need to call syncUI(). It is still recommended
109 // to call syncUI() in these cases though, just to be sure.
110 length = parseFloat( length, 10 ) || 150;
111 thumbSize = parseFloat( thumbSize, 10 ) || 15;
113 this._factor = ( max - min ) / ( length - thumbSize );
118 * Dispatch the new position of the thumb into the value setting
121 * @method _defThumbMoveFn
122 * @param e { EventFacade } The host's thumbMove event
125 _defThumbMoveFn: function ( e ) {
126 var previous = this.get( VALUE ),
127 value = this._offsetToValue( e.offset );
129 // This test avoids duplication of this.set(..) if the origin
130 // of this thumbMove is from slider.set('value',x);
131 // slider.set() -> afterValueChange -> uiMoveThumb ->
132 // fire(thumbMove) -> _defThumbMoveFn -> this.set()
133 if ( previous !== value ) {
134 this.set( VALUE, value, { positioned: true } );
139 * <p>Converts a pixel position into a value. Calculates current
140 * thumb offset from the leading edge of the rail multiplied by the
141 * ratio of <code>(max - min) / (constraining dim)</code>.</p>
143 * <p>Override this if you want to use a different value mapping
146 * @method _offsetToValue
147 * @param offset { Number } X or Y pixel offset
148 * @return { mixed } Value corresponding to the provided pixel offset
151 _offsetToValue: function ( offset ) {
153 var value = round( offset * this._factor ) + this.get( MIN );
155 return round( this._nearestValue( value ) );
159 * Converts a value into a pixel offset for use in positioning
160 * the thumb according to the reverse of the
161 * <code>_offsetToValue( xy )</code> operation.
163 * @method _valueToOffset
164 * @param val { Number } The value to map to pixel X or Y position
165 * @return { Number } The pixel offset
168 _valueToOffset: function ( value ) {
169 var offset = round( ( value - this.get( MIN ) ) / this._factor );
175 * Returns the current value. Override this if you want to introduce
176 * output formatting. Otherwise equivalent to slider.get( "value" );
181 getValue: function () {
182 return this.get( VALUE );
186 * Updates the current value. Override this if you want to introduce
187 * input value parsing or preprocessing. Otherwise equivalent to
188 * slider.set( "value", v );
191 * @param val {Number} The new value
195 setValue: function ( val ) {
196 return this.set( VALUE, val );
200 * Update position according to new min value. If the new min results
201 * in the current value being out of range, the value is set to the
202 * closer of min or max.
204 * @method _afterMinChange
205 * @param e { EventFacade } The <code>min</code> attribute change event.
208 _afterMinChange: function ( e ) {
211 this._syncThumbPosition();
215 * Update position according to new max value. If the new max results
216 * in the current value being out of range, the value is set to the
217 * closer of min or max.
219 * @method _afterMaxChange
220 * @param e { EventFacade } The <code>max</code> attribute change event.
223 _afterMaxChange: function ( e ) {
226 this._syncThumbPosition();
230 * Verifies that the current value is within the min - max range. If
231 * not, value is set to either min or max, depending on which is
234 * @method _verifyValue
237 _verifyValue: function () {
238 var value = this.get( VALUE ),
239 nearest = this._nearestValue( value );
241 if ( value !== nearest ) {
242 // @TODO Can/should valueChange, minChange, etc be queued
243 // events? To make dd.set( 'min', n ); execute after minChange
244 // subscribers before on/after valueChange subscribers.
245 this.set( VALUE, nearest );
250 * Propagate change to the thumb position unless the change originated
251 * from the thumbMove event.
253 * @method _afterValueChange
254 * @param e { EventFacade } The <code>valueChange</code> event.
257 _afterValueChange: function ( e ) {
258 if ( !e.positioned ) {
259 this._setPosition( e.newVal );
264 * Positions the thumb in accordance with the translated value.
266 * @method _setPosition
269 _setPosition: function ( value ) {
270 this._uiMoveThumb( this._valueToOffset( value ) );
274 * Validates new values assigned to <code>min</code> attribute. Numbers
275 * are acceptable. Override this to enforce different rules.
277 * @method _validateNewMin
278 * @param value { mixed } Value assigned to <code>min</code> attribute.
279 * @return { Boolean } True for numbers. False otherwise.
282 _validateNewMin: function ( value ) {
283 return Y.Lang.isNumber( value );
287 * Validates new values assigned to <code>max</code> attribute. Numbers
288 * are acceptable. Override this to enforce different rules.
290 * @method _validateNewMax
291 * @param value { mixed } Value assigned to <code>max</code> attribute.
292 * @return { Boolean } True for numbers. False otherwise.
295 _validateNewMax: function ( value ) {
296 return Y.Lang.isNumber( value );
300 * Restricts new values assigned to <code>value</code> attribute to be
301 * between the configured <code>min</code> and <code>max</code>.
302 * Rounds to nearest integer value.
304 * @method _setNewValue
305 * @param value { Number } Value assigned to <code>value</code> attribute
306 * @return { Number } Normalized and constrained value
309 _setNewValue: function ( value ) {
310 return round( this._nearestValue( value ) );
314 * Returns the nearest valid value to the value input. If the provided
315 * value is outside the min - max range, accounting for min > max
316 * scenarios, the nearest of either min or max is returned. Otherwise,
317 * the provided value is returned.
319 * @method _nearestValue
320 * @param value { mixed } Value to test against current min - max range
321 * @return { Number } Current min, max, or value if within range
324 _nearestValue: function ( value ) {
325 var min = this.get( MIN ),
326 max = this.get( MAX ),
329 // Account for reverse value range (min > max)
330 tmp = ( max > min ) ? max : min;
331 min = ( max > min ) ? min : max;
334 return ( value < min ) ?
344 * Attributes that will be added onto host class.
353 * The value associated with the farthest top, left position of the
354 * rail. Can be greater than the configured <code>max</code> if you
355 * want values to increase from right-to-left or bottom-to-top.
363 validator: '_validateNewMin'
367 * The value associated with the farthest bottom, right position of
368 * the rail. Can be less than the configured <code>min</code> if
369 * you want values to increase from right-to-left or bottom-to-top.
377 validator: '_validateNewMax'
381 * The value associated with the thumb's current position on the
382 * rail. Defaults to the value inferred from the thumb's current
383 * position. Specifying value in the constructor will move the
384 * thumb to the position that corresponds to the supplied value.
388 * @default (inferred from current thumb position)
392 setter: '_setNewValue'
398 }, '3.3.0' ,{requires:['slider-base']});