Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / form / field / Spinner.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.form.field.Spinner
17  * @extends Ext.form.field.Trigger
18  * <p>A field with a pair of up/down spinner buttons. This class is not normally instantiated directly,
19  * instead it is subclassed and the {@link #onSpinUp} and {@link #onSpinDown} methods are implemented
20  * to handle when the buttons are clicked. A good example of this is the {@link Ext.form.field.Number} field
21  * which uses the spinner to increment and decrement the field's value by its {@link Ext.form.field.Number#step step}
22  * config value.</p>
23  * {@img Ext.form.field.Spinner/Ext.form.field.Spinner.png Ext.form.field.Spinner field}
24  * For example:
25      Ext.define('Ext.ux.CustomSpinner', {
26         extend: 'Ext.form.field.Spinner',
27         alias: 'widget.customspinner',
28         
29         // override onSpinUp (using step isn't neccessary)
30         onSpinUp: function() {
31             var me = this;
32             if (!me.readOnly) {
33                 var val = me.step; // set the default value to the step value
34                 if(me.getValue() !== '') {
35                     val = parseInt(me.getValue().slice(0, -5)); // gets rid of " Pack"
36                 }                          
37                 me.setValue((val + me.step) + ' Pack');
38             }
39         },
40         
41         // override onSpinDown
42         onSpinDown: function() {
43             var me = this;
44             if (!me.readOnly) {
45                 if(me.getValue() !== '') {
46                     val = parseInt(me.getValue().slice(0, -5)); // gets rid of " Pack"
47                 }            
48                 me.setValue((val - me.step) + ' Pack');
49             }
50         }
51     });
52     
53     Ext.create('Ext.form.FormPanel', {
54         title: 'Form with SpinnerField',
55         bodyPadding: 5,
56         width: 350,
57         renderTo: Ext.getBody(),
58         items:[{
59             xtype: 'customspinner',
60             fieldLabel: 'How Much Beer?',
61             step: 6
62         }]
63     });
64  * <p>By default, pressing the up and down arrow keys will also trigger the onSpinUp and onSpinDown methods;
65  * to prevent this, set <tt>{@link #keyNavEnabled} = false</tt>.</p>
66  *
67  */
68 Ext.define('Ext.form.field.Spinner', {
69     extend: 'Ext.form.field.Trigger',
70     alias: 'widget.spinnerfield',
71     alternateClassName: 'Ext.form.Spinner',
72     requires: ['Ext.util.KeyNav'],
73
74     trigger1Cls: Ext.baseCSSPrefix + 'form-spinner-up',
75     trigger2Cls: Ext.baseCSSPrefix + 'form-spinner-down',
76
77     /**
78      * @cfg {Boolean} spinUpEnabled
79      * Specifies whether the up spinner button is enabled. Defaults to <tt>true</tt>. To change this
80      * after the component is created, use the {@link #setSpinUpEnabled} method.
81      */
82     spinUpEnabled: true,
83
84     /**
85      * @cfg {Boolean} spinDownEnabled
86      * Specifies whether the down spinner button is enabled. Defaults to <tt>true</tt>. To change this
87      * after the component is created, use the {@link #setSpinDownEnabled} method.
88      */
89     spinDownEnabled: true,
90
91     /**
92      * @cfg {Boolean} keyNavEnabled
93      * Specifies whether the up and down arrow keys should trigger spinning up and down.
94      * Defaults to <tt>true</tt>.
95      */
96     keyNavEnabled: true,
97
98     /**
99      * @cfg {Boolean} mouseWheelEnabled
100      * Specifies whether the mouse wheel should trigger spinning up and down while the field has
101      * focus. Defaults to <tt>true</tt>.
102      */
103     mouseWheelEnabled: true,
104
105     /**
106      * @cfg {Boolean} repeatTriggerClick Whether a {@link Ext.util.ClickRepeater click repeater} should be
107      * attached to the spinner buttons. Defaults to <tt>true</tt>.
108      */
109     repeatTriggerClick: true,
110
111     /**
112      * This method is called when the spinner up button is clicked, or when the up arrow key is pressed
113      * if {@link #keyNavEnabled} is <tt>true</tt>. Must be implemented by subclasses.
114      */
115     onSpinUp: Ext.emptyFn,
116
117     /**
118      * This method is called when the spinner down button is clicked, or when the down arrow key is pressed
119      * if {@link #keyNavEnabled} is <tt>true</tt>. Must be implemented by subclasses.
120      */
121     onSpinDown: Ext.emptyFn,
122
123     initComponent: function() {
124         this.callParent();
125
126         this.addEvents(
127             /**
128              * @event spin
129              * Fires when the spinner is made to spin up or down.
130              * @param {Ext.form.field.Spinner} this
131              * @param {String} direction Either 'up' if spinning up, or 'down' if spinning down.
132              */
133             'spin',
134
135             /**
136              * @event spinup
137              * Fires when the spinner is made to spin up.
138              * @param {Ext.form.field.Spinner} this
139              */
140             'spinup',
141
142             /**
143              * @event spindown
144              * Fires when the spinner is made to spin down.
145              * @param {Ext.form.field.Spinner} this
146              */
147             'spindown'
148         );
149     },
150
151     /**
152      * @private override
153      */
154     onRender: function() {
155         var me = this,
156             triggers;
157
158         me.callParent(arguments);
159         triggers = me.triggerEl;
160
161         /**
162          * @property spinUpEl
163          * @type Ext.core.Element
164          * The spinner up button element
165          */
166         me.spinUpEl = triggers.item(0);
167         /**
168          * @property spinDownEl
169          * @type Ext.core.Element
170          * The spinner down button element
171          */
172         me.spinDownEl = triggers.item(1);
173
174         // Set initial enabled/disabled states
175         me.setSpinUpEnabled(me.spinUpEnabled);
176         me.setSpinDownEnabled(me.spinDownEnabled);
177
178         // Init up/down arrow keys
179         if (me.keyNavEnabled) {
180             me.spinnerKeyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
181                 scope: me,
182                 up: me.spinUp,
183                 down: me.spinDown
184             });
185         }
186
187         // Init mouse wheel
188         if (me.mouseWheelEnabled) {
189             me.mon(me.bodyEl, 'mousewheel', me.onMouseWheel, me);
190         }
191     },
192
193     /**
194      * @private override
195      * Since the triggers are stacked, only measure the width of one of them.
196      */
197     getTriggerWidth: function() {
198         return this.hideTrigger || this.readOnly ? 0 : this.spinUpEl.getWidth() + this.triggerWrap.getFrameWidth('lr');
199     },
200
201     /**
202      * @private Handles the spinner up button clicks.
203      */
204     onTrigger1Click: function() {
205         this.spinUp();
206     },
207
208     /**
209      * @private Handles the spinner down button clicks.
210      */
211     onTrigger2Click: function() {
212         this.spinDown();
213     },
214
215     /**
216      * Triggers the spinner to step up; fires the {@link #spin} and {@link #spinup} events and calls the
217      * {@link #onSpinUp} method. Does nothing if the field is {@link #disabled} or if {@link #spinUpEnabled}
218      * is false.
219      */
220     spinUp: function() {
221         var me = this;
222         if (me.spinUpEnabled && !me.disabled) {
223             me.fireEvent('spin', me, 'up');
224             me.fireEvent('spinup', me);
225             me.onSpinUp();
226         }
227     },
228
229     /**
230      * Triggers the spinner to step down; fires the {@link #spin} and {@link #spindown} events and calls the
231      * {@link #onSpinDown} method. Does nothing if the field is {@link #disabled} or if {@link #spinDownEnabled}
232      * is false.
233      */
234     spinDown: function() {
235         var me = this;
236         if (me.spinDownEnabled && !me.disabled) {
237             me.fireEvent('spin', me, 'down');
238             me.fireEvent('spindown', me);
239             me.onSpinDown();
240         }
241     },
242
243     /**
244      * Sets whether the spinner up button is enabled.
245      * @param {Boolean} enabled true to enable the button, false to disable it.
246      */
247     setSpinUpEnabled: function(enabled) {
248         var me = this,
249             wasEnabled = me.spinUpEnabled;
250         me.spinUpEnabled = enabled;
251         if (wasEnabled !== enabled && me.rendered) {
252             me.spinUpEl[enabled ? 'removeCls' : 'addCls'](me.trigger1Cls + '-disabled');
253         }
254     },
255
256     /**
257      * Sets whether the spinner down button is enabled.
258      * @param {Boolean} enabled true to enable the button, false to disable it.
259      */
260     setSpinDownEnabled: function(enabled) {
261         var me = this,
262             wasEnabled = me.spinDownEnabled;
263         me.spinDownEnabled = enabled;
264         if (wasEnabled !== enabled && me.rendered) {
265             me.spinDownEl[enabled ? 'removeCls' : 'addCls'](me.trigger2Cls + '-disabled');
266         }
267     },
268
269     /**
270      * @private
271      * Handles mousewheel events on the field
272      */
273     onMouseWheel: function(e) {
274         var me = this,
275             delta;
276         if (me.hasFocus) {
277             delta = e.getWheelDelta();
278             if (delta > 0) {
279                 me.spinUp();
280             }
281             else if (delta < 0) {
282                 me.spinDown();
283             }
284             e.stopEvent();
285         }
286     },
287
288     onDestroy: function() {
289         Ext.destroyMembers(this, 'spinnerKeyNav', 'spinUpEl', 'spinDownEl');
290         this.callParent();
291     }
292
293 });