Roo/bootstrap/NumberField.js
[roojs1] / Roo / bootstrap / NumberField.js
1 /*
2  * - LGPL
3  *
4  * Input
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.NumberField
10  * @extends Roo.bootstrap.Input
11  * Bootstrap NumberField class
12  * 
13  * 
14  * 
15  * 
16  * @constructor
17  * Create a new NumberField
18  * @param {Object} config The config object
19  */
20
21 Roo.bootstrap.NumberField = function(config){
22     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
23 };
24
25 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
26     
27     /**
28      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
29      */
30     allowDecimals : true,
31     /**
32      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33      */
34     decimalSeparator : ".",
35     /**
36      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37      */
38     decimalPrecision : 2,
39     /**
40      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41      */
42     allowNegative : true,
43     
44     /**
45      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
46      */
47     allowZero: true,
48     /**
49      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
50      */
51     minValue : Number.NEGATIVE_INFINITY,
52     /**
53      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
54      */
55     maxValue : Number.MAX_VALUE,
56     /**
57      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
58      */
59     minText : "The minimum value for this field is {0}",
60     /**
61      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
62      */
63     maxText : "The maximum value for this field is {0}",
64     /**
65      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
66      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
67      */
68     nanText : "{0} is not a valid number",
69     /**
70      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
71      */
72     castInt : true,
73     /**
74      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
75      */
76     thousandsDelimiter : false,
77     /**
78      * @cfg {String} valueAlign alignment of value
79      */
80     valueAlign : "left",
81
82     getAutoCreate : function()
83     {
84         var hiddenInput = {
85             tag: 'input',
86             type: 'hidden',
87             id: Roo.id(),
88             cls: 'hidden-number-input'
89         };
90         
91         if (this.name) {
92             hiddenInput.name = this.name;
93         }
94         
95         this.name = '';
96         
97         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
98         
99         this.name = hiddenInput.name;
100         
101         if(cfg.cn.length > 0) {
102             cfg.cn.push(hiddenInput);
103         }
104         
105         return cfg;
106     },
107
108     // private
109     initEvents : function()
110     {   
111         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
112         
113         var allowed = "0123456789";
114         
115         if(this.allowDecimals){
116             allowed += this.decimalSeparator;
117         }
118         
119         if(this.allowNegative){
120             allowed += "-";
121         }
122         
123         if(this.thousandsDelimiter) {
124             allowed += ",";
125         }
126         
127         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
128         
129         var keyPress = function(e){
130             
131             var k = e.getKey();
132             
133             var c = e.getCharCode();
134             
135             if(
136                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
137                     allowed.indexOf(String.fromCharCode(c)) === -1
138             ){
139                 e.stopEvent();
140                 return;
141             }
142             
143             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
144                 return;
145             }
146             
147             if(allowed.indexOf(String.fromCharCode(c)) === -1){
148                 e.stopEvent();
149             }
150         };
151         
152         this.el.on("keypress", keyPress, this);
153     },
154     
155     validateValue : function(value)
156     {
157         
158         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
159             return false;
160         }
161         
162         var num = this.parseValue(value);
163         
164         if(isNaN(num)){
165             this.markInvalid(String.format(this.nanText, value));
166             return false;
167         }
168         
169         if(num < this.minValue){
170             this.markInvalid(String.format(this.minText, this.minValue));
171             return false;
172         }
173         
174         if(num > this.maxValue){
175             this.markInvalid(String.format(this.maxText, this.maxValue));
176             return false;
177         }
178         
179         return true;
180     },
181
182     getValue : function()
183     {
184         var v = this.hiddenEl().getValue();
185         
186         return this.fixPrecision(this.parseValue(v));
187     },
188
189     parseValue : function(value)
190     {
191         if(this.thousandsDelimiter) {
192             value += "";
193             r = new RegExp(",", "g");
194             value = value.replace(r, "");
195         }
196         
197         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
198         return isNaN(value) ? '' : value;
199     },
200
201     fixPrecision : function(value)
202     {
203         if(this.thousandsDelimiter) {
204             value += "";
205             r = new RegExp(",", "g");
206             value = value.replace(r, "");
207         }
208         
209         var nan = isNaN(value);
210         
211         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
212             return nan ? '' : value;
213         }
214         return parseFloat(value).toFixed(this.decimalPrecision);
215     },
216
217     setValue : function(v)
218     {
219         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
220         
221         this.value = v;
222         
223         if(this.rendered){
224             
225             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
226             
227             this.inputEl().dom.value = Roo.util.Format.number(v, this.decimalPrecision, 
228                 this.thousandsDelimiter || ''
229             );
230             
231             
232             if(!this.allowZero && !v) {
233                 this.hiddenEl().dom.value = '';
234                 this.inputEl().dom.value = '';
235             }
236              
237             
238             this.validate();
239         }
240     },
241
242     decimalPrecisionFcn : function(v)
243     {
244         return Math.floor(v);
245     },
246
247     beforeBlur : function()
248     {
249         if(!this.castInt){
250             return;
251         }
252         
253         var v = this.parseValue(this.getRawValue());
254         
255         if(v || v == 0){
256             this.setValue(v);
257         }
258     },
259     
260     hiddenEl : function()
261     {
262         return this.el.select('input.hidden-number-input',true).first();
263     }
264     
265 });
266
267