Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / Multi.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-slider-Multi'>/**
19 </span> * @class Ext.slider.Multi
20  * @extends Ext.form.field.Base
21  * &lt;p&gt;Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis
22  * clicking and animation. Can be added as an item to any container. In addition,  
23  * {@img Ext.slider.Multi/Ext.slider.Multi.png Ext.slider.Multi component}
24  * &lt;p&gt;Example usage:&lt;/p&gt;
25  * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
26 &lt;pre&gt;
27     Ext.create('Ext.slider.Multi', {
28         width: 200,
29         values: [25, 50, 75],
30         increment: 5,
31         minValue: 0,
32         maxValue: 100,
33
34         //this defaults to true, setting to false allows the thumbs to pass each other
35         {@link #constrainThumbs}: false,
36         renderTo: Ext.getBody()
37     });  
38 &lt;/pre&gt;
39  * @xtype multislider
40  */
41 Ext.define('Ext.slider.Multi', {
42     extend: 'Ext.form.field.Base',
43     alias: 'widget.multislider',
44     alternateClassName: 'Ext.slider.MultiSlider',
45
46     requires: [
47         'Ext.slider.Thumb',
48         'Ext.slider.Tip',
49         'Ext.Number',
50         'Ext.util.Format',
51         'Ext.Template',
52         'Ext.layout.component.field.Slider'
53     ],
54
55     fieldSubTpl: [
56         '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'slider {fieldCls} {vertical}&quot; aria-valuemin=&quot;{minValue}&quot; aria-valuemax=&quot;{maxValue}&quot; aria-valuenow=&quot;{value}&quot; aria-valuetext=&quot;{value}&quot;&gt;',
57             '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'slider-end&quot; role=&quot;presentation&quot;&gt;',
58                 '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'slider-inner&quot; role=&quot;presentation&quot;&gt;',
59                     '&lt;a class=&quot;' + Ext.baseCSSPrefix + 'slider-focus&quot; href=&quot;#&quot; tabIndex=&quot;-1&quot; hidefocus=&quot;on&quot; role=&quot;presentation&quot;&gt;&lt;/a&gt;',
60                 '&lt;/div&gt;',
61             '&lt;/div&gt;',
62         '&lt;/div&gt;',
63         {
64             disableFormats: true,
65             compiled: true
66         }
67     ],
68
69 <span id='Ext-slider-Multi-cfg-value'>    /**
70 </span>     * @cfg {Number} value
71      * A value with which to initialize the slider. Defaults to minValue. Setting this will only
72      * result in the creation of a single slider thumb; if you want multiple thumbs then use the
73      * {@link #values} config instead.
74      */
75
76 <span id='Ext-slider-Multi-cfg-values'>    /**
77 </span>     * @cfg {Array} values
78      * Array of Number values with which to initalize the slider. A separate slider thumb will be created for
79      * each value in this array. This will take precedence over the single {@link #value} config.
80      */
81
82 <span id='Ext-slider-Multi-cfg-vertical'>    /**
83 </span>     * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
84      */
85     vertical: false,
86 <span id='Ext-slider-Multi-cfg-minValue'>    /**
87 </span>     * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
88      */
89     minValue: 0,
90 <span id='Ext-slider-Multi-cfg-maxValue'>    /**
91 </span>     * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
92      */
93     maxValue: 100,
94 <span id='Ext-slider-Multi-cfg-decimalPrecision'>    /**
95 </span>     * @cfg {Number/Boolean} decimalPrecision.
96      * &lt;p&gt;The number of decimal places to which to round the Slider's value. Defaults to 0.&lt;/p&gt;
97      * &lt;p&gt;To disable rounding, configure as &lt;tt&gt;&lt;b&gt;false&lt;/b&gt;&lt;/tt&gt;.&lt;/p&gt;
98      */
99     decimalPrecision: 0,
100 <span id='Ext-slider-Multi-cfg-keyIncrement'>    /**
101 </span>     * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead.
102      */
103     keyIncrement: 1,
104 <span id='Ext-slider-Multi-cfg-increment'>    /**
105 </span>     * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
106      */
107     increment: 0,
108
109 <span id='Ext-slider-Multi-property-clickRange'>    /**
110 </span>     * @private
111      * @property clickRange
112      * @type Array
113      * Determines whether or not a click to the slider component is considered to be a user request to change the value. Specified as an array of [top, bottom],
114      * the click event's 'top' property is compared to these numbers and the click only considered a change request if it falls within them. e.g. if the 'top'
115      * value of the click event is 4 or 16, the click is not considered a change request as it falls outside of the [5, 15] range
116      */
117     clickRange: [5,15],
118
119 <span id='Ext-slider-Multi-cfg-clickToChange'>    /**
120 </span>     * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
121      */
122     clickToChange : true,
123 <span id='Ext-slider-Multi-cfg-animate'>    /**
124 </span>     * @cfg {Boolean} animate Turn on or off animation. Defaults to true
125      */
126     animate: true,
127
128 <span id='Ext-slider-Multi-property-dragging'>    /**
129 </span>     * True while the thumb is in a drag operation
130      * @type Boolean
131      */
132     dragging: false,
133
134 <span id='Ext-slider-Multi-cfg-constrainThumbs'>    /**
135 </span>     * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
136      */
137     constrainThumbs: true,
138
139     componentLayout: 'sliderfield',
140
141 <span id='Ext-slider-Multi-cfg-useTips'>    /**
142 </span>     * @cfg {Boolean} useTips
143      * True to use an Ext.slider.Tip to display tips for the value. Defaults to &lt;tt&gt;true&lt;/tt&gt;.
144      */
145     useTips : true,
146
147 <span id='Ext-slider-Multi-cfg-tipText'>    /**
148 </span>     * @cfg {Function} tipText
149      * A function used to display custom text for the slider tip. Defaults to &lt;tt&gt;null&lt;/tt&gt;, which will
150      * use the default on the plugin.
151      */
152     tipText : null,
153
154     ariaRole: 'slider',
155
156     // private override
157     initValue: function() {
158         var me = this,
159             extValue = Ext.value,
160             // Fallback for initial values: values config -&gt; value config -&gt; minValue config -&gt; 0
161             values = extValue(me.values, [extValue(me.value, extValue(me.minValue, 0))]),
162             i = 0,
163             len = values.length;
164
165         // Store for use in dirty check
166         me.originalValue = values;
167
168         // Add a thumb for each value
169         for (; i &lt; len; i++) {
170             me.addThumb(values[i]);
171         }
172     },
173
174     // private override
175     initComponent : function() {
176         var me = this,
177             tipPlug,
178             hasTip;
179         
180 <span id='Ext-slider-Multi-property-thumbs'>        /**
181 </span>         * @property thumbs
182          * @type Array
183          * Array containing references to each thumb
184          */
185         me.thumbs = [];
186
187         me.keyIncrement = Math.max(me.increment, me.keyIncrement);
188
189         me.addEvents(
190 <span id='Ext-slider-Multi-event-beforechange'>            /**
191 </span>             * @event beforechange
192              * Fires before the slider value is changed. By returning false from an event handler,
193              * you can cancel the event and prevent the slider from changing.
194              * @param {Ext.slider.Multi} slider The slider
195              * @param {Number} newValue The new value which the slider is being changed to.
196              * @param {Number} oldValue The old value which the slider was previously.
197              */
198             'beforechange',
199
200 <span id='Ext-slider-Multi-event-change'>            /**
201 </span>             * @event change
202              * Fires when the slider value is changed.
203              * @param {Ext.slider.Multi} slider The slider
204              * @param {Number} newValue The new value which the slider has been changed to.
205              * @param {Ext.slider.Thumb} thumb The thumb that was changed
206              */
207             'change',
208
209 <span id='Ext-slider-Multi-event-changecomplete'>            /**
210 </span>             * @event changecomplete
211              * Fires when the slider value is changed by the user and any drag operations have completed.
212              * @param {Ext.slider.Multi} slider The slider
213              * @param {Number} newValue The new value which the slider has been changed to.
214              * @param {Ext.slider.Thumb} thumb The thumb that was changed
215              */
216             'changecomplete',
217
218 <span id='Ext-slider-Multi-event-dragstart'>            /**
219 </span>             * @event dragstart
220              * Fires after a drag operation has started.
221              * @param {Ext.slider.Multi} slider The slider
222              * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
223              */
224             'dragstart',
225
226 <span id='Ext-slider-Multi-event-drag'>            /**
227 </span>             * @event drag
228              * Fires continuously during the drag operation while the mouse is moving.
229              * @param {Ext.slider.Multi} slider The slider
230              * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
231              */
232             'drag',
233
234 <span id='Ext-slider-Multi-event-dragend'>            /**
235 </span>             * @event dragend
236              * Fires after the drag operation has completed.
237              * @param {Ext.slider.Multi} slider The slider
238              * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker
239              */
240             'dragend'
241         );
242
243         if (me.vertical) {
244             Ext.apply(me, Ext.slider.Multi.Vertical);
245         }
246
247         me.callParent();
248
249         // only can use it if it exists.
250         if (me.useTips) {
251             tipPlug = me.tipText ? {getText: me.tipText} : {};
252             me.plugins = me.plugins || [];
253             Ext.each(me.plugins, function(plug){
254                 if (plug.isSliderTip) {
255                     hasTip = true;
256                     return false;
257                 }
258             });
259             if (!hasTip) {
260                 me.plugins.push(Ext.create('Ext.slider.Tip', tipPlug));
261             }
262         }
263     },
264
265 <span id='Ext-slider-Multi-method-addThumb'>    /**
266 </span>     * Creates a new thumb and adds it to the slider
267      * @param {Number} value The initial value to set on the thumb. Defaults to 0
268      * @return {Ext.slider.Thumb} The thumb
269      */
270     addThumb: function(value) {
271         var me = this,
272             thumb = Ext.create('Ext.slider.Thumb', {
273             value    : value,
274             slider   : me,
275             index    : me.thumbs.length,
276             constrain: me.constrainThumbs
277         });
278         me.thumbs.push(thumb);
279
280         //render the thumb now if needed
281         if (me.rendered) {
282             thumb.render();
283         }
284
285         return thumb;
286     },
287
288 <span id='Ext-slider-Multi-method-promoteThumb'>    /**
289 </span>     * @private
290      * Moves the given thumb above all other by increasing its z-index. This is called when as drag
291      * any thumb, so that the thumb that was just dragged is always at the highest z-index. This is
292      * required when the thumbs are stacked on top of each other at one of the ends of the slider's
293      * range, which can result in the user not being able to move any of them.
294      * @param {Ext.slider.Thumb} topThumb The thumb to move to the top
295      */
296     promoteThumb: function(topThumb) {
297         var thumbs = this.thumbs,
298             ln = thumbs.length,
299             zIndex, thumb, i;
300             
301         for (i = 0; i &lt; ln; i++) {
302             thumb = thumbs[i];
303
304             if (thumb == topThumb) {
305                 thumb.bringToFront();
306             } else {
307                 thumb.sendToBack();
308             }
309         }
310     },
311
312     // private override
313     onRender : function() {
314         var me = this,
315             i = 0,
316             thumbs = me.thumbs,
317             len = thumbs.length,
318             thumb;
319
320         Ext.applyIf(me.subTplData, {
321             vertical: me.vertical ? Ext.baseCSSPrefix + 'slider-vert' : Ext.baseCSSPrefix + 'slider-horz',
322             minValue: me.minValue,
323             maxValue: me.maxValue,
324             value: me.value
325         });
326
327         Ext.applyIf(me.renderSelectors, {
328             endEl: '.' + Ext.baseCSSPrefix + 'slider-end',
329             innerEl: '.' + Ext.baseCSSPrefix + 'slider-inner',
330             focusEl: '.' + Ext.baseCSSPrefix + 'slider-focus'
331         });
332
333         me.callParent(arguments);
334
335         //render each thumb
336         for (; i &lt; len; i++) {
337             thumbs[i].render();
338         }
339
340         //calculate the size of half a thumb
341         thumb = me.innerEl.down('.' + Ext.baseCSSPrefix + 'slider-thumb');
342         me.halfThumb = (me.vertical ? thumb.getHeight() : thumb.getWidth()) / 2;
343
344     },
345
346 <span id='Ext-slider-Multi-method-onChange'>    /**
347 </span>     * Utility method to set the value of the field when the slider changes.
348      * @param {Object} slider The slider object.
349      * @param {Object} v The new value.
350      * @private
351      */
352     onChange : function(slider, v) {
353         this.setValue(v, undefined, true);
354     },
355
356 <span id='Ext-slider-Multi-method-initEvents'>    /**
357 </span>     * @private
358      * Adds keyboard and mouse listeners on this.el. Ignores click events on the internal focus element.
359      */
360     initEvents : function() {
361         var me = this;
362         
363         me.mon(me.el, {
364             scope    : me,
365             mousedown: me.onMouseDown,
366             keydown  : me.onKeyDown,
367             change : me.onChange
368         });
369
370         me.focusEl.swallowEvent(&quot;click&quot;, true);
371     },
372
373 <span id='Ext-slider-Multi-method-onMouseDown'>    /**
374 </span>     * @private
375      * Mousedown handler for the slider. If the clickToChange is enabled and the click was not on the draggable 'thumb',
376      * this calculates the new value of the slider and tells the implementation (Horizontal or Vertical) to move the thumb
377      * @param {Ext.EventObject} e The click event
378      */
379     onMouseDown : function(e) {
380         var me = this,
381             thumbClicked = false,
382             i = 0,
383             thumbs = me.thumbs,
384             len = thumbs.length,
385             local;
386             
387         if (me.disabled) {
388             return;
389         }
390
391         //see if the click was on any of the thumbs
392         for (; i &lt; len; i++) {
393             thumbClicked = thumbClicked || e.target == thumbs[i].el.dom;
394         }
395
396         if (me.clickToChange &amp;&amp; !thumbClicked) {
397             local = me.innerEl.translatePoints(e.getXY());
398             me.onClickChange(local);
399         }
400         me.focus();
401     },
402
403 <span id='Ext-slider-Multi-method-onClickChange'>    /**
404 </span>     * @private
405      * Moves the thumb to the indicated position. Note that a Vertical implementation is provided in Ext.slider.Multi.Vertical.
406      * Only changes the value if the click was within this.clickRange.
407      * @param {Object} local Object containing top and left values for the click event.
408      */
409     onClickChange : function(local) {
410         var me = this,
411             thumb, index;
412             
413         if (local.top &gt; me.clickRange[0] &amp;&amp; local.top &lt; me.clickRange[1]) {
414             //find the nearest thumb to the click event
415             thumb = me.getNearest(local, 'left');
416             if (!thumb.disabled) {
417                 index = thumb.index;
418                 me.setValue(index, Ext.util.Format.round(me.reverseValue(local.left), me.decimalPrecision), undefined, true);
419             }
420         }
421     },
422
423 <span id='Ext-slider-Multi-method-getNearest'>    /**
424 </span>     * @private
425      * Returns the nearest thumb to a click event, along with its distance
426      * @param {Object} local Object containing top and left values from a click event
427      * @param {String} prop The property of local to compare on. Use 'left' for horizontal sliders, 'top' for vertical ones
428      * @return {Object} The closest thumb object and its distance from the click event
429      */
430     getNearest: function(local, prop) {
431         var me = this,
432             localValue = prop == 'top' ? me.innerEl.getHeight() - local[prop] : local[prop],
433             clickValue = me.reverseValue(localValue),
434             nearestDistance = (me.maxValue - me.minValue) + 5, //add a small fudge for the end of the slider
435             index = 0,
436             nearest = null,
437             thumbs = me.thumbs,
438             i = 0,
439             len = thumbs.length,
440             thumb,
441             value,
442             dist;
443
444         for (; i &lt; len; i++) {
445             thumb = me.thumbs[i];
446             value = thumb.value;
447             dist  = Math.abs(value - clickValue);
448
449             if (Math.abs(dist &lt;= nearestDistance)) {
450                 nearest = thumb;
451                 index = i;
452                 nearestDistance = dist;
453             }
454         }
455         return nearest;
456     },
457
458 <span id='Ext-slider-Multi-method-onKeyDown'>    /**
459 </span>     * @private
460      * Handler for any keypresses captured by the slider. If the key is UP or RIGHT, the thumb is moved along to the right
461      * by this.keyIncrement. If DOWN or LEFT it is moved left. Pressing CTRL moves the slider to the end in either direction
462      * @param {Ext.EventObject} e The Event object
463      */
464     onKeyDown : function(e) {
465         /*
466          * The behaviour for keyboard handling with multiple thumbs is currently undefined.
467          * There's no real sane default for it, so leave it like this until we come up
468          * with a better way of doing it.
469          */
470         var me = this,
471             k,
472             val;
473         
474         if(me.disabled || me.thumbs.length !== 1) {
475             e.preventDefault();
476             return;
477         }
478         k = e.getKey();
479         
480         switch(k) {
481             case e.UP:
482             case e.RIGHT:
483                 e.stopEvent();
484                 val = e.ctrlKey ? me.maxValue : me.getValue(0) + me.keyIncrement;
485                 me.setValue(0, val, undefined, true);
486             break;
487             case e.DOWN:
488             case e.LEFT:
489                 e.stopEvent();
490                 val = e.ctrlKey ? me.minValue : me.getValue(0) - me.keyIncrement;
491                 me.setValue(0, val, undefined, true);
492             break;
493             default:
494                 e.preventDefault();
495         }
496     },
497
498 <span id='Ext-slider-Multi-method-doSnap'>    /**
499 </span>     * @private
500      * If using snapping, this takes a desired new value and returns the closest snapped
501      * value to it
502      * @param {Number} value The unsnapped value
503      * @return {Number} The value of the nearest snap target
504      */
505     doSnap : function(value) {
506         var newValue = value,
507             inc = this.increment,
508             m;
509             
510         if (!(inc &amp;&amp; value)) {
511             return value;
512         }
513         m = value % inc;
514         if (m !== 0) {
515             newValue -= m;
516             if (m * 2 &gt;= inc) {
517                 newValue += inc;
518             } else if (m * 2 &lt; -inc) {
519                 newValue -= inc;
520             }
521         }
522         return Ext.Number.constrain(newValue, this.minValue,  this.maxValue);
523     },
524
525     // private
526     afterRender : function() {
527         var me = this,
528             i = 0,
529             thumbs = me.thumbs,
530             len = thumbs.length,
531             thumb,
532             v;
533             
534         me.callParent(arguments);
535
536         for (; i &lt; len; i++) {
537             thumb = thumbs[i];
538
539             if (thumb.value !== undefined) {
540                 v = me.normalizeValue(thumb.value);
541                 if (v !== thumb.value) {
542                     // delete this.value;
543                     me.setValue(i, v, false);
544                 } else {
545                     thumb.move(me.translateValue(v), false);
546                 }
547             }
548         }
549     },
550
551 <span id='Ext-slider-Multi-method-getRatio'>    /**
552 </span>     * @private
553      * Returns the ratio of pixels to mapped values. e.g. if the slider is 200px wide and maxValue - minValue is 100,
554      * the ratio is 2
555      * @return {Number} The ratio of pixels to mapped values
556      */
557     getRatio : function() {
558         var w = this.innerEl.getWidth(),
559             v = this.maxValue - this.minValue;
560         return v === 0 ? w : (w/v);
561     },
562
563 <span id='Ext-slider-Multi-method-normalizeValue'>    /**
564 </span>     * @private
565      * Returns a snapped, constrained value when given a desired value
566      * @param {Number} value Raw number value
567      * @return {Number} The raw value rounded to the correct d.p. and constrained within the set max and min values
568      */
569     normalizeValue : function(v) {
570         var me = this;
571         
572         v = me.doSnap(v);
573         v = Ext.util.Format.round(v, me.decimalPrecision);
574         v = Ext.Number.constrain(v, me.minValue, me.maxValue);
575         return v;
576     },
577
578 <span id='Ext-slider-Multi-method-setMinValue'>    /**
579 </span>     * Sets the minimum value for the slider instance. If the current value is less than the
580      * minimum value, the current value will be changed.
581      * @param {Number} val The new minimum value
582      */
583     setMinValue : function(val) {
584         var me = this,
585             i = 0,
586             thumbs = me.thumbs,
587             len = thumbs.length,
588             t;
589             
590         me.minValue = val;
591         me.inputEl.dom.setAttribute('aria-valuemin', val);
592
593         for (; i &lt; len; ++i) {
594             t = thumbs[i];
595             t.value = t.value &lt; val ? val : t.value;
596         }
597         me.syncThumbs();
598     },
599
600 <span id='Ext-slider-Multi-method-setMaxValue'>    /**
601 </span>     * Sets the maximum value for the slider instance. If the current value is more than the
602      * maximum value, the current value will be changed.
603      * @param {Number} val The new maximum value
604      */
605     setMaxValue : function(val) {
606         var me = this,
607             i = 0,
608             thumbs = me.thumbs,
609             len = thumbs.length,
610             t;
611             
612         me.maxValue = val;
613         me.inputEl.dom.setAttribute('aria-valuemax', val);
614
615         for (; i &lt; len; ++i) {
616             t = thumbs[i];
617             t.value = t.value &gt; val ? val : t.value;
618         }
619         me.syncThumbs();
620     },
621
622 <span id='Ext-slider-Multi-method-setValue'>    /**
623 </span>     * Programmatically sets the value of the Slider. Ensures that the value is constrained within
624      * the minValue and maxValue.
625      * @param {Number} index Index of the thumb to move
626      * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
627      * @param {Boolean} animate Turn on or off animation, defaults to true
628      */
629     setValue : function(index, value, animate, changeComplete) {
630         var me = this,
631             thumb = me.thumbs[index];
632
633         // ensures value is contstrained and snapped
634         value = me.normalizeValue(value);
635
636         if (value !== thumb.value &amp;&amp; me.fireEvent('beforechange', me, value, thumb.value, thumb) !== false) {
637             thumb.value = value;
638             if (me.rendered) {
639                 // TODO this only handles a single value; need a solution for exposing multiple values to aria.
640                 // Perhaps this should go on each thumb element rather than the outer element.
641                 me.inputEl.set({
642                     'aria-valuenow': value,
643                     'aria-valuetext': value
644                 });
645
646                 thumb.move(me.translateValue(value), Ext.isDefined(animate) ? animate !== false : me.animate);
647
648                 me.fireEvent('change', me, value, thumb);
649                 if (changeComplete) {
650                     me.fireEvent('changecomplete', me, value, thumb);
651                 }
652             }
653         }
654     },
655
656 <span id='Ext-slider-Multi-method-translateValue'>    /**
657 </span>     * @private
658      */
659     translateValue : function(v) {
660         var ratio = this.getRatio();
661         return (v * ratio) - (this.minValue * ratio) - this.halfThumb;
662     },
663
664 <span id='Ext-slider-Multi-method-reverseValue'>    /**
665 </span>     * @private
666      * Given a pixel location along the slider, returns the mapped slider value for that pixel.
667      * E.g. if we have a slider 200px wide with minValue = 100 and maxValue = 500, reverseValue(50)
668      * returns 200
669      * @param {Number} pos The position along the slider to return a mapped value for
670      * @return {Number} The mapped value for the given position
671      */
672     reverseValue : function(pos) {
673         var ratio = this.getRatio();
674         return (pos + (this.minValue * ratio)) / ratio;
675     },
676
677     // private
678     focus : function() {
679         this.focusEl.focus(10);
680     },
681
682     //private
683     onDisable: function() {
684         var me = this,
685             i = 0,
686             thumbs = me.thumbs,
687             len = thumbs.length,
688             thumb,
689             el,
690             xy;
691             
692         me.callParent();
693
694         for (; i &lt; len; i++) {
695             thumb = thumbs[i];
696             el = thumb.el;
697
698             thumb.disable();
699
700             if(Ext.isIE) {
701                 //IE breaks when using overflow visible and opacity other than 1.
702                 //Create a place holder for the thumb and display it.
703                 xy = el.getXY();
704                 el.hide();
705
706                 me.innerEl.addCls(me.disabledCls).dom.disabled = true;
707
708                 if (!me.thumbHolder) {
709                     me.thumbHolder = me.endEl.createChild({cls: Ext.baseCSSPrefix + 'slider-thumb ' + me.disabledCls});
710                 }
711
712                 me.thumbHolder.show().setXY(xy);
713             }
714         }
715     },
716
717     //private
718     onEnable: function() {
719         var me = this,
720             i = 0,
721             thumbs = me.thumbs,
722             len = thumbs.length,
723             thumb,
724             el;
725             
726         this.callParent();
727
728         for (; i &lt; len; i++) {
729             thumb = thumbs[i];
730             el = thumb.el;
731
732             thumb.enable();
733
734             if (Ext.isIE) {
735                 me.innerEl.removeCls(me.disabledCls).dom.disabled = false;
736
737                 if (me.thumbHolder) {
738                     me.thumbHolder.hide();
739                 }
740
741                 el.show();
742                 me.syncThumbs();
743             }
744         }
745     },
746
747 <span id='Ext-slider-Multi-method-syncThumbs'>    /**
748 </span>     * Synchronizes thumbs position to the proper proportion of the total component width based
749      * on the current slider {@link #value}.  This will be called automatically when the Slider
750      * is resized by a layout, but if it is rendered auto width, this method can be called from
751      * another resize handler to sync the Slider if necessary.
752      */
753     syncThumbs : function() {
754         if (this.rendered) {
755             var thumbs = this.thumbs,
756                 length = thumbs.length,
757                 i = 0;
758
759             for (; i &lt; length; i++) {
760                 thumbs[i].move(this.translateValue(thumbs[i].value));
761             }
762         }
763     },
764
765 <span id='Ext-slider-Multi-method-getValue'>    /**
766 </span>     * Returns the current value of the slider
767      * @param {Number} index The index of the thumb to return a value for
768      * @return {Number/Array} The current value of the slider at the given index, or an array of
769      * all thumb values if no index is given.
770      */
771     getValue : function(index) {
772         return Ext.isNumber(index) ? this.thumbs[index].value : this.getValues();
773     },
774
775 <span id='Ext-slider-Multi-method-getValues'>    /**
776 </span>     * Returns an array of values - one for the location of each thumb
777      * @return {Array} The set of thumb values
778      */
779     getValues: function() {
780         var values = [],
781             i = 0,
782             thumbs = this.thumbs,
783             len = thumbs.length;
784
785         for (; i &lt; len; i++) {
786             values.push(thumbs[i].value);
787         }
788
789         return values;
790     },
791
792     getSubmitValue: function() {
793         var me = this;
794         return (me.disabled || !me.submitValue) ? null : me.getValue();
795     },
796
797     reset: function() {
798         var me = this,
799             Array = Ext.Array;
800         Array.forEach(Array.from(me.originalValue), function(val, i) {
801             me.setValue(i, val);
802         });
803         me.clearInvalid();
804         // delete here so we reset back to the original state
805         delete me.wasValid;
806     },
807
808     // private
809     beforeDestroy : function() {
810         var me = this;
811         
812         Ext.destroyMembers(me.innerEl, me.endEl, me.focusEl);
813         Ext.each(me.thumbs, function(thumb) {
814             Ext.destroy(thumb);
815         }, me);
816
817         me.callParent();
818     },
819
820     statics: {
821         // Method overrides to support slider with vertical orientation
822         Vertical: {
823             getRatio : function() {
824                 var h = this.innerEl.getHeight(),
825                     v = this.maxValue - this.minValue;
826                 return h/v;
827             },
828
829             onClickChange : function(local) {
830                 var me = this,
831                     thumb, index, bottom;
832
833                 if (local.left &gt; me.clickRange[0] &amp;&amp; local.left &lt; me.clickRange[1]) {
834                     thumb = me.getNearest(local, 'top');
835                     if (!thumb.disabled) {
836                         index = thumb.index;
837                         bottom =  me.reverseValue(me.innerEl.getHeight() - local.top);
838
839                         me.setValue(index, Ext.util.Format.round(me.minValue + bottom, me.decimalPrecision), undefined, true);
840                     }
841                 }
842             }
843         }
844     }
845 });
846 </pre>
847 </body>
848 </html>