Merge lp:~methanal-developers/methanal/float-input into lp:methanal
- float-input
- Merge into trunk
Proposed by
Jonathan Jacobs
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Tristan Seligmann | ||||
Approved revision: | 164 | ||||
Merged at revision: | 158 | ||||
Proposed branch: | lp:~methanal-developers/methanal/float-input | ||||
Merge into: | lp:methanal | ||||
Diff against target: |
576 lines (+363/-31) 11 files modified
methanal/js/Methanal/Tests/TestUtil.js (+39/-8) methanal/js/Methanal/Tests/TestView.js (+137/-0) methanal/js/Methanal/Tests/TestWidgets.js (+19/-0) methanal/js/Methanal/Tests/Util.js (+18/-0) methanal/js/Methanal/Util.js (+34/-6) methanal/js/Methanal/View.js (+20/-0) methanal/js/Methanal/Widgets.js (+7/-0) methanal/model.py (+6/-5) methanal/test/test_view.py (+36/-0) methanal/view.py (+46/-12) methanal/widgets.py (+1/-0) |
||||
To merge this branch: | bzr merge lp:~methanal-developers/methanal/float-input | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tristan Seligmann | Approve | ||
Review via email: mp+42248@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
- 162. By Jonathan Jacobs
-
Correct docstrings.
- 163. By Jonathan Jacobs
-
Slightly improve floating point regex.
- 164. By Jonathan Jacobs
-
Remove pointless checks.
Revision history for this message
Jonathan Jacobs (jjacobs) wrote : | # |
> This docstring can't be accurate, as there is no such thing as Float in
> JavaScript.
Fixed.
> This regex could also be written as /^[-+]?\d*\.?\d*$/ but I can't really
> decide which one is easier to understand.
I think your version is slightly more readable.
> These changes look pointless; if value === undefined, the earlier case will
> match, thus by the time we reach the latter two, value !== undefined must be
> true.
Fixed.
Revision history for this message
Tristan Seligmann (mithrandi) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'methanal/js/Methanal/Tests/TestUtil.js' |
2 | --- methanal/js/Methanal/Tests/TestUtil.js 2011-02-13 18:50:04 +0000 |
3 | +++ methanal/js/Methanal/Tests/TestUtil.js 2011-02-18 09:27:38 +0000 |
4 | @@ -180,6 +180,26 @@ |
5 | |
6 | |
7 | /** |
8 | + * Return C{true} iff the given string represents a base-10 numerical value. |
9 | + */ |
10 | + function test_isNumericalString(self) { |
11 | + var CASES = [ |
12 | + ['1234', true], |
13 | + ['1.23', true], |
14 | + ['0', true], |
15 | + ['01', true], |
16 | + [1234, false], |
17 | + [1.23, false], |
18 | + ['0x1', false], |
19 | + ['abc', false], |
20 | + [null, false], |
21 | + [undefined, false]]; |
22 | + Methanal.Tests.Util.assertCases( |
23 | + self, Methanal.Util.isNumericalString, CASES); |
24 | + }, |
25 | + |
26 | + |
27 | + /** |
28 | * L{Methanal.Util.strToInt} converts a base-10 integer value, represented |
29 | * as a C{String}, to an C{Integer}. |
30 | */ |
31 | @@ -192,14 +212,25 @@ |
32 | ['123abc', undefined], |
33 | ['abc123', undefined], |
34 | ['0x123', undefined]]; |
35 | - |
36 | - for (var i = 0; i < CASES.length; ++i) { |
37 | - var input = CASES[i][0]; |
38 | - var expected = CASES[i][1]; |
39 | - var actual = Methanal.Util.strToInt(input); |
40 | - self.assert(expected === actual, 'input = ' + input + |
41 | - ' :: expected = ' + expected + ' :: actual = ' + actual); |
42 | - } |
43 | + Methanal.Tests.Util.assertCases(self, Methanal.Util.strToInt, CASES); |
44 | + }, |
45 | + |
46 | + |
47 | + /** |
48 | + * L{Methanal.Util.strToFloat} converts a float value, represented |
49 | + * as a C{String}, to a floating point C{Number}. |
50 | + */ |
51 | + function test_strToFloat(self) { |
52 | + var CASES = [ |
53 | + ['1234', 1234], |
54 | + ['01234.56', 1234.56], |
55 | + ['.0', 0], |
56 | + ['.5', 0.5], |
57 | + ['-1', -1], |
58 | + ['123.45abc', undefined], |
59 | + ['abc123.45', undefined], |
60 | + ['0x123', undefined]]; |
61 | + Methanal.Tests.Util.assertCases(self, Methanal.Util.strToFloat, CASES); |
62 | }, |
63 | |
64 | |
65 | |
66 | === modified file 'methanal/js/Methanal/Tests/TestView.js' |
67 | --- methanal/js/Methanal/Tests/TestView.js 2010-11-19 12:32:22 +0000 |
68 | +++ methanal/js/Methanal/Tests/TestView.js 2011-02-18 09:27:38 +0000 |
69 | @@ -1006,6 +1006,34 @@ |
70 | |
71 | |
72 | /** |
73 | + * L{Methanal.View.IntegerInput.getValue} returns an integer value if the |
74 | + * input node's value is a valid number, C{null} if it is blank and |
75 | + * C{undefined} if the value is invalid. |
76 | + */ |
77 | + function test_getValue(self) { |
78 | + var CASES = [ |
79 | + [null, null], |
80 | + ['', null], |
81 | + ['abc', undefined], |
82 | + ['0.5', undefined], |
83 | + ['1a', undefined], |
84 | + ['0', 0], |
85 | + ['-1', -1], |
86 | + ['42', 42]]; |
87 | + |
88 | + self.testControl({value: null}, |
89 | + function (control) { |
90 | + Methanal.Tests.Util.assertCases( |
91 | + self, |
92 | + function (value) { |
93 | + control.setValue(value); |
94 | + return control.getValue(); |
95 | + }, CASES); |
96 | + }); |
97 | + }, |
98 | + |
99 | + |
100 | + /** |
101 | * L{Methanal.View.IntegerInput} only accepts input that is a valid integer. |
102 | */ |
103 | function test_inputValidation(self) { |
104 | @@ -1063,6 +1091,115 @@ |
105 | |
106 | |
107 | /** |
108 | + * Tests for L{Methanal.View.FloatInput}. |
109 | + */ |
110 | +Methanal.Tests.TestView.BaseTestTextInput.subclass( |
111 | + Methanal.Tests.TestView, 'TestFloatInput').methods( |
112 | + function setUp(self) { |
113 | + self.controlType = Methanal.View.FloatInput; |
114 | + }, |
115 | + |
116 | + |
117 | + /** |
118 | + * L{Methanal.View.FloatInput.getValue} returns an float value if the |
119 | + * input node's value is a valid number, C{null} if it is blank and |
120 | + * C{undefined} if the value is invalid. |
121 | + */ |
122 | + function test_getValue(self) { |
123 | + var CASES = [ |
124 | + [null, null], |
125 | + ['', null], |
126 | + ['abc', undefined], |
127 | + ['0.5', 0.5], |
128 | + ['.5', 0.5], |
129 | + ['-.5', -0.5], |
130 | + ['1a', undefined], |
131 | + ['0', 0], |
132 | + ['-1', -1], |
133 | + ['42', 42], |
134 | + ['1.2', 1.2]]; |
135 | + |
136 | + self.testControl({value: null}, |
137 | + function (control) { |
138 | + Methanal.Tests.Util.assertCases( |
139 | + self, |
140 | + function (value) { |
141 | + control.setValue(value); |
142 | + return control.getValue(); |
143 | + }, CASES); |
144 | + }); |
145 | + }, |
146 | + |
147 | + |
148 | + /** |
149 | + * L{Methanal.View.FloatInput} only accepts input that is a valid float. |
150 | + */ |
151 | + function test_inputValidation(self) { |
152 | + self.testControl({value: null}, |
153 | + function (control) { |
154 | + self.assertValidInput(control, null); |
155 | + self.assertValidInput(control, ''); |
156 | + self.assertValidInput(control, '1'); |
157 | + self.assertValidInput(control, '1.1'); |
158 | + self.assertValidInput(control, '+1.0'); |
159 | + self.assertValidInput(control, '1.'); |
160 | + self.assertValidInput(control, '-1.0'); |
161 | + self.assertValidInput(control, '.1'); |
162 | + self.assertValidInput(control, '+.1'); |
163 | + self.assertValidInput(control, '-.1'); |
164 | + self.assertValidInput(control, '.0'); |
165 | + self.assertInvalidInput(control, 'a'); |
166 | + self.assertInvalidInput(control, '1.2.1'); |
167 | + }); |
168 | + }, |
169 | + |
170 | + |
171 | + /** |
172 | + * L{Methanal.View.FloatInput} validates that values fall within a certain |
173 | + * exclusive range. |
174 | + */ |
175 | + function test_bounds(self) { |
176 | + self.testControl({value: null, |
177 | + lowerBound: -11, |
178 | + upperBound: 8,}, |
179 | + function (control) { |
180 | + self.assertValidInput(control, '-10.99'); |
181 | + self.assertInvalidInput(control, '-11.0'); |
182 | + self.assertValidInput(control, '7.99'); |
183 | + self.assertInvalidInput(control, '8.0'); |
184 | + }); |
185 | + }, |
186 | + |
187 | + |
188 | + /** |
189 | + * L{Methanal.View.FloatInput} validates that values fall within a certain |
190 | + * exclusive range, even for really big numbers that have precision |
191 | + * problems in Javascript. |
192 | + */ |
193 | + function test_bigBounds(self) { |
194 | + // These turn into -9223372036854776000 and 9223372036854776000. |
195 | + self.testControl({value: null, |
196 | + decimalPlaces: 2, |
197 | + lowerBound: -9223372036854775809.5, |
198 | + upperBound: 9223372036854775808.5}, |
199 | + function (control) { |
200 | + self.assertValidInput(control, null); |
201 | + self.assertValidInput(control, ''); |
202 | + self.assertValidInput(control, '1'); |
203 | + self.assertInvalidInput(control, '-9223372036854775800'); |
204 | + self.assertInvalidInput(control, '-9223372036854775809'); |
205 | + self.assertInvalidInput(control, '-9223372036854775808.5'); |
206 | + self.assertInvalidInput(control, '-92233720368547758090'); |
207 | + self.assertInvalidInput(control, '9223372036854775800'); |
208 | + self.assertInvalidInput(control, '9223372036854775808'); |
209 | + self.assertInvalidInput(control, '9223372036854775807.5'); |
210 | + self.assertInvalidInput(control, '92233720368547758080'); |
211 | + }); |
212 | + }); |
213 | + |
214 | + |
215 | + |
216 | +/** |
217 | * Tests for L{Methanal.View.DecimalInput}. |
218 | */ |
219 | Methanal.Tests.TestView.BaseTestTextInput.subclass( |
220 | |
221 | === modified file 'methanal/js/Methanal/Tests/TestWidgets.js' |
222 | --- methanal/js/Methanal/Tests/TestWidgets.js 2010-07-11 19:17:21 +0000 |
223 | +++ methanal/js/Methanal/Tests/TestWidgets.js 2011-02-18 09:27:38 +0000 |
224 | @@ -276,6 +276,25 @@ |
225 | |
226 | |
227 | /** |
228 | + * Tests for L{Methanal.Widgets.FloatColumn}. |
229 | + */ |
230 | +Methanal.Tests.TestWidgets.SimpleColumnTest.subclass( |
231 | + Methanal.Tests.TestWidgets, 'TestFloatColumn').methods( |
232 | + function setUp(self) { |
233 | + self.columnType = Methanal.Widgets.FloatColumn; |
234 | + self.columnValues = { |
235 | + 'a': {value: 42.0, |
236 | + link: null, |
237 | + nodeValue: '42'}, |
238 | + 'b': {value: 1.23, |
239 | + link: 'quux', |
240 | + nodeValue: '1.23'}}; |
241 | + Methanal.Tests.TestWidgets.TestFloatColumn.upcall(self, 'setUp'); |
242 | + }); |
243 | + |
244 | + |
245 | + |
246 | +/** |
247 | * Tests for L{Methanal.Widgets.BooleanColumn}. |
248 | */ |
249 | Methanal.Tests.TestWidgets.SimpleColumnTest.subclass( |
250 | |
251 | === modified file 'methanal/js/Methanal/Tests/Util.js' |
252 | --- methanal/js/Methanal/Tests/Util.js 2010-07-23 20:07:38 +0000 |
253 | +++ methanal/js/Methanal/Tests/Util.js 2011-02-18 09:27:38 +0000 |
254 | @@ -111,3 +111,21 @@ |
255 | } |
256 | throw new Error('Setter properties not supported!'); |
257 | } |
258 | + |
259 | + |
260 | +/** |
261 | + * Assert that an C{Array} of input and expected pairs (C{[input, |
262 | + * expectedOutput]}) match when the input is processed by C{fn}. |
263 | + */ |
264 | +Methanal.Tests.Util.assertCases = function assertCases(testcase, fn, cases) { |
265 | + for (var i = 0; i < cases.length; ++i) { |
266 | + var input = cases[i][0]; |
267 | + var expected = cases[i][1]; |
268 | + var actual = fn(input); |
269 | + var repr = Methanal.Util.repr; |
270 | + testcase.assert( |
271 | + expected === actual, |
272 | + 'input = ' + repr(input) + ' :: expected = ' + repr(expected) + |
273 | + ' :: actual = ' + repr(actual)); |
274 | + } |
275 | +}; |
276 | |
277 | === modified file 'methanal/js/Methanal/Util.js' |
278 | --- methanal/js/Methanal/Util.js 2011-02-13 18:50:04 +0000 |
279 | +++ methanal/js/Methanal/Util.js 2011-02-18 09:27:38 +0000 |
280 | @@ -133,20 +133,32 @@ |
281 | |
282 | |
283 | /** |
284 | + * Return C{true} iff the given string represents a base-10 numerical value. |
285 | + */ |
286 | +Methanal.Util.isNumericalString = function isNumericalString(s) { |
287 | + if (typeof s !== 'string') { |
288 | + return false; |
289 | + } else if (s.indexOf('x') !== -1) { |
290 | + return false; |
291 | + } else if (isNaN(s)) { |
292 | + return false; |
293 | + } |
294 | + return true; |
295 | +}; |
296 | + |
297 | + |
298 | + |
299 | +/** |
300 | * Convert a string to a base-10 integer. |
301 | * |
302 | * Not quite as simple to do properly as one might think. |
303 | * |
304 | * @type s: C{String} |
305 | * |
306 | - * @rtype: C{Integer} |
307 | + * @rtype: C{Number} or C{undefined} |
308 | */ |
309 | Methanal.Util.strToInt = function strToInt(s) { |
310 | - if (typeof s !== 'string') { |
311 | - return undefined; |
312 | - } else if (s.indexOf('x') !== -1) { |
313 | - return undefined; |
314 | - } else if (isNaN(s)) { |
315 | + if (!Methanal.Util.isNumericalString(s)) { |
316 | return undefined; |
317 | } |
318 | return parseInt(s, 10); |
319 | @@ -155,6 +167,22 @@ |
320 | |
321 | |
322 | /** |
323 | + * Convert a string to a floating point C{Number}. |
324 | + * |
325 | + * @type s: C{String} |
326 | + * |
327 | + * @rtype: C{Number} or C{undefined} |
328 | + */ |
329 | +Methanal.Util.strToFloat = function strToFloat(s) { |
330 | + if (!Methanal.Util.isNumericalString(s)) { |
331 | + return undefined; |
332 | + } |
333 | + return parseFloat(s); |
334 | +}; |
335 | + |
336 | + |
337 | + |
338 | +/** |
339 | * Pretty print a decimal number with thousands separators. |
340 | * |
341 | * Useful for formatting large currency amounts in a human-readable way. |
342 | |
343 | === modified file 'methanal/js/Methanal/View.js' |
344 | --- methanal/js/Methanal/View.js 2010-11-22 17:37:26 +0000 |
345 | +++ methanal/js/Methanal/View.js 2011-02-18 09:27:38 +0000 |
346 | @@ -2364,6 +2364,26 @@ |
347 | |
348 | |
349 | /** |
350 | + * Float input. |
351 | + */ |
352 | +Methanal.View.NumericInput.subclass(Methanal.View, 'FloatInput').methods( |
353 | + function __init__(self, node, args) { |
354 | + Methanal.View.FloatInput.upcall(self, '__init__', node, args); |
355 | + self._validInput = /^[-+]?\d*\.?\d*$/; |
356 | + }, |
357 | + |
358 | + |
359 | + function getValue(self) { |
360 | + var value = Methanal.View.FloatInput.upcall(self, 'getValue'); |
361 | + if (value) { |
362 | + value = Methanal.Util.strToFloat(value); |
363 | + } |
364 | + return value; |
365 | + }); |
366 | + |
367 | + |
368 | + |
369 | +/** |
370 | * Decimal number input. |
371 | * |
372 | * @type decimalPlaces: C{Integer} |
373 | |
374 | === modified file 'methanal/js/Methanal/Widgets.js' |
375 | --- methanal/js/Methanal/Widgets.js 2010-11-17 15:58:21 +0000 |
376 | +++ methanal/js/Methanal/Widgets.js 2011-02-18 09:27:38 +0000 |
377 | @@ -187,6 +187,13 @@ |
378 | |
379 | |
380 | /** |
381 | + * Column representing float values. |
382 | + */ |
383 | +Methanal.Widgets.Column.subclass(Methanal.Widgets, 'FloatColumn'); |
384 | + |
385 | + |
386 | + |
387 | +/** |
388 | * Column representing boolean values. |
389 | */ |
390 | Methanal.Widgets.Column.subclass(Methanal.Widgets, 'BooleanColumn'); |
391 | |
392 | === modified file 'methanal/model.py' |
393 | --- methanal/model.py 2010-02-22 21:29:52 +0000 |
394 | +++ methanal/model.py 2011-02-18 09:27:38 +0000 |
395 | @@ -279,11 +279,12 @@ |
396 | |
397 | |
398 | _paramTypes = { |
399 | - attributes.integer: Value, |
400 | - attributes.text: Value, |
401 | - attributes.boolean: Value, |
402 | - attributes.textlist: List, |
403 | - attributes.timestamp: Value} |
404 | + attributes.integer: Value, |
405 | + attributes.ieee754_double: Value, |
406 | + attributes.text: Value, |
407 | + attributes.boolean: Value, |
408 | + attributes.textlist: List, |
409 | + attributes.timestamp: Value} |
410 | |
411 | def paramFromAttribute(store, attr, value, name=None): |
412 | doc = attr.doc or None |
413 | |
414 | === modified file 'methanal/test/test_view.py' |
415 | --- methanal/test/test_view.py 2010-07-17 20:16:49 +0000 |
416 | +++ methanal/test/test_view.py 2011-02-18 09:27:38 +0000 |
417 | @@ -342,6 +342,42 @@ |
418 | |
419 | |
420 | |
421 | +class FloatInputTests(FormInputTests, NumericInputTestsMixin): |
422 | + """ |
423 | + Tests for L{methanal.view.FloatInput}. |
424 | + """ |
425 | + controlType = view.FloatInput |
426 | + |
427 | + |
428 | + def test_getValue(self): |
429 | + """ |
430 | + L{methanal.view.FloatInput.getValue} retrieves an empty string in the |
431 | + C{None} case and a C{float} in the case where a value exists. |
432 | + """ |
433 | + control = self.createControl(dict()) |
434 | + param = control.parent.param |
435 | + |
436 | + param.value = None |
437 | + self.assertEquals(control.getValue(), u'') |
438 | + |
439 | + param.value = u'5' |
440 | + self.assertTrue(isinstance(control.getValue(), float)) |
441 | + self.assertEquals(control.getValue(), 5.0) |
442 | + param.value = 5.0 |
443 | + self.assertTrue(isinstance(control.getValue(), float)) |
444 | + self.assertEquals(control.getValue(), 5.0) |
445 | + |
446 | + |
447 | + def test_minimumMaximumDefaultValues(self): |
448 | + """ |
449 | + The limits for SQL and Python float types are the same value, so no |
450 | + minimum or maximum checking is required in Methanal for the default |
451 | + ranges. |
452 | + """ |
453 | + pass |
454 | + |
455 | + |
456 | + |
457 | class DecimalInputTests(FormInputTests, NumericInputTestsMixin): |
458 | """ |
459 | Tests for L{methanal.view.DecimalInput}. |
460 | |
461 | === modified file 'methanal/view.py' |
462 | --- methanal/view.py 2010-09-10 13:41:41 +0000 |
463 | +++ methanal/view.py 2011-02-18 09:27:38 +0000 |
464 | @@ -9,7 +9,7 @@ |
465 | from twisted.python.versions import Version |
466 | from twisted.python.deprecate import deprecated |
467 | |
468 | -from axiom.attributes import text, integer, timestamp, boolean |
469 | +from axiom.attributes import text, integer, timestamp, boolean, ieee754_double |
470 | |
471 | from nevow.page import renderer |
472 | from nevow.athena import expose |
473 | @@ -649,6 +649,8 @@ |
474 | MINIMUM = -9223372036854775808 |
475 | MAXIMUM = 9223372036854775807 |
476 | |
477 | + NO_BOUNDS = object() |
478 | + |
479 | |
480 | def __init__(self, minimumValue=None, maximumValue=None, **kw): |
481 | super(NumericInput, self).__init__(**kw) |
482 | @@ -662,9 +664,12 @@ |
483 | |
484 | |
485 | def getArgs(self): |
486 | - return { |
487 | - u'lowerBound': self.minimumValue - 1, |
488 | - u'upperBound': self.maximumValue + 1} |
489 | + args = {} |
490 | + if self.minimumValue is not self.NO_BOUNDS: |
491 | + args[u'lowerBound'] = self.minimumValue - 1 |
492 | + if self.maximumValue is not self.NO_BOUNDS: |
493 | + args[u'upperBound'] = self.maximumValue + 1 |
494 | + return args |
495 | |
496 | |
497 | def checkValue(self, value): |
498 | @@ -674,12 +679,13 @@ |
499 | """ |
500 | if value is None: |
501 | return |
502 | - if value > self.maximumValue: |
503 | + maximumValue, minimumValue = self.maximumValue, self.minimumValue |
504 | + if maximumValue is not self.NO_BOUNDS and value > maximumValue: |
505 | raise ValueError('%s is larger than %s' % ( |
506 | - value, self.maximumValue)) |
507 | - elif value < self.minimumValue: |
508 | + value, maximumValue)) |
509 | + elif minimumValue is not self.NO_BOUNDS and value < minimumValue: |
510 | raise ValueError('%s is smaller than %s' % ( |
511 | - value, self.minimumValue)) |
512 | + value, minimumValue)) |
513 | |
514 | |
515 | def convertValue(self, value): |
516 | @@ -708,6 +714,33 @@ |
517 | |
518 | |
519 | |
520 | +class FloatInput(NumericInput): |
521 | + """ |
522 | + Float input. |
523 | + """ |
524 | + jsClass = u'Methanal.View.FloatInput' |
525 | + |
526 | + |
527 | + def __init__(self, minimumValue=NumericInput.NO_BOUNDS, |
528 | + maximumValue=NumericInput.NO_BOUNDS, **kw): |
529 | + super(FloatInput, self).__init__( |
530 | + minimumValue=minimumValue, maximumValue=maximumValue, **kw) |
531 | + |
532 | + |
533 | + def convertValue(self, value): |
534 | + if value is not None: |
535 | + value = float(value) |
536 | + return value |
537 | + |
538 | + |
539 | + def getValue(self): |
540 | + value = self.param.value |
541 | + if value is None: |
542 | + return u'' |
543 | + return float(value) |
544 | + |
545 | + |
546 | + |
547 | class DecimalInput(NumericInput): |
548 | """ |
549 | Decimal input. |
550 | @@ -1320,10 +1353,11 @@ |
551 | |
552 | |
553 | _inputTypes = { |
554 | - boolean: lambda env: CheckboxInput, |
555 | - text: lambda env: TextInput, |
556 | - integer: lambda env: IntegerInput, |
557 | - timestamp: lambda env: |
558 | + boolean: lambda env: CheckboxInput, |
559 | + text: lambda env: TextInput, |
560 | + integer: lambda env: IntegerInput, |
561 | + ieee754_double: lambda env: FloatInput, |
562 | + timestamp: lambda env: |
563 | lambda **kw: DateInput(timezone=env['timezone'], **kw)} |
564 | |
565 | def inputTypeFromAttribute(attr, **env): |
566 | |
567 | === modified file 'methanal/widgets.py' |
568 | --- methanal/widgets.py 2010-04-25 13:48:54 +0000 |
569 | +++ methanal/widgets.py 2011-02-18 09:27:38 +0000 |
570 | @@ -211,6 +211,7 @@ |
571 | columnTypes = { |
572 | 'text': u'Methanal.Widgets.TextColumn', |
573 | 'integer': u'Methanal.Widgets.IntegerColumn', |
574 | + 'ieee754_double': u'Methanal.Widgets.FloatColumn', |
575 | 'boolean': u'Methanal.Widgets.BooleanColumn', |
576 | 'timestamp': u'Methanal.Widgets.TimestampColumn'} |
577 |
48 + * L{Methanal. Util.strToFloat } converts a float value, represented
49 + * as a C{String}, to a C{Float}.
This docstring can't be accurate, as there is no such thing as Float in JavaScript.
367 + self._validInput = /^[-+]? \d*(\.\ d*)?$/;
This regex could also be written as /^[-+]?\d*\.?\d*$/ but I can't really decide which one is easier to understand.
348 } else if (value === undefined || isNaN(value)) {
349 return 'Numerical value only';
350 - } else if (value <= self.lowerBound) {
351 + } else if (value !== undefined && value <= self.lowerBound) {
352 return 'Value too small; must be greater than ' + self.lowerBound;
353 - } else if (value >= self.upperBound) {
354 + } else if (value !== undefined && value >= self.upperBound) {
These changes look pointless; if value === undefined, the earlier case will match, thus by the time we reach the latter two, value !== undefined must be true.