Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / slider / Thumb.js
1 /**
2  * @private
3  * @class Ext.slider.Thumb
4  * @extends Ext.Base
5  * @private
6  * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
7  * be created internally by an {@link Ext.slider.Multi Ext.Slider}.
8  */
9 Ext.define('Ext.slider.Thumb', {
10     requires: ['Ext.dd.DragTracker', 'Ext.util.Format'],
11     /**
12      * @private
13      * @property topThumbZIndex
14      * @type Number
15      * The number used internally to set the z index of the top thumb (see promoteThumb for details)
16      */
17     topZIndex: 10000,
18     /**
19      * @constructor
20      * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
21      */
22     constructor: function(config) {
23         var me = this;
24         
25         /**
26          * @property slider
27          * @type Ext.slider.MultiSlider
28          * The slider this thumb is contained within
29          */
30         Ext.apply(me, config || {}, {
31             cls: Ext.baseCSSPrefix + 'slider-thumb',
32
33             /**
34              * @cfg {Boolean} constrain True to constrain the thumb so that it cannot overlap its siblings
35              */
36             constrain: false
37         });
38         me.callParent([config]);
39
40         if (me.slider.vertical) {
41             Ext.apply(me, Ext.slider.Thumb.Vertical);
42         }
43     },
44
45     /**
46      * Renders the thumb into a slider
47      */
48     render: function() {
49         var me = this;
50         
51         me.el = me.slider.innerEl.insertFirst({cls: me.cls});
52         if (me.disabled) {
53             me.disable();
54         }
55         me.initEvents();
56     },
57     
58     /**
59      * @private
60      * move the thumb
61      */
62     move: function(v, animate){
63         if(!animate){
64             this.el.setLeft(v);
65         }else{
66             Ext.create('Ext.fx.Anim', {
67                 target: this.el,
68                 duration: 350,
69                 to: {
70                     left: v
71                 }
72             });
73         }
74     },
75
76     /**
77      * @private
78      * Bring thumb dom element to front.
79      */
80     bringToFront: function() {
81         this.el.setStyle('zIndex', this.topZIndex);
82     },
83     
84     /**
85      * @private
86      * Send thumb dom element to back.
87      */
88     sendToBack: function() {
89         this.el.setStyle('zIndex', '');
90     },
91     
92     /**
93      * Enables the thumb if it is currently disabled
94      */
95     enable: function() {
96         var me = this;
97         
98         me.disabled = false;
99         if (me.el) {
100             me.el.removeCls(me.slider.disabledCls);
101         }
102     },
103
104     /**
105      * Disables the thumb if it is currently enabled
106      */
107     disable: function() {
108         var me = this;
109         
110         me.disabled = true;
111         if (me.el) {
112             me.el.addCls(me.slider.disabledCls);
113         }
114     },
115
116     /**
117      * Sets up an Ext.dd.DragTracker for this thumb
118      */
119     initEvents: function() {
120         var me = this,
121             el = me.el;
122
123         me.tracker = Ext.create('Ext.dd.DragTracker', {
124             onBeforeStart: Ext.Function.bind(me.onBeforeDragStart, me),
125             onStart      : Ext.Function.bind(me.onDragStart, me),
126             onDrag       : Ext.Function.bind(me.onDrag, me),
127             onEnd        : Ext.Function.bind(me.onDragEnd, me),
128             tolerance    : 3,
129             autoStart    : 300,
130             overCls      : Ext.baseCSSPrefix + 'slider-thumb-over'
131         });
132
133         me.tracker.initEl(el);
134     },
135
136     /**
137      * @private
138      * This is tied into the internal Ext.dd.DragTracker. If the slider is currently disabled,
139      * this returns false to disable the DragTracker too.
140      * @return {Boolean} False if the slider is currently disabled
141      */
142     onBeforeDragStart : function(e) {
143         if (this.disabled) {
144             return false;
145         } else {
146             this.slider.promoteThumb(this);
147             return true;
148         }
149     },
150
151     /**
152      * @private
153      * This is tied into the internal Ext.dd.DragTracker's onStart template method. Adds the drag CSS class
154      * to the thumb and fires the 'dragstart' event
155      */
156     onDragStart: function(e){
157         var me = this;
158         
159         me.el.addCls(Ext.baseCSSPrefix + 'slider-thumb-drag');
160         me.dragging = true;
161         me.dragStartValue = me.value;
162
163         me.slider.fireEvent('dragstart', me.slider, e, me);
164     },
165
166     /**
167      * @private
168      * This is tied into the internal Ext.dd.DragTracker's onDrag template method. This is called every time
169      * the DragTracker detects a drag movement. It updates the Slider's value using the position of the drag
170      */
171     onDrag: function(e) {
172         var me       = this,
173             slider   = me.slider,
174             index    = me.index,
175             newValue = me.getNewValue(),
176             above,
177             below;
178
179         if (me.constrain) {
180             above = slider.thumbs[index + 1];
181             below = slider.thumbs[index - 1];
182
183             if (below !== undefined && newValue <= below.value) {
184                 newValue = below.value;
185             }
186             
187             if (above !== undefined && newValue >= above.value) {
188                 newValue = above.value;
189             }
190         }
191
192         slider.setValue(index, newValue, false);
193         slider.fireEvent('drag', slider, e, me);
194     },
195
196     getNewValue: function() {
197         var slider = this.slider,
198             pos = slider.innerEl.translatePoints(this.tracker.getXY());
199
200         return Ext.util.Format.round(slider.reverseValue(pos.left), slider.decimalPrecision);
201     },
202
203     /**
204      * @private
205      * This is tied to the internal Ext.dd.DragTracker's onEnd template method. Removes the drag CSS class and
206      * fires the 'changecomplete' event with the new value
207      */
208     onDragEnd: function(e) {
209         var me     = this,
210             slider = me.slider,
211             value  = me.value;
212
213         me.el.removeCls(Ext.baseCSSPrefix + 'slider-thumb-drag');
214
215         me.dragging = false;
216         slider.fireEvent('dragend', slider, e);
217
218         if (me.dragStartValue != value) {
219             slider.fireEvent('changecomplete', slider, value, me);
220         }
221     },
222
223     destroy: function() {
224         Ext.destroy(this.tracker);
225     },
226     statics: {
227         // Method overrides to support vertical dragging of thumb within slider
228         Vertical: {
229             getNewValue: function() {
230                 var slider   = this.slider,
231                     innerEl  = slider.innerEl,
232                     pos      = innerEl.translatePoints(this.tracker.getXY()),
233                     bottom   = innerEl.getHeight() - pos.top;
234
235                 return Ext.util.Format.round(slider.reverseValue(bottom), slider.decimalPrecision);
236             },
237             move: function(v, animate) {
238                 if (!animate) {
239                     this.el.setBottom(v);
240                 } else {
241                     Ext.create('Ext.fx.Anim', {
242                         target: this.el,
243                         duration: 350,
244                         to: {
245                             bottom: v
246                         }
247                     });
248                 }
249             }
250         }
251     }
252 });