2017-05-17 00:30:22 +02:00
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 )
}
/ * B n a s D e c i m a l I n p u t
*
* A component for allowing easy , decimal editing
2017-05-17 01:20:58 +02:00
* of a passed in bn string value .
2017-05-17 00:30:22 +02:00
*
* On change , calls back its ` onChange ` function parameter
2017-05-17 01:20:58 +02:00
* and passes it an updated bn string .
2017-05-17 00:30:22 +02:00
* /
BnAsDecimalInput . prototype . render = function ( ) {
const props = this . props
const state = this . state
2017-05-23 23:26:37 +02:00
const { value , scale , precision , onChange , min , max } = props
2017-05-17 00:30:22 +02:00
const suffix = props . suffix
const style = props . style
2017-05-23 19:43:37 +02:00
const valueString = value . toString ( 10 )
2017-10-25 01:43:03 +02:00
const newMin = min && this . downsize ( min . toString ( 10 ) , scale )
const newMax = max && this . downsize ( max . toString ( 10 ) , scale )
2017-10-06 00:26:03 +02:00
const newValue = this . downsize ( valueString , scale )
2017-05-17 00:30:22 +02:00
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 ,
2017-10-25 01:43:03 +02:00
min : newMin ,
max : newMax ,
2017-05-17 00:30:22 +02:00
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
2017-05-23 19:43:37 +02:00
2017-05-24 18:55:16 +02:00
const scaledNumber = this . upsize ( value , scale , precision )
2017-05-17 00:30:22 +02:00
const precisionBN = new BN ( scaledNumber , 10 )
2017-05-24 19:13:43 +02:00
onChange ( precisionBN , event . target . checkValidity ( ) )
2017-05-17 00:30:22 +02:00
} ,
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 ( ) {
2017-10-25 01:43:03 +02:00
const { name , min , max , scale } = this . props
2017-05-17 00:30:22 +02:00
let message = name ? name + ' ' : ''
if ( min && max ) {
2017-10-25 01:43:03 +02:00
message += ` must be greater than or equal to ${ this . downsize ( min . toString ( 10 ) , scale ) } and less than or equal to ${ this . downsize ( max . toString ( 10 ) , scale ) } . `
2017-05-17 00:30:22 +02:00
} else if ( min ) {
2017-10-25 01:43:03 +02:00
message += ` must be greater than or equal to ${ this . downsize ( min . toString ( 10 ) , scale ) } . `
2017-05-17 00:30:22 +02:00
} else if ( max ) {
2017-10-25 01:43:03 +02:00
message += ` must be less than or equal to ${ this . downsize ( max . toString ( 10 ) , scale ) } . `
2017-05-17 00:30:22 +02:00
} else {
message += 'Invalid input.'
}
return message
}
2017-05-23 19:43:37 +02:00
2017-10-06 00:26:03 +02:00
BnAsDecimalInput . prototype . downsize = function ( number , scale ) {
2017-05-24 18:55:16 +02:00
// if there is no scaling, simply return the number
2017-05-23 19:43:37 +02:00
if ( scale === 0 ) {
return Number ( number )
} else {
2017-05-24 18:55:16 +02:00
// if the scale is the same as the precision, account for this edge case.
2017-10-06 00:26:03 +02:00
var adjustedNumber = number
while ( adjustedNumber . length < scale ) {
adjustedNumber = '0' + adjustedNumber
}
return Number ( adjustedNumber . slice ( 0 , - scale ) + '.' + adjustedNumber . slice ( - scale ) )
2017-05-23 19:43:37 +02:00
}
}
2017-05-24 18:55:16 +02:00
BnAsDecimalInput . prototype . upsize = function ( number , scale , precision ) {
var stringArray = number . toString ( ) . split ( '.' )
2017-05-23 19:43:37 +02:00
var decimalLength = stringArray [ 1 ] ? stringArray [ 1 ] . length : 0
2017-05-24 18:55:16 +02:00
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.
2017-05-23 19:43:37 +02:00
for ( var i = decimalLength ; i < scale ; i ++ ) {
newString += '0'
}
return newString
}