Upgrade to ExtJS 4.0.7 - Released 10/19/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  * A field with a pair of up/down spinner buttons. This class is not normally instantiated directly,
17  * instead it is subclassed and the {@link #onSpinUp} and {@link #onSpinDown} methods are implemented
18  * to handle when the buttons are clicked. A good example of this is the {@link Ext.form.field.Number}
19  * field which uses the spinner to increment and decrement the field's value by its
20  * {@link Ext.form.field.Number#step step} config value.
21  *
22  * For example:
23  *
24  *     @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 val, 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  *
65  * By default, pressing the up and down arrow keys will also trigger the onSpinUp and onSpinDown methods;
66  * to prevent this, set `{@link #keyNavEnabled} = false`.
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 true. To change this after the component is
80      * 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 true. To change this after the component is
87      * 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. Defaults to true.
94      */
95     keyNavEnabled: true,
96
97     /**
98      * @cfg {Boolean} mouseWheelEnabled
99      * Specifies whether the mouse wheel should trigger spinning up and down while the field has focus.
100      * Defaults to true.
101      */
102     mouseWheelEnabled: true,
103
104     /**
105      * @cfg {Boolean} repeatTriggerClick
106      * Whether a {@link Ext.util.ClickRepeater click repeater} should be attached to the spinner buttons.
107      * Defaults to true.
108      */
109     repeatTriggerClick: true,
110
111     /**
112      * @method
113      * @protected
114      * This method is called when the spinner up button is clicked, or when the up arrow key is pressed if
115      * {@link #keyNavEnabled} is true. Must be implemented by subclasses.
116      */
117     onSpinUp: Ext.emptyFn,
118
119     /**
120      * @method
121      * @protected
122      * This method is called when the spinner down button is clicked, or when the down arrow key is pressed if
123      * {@link #keyNavEnabled} is true. Must be implemented by subclasses.
124      */
125     onSpinDown: Ext.emptyFn,
126
127     initComponent: function() {
128         this.callParent();
129
130         this.addEvents(
131             /**
132              * @event spin
133              * Fires when the spinner is made to spin up or down.
134              * @param {Ext.form.field.Spinner} this
135              * @param {String} direction Either 'up' if spinning up, or 'down' if spinning down.
136              */
137             'spin',
138
139             /**
140              * @event spinup
141              * Fires when the spinner is made to spin up.
142              * @param {Ext.form.field.Spinner} this
143              */
144             'spinup',
145
146             /**
147              * @event spindown
148              * Fires when the spinner is made to spin down.
149              * @param {Ext.form.field.Spinner} this
150              */
151             'spindown'
152         );
153     },
154
155     /**
156      * @private
157      * Override.
158      */
159     onRender: function() {
160         var me = this,
161             triggers;
162
163         me.callParent(arguments);
164         triggers = me.triggerEl;
165
166         /**
167          * @property {Ext.Element} spinUpEl
168          * The spinner up button element
169          */
170         me.spinUpEl = triggers.item(0);
171         /**
172          * @property {Ext.Element} spinDownEl
173          * The spinner down button element
174          */
175         me.spinDownEl = triggers.item(1);
176
177         // Set initial enabled/disabled states
178         me.setSpinUpEnabled(me.spinUpEnabled);
179         me.setSpinDownEnabled(me.spinDownEnabled);
180
181         // Init up/down arrow keys
182         if (me.keyNavEnabled) {
183             me.spinnerKeyNav = Ext.create('Ext.util.KeyNav', me.inputEl, {
184                 scope: me,
185                 up: me.spinUp,
186                 down: me.spinDown
187             });
188         }
189
190         // Init mouse wheel
191         if (me.mouseWheelEnabled) {
192             me.mon(me.bodyEl, 'mousewheel', me.onMouseWheel, me);
193         }
194     },
195
196     /**
197      * @private
198      * Override. Since the triggers are stacked, only measure the width of one of them.
199      */
200     getTriggerWidth: function() {
201         return this.hideTrigger || this.readOnly ? 0 : this.spinUpEl.getWidth() + this.triggerWrap.getFrameWidth('lr');
202     },
203
204     /**
205      * @private
206      * Handles the spinner up button clicks.
207      */
208     onTrigger1Click: function() {
209         this.spinUp();
210     },
211
212     /**
213      * @private
214      * Handles the spinner down button clicks.
215      */
216     onTrigger2Click: function() {
217         this.spinDown();
218     },
219
220     /**
221      * Triggers the spinner to step up; fires the {@link #spin} and {@link #spinup} events and calls the
222      * {@link #onSpinUp} method. Does nothing if the field is {@link #disabled} or if {@link #spinUpEnabled}
223      * is false.
224      */
225     spinUp: function() {
226         var me = this;
227         if (me.spinUpEnabled && !me.disabled) {
228             me.fireEvent('spin', me, 'up');
229             me.fireEvent('spinup', me);
230             me.onSpinUp();
231         }
232     },
233
234     /**
235      * Triggers the spinner to step down; fires the {@link #spin} and {@link #spindown} events and calls the
236      * {@link #onSpinDown} method. Does nothing if the field is {@link #disabled} or if {@link #spinDownEnabled}
237      * is false.
238      */
239     spinDown: function() {
240         var me = this;
241         if (me.spinDownEnabled && !me.disabled) {
242             me.fireEvent('spin', me, 'down');
243             me.fireEvent('spindown', me);
244             me.onSpinDown();
245         }
246     },
247
248     /**
249      * Sets whether the spinner up button is enabled.
250      * @param {Boolean} enabled true to enable the button, false to disable it.
251      */
252     setSpinUpEnabled: function(enabled) {
253         var me = this,
254             wasEnabled = me.spinUpEnabled;
255         me.spinUpEnabled = enabled;
256         if (wasEnabled !== enabled && me.rendered) {
257             me.spinUpEl[enabled ? 'removeCls' : 'addCls'](me.trigger1Cls + '-disabled');
258         }
259     },
260
261     /**
262      * Sets whether the spinner down button is enabled.
263      * @param {Boolean} enabled true to enable the button, false to disable it.
264      */
265     setSpinDownEnabled: function(enabled) {
266         var me = this,
267             wasEnabled = me.spinDownEnabled;
268         me.spinDownEnabled = enabled;
269         if (wasEnabled !== enabled && me.rendered) {
270             me.spinDownEl[enabled ? 'removeCls' : 'addCls'](me.trigger2Cls + '-disabled');
271         }
272     },
273
274     /**
275      * @private
276      * Handles mousewheel events on the field
277      */
278     onMouseWheel: function(e) {
279         var me = this,
280             delta;
281         if (me.hasFocus) {
282             delta = e.getWheelDelta();
283             if (delta > 0) {
284                 me.spinUp();
285             }
286             else if (delta < 0) {
287                 me.spinDown();
288             }
289             e.stopEvent();
290         }
291     },
292
293     onDestroy: function() {
294         Ext.destroyMembers(this, 'spinnerKeyNav', 'spinUpEl', 'spinDownEl');
295         this.callParent();
296     }
297
298 });