forked from sheetjs/sheetjs
version bump 0.6.5: eliminating bad idioms
- cleaned up implicit boolean to number conversions - web demo improved (h/t /u/SpsD3GoiFSmXBAl on reddit)
This commit is contained in:
parent
c156693778
commit
2dd9c7ec99
18
index.html
18
index.html
@ -4,7 +4,7 @@
|
||||
<script src="ssf.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<b>SSF (Spreadsheet Format) Live Demo</b><br />
|
||||
<b>SSF (Spreadsheet Number Format) Live Demo</b><br />
|
||||
<a href="https://github.com/SheetJS/ssf">Github Repo</a><br />
|
||||
<a href="https://github.com/SheetJS/ssf/issues">Issues? Something look weird? Click here and report an issue</a><br />
|
||||
<div>
|
||||
@ -20,11 +20,19 @@
|
||||
var N = document.getElementById('num');
|
||||
var T = document.getElementById('txt');
|
||||
function update() {
|
||||
try { N.innerText = SSF.format(F.value, Number(V.value)); } catch(e) { N.innerText = e; }
|
||||
try { T.innerText = SSF.format(F.value, V.value); } catch(e) { T.innerText = e; }
|
||||
try { N.innerHTML = SSF.format(F.value, Number(V.value)); } catch(e) { N.innerHTML = e; }
|
||||
try { T.innerHTML = SSF.format(F.value, V.value); } catch(e) { T.innerHTML = e; }
|
||||
}
|
||||
if(F.addEventListener) {
|
||||
F.addEventListener('keyup', update);
|
||||
V.addEventListener('keyup', update);
|
||||
} else if(F.attachEvent) {
|
||||
F.attachEvent('onkeyup', update);
|
||||
V.attachEvent('onkeyup', update);
|
||||
} else {
|
||||
F.oninput = update;
|
||||
V.oninput = update;
|
||||
}
|
||||
F.oninput = update;
|
||||
V.oninput = update;
|
||||
update();
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ssf",
|
||||
"version": "0.6.4",
|
||||
"version": "0.6.5",
|
||||
"author": "SheetJS",
|
||||
"description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes",
|
||||
"keywords": [ "format", "sprintf", "spreadsheet" ],
|
||||
|
46
ssf.js
46
ssf.js
@ -5,13 +5,15 @@ var _strrev = function(x) { return String(x).split("").reverse().join("");};
|
||||
function fill(c,l) { return new Array(l+1).join(c); }
|
||||
function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);}
|
||||
function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));}
|
||||
SSF.version = '0.6.4';
|
||||
SSF.version = '0.6.5';
|
||||
/* Options */
|
||||
var opts_fmt = {};
|
||||
var opts_fmt = {
|
||||
date1904:0,
|
||||
output:"",
|
||||
WTF:false
|
||||
};
|
||||
function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
|
||||
SSF.opts = opts_fmt;
|
||||
opts_fmt.date1904 = 0;
|
||||
opts_fmt.output = "";
|
||||
var table_fmt = {
|
||||
0: 'General',
|
||||
1: '0',
|
||||
@ -89,7 +91,7 @@ var frac = function frac(x, D, mixed) {
|
||||
var q = Math.floor(sgn * P/Q);
|
||||
return [q, sgn*P - q*Q, Q];
|
||||
};
|
||||
var general_fmt = function(v) {
|
||||
var general_fmt = function(v, opts) {
|
||||
if(typeof v === 'boolean') return v ? "TRUE" : "FALSE";
|
||||
if(typeof v === 'number') {
|
||||
var o, V = v < 0 ? -v : v;
|
||||
@ -100,12 +102,12 @@ var general_fmt = function(v) {
|
||||
else if(V >= Math.pow(10,10) && V < Math.pow(10,11)) o = v.toFixed(10).substr(0,12);
|
||||
else if(V > Math.pow(10,-9) && V < Math.pow(10,11)) {
|
||||
o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
|
||||
if(o.length > 11+(v<0?1:0)) o = v.toPrecision(10);
|
||||
if(o.length > 11+(v<0?1:0)) o = v.toExponential(5);
|
||||
if(o.length > (v<0?12:11)) o = v.toPrecision(10);
|
||||
if(o.length > (v<0?12:11)) o = v.toExponential(5);
|
||||
}
|
||||
else {
|
||||
o = v.toFixed(11).replace(/(\.[0-9]*[1-9])0*$/,"$1");
|
||||
if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
|
||||
if(o.length > (v<0?12:11)) o = v.toPrecision(6);
|
||||
}
|
||||
o = o.replace(/(\.[0-9]*[1-9])0+e/,"$1e").replace(/\.0*e/,"e");
|
||||
return o.replace("e","E").replace(/\.0*$/,"").replace(/\.([0-9]*[^0])0*$/,".$1").replace(/(E[+-])([0-9])$/,"$1"+"0"+"$2");
|
||||
@ -114,10 +116,12 @@ var general_fmt = function(v) {
|
||||
throw new Error("unsupported value in General format: " + v);
|
||||
};
|
||||
SSF._general = general_fmt;
|
||||
function fix_hijri(date, o) { }
|
||||
function fix_hijri(date, o) { return 0; }
|
||||
var parse_date_code = function parse_date_code(v,opts,b2) {
|
||||
var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0;
|
||||
var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
|
||||
var dout=[];
|
||||
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
|
||||
fixopts(opts = (opts||{}));
|
||||
if(opts.date1904) date += 1462;
|
||||
if(date > 2958465) return null;
|
||||
if(out.u > 0.999) {
|
||||
@ -146,7 +150,6 @@ var parse_date_code = function parse_date_code(v,opts,b2) {
|
||||
SSF.parse_date_code = parse_date_code;
|
||||
/*jshint -W086 */
|
||||
var write_date = function(type, fmt, val) {
|
||||
if(val < 0) return "";
|
||||
var o, ss, y = val.y;
|
||||
switch(type) {
|
||||
case 'b': y = val.y + 543;
|
||||
@ -218,11 +221,11 @@ var write_num = function(type, fmt, val) {
|
||||
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
|
||||
if(fmt.match(/^#+0.0E\+0$/)) {
|
||||
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
|
||||
var ee = (Number(val.toExponential(0).substr(2+(val<0))))%period;
|
||||
var ee = (Number(val.toExponential(0).substr(2+(val<0?1:0))))%period;
|
||||
if(ee < 0) ee += period;
|
||||
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
|
||||
if(!o.match(/[Ee]/)) {
|
||||
var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
|
||||
var fakee = (Number(val.toExponential(0).substr(2+(val<0?1:0))));
|
||||
if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
|
||||
else o += "E+" + (fakee - ee);
|
||||
while(o.substr(0,2) === "0.") {
|
||||
@ -242,7 +245,7 @@ var write_num = function(type, fmt, val) {
|
||||
if((r = fmt.match(/# (\?+)([ ]?)\/([ ]?)(\d+)/))) {
|
||||
var den = Number(r[4]), rnd = Math.round(aval * den), base = Math.floor(rnd/den);
|
||||
var myn = (rnd - base*den), myd = den;
|
||||
return sign + (base?base:"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad(myn,r[1].length," ") + r[2] + "/" + r[3] + pad(myd,r[4].length));
|
||||
return sign + String(base||"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad(myn,r[1].length," ") + r[2] + "/" + r[3] + pad(myd,r[4].length));
|
||||
}
|
||||
if(fmt.match(/^#+0+$/)) fmt = fmt.replace(/#/g,"");
|
||||
if(fmt.match(/^00+$/)) return (val<0?"-":"")+pad(Math.round(aval),fmt.length);
|
||||
@ -263,13 +266,10 @@ var write_num = function(type, fmt, val) {
|
||||
return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))) + "." + pad(rr,r[1].length,0);
|
||||
}
|
||||
if((r = fmt.match(/^#,#*,#0/))) return write_num(type,fmt.replace(/^#,#*,/,""),val);
|
||||
if((r = fmt.match(/^([0#]+)\\?-([0#]+)$/))) {
|
||||
ff = write_num(type, fmt.replace(/[\\-]/g,""), val);
|
||||
return ff.substr(0,ff.length - r[2].length) + "-" + ff.substr(ff.length-r[2].length);
|
||||
}
|
||||
if((r = fmt.match(/^([0#]+)\\?-([0#]+)\\?-([0#]+)$/))) {
|
||||
ff = write_num(type, fmt.replace(/[\\-]/g,""), val);
|
||||
return ff.substr(0,ff.length - r[2].length - r[3].length) + "-" + ff.substr(ff.length-r[2].length - r[3].length, r[2].length) + "-" + ff.substr(ff.length-r[3].length);
|
||||
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
|
||||
ff = _strrev(write_num(type, fmt.replace(/[\\-]/g,""), val));
|
||||
rr = 0;
|
||||
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return rr<ff.length?ff[rr++]:x==='0'?'0':'';}));
|
||||
}
|
||||
if(fmt.match(/\(###\) ###\\?-####/)) {
|
||||
ff = write_num(type, "##########", val);
|
||||
@ -290,7 +290,7 @@ var write_num = function(type, fmt, val) {
|
||||
return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad(0,3-$$.length) : "") + $$; }) + "." + pad(rr,r[1].length,0);
|
||||
}
|
||||
switch(fmt) {
|
||||
case "0": case "#0": return Math.round(val);
|
||||
case "0": case "#0": return ""+Math.round(val);
|
||||
case "#,###": var x = commaify(String(Math.round(aval))); return x !== "0" ? sign + x : "";
|
||||
default:
|
||||
}
|
||||
@ -313,7 +313,7 @@ function split_fmt(fmt) {
|
||||
}
|
||||
SSF._split = split_fmt;
|
||||
function eval_fmt(fmt, v, opts, flen) {
|
||||
var out = [], o = "", i = 0, c = "", lst='t', q = {}, dt;
|
||||
var out = [], o = "", i = 0, c = "", lst='t', q, dt;
|
||||
fixopts(opts = (opts || {}));
|
||||
var hr='H';
|
||||
/* Tokenize */
|
||||
|
55
ssf.md
55
ssf.md
@ -10,9 +10,7 @@ default options are described below:
|
||||
|
||||
```js>tmp/10_opts.js
|
||||
/* Options */
|
||||
var opts_fmt = {};
|
||||
function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
|
||||
SSF.opts = opts_fmt;
|
||||
var opts_fmt = {
|
||||
```
|
||||
|
||||
There are two commonly-recognized date code formats:
|
||||
@ -25,7 +23,7 @@ the 1904 date mode was only default in a few Mac variants of Excel (2011 uses
|
||||
`date1904`:
|
||||
|
||||
```
|
||||
opts_fmt.date1904 = 0;
|
||||
date1904:0,
|
||||
```
|
||||
|
||||
The default output is a text representation (no effort to capture colors). To
|
||||
@ -36,7 +34,16 @@ control the output, set the `output` variable:
|
||||
- `ansi`: ansi color codes (requires `colors` module)
|
||||
|
||||
```
|
||||
opts_fmt.output = "";
|
||||
output:"",
|
||||
```
|
||||
|
||||
These options are made available via the `opts` field:
|
||||
|
||||
```
|
||||
WTF:false
|
||||
};
|
||||
function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
|
||||
SSF.opts = opts_fmt;
|
||||
```
|
||||
|
||||
## Conditional Format Codes
|
||||
@ -112,7 +119,7 @@ context-sensitive and the implementation tries to follow the format to the best
|
||||
of its abilities given the knowledge.
|
||||
|
||||
```js>tmp/40_general.js
|
||||
var general_fmt = function(v) {
|
||||
var general_fmt = function(v, opts) {
|
||||
```
|
||||
|
||||
Booleans are serialized in upper case:
|
||||
@ -134,12 +141,12 @@ For numbers, try to display up to 11 digits of the number (the original code
|
||||
else if(V >= Math.pow(10,10) && V < Math.pow(10,11)) o = v.toFixed(10).substr(0,12);
|
||||
else if(V > Math.pow(10,-9) && V < Math.pow(10,11)) {
|
||||
o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
|
||||
if(o.length > 11+(v<0?1:0)) o = v.toPrecision(10);
|
||||
if(o.length > 11+(v<0?1:0)) o = v.toExponential(5);
|
||||
if(o.length > (v<0?12:11)) o = v.toPrecision(10);
|
||||
if(o.length > (v<0?12:11)) o = v.toExponential(5);
|
||||
}
|
||||
else {
|
||||
o = v.toFixed(11).replace(/(\.[0-9]*[1-9])0*$/,"$1");
|
||||
if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
|
||||
if(o.length > (v<0?12:11)) o = v.toPrecision(6);
|
||||
}
|
||||
o = o.replace(/(\.[0-9]*[1-9])0+e/,"$1e").replace(/\.0*e/,"e");
|
||||
return o.replace("e","E").replace(/\.0*$/,"").replace(/\.([0-9]*[^0])0*$/,".$1").replace(/(E[+-])([0-9])$/,"$1"+"0"+"$2");
|
||||
@ -265,7 +272,9 @@ Excel supports the alternative Hijri calendar (indicated with `b2`):
|
||||
```js>tmp/50_date.js
|
||||
var parse_date_code = function parse_date_code(v,opts,b2) {
|
||||
var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0;
|
||||
var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
|
||||
var dout=[];
|
||||
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
|
||||
fixopts(opts = (opts||{}));
|
||||
```
|
||||
|
||||
Excel help actually recommends treating the 1904 date codes as 1900 date codes
|
||||
@ -347,7 +356,7 @@ SSF.parse_date_code = parse_date_code;
|
||||
TODO: suitable hijri correction
|
||||
|
||||
```js>tmp/45_hijri.js
|
||||
function fix_hijri(date, o) { }
|
||||
function fix_hijri(date, o) { return 0; }
|
||||
```
|
||||
|
||||
## Evaluating Number Formats
|
||||
@ -395,7 +404,7 @@ For the special case of engineering notation, "shift" the decimal:
|
||||
```
|
||||
if(fmt.match(/^#+0.0E\+0$/)) {
|
||||
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
|
||||
var ee = (Number(val.toExponential(0).substr(2+(val<0))))%period;
|
||||
var ee = (Number(val.toExponential(0).substr(2+(val<0?1:0))))%period;
|
||||
if(ee < 0) ee += period;
|
||||
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
|
||||
if(!o.match(/[Ee]/)) {
|
||||
@ -404,7 +413,7 @@ For the special case of engineering notation, "shift" the decimal:
|
||||
TODO: something reasonable
|
||||
|
||||
```
|
||||
var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
|
||||
var fakee = (Number(val.toExponential(0).substr(2+(val<0?1:0))));
|
||||
if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
|
||||
else o += "E+" + (fakee - ee);
|
||||
while(o.substr(0,2) === "0.") {
|
||||
@ -434,7 +443,7 @@ Fractions with known denominator are resolved by rounding:
|
||||
if((r = fmt.match(/# (\?+)([ ]?)\/([ ]?)(\d+)/))) {
|
||||
var den = Number(r[4]), rnd = Math.round(aval * den), base = Math.floor(rnd/den);
|
||||
var myn = (rnd - base*den), myd = den;
|
||||
return sign + (base?base:"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad(myn,r[1].length," ") + r[2] + "/" + r[3] + pad(myd,r[4].length));
|
||||
return sign + String(base||"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad(myn,r[1].length," ") + r[2] + "/" + r[3] + pad(myd,r[4].length));
|
||||
}
|
||||
```
|
||||
|
||||
@ -470,13 +479,10 @@ The next few simplifications ignore leading optional sigils (`#`):
|
||||
The `Zip Code + 4` format needs to treat an interstitial hyphen as a character:
|
||||
|
||||
```
|
||||
if((r = fmt.match(/^([0#]+)\\?-([0#]+)$/))) {
|
||||
ff = write_num(type, fmt.replace(/[\\-]/g,""), val);
|
||||
return ff.substr(0,ff.length - r[2].length) + "-" + ff.substr(ff.length-r[2].length);
|
||||
}
|
||||
if((r = fmt.match(/^([0#]+)\\?-([0#]+)\\?-([0#]+)$/))) {
|
||||
ff = write_num(type, fmt.replace(/[\\-]/g,""), val);
|
||||
return ff.substr(0,ff.length - r[2].length - r[3].length) + "-" + ff.substr(ff.length-r[2].length - r[3].length, r[2].length) + "-" + ff.substr(ff.length-r[3].length);
|
||||
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
|
||||
ff = _strrev(write_num(type, fmt.replace(/[\\-]/g,""), val));
|
||||
rr = 0;
|
||||
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return rr<ff.length?ff[rr++]:x==='0'?'0':'';}));
|
||||
}
|
||||
```
|
||||
|
||||
@ -518,7 +524,7 @@ Note that this is technically incorrect
|
||||
return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad(0,3-$$.length) : "") + $$; }) + "." + pad(rr,r[1].length,0);
|
||||
}
|
||||
switch(fmt) {
|
||||
case "0": case "#0": return Math.round(val);
|
||||
case "0": case "#0": return ""+Math.round(val);
|
||||
case "#,###": var x = commaify(String(Math.round(aval))); return x !== "0" ? sign + x : "";
|
||||
```
|
||||
|
||||
@ -535,7 +541,7 @@ For now, the default case is an error:
|
||||
|
||||
```js>tmp/90_main.js
|
||||
function eval_fmt(fmt, v, opts, flen) {
|
||||
var out = [], o = "", i = 0, c = "", lst='t', q = {}, dt;
|
||||
var out = [], o = "", i = 0, c = "", lst='t', q, dt;
|
||||
fixopts(opts = (opts || {}));
|
||||
var hr='H';
|
||||
/* Tokenize */
|
||||
@ -814,7 +820,6 @@ display minutes instead of the month.
|
||||
```js>tmp/50_date.js
|
||||
/*jshint -W086 */
|
||||
var write_date = function(type, fmt, val) {
|
||||
if(val < 0) return "";
|
||||
var o, ss, y = val.y;
|
||||
switch(type) {
|
||||
```
|
||||
@ -1140,7 +1145,7 @@ coveralls:
|
||||
```json>package.json
|
||||
{
|
||||
"name": "ssf",
|
||||
"version": "0.6.4",
|
||||
"version": "0.6.5",
|
||||
"author": "SheetJS",
|
||||
"description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes",
|
||||
"keywords": [ "format", "sprintf", "spreadsheet" ],
|
||||
|
Loading…
Reference in New Issue
Block a user