Skip to content

Commit ba44b95

Browse files
committed
getting branch setup
1 parent 9723693 commit ba44b95

File tree

4 files changed

+318
-1
lines changed

4 files changed

+318
-1
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
.idea/
2-
lib/
32
node_modules/
43
npm-debug.log
54
coverage

lib/index.js

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
7+
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8+
9+
var _react = require('react');
10+
11+
var _react2 = _interopRequireDefault(_react);
12+
13+
var _mask3 = require('./mask.js');
14+
15+
var _mask4 = _interopRequireDefault(_mask3);
16+
17+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18+
19+
var CurrencyInput = _react2.default.createClass({
20+
displayName: 'CurrencyInput',
21+
22+
23+
/**
24+
* Prop validation.
25+
* @see https://facebook.github.io/react/docs/component-specs.html#proptypes
26+
*/
27+
propTypes: {
28+
onChange: _react.PropTypes.func,
29+
value: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
30+
decimalSeparator: _react.PropTypes.string,
31+
thousandSeparator: _react.PropTypes.string,
32+
precision: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]),
33+
inputType: _react.PropTypes.string,
34+
allowNegative: _react.PropTypes.bool,
35+
allowEmpty: _react.PropTypes.bool,
36+
prefix: _react.PropTypes.string,
37+
suffix: _react.PropTypes.string
38+
},
39+
40+
/**
41+
* Component lifecycle function.
42+
*
43+
* Invoked once and cached when the class is created. Values in the mapping will be set on this.props if that
44+
* prop is not specified by the parent component
45+
*
46+
* @see https://facebook.github.io/react/docs/component-specs.html#getdefaultprops
47+
*/
48+
getDefaultProps: function getDefaultProps() {
49+
return {
50+
onChange: function onChange(maskValue, value, event) {/*no-op*/},
51+
value: '0',
52+
decimalSeparator: '.',
53+
thousandSeparator: ',',
54+
precision: '2',
55+
inputType: 'text',
56+
allowNegative: false,
57+
prefix: '',
58+
suffix: ''
59+
};
60+
},
61+
62+
63+
/**
64+
* General function used to cleanup and define the final props used for rendering
65+
* @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
66+
*/
67+
prepareProps: function prepareProps(props) {
68+
var customProps = _extends({}, props); // babeljs converts to Object.assign, then polyfills.
69+
delete customProps.onChange;
70+
delete customProps.value;
71+
delete customProps.decimalSeparator;
72+
delete customProps.thousandSeparator;
73+
delete customProps.precision;
74+
delete customProps.inputType;
75+
delete customProps.allowNegative;
76+
delete customProps.allowEmpty;
77+
delete customProps.prefix;
78+
delete customProps.suffix;
79+
80+
var initialValue = props.value;
81+
if (!initialValue) {
82+
initialValue = props.allowEmpty ? null : '';
83+
} else {
84+
85+
if (typeof initialValue == 'string') {
86+
// Some people, when confronted with a problem, think "I know, I'll use regular expressions."
87+
// Now they have two problems.
88+
89+
// Strip out thousand separators, prefix, and suffix, etc.
90+
if (props.thousandSeparator === ".") {
91+
// special handle the . thousand separator
92+
initialValue = initialValue.replace(/\./g, '');
93+
}
94+
95+
if (props.decimalSeparator != ".") {
96+
// fix the decimal separator
97+
initialValue = initialValue.replace(new RegExp(props.decimalSeparator, 'g'), '.');
98+
}
99+
100+
//Strip out anything that is not a digit, -, or decimal separator
101+
initialValue = initialValue.replace(/[^0-9-.]/g, '');
102+
103+
// now we can parse.
104+
initialValue = Number.parseFloat(initialValue);
105+
}
106+
initialValue = Number(initialValue).toLocaleString(undefined, {
107+
style: 'decimal',
108+
minimumFractionDigits: props.precision,
109+
maximumFractionDigits: props.precision
110+
});
111+
}
112+
113+
var _mask = (0, _mask4.default)(initialValue, props.precision, props.decimalSeparator, props.thousandSeparator, props.allowNegative, props.prefix, props.suffix);
114+
115+
var maskedValue = _mask.maskedValue;
116+
var value = _mask.value;
117+
118+
119+
return { maskedValue: maskedValue, value: value, customProps: customProps };
120+
},
121+
122+
123+
/**
124+
* Component lifecycle function.
125+
* Invoked once before the component is mounted. The return value will be used as the initial value of this.state
126+
*
127+
* @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
128+
* @see https://facebook.github.io/react/docs/component-specs.html#getinitialstate
129+
*/
130+
getInitialState: function getInitialState() {
131+
return this.prepareProps(this.props);
132+
},
133+
134+
135+
/**
136+
* Component lifecycle function.
137+
* Invoked when a component is receiving new props. This method is not called for the initial render.
138+
*
139+
* @param nextProps
140+
* @see https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
141+
*/
142+
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
143+
this.setState(this.prepareProps(nextProps));
144+
},
145+
146+
147+
/**
148+
* Exposes the current masked value.
149+
*
150+
* @returns {String}
151+
*/
152+
getMaskedValue: function getMaskedValue() {
153+
return this.state.maskedValue;
154+
},
155+
156+
157+
/**
158+
* onChange Event Handler
159+
* @param event
160+
*/
161+
handleChange: function handleChange(event) {
162+
event.preventDefault();
163+
164+
var _mask2 = (0, _mask4.default)(event.target.value, this.props.precision, this.props.decimalSeparator, this.props.thousandSeparator, this.props.allowNegative, this.props.prefix, this.props.suffix);
165+
166+
var maskedValue = _mask2.maskedValue;
167+
var value = _mask2.value;
168+
169+
this.setState({ maskedValue: maskedValue, value: value });
170+
this.props.onChange(maskedValue, value, event);
171+
},
172+
173+
174+
/**
175+
* Component lifecycle function.
176+
* @returns {XML}
177+
* @see https://facebook.github.io/react/docs/component-specs.html#render
178+
*/
179+
render: function render() {
180+
return _react2.default.createElement('input', _extends({
181+
type: this.props.inputType,
182+
value: this.state.maskedValue,
183+
onChange: this.handleChange
184+
}, this.state.customProps));
185+
}
186+
});
187+
188+
exports.default = CurrencyInput;

lib/mask.js

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = mask;
7+
function mask(value) {
8+
var precision = arguments.length <= 1 || arguments[1] === undefined ? 2 : arguments[1];
9+
var decimalSeparator = arguments.length <= 2 || arguments[2] === undefined ? '.' : arguments[2];
10+
var thousandSeparator = arguments.length <= 3 || arguments[3] === undefined ? ',' : arguments[3];
11+
var allowNegative = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];
12+
var prefix = arguments.length <= 5 || arguments[5] === undefined ? '' : arguments[5];
13+
var suffix = arguments.length <= 6 || arguments[6] === undefined ? '' : arguments[6];
14+
15+
// provide some default values and arg validation.
16+
if (precision < 0) {
17+
precision = 0;
18+
} // precision cannot be negative
19+
if (precision > 20) {
20+
precision = 20;
21+
} // precision cannot be greater than 20
22+
23+
if (value === null || value === undefined) {
24+
return {
25+
value: 0,
26+
maskedValue: ''
27+
};
28+
}
29+
30+
value = String(value); //if the given value is a Number, let's convert into String to manipulate that
31+
32+
if (value.length == 0) {
33+
return {
34+
value: 0,
35+
maskedValue: ''
36+
};
37+
}
38+
39+
// extract digits. if no digits, fill in a zero.
40+
var digits = value.match(/\d/g) || ['0'];
41+
42+
var numberIsNegative = false;
43+
if (allowNegative) {
44+
var negativeSignCount = (value.match(/-/g) || []).length;
45+
// number will be negative if we have an odd number of "-"
46+
// ideally, we should only ever have 0, 1 or 2 (positive number, making a number negative
47+
// and making a negative number positive, respectively)
48+
numberIsNegative = negativeSignCount % 2 === 1;
49+
50+
// if every digit in the array is '0', then the number should never be negative
51+
var allDigitsAreZero = true;
52+
for (var idx = 0; idx < digits.length; idx += 1) {
53+
if (digits[idx] !== '0') {
54+
allDigitsAreZero = false;
55+
break;
56+
}
57+
}
58+
if (allDigitsAreZero) {
59+
numberIsNegative = false;
60+
}
61+
}
62+
63+
// zero-pad a input
64+
while (digits.length <= precision) {
65+
digits.unshift('0');
66+
}
67+
68+
if (precision > 0) {
69+
// add the decimal separator
70+
digits.splice(digits.length - precision, 0, ".");
71+
}
72+
73+
// clean up extraneous digits like leading zeros.
74+
digits = Number(digits.join('')).toFixed(precision).split('');
75+
var raw = Number(digits.join(''));
76+
77+
var decimalpos = digits.length - precision - 1; // -1 needed to position the decimal separator before the digits.
78+
if (precision > 0) {
79+
// set the final decimal separator
80+
digits[decimalpos] = decimalSeparator;
81+
} else {
82+
// when precision is 0, there is no decimal separator.
83+
decimalpos = digits.length;
84+
}
85+
86+
// add in any thousand separators
87+
for (var x = decimalpos - 3; x > 0; x = x - 3) {
88+
digits.splice(x, 0, thousandSeparator);
89+
}
90+
91+
// if we have a prefix or suffix, add them in.
92+
if (prefix.length > 0) {
93+
digits.unshift(prefix);
94+
}
95+
if (suffix.length > 0) {
96+
digits.push(suffix);
97+
}
98+
99+
// if the number is negative, insert a "-" to
100+
// the front of the array and negate the raw value
101+
if (allowNegative && numberIsNegative) {
102+
digits.unshift('-');
103+
raw = -raw;
104+
}
105+
106+
return {
107+
value: raw,
108+
maskedValue: digits.join('').trim()
109+
};
110+
}

src/index.js

+20
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,24 @@ const CurrencyInput = React.createClass({
161161
this.props.onChange(maskedValue, value, event);
162162
},
163163

164+
/**
165+
* onFocus Event Handler
166+
* @param event
167+
*/
168+
handleFocus(event) {
169+
//Whenever we receive focus check to see if the position is before the suffix, if not, move it.
170+
171+
172+
173+
},
174+
175+
176+
handleBlur(event) {
177+
178+
179+
},
180+
181+
164182

165183
/**
166184
* Component lifecycle function.
@@ -173,6 +191,8 @@ const CurrencyInput = React.createClass({
173191
type={this.props.inputType}
174192
value={this.state.maskedValue}
175193
onChange={this.handleChange}
194+
onFocus={this.handleFocus}
195+
onBlur={this.handleBlur}
176196
{...this.state.customProps}
177197
/>
178198
)

0 commit comments

Comments
 (0)