Skip to content

Commit

Permalink
[fixed] correctly localize number when editing
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense committed Dec 23, 2015
1 parent 735c267 commit c8bcb1e
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 77 deletions.
10 changes: 5 additions & 5 deletions dev/configure-globalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ var Globalize = require('globalize')
var localizers = require('../src/localizers/globalize')

Globalize.load(
require('cldr-data/main/en-GB/ca-gregorian.json'),
require('cldr-data/main/en-GB/currencies.json'),
require('cldr-data/main/en-GB/dateFields.json'),
require('cldr-data/main/en-GB/numbers.json'),
require('cldr-data/main/sk/ca-gregorian.json'),
require('cldr-data/main/sk/currencies.json'),
require('cldr-data/main/sk/dateFields.json'),
require('cldr-data/main/sk/numbers.json'),
require('cldr-data/supplemental/numberingSystems.json'),
require('cldr-data/supplemental/currencyData.json'),
require('cldr-data/supplemental/likelySubtags.json'),
require('cldr-data/supplemental/timeData.json'),
require('cldr-data/supplemental/weekData.json')
);
Globalize.locale('en-GB')
Globalize.locale('sk')

localizers(Globalize)
3 changes: 3 additions & 0 deletions dev/configure-simplenumber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var localizers = require('../src/localizers/simple-number')

localizers()
10 changes: 3 additions & 7 deletions dev/dev.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var NumberPicker = require('../src/NumberPicker.jsx')
// var List = require('../src/List.jsx')

require('../src/less/react-widgets.less')
require('./configure-moment')
require('./configure-globalize')
//require('./configure-simplenumber')

var chance = new (require('chance'))

Expand Down Expand Up @@ -96,12 +97,7 @@ var App = React.createClass({
>
add
</button>
<DropdownList
dropUp={this.state.dropUp}
open={this.state.open}
onToggle={this.onToggle}
data={this.state.data}
/>
<NumberPicker />
</section>
</div>
</div>
Expand Down
10 changes: 10 additions & 0 deletions docs/components/pages/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,16 @@ function(
) -> String
```

#### `decimalChar` -> '.'

Return the decimal separator character.

```
function(
format: String|Object,
culture: String?
) -> String
```

#### `precision`

Expand Down
63 changes: 34 additions & 29 deletions src/NumberInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import CustomPropTypes from './util/propTypes';
import { number as numberLocalizer } from './util/localizers';

var format = props => numberLocalizer.getFormat('default', props.format)
let getFormat = props => numberLocalizer.getFormat('default', props.format)

export default React.createClass({

Expand All @@ -13,6 +13,7 @@ export default React.createClass({
placeholder: React.PropTypes.string,

format: CustomPropTypes.numberFormat,

parse: React.PropTypes.func.isRequired,
culture: React.PropTypes.string,

Expand All @@ -25,28 +26,31 @@ export default React.createClass({
getDefaultProps(){
return {
value: null,
editing: false,
parse: (number, culture) => numberLocalizer.parse(number, culture)
editing: false
}
},

getDefaultState(props){
var value = props.editing
? props.value
: formatNumber(props.value, format(props), props.culture)
getDefaultState(props = this.props){
var value = props.value
, decimal = numberLocalizer.decimalChar(null, props.culture)
, format = getFormat(props);

this._beginningWithSign = false;

if (value == null || isNaN(props.value))
value = ''
else
value = props.editing
? ('' + value).replace('.', decimal)
: numberLocalizer.format(value, format, props.culture)

return {
stringValue: '' + value
}
},

getInitialState() {
return this.getDefaultState(this.props)
return this.getDefaultState()
},

componentWillReceiveProps(nextProps) {
Expand Down Expand Up @@ -82,7 +86,7 @@ export default React.createClass({

_change(e) {
var val = e.target.value
, number = this.props.parse(e.target.value, this.props.culture)
, number = this._parse(e.target.value)
, atSign = this.isSign(val.trim())
, startingWithSign = this._beginningWithSign;

Expand All @@ -93,16 +97,20 @@ export default React.createClass({
return this.props.onChange(null)
}

if (this.isFlushable(number, val))
return this.props.onChange(number)
if (this.isFlushable(number, val)) {
if (number !== this.props.value)
return this.props.onChange(number)
else
this.setState(this.getDefaultState()) // 5. -> 5
}

if (!isNaN(number) || (atSign && startingWithSign) || this.isAtDelimiter(number, val))
if ((atSign && startingWithSign) || this.isAtDelimiter(number, val))
this.current(e.target.value)
},

_finish() {
var str = this.state.stringValue
, number = this.props.parse(str, this.props.culture);
, number = this._parse(str);

// if number is below the min
// we need to flush low values and decimal stops, onBlur means i'm done inputing
Expand All @@ -113,19 +121,21 @@ export default React.createClass({

_parse(strVal) {
let culture = this.props.culture
, format = this.props.editFormat
, delimChar = numberLocalizer.decimalChar(null, culture)
, userParse = this.props.parse;

if (userParse)
return userParse(strVal, culture)

return format ? numberLocalizer.parse(strVal, culture) : +strVal
strVal = strVal.replace(delimChar, '.')
strVal = parseFloat(strVal);

return strVal
},

isFlushable(num, str) {
return (
this.isValid(num)
&& num !== this.props.value
this.isValid(num)
&& !this.isAtDelimiter(num, str)
&& !this.isSign(str)
)
Expand All @@ -135,17 +145,17 @@ export default React.createClass({
return (val || '').trim() === '-';
},

isAtDelimiter(num, str) {
var next;
isAtDelimiter(num, str, props = this.props) {
var localeChar = numberLocalizer.decimalChar(null, props.culture)
, lastIndex = str.length - 1
, char;

if (str.length <= 1) return false

next = this.props.parse(
str.substr(0, str.length - 1), this.props.culture)
char = str[lastIndex]

return typeof next === 'number'
&& !isNaN(next)
&& next === num
return char === localeChar
&& str.indexOf(char) === lastIndex
},

isValid(num) {
Expand All @@ -160,8 +170,3 @@ export default React.createClass({
}

});


function formatNumber(number, format, culture){
return numberLocalizer.format(number, format, culture)
}
2 changes: 1 addition & 1 deletion src/NumberPicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ let NumberPicker = React.createClass({
},

@widgetEnabled
_focus(focused, e){
_focus(focused, e) {

focused && compat.findDOMNode(this.refs.input).focus()

Expand Down
50 changes: 33 additions & 17 deletions src/localizers/globalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ function newGlobalize(globalize){

propType: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),

parse(value, format, culture){
return locale(culture).parseNumber(value, format)
// TODO major bump consistent ordering
parse(value, culture) {
return locale(culture).parseNumber(value)
},

format(value, format, culture){
format(value, format, culture) {
if (value == null)
return value

Expand All @@ -91,7 +92,12 @@ function newGlobalize(globalize){
return locale(culture).formatNumber(value, format)
},

precision(format){
decimalChar(format, culture) {
let str = this.format(1.1, { raw: '0.0' }, culture)
return str[str.length - 2] || '.'
},

precision(format) {
return !format || format.maximumFractionDigits == null
? null : format.maximumFractionDigits
}
Expand Down Expand Up @@ -154,35 +160,45 @@ function oldGlobalize(globalize){
}
}

function formatData(format, _culture){
var culture = getCulture(_culture)
, numFormat = culture.numberFormat

if (typeof format === 'string') {
if (format.indexOf('p') !== -1) numFormat = numFormat.percent
if (format.indexOf('c') !== -1) numFormat = numFormat.curency
}

return numFormat
}

var number = {

formats: {
default: 'D'
},

parse(value, culture){
// TODO major bump consistent ordering
parse(value, culture) {
return globalize.parseFloat(value, 10, culture)
},

format(value, format, culture){
return globalize.format(value, format, culture)
},

precision(format, _culture){
var culture = getCulture(_culture)
, numFormat = culture.numberFormat

if (typeof format === 'string') {
if (format.length > 1)
return parseFloat(format.substr(1))
decimalChar(format, culture){
var data = formatData(format, culture)
return data['.'] || '.'
},

if (format.indexOf('p') !== -1) numFormat = numFormat.percent
if (format.indexOf('c') !== -1) numFormat = numFormat.curency
precision(format, _culture){
var data = formatData(format, _culture)

return numFormat.decimals || null
}
if (typeof format === 'string' && format.length > 1)
return parseFloat(format.substr(1))

return null
return data ? data.decimals : null
}
}

Expand Down
44 changes: 29 additions & 15 deletions src/localizers/simple-number.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,27 @@ import configure from '../configure'
import formatNumber from 'format-number-with-string';
import deconstruct from 'deconstruct-number-format';

export default function simpleNumber(){
let defaults = {
decimal: '.',
grouping: ','
}


let localizer = {
formats: {
default: '-#,##0.'
default: `-#${grouping}##0${decimal}`,
},

parse(value, format){

// TODO major bump consistent ordering
parse(value, culture, format) {
if (format) {
let data = deconstruct(format)

if (data.negativeLeftPos !== -1)
value = value.substr(data.negativeLeftPos + 1)

if (data.negativeRightPos !== -1)
value = value.substring(0, data.negativeRightPos)
, negative = (data.negativeLeftSymbol && value.indexOf(data.negativeLeftSymbol) !== -1)
|| (data.negativeRightSymbol && value.indexOf(data.negativeRightSymbol) !== -1)

value = value
.replace(data.negativeLeftSymbol, '')
.replace(data.negativeRightSymbol, '')
.replace(data.prefix, '')
.replace(data.suffix, '')

Expand All @@ -31,18 +34,29 @@ export default function simpleNumber(){
if (data.decimalsSeparator)
halves[1] = halves[1].replace(new RegExp('\\' + data.decimalsSeparator, 'g'))

value = halves.join(data.decimalChar)
if (halves[1] === '') halves.pop();

value = halves.join('.')
value = +value

if (negative)
value = -1 * value
}
let number = parseFloat(value)
else
value = parseFloat(value)

return number
return isNaN(value) ? null : value
},

format(value, format){
format(value, format) {
return formatNumber(value, format)
},

precision(format){
decimalChar(format) {
return format && deconstruct(format).decimalsSeparator || '.'
},

precision(format) {
let data = deconstruct(format)
return data.maxRight !== -1 ? data.maxRight : null
}
Expand Down
Loading

0 comments on commit c8bcb1e

Please sign in to comment.