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