Skip to content

Commit 810156d

Browse files
committed
2.0.0
1 parent f4b13a4 commit 810156d

File tree

5 files changed

+278
-99
lines changed

5 files changed

+278
-99
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ And a jsFiddle was created to aid in testing: https://jsfiddle.net/Mottie/t2etyo
7171

7272
View the [complete change log here](https://github.com/Mottie/javascript-number-formatter/wiki).
7373

74+
### v2.0.0 (2018-10-26)
75+
76+
* Add `ignoreSign` option (modified to `enforeceMaskSign`!).
77+
* Switch to XO, AVA & rollup.
78+
* Meta: Update dot files & remove bower support.
79+
* Code cleanup & convert to ES2015.
80+
* Rename `ignoreSign` to `enforceMaskSign` (default `false`).
81+
* Reduce code complexity.
82+
* Export as node module.
83+
* Update TS with options.
84+
* Switch demo to use lib file & highlight valid results.
85+
* Switch from Grunt to rollup.
86+
7487
### v1.1.12 (2018-09-05)
7588

7689
* Core

lib/format.esm.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Javascript-number-formatter
3+
* Lightweight & Fast JavaScript Number Formatter
4+
*
5+
* @preserve IntegraXor Web SCADA - JavaScript Number Formatter (http://www.integraxor.com/)
6+
* @author KPL
7+
* @maintainer Rob Garrison
8+
* @copyright 2018 ecava
9+
* @license MIT
10+
* @link http://mottie.github.com/javascript-number-formatter/
11+
* @version 2.0.0
12+
*/
13+
const maskRegex = /[0-9\-+#]/;
14+
const notMaskRegex = /[^\d\-+#]/g;
15+
16+
function getIndex(mask) {
17+
return mask.search(maskRegex);
18+
}
19+
20+
function processMask(mask = "#.##") {
21+
const maskObj = {};
22+
const len = mask.length;
23+
const start = getIndex(mask);
24+
maskObj.prefix = start > 0 ? mask.substring(0, start) : "";
25+
26+
// Reverse string: not an ideal method if there are surrogate pairs
27+
const end = getIndex(mask.split("").reverse().join(""));
28+
const offset = len - end;
29+
const substr = mask.substring(offset, offset + 1);
30+
// Add 1 to offset if mask has a trailing decimal/comma
31+
const indx = offset + ((substr === "." || (substr === ",")) ? 1 : 0);
32+
maskObj.suffix = end > 0 ? mask.substring(indx, len) : "";
33+
34+
maskObj.mask = mask.substring(start, indx);
35+
maskObj.maskHasNegativeSign = maskObj.mask.charAt(0) === "-";
36+
maskObj.maskHasPositiveSign = maskObj.mask.charAt(0) === "+";
37+
38+
// Search for group separator & decimal; anything not digit,
39+
// not +/- sign, and not #
40+
let result = maskObj.mask.match(notMaskRegex);
41+
// Treat the right most symbol as decimal
42+
maskObj.decimal = (result && result[result.length - 1]) || ".";
43+
// Treat the left most symbol as group separator
44+
maskObj.separator = (result && result[1] && result[0]) || ",";
45+
46+
// Split the decimal for the format string if any
47+
result = maskObj.mask.split(maskObj.decimal);
48+
maskObj.integer = result[0];
49+
maskObj.fraction = result[1];
50+
return maskObj;
51+
}
52+
53+
function processValue(value, maskObj, options) {
54+
let isNegative = false;
55+
const valObj = {
56+
value
57+
};
58+
if (value < 0) {
59+
isNegative = true;
60+
// Process only abs(), and turn on flag.
61+
valObj.value = -valObj.value;
62+
}
63+
valObj.sign = isNegative ? "-" : "";
64+
65+
// Fix the decimal first, toFixed will auto fill trailing zero.
66+
valObj.value = Number(valObj.value).toFixed(maskObj.fraction && maskObj.fraction.length);
67+
// Convert number to string to trim off *all* trailing decimal zero(es)
68+
valObj.value = valObj.value.toString();
69+
70+
// Fill back any trailing zero according to format
71+
// look for last zero in format
72+
const posTrailZero = maskObj.fraction && maskObj.fraction.lastIndexOf("0");
73+
74+
let [valInteger = "0", valFraction = ""] = valObj.value.split(".");
75+
if (!valFraction || (valFraction && valFraction.length <= posTrailZero)) {
76+
valFraction = (Number("0." + valFraction).toFixed(posTrailZero + 1)).replace("0.", "");
77+
}
78+
valObj.integer = valInteger;
79+
valObj.fraction = valFraction;
80+
addSeparators(valObj, maskObj);
81+
82+
// Remove negative sign if result is zero
83+
if (valObj.result === "0" || valObj.result === "") {
84+
// Remove negative sign if result is zero
85+
isNegative = false;
86+
valObj.sign = "";
87+
}
88+
89+
if (!isNegative && maskObj.maskHasPositiveSign) {
90+
valObj.sign = "+";
91+
} else if (isNegative && maskObj.maskHasPositiveSign) {
92+
valObj.sign = "-";
93+
} else if (isNegative) {
94+
valObj.sign = options && options.enforceMaskSign && !maskObj.maskHasNegativeSign ? "" : "-";
95+
}
96+
return valObj;
97+
}
98+
99+
function addSeparators(valObj, maskObj) {
100+
valObj.result = "";
101+
// Look for separator
102+
const szSep = maskObj.integer.split(maskObj.separator);
103+
// Join back without separator for counting the pos of any leading 0
104+
const maskInteger = szSep.join("");
105+
106+
const posLeadZero = maskInteger && maskInteger.indexOf("0");
107+
if (posLeadZero > -1) {
108+
while (valObj.integer.length < (maskInteger.length - posLeadZero)) {
109+
valObj.integer = "0" + valObj.integer;
110+
}
111+
} else if (Number(valObj.integer) === 0) {
112+
valObj.integer = "";
113+
}
114+
115+
// Process the first group separator from decimal (.) only, the rest ignore.
116+
// get the length of the last slice of split result.
117+
const posSeparator = (szSep[1] && szSep[szSep.length - 1].length);
118+
if (posSeparator) {
119+
const len = valObj.integer.length;
120+
const offset = len % posSeparator;
121+
for (let indx = 0; indx < len; indx++) {
122+
valObj.result += valObj.integer.charAt(indx);
123+
// -posSeparator so that won't trail separator on full length
124+
if (!((indx - offset + 1) % posSeparator) && indx < len - posSeparator) {
125+
valObj.result += maskObj.separator;
126+
}
127+
}
128+
} else {
129+
valObj.result = valObj.integer;
130+
}
131+
valObj.result += (maskObj.fraction && valObj.fraction) ? maskObj.decimal + valObj.fraction : "";
132+
return valObj;
133+
}
134+
135+
var format = (mask, value, options = {}) => {
136+
if (!mask || isNaN(Number(value))) {
137+
// Invalid inputs
138+
return value;
139+
}
140+
const maskObj = processMask(mask);
141+
const valObj = processValue(value, maskObj, options);
142+
return maskObj.prefix + valObj.sign + valObj.result + maskObj.suffix;
143+
};
144+
145+
export default format;

0 commit comments

Comments
 (0)