]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/form/NumberTextBox.js.uncompressed.js
upgrade dojo to 1.8.3 (refs #570)
[tt-rss.git] / lib / dijit / form / NumberTextBox.js.uncompressed.js
1 define("dijit/form/NumberTextBox", [
2 "dojo/_base/declare", // declare
3 "dojo/_base/lang", // lang.hitch lang.mixin
4 "dojo/number", // number._realNumberRegexp number.format number.parse number.regexp
5 "./RangeBoundTextBox"
6 ], function(declare, lang, number, RangeBoundTextBox){
7
8 // module:
9 // dijit/form/NumberTextBox
10
11
12 var NumberTextBoxMixin = declare("dijit.form.NumberTextBoxMixin", null, {
13 // summary:
14 // A mixin for all number textboxes
15 // tags:
16 // protected
17
18 // Override ValidationTextBox.pattern.... we use a reg-ex generating function rather
19 // than a straight regexp to deal with locale (plus formatting options too?)
20 pattern: number.regexp,
21
22 /*=====
23 // constraints: NumberTextBox.__Constraints
24 // Despite the name, this parameter specifies both constraints on the input
25 // (including minimum/maximum allowed values) as well as
26 // formatting options like places (the number of digits to display after
27 // the decimal point).
28 constraints: {},
29 ======*/
30
31 // value: Number
32 // The value of this NumberTextBox as a Javascript Number (i.e., not a String).
33 // If the displayed value is blank, the value is NaN, and if the user types in
34 // an gibberish value (like "hello world"), the value is undefined
35 // (i.e. get('value') returns undefined).
36 //
37 // Symmetrically, set('value', NaN) will clear the displayed value,
38 // whereas set('value', undefined) will have no effect.
39 value: NaN,
40
41 // editOptions: [protected] Object
42 // Properties to mix into constraints when the value is being edited.
43 // This is here because we edit the number in the format "12345", which is
44 // different than the display value (ex: "12,345")
45 editOptions: { pattern: '#.######' },
46
47 /*=====
48 _formatter: function(value, options){
49 // summary:
50 // _formatter() is called by format(). It's the base routine for formatting a number,
51 // as a string, for example converting 12345 into "12,345".
52 // value: Number
53 // The number to be converted into a string.
54 // options: number.__FormatOptions?
55 // Formatting options
56 // tags:
57 // protected extension
58
59 return "12345"; // String
60 },
61 =====*/
62 _formatter: number.format,
63
64 postMixInProperties: function(){
65 this.inherited(arguments);
66 this._set("type", "text"); // in case type="number" was specified which messes up parse/format
67 },
68
69 _setConstraintsAttr: function(/*Object*/ constraints){
70 var places = typeof constraints.places == "number"? constraints.places : 0;
71 if(places){ places++; } // decimal rounding errors take away another digit of precision
72 if(typeof constraints.max != "number"){
73 constraints.max = 9 * Math.pow(10, 15-places);
74 }
75 if(typeof constraints.min != "number"){
76 constraints.min = -9 * Math.pow(10, 15-places);
77 }
78 this.inherited(arguments, [ constraints ]);
79 if(this.focusNode && this.focusNode.value && !isNaN(this.value)){
80 this.set('value', this.value);
81 }
82 },
83
84 _onFocus: function(){
85 if(this.disabled){ return; }
86 var val = this.get('value');
87 if(typeof val == "number" && !isNaN(val)){
88 var formattedValue = this.format(val, this.constraints);
89 if(formattedValue !== undefined){
90 this.textbox.value = formattedValue;
91 }
92 }
93 this.inherited(arguments);
94 },
95
96 format: function(/*Number*/ value, /*number.__FormatOptions*/ constraints){
97 // summary:
98 // Formats the value as a Number, according to constraints.
99 // tags:
100 // protected
101
102 var formattedValue = String(value);
103 if(typeof value != "number"){ return formattedValue; }
104 if(isNaN(value)){ return ""; }
105 // check for exponential notation that dojo/number.format() chokes on
106 if(!("rangeCheck" in this && this.rangeCheck(value, constraints)) && constraints.exponent !== false && /\de[-+]?\d/i.test(formattedValue)){
107 return formattedValue;
108 }
109 if(this.editOptions && this.focused){
110 constraints = lang.mixin({}, constraints, this.editOptions);
111 }
112 return this._formatter(value, constraints);
113 },
114
115 /*=====
116 _parser: function(value, constraints){
117 // summary:
118 // Parses the string value as a Number, according to constraints.
119 // value: String
120 // String representing a number
121 // constraints: number.__ParseOptions
122 // Formatting options
123 // tags:
124 // protected
125
126 return 123.45; // Number
127 },
128 =====*/
129 _parser: number.parse,
130
131 parse: function(/*String*/ value, /*number.__FormatOptions*/ constraints){
132 // summary:
133 // Replaceable function to convert a formatted string to a number value
134 // tags:
135 // protected extension
136
137 var v = this._parser(value, lang.mixin({}, constraints, (this.editOptions && this.focused) ? this.editOptions : {}));
138 if(this.editOptions && this.focused && isNaN(v)){
139 v = this._parser(value, constraints); // parse w/o editOptions: not technically needed but is nice for the user
140 }
141 return v;
142 },
143
144 _getDisplayedValueAttr: function(){
145 var v = this.inherited(arguments);
146 return isNaN(v) ? this.textbox.value : v;
147 },
148
149 filter: function(/*Number*/ value){
150 // summary:
151 // This is called with both the display value (string), and the actual value (a number).
152 // When called with the actual value it does corrections so that '' etc. are represented as NaN.
153 // Otherwise it dispatches to the superclass's filter() method.
154 //
155 // See `dijit/form/TextBox.filter()` for more details.
156 return (value == null /* or undefined */ || value === '') ? NaN : this.inherited(arguments); // set('value', null||''||undefined) should fire onChange(NaN)
157 },
158
159 serialize: function(/*Number*/ value, /*Object?*/ options){
160 // summary:
161 // Convert value (a Number) into a canonical string (ie, how the number literal is written in javascript/java/C/etc.)
162 // tags:
163 // protected
164 return (typeof value != "number" || isNaN(value)) ? '' : this.inherited(arguments);
165 },
166
167 _setBlurValue: function(){
168 var val = lang.hitch(lang.mixin({}, this, { focused: true }), "get")('value'); // parse with editOptions
169 this._setValueAttr(val, true);
170 },
171
172 _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
173 // summary:
174 // Hook so set('value', ...) works.
175 if(value !== undefined && formattedValue === undefined){
176 formattedValue = String(value);
177 if(typeof value == "number"){
178 if(isNaN(value)){ formattedValue = '' }
179 // check for exponential notation that number.format chokes on
180 else if(("rangeCheck" in this && this.rangeCheck(value, this.constraints)) || this.constraints.exponent === false || !/\de[-+]?\d/i.test(formattedValue)){
181 formattedValue = undefined; // lets format compute a real string value
182 }
183 }else if(!value){ // 0 processed in if branch above, ''|null|undefined flows through here
184 formattedValue = '';
185 value = NaN;
186 }else{ // non-numeric values
187 value = undefined;
188 }
189 }
190 this.inherited(arguments, [value, priorityChange, formattedValue]);
191 },
192
193 _getValueAttr: function(){
194 // summary:
195 // Hook so get('value') works.
196 // Returns Number, NaN for '', or undefined for unparseable text
197 var v = this.inherited(arguments); // returns Number for all values accepted by parse() or NaN for all other displayed values
198
199 // If the displayed value of the textbox is gibberish (ex: "hello world"), this.inherited() above
200 // returns NaN; this if() branch converts the return value to undefined.
201 // Returning undefined prevents user text from being overwritten when doing _setValueAttr(_getValueAttr()).
202 // A blank displayed value is still returned as NaN.
203 if(isNaN(v) && this.textbox.value !== ''){
204 if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value) && (new RegExp("^"+number._realNumberRegexp(lang.mixin({}, this.constraints))+"$").test(this.textbox.value))){ // check for exponential notation that parse() rejected (erroneously?)
205 var n = Number(this.textbox.value);
206 return isNaN(n) ? undefined : n; // return exponential Number or undefined for random text (may not be possible to do with the above RegExp check)
207 }else{
208 return undefined; // gibberish
209 }
210 }else{
211 return v; // Number or NaN for ''
212 }
213 },
214
215 isValid: function(/*Boolean*/ isFocused){
216 // Overrides dijit/form/RangeBoundTextBox.isValid() to check that the editing-mode value is valid since
217 // it may not be formatted according to the regExp validation rules
218 if(!this.focused || this._isEmpty(this.textbox.value)){
219 return this.inherited(arguments);
220 }else{
221 var v = this.get('value');
222 if(!isNaN(v) && this.rangeCheck(v, this.constraints)){
223 if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value)){ // exponential, parse doesn't like it
224 return true; // valid exponential number in range
225 }else{
226 return this.inherited(arguments);
227 }
228 }else{
229 return false;
230 }
231 }
232 }
233 });
234
235 var NumberTextBox = declare("dijit.form.NumberTextBox", [RangeBoundTextBox, NumberTextBoxMixin], {
236 // summary:
237 // A TextBox for entering numbers, with formatting and range checking
238 // description:
239 // NumberTextBox is a textbox for entering and displaying numbers, supporting
240 // the following main features:
241 //
242 // 1. Enforce minimum/maximum allowed values (as well as enforcing that the user types
243 // a number rather than a random string)
244 // 2. NLS support (altering roles of comma and dot as "thousands-separator" and "decimal-point"
245 // depending on locale).
246 // 3. Separate modes for editing the value and displaying it, specifically that
247 // the thousands separator character (typically comma) disappears when editing
248 // but reappears after the field is blurred.
249 // 4. Formatting and constraints regarding the number of places (digits after the decimal point)
250 // allowed on input, and number of places displayed when blurred (see `constraints` parameter).
251
252 baseClass: "dijitTextBox dijitNumberTextBox"
253 });
254
255 NumberTextBox.Mixin = NumberTextBoxMixin; // for monkey patching
256
257 /*=====
258 NumberTextBox.__Constraints = declare([RangeBoundTextBox.__Constraints, number.__FormatOptions, number.__ParseOptions], {
259 // summary:
260 // Specifies both the rules on valid/invalid values (minimum, maximum,
261 // number of required decimal places), and also formatting options for
262 // displaying the value when the field is not focused.
263 // example:
264 // Minimum/maximum:
265 // To specify a field between 0 and 120:
266 // | {min:0,max:120}
267 // To specify a field that must be an integer:
268 // | {fractional:false}
269 // To specify a field where 0 to 3 decimal places are allowed on input:
270 // | {places:'0,3'}
271 });
272 =====*/
273
274 return NumberTextBox;
275 });