Merge pull request #1443 from MetaMask/i1412-decimalizethegas
Add decimals to gas price inputfeature/default_network_editable
commit
1ffc6ea0b3
@ -0,0 +1,51 @@ |
||||
var assert = require('assert') |
||||
|
||||
const additions = require('react-testutils-additions') |
||||
const h = require('react-hyperscript') |
||||
const ReactTestUtils = require('react-addons-test-utils') |
||||
const ethUtil = require('ethereumjs-util') |
||||
const BN = ethUtil.BN |
||||
|
||||
var BnInput = require('../../../ui/app/components/bn-as-decimal-input') |
||||
|
||||
describe('BnInput', function () { |
||||
it('can tolerate a gas decimal number at a high precision', function (done) { |
||||
const renderer = ReactTestUtils.createRenderer() |
||||
|
||||
let valueStr = '20' |
||||
while (valueStr.length < 20) { |
||||
valueStr += '0' |
||||
} |
||||
const value = new BN(valueStr, 10) |
||||
|
||||
let inputStr = '2.3' |
||||
|
||||
let targetStr = '23' |
||||
while (targetStr.length < 19) { |
||||
targetStr += '0' |
||||
} |
||||
const target = new BN(targetStr, 10) |
||||
|
||||
const precision = 18 // ether precision
|
||||
const scale = 18 |
||||
|
||||
const props = { |
||||
value, |
||||
scale, |
||||
precision, |
||||
onChange: (newBn) => { |
||||
assert.equal(newBn.toString(), target.toString(), 'should tolerate increase') |
||||
done() |
||||
}, |
||||
} |
||||
|
||||
const inputComponent = h(BnInput, props) |
||||
const component = additions.renderIntoDocument(inputComponent) |
||||
renderer.render(inputComponent) |
||||
const input = additions.find(component, 'input.hex-input')[0] |
||||
ReactTestUtils.Simulate.change(input, { preventDefault() {}, target: { |
||||
value: inputStr, |
||||
checkValidity() { return true } }, |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,174 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const ethUtil = require('ethereumjs-util') |
||||
const BN = ethUtil.BN |
||||
const extend = require('xtend') |
||||
|
||||
module.exports = BnAsDecimalInput |
||||
|
||||
inherits(BnAsDecimalInput, Component) |
||||
function BnAsDecimalInput () { |
||||
this.state = { invalid: null } |
||||
Component.call(this) |
||||
} |
||||
|
||||
/* Bn as Decimal Input |
||||
* |
||||
* A component for allowing easy, decimal editing |
||||
* of a passed in bn string value. |
||||
* |
||||
* On change, calls back its `onChange` function parameter |
||||
* and passes it an updated bn string. |
||||
*/ |
||||
|
||||
BnAsDecimalInput.prototype.render = function () { |
||||
const props = this.props |
||||
const state = this.state |
||||
|
||||
const { value, scale, precision, onChange, min, max } = props |
||||
|
||||
const suffix = props.suffix |
||||
const style = props.style |
||||
const valueString = value.toString(10) |
||||
const newValue = this.downsize(valueString, scale, precision) |
||||
|
||||
return ( |
||||
h('.flex-column', [ |
||||
h('.flex-row', { |
||||
style: { |
||||
alignItems: 'flex-end', |
||||
lineHeight: '13px', |
||||
fontFamily: 'Montserrat Light', |
||||
textRendering: 'geometricPrecision', |
||||
}, |
||||
}, [ |
||||
h('input.hex-input', { |
||||
type: 'number', |
||||
step: 'any', |
||||
required: true, |
||||
min, |
||||
max, |
||||
style: extend({ |
||||
display: 'block', |
||||
textAlign: 'right', |
||||
backgroundColor: 'transparent', |
||||
border: '1px solid #bdbdbd', |
||||
|
||||
}, style), |
||||
value: newValue, |
||||
onBlur: (event) => { |
||||
this.updateValidity(event) |
||||
}, |
||||
onChange: (event) => { |
||||
this.updateValidity(event) |
||||
const value = (event.target.value === '') ? '' : event.target.value |
||||
|
||||
|
||||
const scaledNumber = this.upsize(value, scale, precision) |
||||
const precisionBN = new BN(scaledNumber, 10) |
||||
onChange(precisionBN, event.target.checkValidity()) |
||||
}, |
||||
onInvalid: (event) => { |
||||
const msg = this.constructWarning() |
||||
if (msg === state.invalid) { |
||||
return |
||||
} |
||||
this.setState({ invalid: msg }) |
||||
event.preventDefault() |
||||
return false |
||||
}, |
||||
}), |
||||
h('div', { |
||||
style: { |
||||
color: ' #AEAEAE', |
||||
fontSize: '12px', |
||||
marginLeft: '5px', |
||||
marginRight: '6px', |
||||
width: '20px', |
||||
}, |
||||
}, suffix), |
||||
]), |
||||
|
||||
state.invalid ? h('span.error', { |
||||
style: { |
||||
position: 'absolute', |
||||
right: '0px', |
||||
textAlign: 'right', |
||||
transform: 'translateY(26px)', |
||||
padding: '3px', |
||||
background: 'rgba(255,255,255,0.85)', |
||||
zIndex: '1', |
||||
textTransform: 'capitalize', |
||||
border: '2px solid #E20202', |
||||
}, |
||||
}, state.invalid) : null, |
||||
]) |
||||
) |
||||
} |
||||
|
||||
BnAsDecimalInput.prototype.setValid = function (message) { |
||||
this.setState({ invalid: null }) |
||||
} |
||||
|
||||
BnAsDecimalInput.prototype.updateValidity = function (event) { |
||||
const target = event.target |
||||
const value = this.props.value |
||||
const newValue = target.value |
||||
|
||||
if (value === newValue) { |
||||
return |
||||
} |
||||
|
||||
const valid = target.checkValidity() |
||||
|
||||
if (valid) { |
||||
this.setState({ invalid: null }) |
||||
} |
||||
} |
||||
|
||||
BnAsDecimalInput.prototype.constructWarning = function () { |
||||
const { name, min, max } = this.props |
||||
let message = name ? name + ' ' : '' |
||||
|
||||
if (min && max) { |
||||
message += `must be greater than or equal to ${min} and less than or equal to ${max}.` |
||||
} else if (min) { |
||||
message += `must be greater than or equal to ${min}.` |
||||
} else if (max) { |
||||
message += `must be less than or equal to ${max}.` |
||||
} else { |
||||
message += 'Invalid input.' |
||||
} |
||||
|
||||
return message |
||||
} |
||||
|
||||
|
||||
BnAsDecimalInput.prototype.downsize = function (number, scale, precision) { |
||||
// if there is no scaling, simply return the number
|
||||
if (scale === 0) { |
||||
return Number(number) |
||||
} else { |
||||
// if the scale is the same as the precision, account for this edge case.
|
||||
var decimals = (scale === precision) ? -1 : scale - precision |
||||
return Number(number.slice(0, -scale) + '.' + number.slice(-scale, decimals)) |
||||
} |
||||
} |
||||
|
||||
BnAsDecimalInput.prototype.upsize = function (number, scale, precision) { |
||||
var stringArray = number.toString().split('.') |
||||
var decimalLength = stringArray[1] ? stringArray[1].length : 0 |
||||
var newString = stringArray[0] |
||||
|
||||
// If there is scaling and decimal parts exist, integrate them in.
|
||||
if ((scale !== 0) && (decimalLength !== 0)) { |
||||
newString += stringArray[1].slice(0, precision) |
||||
} |
||||
|
||||
// Add 0s to account for the upscaling.
|
||||
for (var i = decimalLength; i < scale; i++) { |
||||
newString += '0' |
||||
} |
||||
return newString |
||||
} |
Loading…
Reference in new issue