Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / Slider.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js"><div id="cls-Ext.Slider"></div>/**\r
9  * @class Ext.Slider\r
10  * @extends Ext.BoxComponent\r
11  * Slider which supports vertical or horizontal orientation, keyboard adjustments,\r
12  * configurable snapping, axis clicking and animation. Can be added as an item to\r
13  * any container. Example usage:\r
14 <pre><code>\r
15 new Ext.Slider({\r
16     renderTo: Ext.getBody(),\r
17     width: 200,\r
18     value: 50,\r
19     increment: 10,\r
20     minValue: 0,\r
21     maxValue: 100\r
22 });\r
23 </code></pre>\r
24  */\r
25 Ext.Slider = Ext.extend(Ext.BoxComponent, {\r
26         <div id="cfg-Ext.Slider-value"></div>/**\r
27          * @cfg {Number} value The value to initialize the slider with. Defaults to minValue.\r
28          */\r
29         <div id="cfg-Ext.Slider-vertical"></div>/**\r
30          * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.\r
31          */\r
32     vertical: false,\r
33         <div id="cfg-Ext.Slider-minValue"></div>/**\r
34          * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.\r
35          */\r
36     minValue: 0,\r
37         <div id="cfg-Ext.Slider-maxValue"></div>/**\r
38          * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.\r
39          */\r
40     maxValue: 100,\r
41     <div id="cfg-Ext.Slider-decimalPrecision."></div>/**\r
42      * @cfg {Number/Boolean} decimalPrecision.\r
43      * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>\r
44      * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>\r
45      */\r
46     decimalPrecision: 0,\r
47         <div id="cfg-Ext.Slider-keyIncrement"></div>/**\r
48          * @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.\r
49          */\r
50     keyIncrement: 1,\r
51         <div id="cfg-Ext.Slider-increment"></div>/**\r
52          * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.\r
53          */\r
54     increment: 0,\r
55         // private\r
56     clickRange: [5,15],\r
57         <div id="cfg-Ext.Slider-clickToChange"></div>/**\r
58          * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true\r
59          */\r
60     clickToChange : true,\r
61         <div id="cfg-Ext.Slider-animate"></div>/**\r
62          * @cfg {Boolean} animate Turn on or off animation. Defaults to true\r
63          */\r
64     animate: true,\r
65 \r
66     <div id="prop-Ext.Slider-dragging"></div>/**\r
67      * True while the thumb is in a drag operation\r
68      * @type boolean\r
69      */\r
70     dragging: false,\r
71 \r
72     // private override\r
73     initComponent : function(){\r
74         if(!Ext.isDefined(this.value)){\r
75             this.value = this.minValue;\r
76         }\r
77         Ext.Slider.superclass.initComponent.call(this);\r
78         this.keyIncrement = Math.max(this.increment, this.keyIncrement);\r
79         this.addEvents(\r
80             <div id="event-Ext.Slider-beforechange"></div>/**\r
81              * @event beforechange\r
82              * Fires before the slider value is changed. By returning false from an event handler,\r
83              * you can cancel the event and prevent the slider from changing.\r
84                          * @param {Ext.Slider} slider The slider\r
85                          * @param {Number} newValue The new value which the slider is being changed to.\r
86                          * @param {Number} oldValue The old value which the slider was previously.\r
87              */\r
88                         'beforechange',\r
89                         <div id="event-Ext.Slider-change"></div>/**\r
90                          * @event change\r
91                          * Fires when the slider value is changed.\r
92                          * @param {Ext.Slider} slider The slider\r
93                          * @param {Number} newValue The new value which the slider has been changed to.\r
94                          */\r
95                         'change',\r
96                         <div id="event-Ext.Slider-changecomplete"></div>/**\r
97                          * @event changecomplete\r
98                          * Fires when the slider value is changed by the user and any drag operations have completed.\r
99                          * @param {Ext.Slider} slider The slider\r
100                          * @param {Number} newValue The new value which the slider has been changed to.\r
101                          */\r
102                         'changecomplete',\r
103                         <div id="event-Ext.Slider-dragstart"></div>/**\r
104                          * @event dragstart\r
105              * Fires after a drag operation has started.\r
106                          * @param {Ext.Slider} slider The slider\r
107                          * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker\r
108                          */\r
109                         'dragstart',\r
110                         <div id="event-Ext.Slider-drag"></div>/**\r
111                          * @event drag\r
112              * Fires continuously during the drag operation while the mouse is moving.\r
113                          * @param {Ext.Slider} slider The slider\r
114                          * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker\r
115                          */\r
116                         'drag',\r
117                         <div id="event-Ext.Slider-dragend"></div>/**\r
118                          * @event dragend\r
119              * Fires after the drag operation has completed.\r
120                          * @param {Ext.Slider} slider The slider\r
121                          * @param {Ext.EventObject} e The event fired from Ext.dd.DragTracker\r
122                          */\r
123                         'dragend'\r
124                 );\r
125 \r
126         if(this.vertical){\r
127             Ext.apply(this, Ext.Slider.Vertical);\r
128         }\r
129     },\r
130 \r
131         // private override\r
132     onRender : function(){\r
133         this.autoEl = {\r
134             cls: 'x-slider ' + (this.vertical ? 'x-slider-vert' : 'x-slider-horz'),\r
135             cn:{cls:'x-slider-end',cn:{cls:'x-slider-inner',cn:[{cls:'x-slider-thumb'},{tag:'a', cls:'x-slider-focus', href:"#", tabIndex: '-1', hidefocus:'on'}]}}\r
136         };\r
137         Ext.Slider.superclass.onRender.apply(this, arguments);\r
138         this.endEl = this.el.first();\r
139         this.innerEl = this.endEl.first();\r
140         this.thumb = this.innerEl.first();\r
141         this.halfThumb = (this.vertical ? this.thumb.getHeight() : this.thumb.getWidth())/2;\r
142         this.focusEl = this.thumb.next();\r
143         this.initEvents();\r
144     },\r
145 \r
146         // private override\r
147     initEvents : function(){\r
148         this.thumb.addClassOnOver('x-slider-thumb-over');\r
149         this.mon(this.el, {\r
150             scope: this,\r
151             mousedown: this.onMouseDown,\r
152             keydown: this.onKeyDown\r
153         });\r
154 \r
155         this.focusEl.swallowEvent("click", true);\r
156 \r
157         this.tracker = new Ext.dd.DragTracker({\r
158             onBeforeStart: this.onBeforeDragStart.createDelegate(this),\r
159             onStart: this.onDragStart.createDelegate(this),\r
160             onDrag: this.onDrag.createDelegate(this),\r
161             onEnd: this.onDragEnd.createDelegate(this),\r
162             tolerance: 3,\r
163             autoStart: 300\r
164         });\r
165         this.tracker.initEl(this.thumb);\r
166         this.on('beforedestroy', this.tracker.destroy, this.tracker);\r
167     },\r
168 \r
169         // private override\r
170     onMouseDown : function(e){\r
171         if(this.disabled) {return;}\r
172         if(this.clickToChange && e.target != this.thumb.dom){\r
173             var local = this.innerEl.translatePoints(e.getXY());\r
174             this.onClickChange(local);\r
175         }\r
176         this.focus();\r
177     },\r
178 \r
179         // private\r
180     onClickChange : function(local){\r
181         if(local.top > this.clickRange[0] && local.top < this.clickRange[1]){\r
182             this.setValue(Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision), undefined, true);\r
183         }\r
184     },\r
185 \r
186         // private\r
187     onKeyDown : function(e){\r
188         if(this.disabled){e.preventDefault();return;}\r
189         var k = e.getKey();\r
190         switch(k){\r
191             case e.UP:\r
192             case e.RIGHT:\r
193                 e.stopEvent();\r
194                 if(e.ctrlKey){\r
195                     this.setValue(this.maxValue, undefined, true);\r
196                 }else{\r
197                     this.setValue(this.value+this.keyIncrement, undefined, true);\r
198                 }\r
199             break;\r
200             case e.DOWN:\r
201             case e.LEFT:\r
202                 e.stopEvent();\r
203                 if(e.ctrlKey){\r
204                     this.setValue(this.minValue, undefined, true);\r
205                 }else{\r
206                     this.setValue(this.value-this.keyIncrement, undefined, true);\r
207                 }\r
208             break;\r
209             default:\r
210                 e.preventDefault();\r
211         }\r
212     },\r
213 \r
214         // private\r
215     doSnap : function(value){\r
216         if(!this.increment || this.increment == 1 || !value) {\r
217             return value;\r
218         }\r
219         var newValue = value, inc = this.increment;\r
220         var m = value % inc;\r
221         if(m != 0){\r
222             newValue -= m;\r
223             if(m * 2 > inc){\r
224                 newValue += inc;\r
225             }else if(m * 2 < -inc){\r
226                 newValue -= inc;\r
227             }\r
228         }\r
229         return newValue.constrain(this.minValue,  this.maxValue);\r
230     },\r
231 \r
232         // private\r
233     afterRender : function(){\r
234         Ext.Slider.superclass.afterRender.apply(this, arguments);\r
235         if(this.value !== undefined){\r
236             var v = this.normalizeValue(this.value);\r
237             if(v !== this.value){\r
238                 delete this.value;\r
239                 this.setValue(v, false);\r
240             }else{\r
241                 this.moveThumb(this.translateValue(v), false);\r
242             }\r
243         }\r
244     },\r
245 \r
246         // private\r
247     getRatio : function(){\r
248         var w = this.innerEl.getWidth();\r
249         var v = this.maxValue - this.minValue;\r
250         return v == 0 ? w : (w/v);\r
251     },\r
252 \r
253         // private\r
254     normalizeValue : function(v){\r
255         v = this.doSnap(v);\r
256         v = Ext.util.Format.round(v, this.decimalPrecision);\r
257         v = v.constrain(this.minValue, this.maxValue);\r
258         return v;\r
259     },\r
260 \r
261         <div id="method-Ext.Slider-setValue"></div>/**\r
262          * Programmatically sets the value of the Slider. Ensures that the value is constrained within\r
263          * the minValue and maxValue.\r
264          * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)\r
265          * @param {Boolean} animate Turn on or off animation, defaults to true\r
266          */\r
267     setValue : function(v, animate, changeComplete){\r
268         v = this.normalizeValue(v);\r
269         if(v !== this.value && this.fireEvent('beforechange', this, v, this.value) !== false){\r
270             this.value = v;\r
271             this.moveThumb(this.translateValue(v), animate !== false);\r
272             this.fireEvent('change', this, v);\r
273             if(changeComplete){\r
274                 this.fireEvent('changecomplete', this, v);\r
275             }\r
276         }\r
277     },\r
278 \r
279         // private\r
280     translateValue : function(v){\r
281         var ratio = this.getRatio();\r
282         return (v * ratio)-(this.minValue * ratio)-this.halfThumb;\r
283     },\r
284 \r
285         reverseValue : function(pos){\r
286         var ratio = this.getRatio();\r
287         return (pos+this.halfThumb+(this.minValue * ratio))/ratio;\r
288     },\r
289 \r
290         // private\r
291     moveThumb: function(v, animate){\r
292         if(!animate || this.animate === false){\r
293             this.thumb.setLeft(v);\r
294         }else{\r
295             this.thumb.shift({left: v, stopFx: true, duration:.35});\r
296         }\r
297     },\r
298 \r
299         // private\r
300     focus : function(){\r
301         this.focusEl.focus(10);\r
302     },\r
303 \r
304         // private\r
305     onBeforeDragStart : function(e){\r
306         return !this.disabled;\r
307     },\r
308 \r
309         // private\r
310     onDragStart: function(e){\r
311         this.thumb.addClass('x-slider-thumb-drag');\r
312         this.dragging = true;\r
313         this.dragStartValue = this.value;\r
314         this.fireEvent('dragstart', this, e);\r
315     },\r
316 \r
317         // private\r
318     onDrag: function(e){\r
319         var pos = this.innerEl.translatePoints(this.tracker.getXY());\r
320         this.setValue(Ext.util.Format.round(this.reverseValue(pos.left), this.decimalPrecision), false);\r
321         this.fireEvent('drag', this, e);\r
322     },\r
323 \r
324         // private\r
325     onDragEnd: function(e){\r
326         this.thumb.removeClass('x-slider-thumb-drag');\r
327         this.dragging = false;\r
328         this.fireEvent('dragend', this, e);\r
329         if(this.dragStartValue != this.value){\r
330             this.fireEvent('changecomplete', this, this.value);\r
331         }\r
332     },\r
333 \r
334         // private\r
335     onResize : function(w, h){\r
336         this.innerEl.setWidth(w - (this.el.getPadding('l') + this.endEl.getPadding('r')));\r
337         this.syncThumb();\r
338     },\r
339     \r
340     //private\r
341     onDisable: function(){\r
342         Ext.Slider.superclass.onDisable.call(this);\r
343         this.thumb.addClass(this.disabledClass);\r
344         if(Ext.isIE){\r
345             //IE breaks when using overflow visible and opacity other than 1.\r
346             //Create a place holder for the thumb and display it.\r
347             var xy = this.thumb.getXY();\r
348             this.thumb.hide();\r
349             this.innerEl.addClass(this.disabledClass).dom.disabled = true;\r
350             if (!this.thumbHolder){\r
351                 this.thumbHolder = this.endEl.createChild({cls: 'x-slider-thumb ' + this.disabledClass});    \r
352             }\r
353             this.thumbHolder.show().setXY(xy);\r
354         }\r
355     },\r
356     \r
357     //private\r
358     onEnable: function(){\r
359         Ext.Slider.superclass.onEnable.call(this);\r
360         this.thumb.removeClass(this.disabledClass);\r
361         if(Ext.isIE){\r
362             this.innerEl.removeClass(this.disabledClass).dom.disabled = false;\r
363             if (this.thumbHolder){\r
364                 this.thumbHolder.hide();\r
365             }\r
366             this.thumb.show();\r
367             this.syncThumb();\r
368         }\r
369     },\r
370     \r
371     <div id="method-Ext.Slider-syncThumb"></div>/**\r
372      * Synchronizes the thumb position to the proper proportion of the total component width based\r
373      * on the current slider {@link #value}.  This will be called automatically when the Slider\r
374      * is resized by a layout, but if it is rendered auto width, this method can be called from\r
375      * another resize handler to sync the Slider if necessary.\r
376      */\r
377     syncThumb : function(){\r
378         if(this.rendered){\r
379             this.moveThumb(this.translateValue(this.value));\r
380         }\r
381     },\r
382 \r
383         <div id="method-Ext.Slider-getValue"></div>/**\r
384          * Returns the current value of the slider\r
385          * @return {Number} The current value of the slider\r
386          */\r
387     getValue : function(){\r
388         return this.value;\r
389     }\r
390 });\r
391 Ext.reg('slider', Ext.Slider);\r
392 \r
393 // private class to support vertical sliders\r
394 Ext.Slider.Vertical = {\r
395     onResize : function(w, h){\r
396         this.innerEl.setHeight(h - (this.el.getPadding('t') + this.endEl.getPadding('b')));\r
397         this.syncThumb();\r
398     },\r
399 \r
400     getRatio : function(){\r
401         var h = this.innerEl.getHeight();\r
402         var v = this.maxValue - this.minValue;\r
403         return h/v;\r
404     },\r
405 \r
406     moveThumb: function(v, animate){\r
407         if(!animate || this.animate === false){\r
408             this.thumb.setBottom(v);\r
409         }else{\r
410             this.thumb.shift({bottom: v, stopFx: true, duration:.35});\r
411         }\r
412     },\r
413 \r
414     onDrag: function(e){\r
415         var pos = this.innerEl.translatePoints(this.tracker.getXY());\r
416         var bottom = this.innerEl.getHeight()-pos.top;\r
417         this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), false);\r
418         this.fireEvent('drag', this, e);\r
419     },\r
420 \r
421     onClickChange : function(local){\r
422         if(local.left > this.clickRange[0] && local.left < this.clickRange[1]){\r
423             var bottom = this.innerEl.getHeight()-local.top;\r
424             this.setValue(this.minValue + Ext.util.Format.round(bottom/this.getRatio(), this.decimalPrecision), undefined, true);\r
425         }\r
426     }\r
427 };</pre>    \r
428 </body>\r
429 </html>