Skip to content

Commit 816c0ce

Browse files
authored
Merge pull request jdorn#707 from tohosaku/validate_number
Fix jdorn#701. Validate number properly.
2 parents 5d6c41c + da44539 commit 816c0ce

File tree

9 files changed

+116
-11
lines changed

9 files changed

+116
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Cleaned src/defaults.js and move resolvers to a separate module, src/resolvers.js
1212
- Cleaned how default themes, iconlibs, editors and templates are imported to JSONEditor
1313
- Added ability to attache editors and themes style rules to the shadowRoot if the editor is inside a Web Component.
14+
- Fix of #701 - editors/number.js and editors/integer.js don't change values when validation is failed
1415

1516
### 2.0.0-dev
1617
- Fix of #643 - Allow use of themes not compiled directly into the build

src/editors/integer.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { NumberEditor } from './number.js'
2+
import { isInteger } from '../utilities.js'
23

34
export class IntegerEditor extends NumberEditor {
4-
sanitize (value) {
5-
value = `${value}`
6-
return value.replace(/[^0-9-]/g, '')
7-
}
8-
95
getNumColumns () {
106
return 2
117
}
8+
9+
getValue () {
10+
if (!this.dependenciesFulfilled) {
11+
return undefined
12+
}
13+
return isInteger(this.value) ? parseInt(this.value) : this.value
14+
}
1215
}

src/editors/number.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { StringEditor } from './string.js'
2+
import { isNumber } from '../utilities'
23

34
export class NumberEditor extends StringEditor {
45
build () {
@@ -33,10 +34,6 @@ export class NumberEditor extends StringEditor {
3334
this.setInputAttributes(['maxlength', 'pattern', 'readonly', 'min', 'max', 'step'])
3435
}
3536

36-
sanitize (value) {
37-
return (`${value}`).replace(/[^0-9.\-eE]/g, '')
38-
}
39-
4037
getNumColumns () {
4138
return 2
4239
}
@@ -45,6 +42,6 @@ export class NumberEditor extends StringEditor {
4542
if (!this.dependenciesFulfilled) {
4643
return undefined
4744
}
48-
return this.value === '' ? undefined : this.value * 1
45+
return isNumber(this.value) ? parseFloat(this.value) : this.value
4946
}
5047
}

src/utilities.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,22 @@ export function getShadowParent (node) {
6565
export function hasOwnProperty (obj, key) {
6666
return obj && Object.prototype.hasOwnProperty.call(obj, key)
6767
}
68+
69+
// From https://github.com/angular/angular.js/blob/master/src/ng/directive/input.js
70+
const NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/
71+
72+
export function isNumber (value) {
73+
if (typeof value === 'undefined' || value === null) return false
74+
const match = value.match(NUMBER_REGEXP)
75+
const v = parseFloat(value)
76+
return match !== null && !isNaN(v) && isFinite(v)
77+
}
78+
79+
const INTEGER_REGEXP = /^\s*(-|\+)?(\d+)\s*$/
80+
81+
export function isInteger (value) {
82+
if (typeof value === 'undefined' || value === null) return false
83+
const match = value.match(INTEGER_REGEXP)
84+
const v = parseInt(value)
85+
return match !== null && !isNaN(v) && isFinite(v)
86+
}

tests/codeceptjs/editors/integer_test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,13 @@ Scenario('should update output when setValue is called', async (I) => {
7272
I.click('.set-value');
7373
I.see('2', '[data-schemapath="root.integer_range"] output');
7474
});
75+
76+
Scenario('should validate value', async (I) => {
77+
I.amOnPage('integer.html');
78+
await I.fillField('[name="root[integer]"]', '5-5');
79+
I.click('.get-value');
80+
I.see('Value must be of type integer.', '[data-schemapath="root.integer"] div');
81+
assert.equal(await I.grabValueFrom('.value'), '{"integer":"5-5","integer_number":5,"integer_range":5}');
82+
});
83+
84+

tests/codeceptjs/editors/number_test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ Scenario('should have correct initial value', async (I) => {
88
assert.equal(await I.grabValueFrom('.value'), '{"number":5.75,"number_number":5.75,"number_range":5.75}');
99
});
1010

11+
Scenario('should validate value', async (I) => {
12+
I.amOnPage('number.html');
13+
await I.fillField('[name="root[number]"]', '12-12');
14+
I.click('.get-value');
15+
I.see('Value must be of type number.', '[data-schemapath="root.number"] div');
16+
assert.equal(await I.grabValueFrom('.value'), '{"number":"12-12","number_number":5.75,"number_range":5.75}');
17+
});
18+
1119
Scenario('should respect step by incrementing and decrementing the value of a number', async (I) => {
1220
I.amOnPage('number.html');
1321
I.seeElement('[data-schemapath="root.number_number"] input');

tests/codeceptjs/editors/validation_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Feature('Validations');
44

55
Scenario('test validations in validation.html', (I) => {
66
I.amOnPage('validation.html');
7-
var numberOfTestItemsExpected = 131;
7+
var numberOfTestItemsExpected = 136;
88
I.waitForElement("#output div:nth-child("+numberOfTestItemsExpected+")", 10);
99
I.seeNumberOfElements("#output div", numberOfTestItemsExpected);
1010
I.see("success");

tests/fixtures/validation.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
{
2+
"primitive": {
3+
"schema": {
4+
"type": "number"
5+
},
6+
"valid": [
7+
0,
8+
1000,
9+
-100
10+
],
11+
"invalid": [
12+
"12-12",
13+
"12*12"
14+
]
15+
},
216
"required3": {
317
"schema": {
418
"type": "object",

tests/unit/editor.spec.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,56 @@ describe('Editor', () => {
7777
expect(JSON.stringify(editor.getValue())).toBe('[1,2,3,4,5]')
7878
})
7979
})
80+
81+
const fixture = [
82+
{
83+
title: 'NumberEditor test',
84+
schema: {
85+
type: 'number'
86+
},
87+
input: ' 123.45 ',
88+
value: 123.45
89+
},
90+
{
91+
title: 'NumberEditor test (invalid value)',
92+
schema: {
93+
type: 'number'
94+
},
95+
input: '12-12',
96+
value: '12-12'
97+
},
98+
{
99+
title: 'Integer test',
100+
schema: {
101+
type: 'integer'
102+
},
103+
input: ' 123 ',
104+
value: 123
105+
}
106+
]
107+
108+
describe('Number Editor', () => {
109+
let element
110+
let editor
111+
112+
beforeEach(() => {
113+
document.body.insertAdjacentHTML(
114+
'afterbegin',
115+
'<div id="fixture"></div>')
116+
element = document.getElementById('fixture')
117+
})
118+
119+
afterEach(() => {
120+
editor.destroy()
121+
})
122+
123+
fixture.forEach(spec => {
124+
it(spec.title, () => {
125+
editor = new JSONEditor(element, {
126+
schema: spec.schema
127+
})
128+
editor.setValue(spec.input)
129+
expect(editor.getValue()).toBe(spec.value)
130+
})
131+
})
132+
})

0 commit comments

Comments
 (0)