version bump 0.9.7: write features
- write !cols widths : XLSX XLSB XLML - write hyperlinks : XLML - XLSB convert date cell to numeric on write - fixed issue with assigning self in jszip issues: - closes #607 h/t @jscheid - closes #195 h/t @asfman
This commit is contained in:
parent
085150db3b
commit
b89a876076
@ -8,6 +8,7 @@ changes may not be included if they are not expected to break existing code.
|
||||
## Unreleased
|
||||
|
||||
* XLS legacy `!range` field removed
|
||||
* Hyperlink tooltip is stored in the `Tooltip` field
|
||||
|
||||
## 0.9.6 (2017-03-25)
|
||||
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.9.6';
|
||||
XLSX.version = '0.9.7';
|
||||
|
@ -95,7 +95,7 @@ function ReadShift(size/*:number*/, t/*:?string*/) {
|
||||
case 'cstr': size = 0; o = "";
|
||||
while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
|
||||
o = oo.join(""); break;
|
||||
case 'wstr': size = 0; o = "";
|
||||
case '_wstr': size = 0; o = "";
|
||||
while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
|
||||
size+=2; o = oo.join(""); break;
|
||||
|
||||
|
@ -226,6 +226,15 @@ var CTYPE_XML_ROOT = writextag('Types', null, {
|
||||
var CTYPE_DEFAULTS = [
|
||||
['xml', 'application/xml'],
|
||||
['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
|
||||
/* from test files */
|
||||
['bmp', 'image/bmp'],
|
||||
['png', 'image/png'],
|
||||
['gif', 'image/gif'],
|
||||
['emf', 'image/x-emf'],
|
||||
['wmf', 'image/x-wmf'],
|
||||
['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
|
||||
['tif', 'image/tiff'], ['tiff', 'image/tiff'],
|
||||
['pdf', 'application/pdf'],
|
||||
['rels', type2ct.rels[0]]
|
||||
].map(function(x) {
|
||||
return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
|
||||
@ -267,6 +276,7 @@ function write_ct(ct, opts)/*:string*/ {
|
||||
['strs', 'styles'].forEach(f1);
|
||||
['coreprops', 'extprops', 'custprops'].forEach(f3);
|
||||
f3('vba');
|
||||
f3('comments');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ function parse_cust_props(data/*:string*/, opts) {
|
||||
var type = toks[0].substring(4), text = toks[1];
|
||||
/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
|
||||
switch(type) {
|
||||
case 'lpstr': case 'lpwstr': case 'bstr': case 'lpwstr':
|
||||
case 'lpstr': case 'bstr': case 'lpwstr':
|
||||
p[name] = unescapexml(text);
|
||||
break;
|
||||
case 'bool':
|
||||
|
@ -51,7 +51,7 @@ function rgb_tint(hex, tint) {
|
||||
|
||||
/* 18.3.1.13 width calculations */
|
||||
/* [MS-OI29500] 2.1.595 Column Width & Formatting */
|
||||
var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
|
||||
function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
|
||||
function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
|
||||
|
@ -75,8 +75,8 @@ function parse_fills(t, styles, themes, opts) {
|
||||
case '</fill>': styles.Fills.push(fill); fill = {}; break;
|
||||
|
||||
/* 18.8.24 gradientFill CT_GradientFill */
|
||||
case '<fill>': break;
|
||||
case '</fill>': styles.Fills.push(fill); fill = {}; break;
|
||||
case '<gradientFill>': break;
|
||||
case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
|
||||
|
||||
/* 18.8.32 patternFill CT_PatternFill */
|
||||
case '<patternFill': case '<patternFill>':
|
||||
|
@ -11,6 +11,18 @@ function get_sst_id(sst/*:SST*/, str/*:string*/)/*:number*/ {
|
||||
sst[len] = {t:str}; sst.Count ++; sst.Unique ++; return len;
|
||||
}
|
||||
|
||||
function col_obj_w(C/*:number*/, col) {
|
||||
var p = ({min:C+1,max:C+1}/*:any*/);
|
||||
/* wch (chars), wpx (pixels) */
|
||||
var width = -1;
|
||||
if(col.MDW) MDW = col.MDW;
|
||||
if(col.width != null) p.customWidth = 1;
|
||||
else if(col.wpx != null) width = px2char(col.wpx);
|
||||
else if(col.wch != null) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth = 1; }
|
||||
return p;
|
||||
}
|
||||
|
||||
function get_cell_style(styles, cell, opts) {
|
||||
var z = opts.revssf[cell.z != null ? cell.z : "General"];
|
||||
for(var i = 0, len = styles.length; i != len; ++i) if(styles[i].numFmtId === z) return i;
|
||||
|
@ -70,7 +70,7 @@ function write_ws_xml_merges(merges) {
|
||||
return o + '</mergeCells>';
|
||||
}
|
||||
|
||||
function parse_ws_xml_hlinks(s, data, rels) {
|
||||
function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
|
||||
for(var i = 0; i != data.length; ++i) {
|
||||
var val = parsexmltag(data[i], true);
|
||||
if(!val.ref) return;
|
||||
@ -84,6 +84,7 @@ function parse_ws_xml_hlinks(s, data, rels) {
|
||||
rel = {Target: val.location, TargetMode: 'Internal'};
|
||||
val.Rel = rel;
|
||||
}
|
||||
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
|
||||
var rng = safe_decode_range(val.ref);
|
||||
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
|
||||
var addr = encode_cell({c:C,r:R});
|
||||
@ -109,15 +110,7 @@ function write_ws_xml_cols(ws, cols)/*:string*/ {
|
||||
var o = ["<cols>"], col, width;
|
||||
for(var i = 0; i != cols.length; ++i) {
|
||||
if(!(col = cols[i])) continue;
|
||||
var p = ({min:i+1,max:i+1}/*:any*/);
|
||||
/* wch (chars), wpx (pixels) */
|
||||
width = -1;
|
||||
if(col.MDW) MDW = col.MDW;
|
||||
if(col.width);
|
||||
else if(col.wpx) width = px2char(col.wpx);
|
||||
else if(col.wch) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth= 1; }
|
||||
o[o.length] = (writextag('col', null, p));
|
||||
o[o.length] = (writextag('col', null, col_obj_w(i, col)));
|
||||
}
|
||||
o[o.length] = "</cols>";
|
||||
return o.join("");
|
||||
@ -328,14 +321,16 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
|
||||
|
||||
if(ws['!cols'] !== undefined && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
|
||||
o[sidx = o.length] = '<sheetData/>';
|
||||
if(ws['!ref'] !== undefined) {
|
||||
if(ws['!ref'] != null) {
|
||||
rdata = write_ws_xml_data(ws, opts, idx, wb);
|
||||
if(rdata.length > 0) o[o.length] = (rdata);
|
||||
}
|
||||
if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
|
||||
|
||||
if(ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
|
||||
if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
|
||||
|
||||
delete ws['!links'];
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ function parse_BrtHLink(data, length, opts) {
|
||||
var tooltip = parse_XLWideString(data);
|
||||
var display = parse_XLWideString(data);
|
||||
data.l = end;
|
||||
return {rfx:rfx, relId:relId, loc:loc, tooltip:tooltip, display:display};
|
||||
return {rfx:rfx, relId:relId, loc:loc, Tooltip:tooltip, display:display};
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.6 BrtArrFmla */
|
||||
@ -255,6 +255,20 @@ function parse_BrtShrFmla(data, length, opts) {
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.323 BrtColInfo */
|
||||
/* TODO: once XLS ColInfo is set, combine the functions */
|
||||
function write_BrtColInfo(C/*:number*/, col, o) {
|
||||
if(o == null) o = new_buf(18);
|
||||
var p = col_obj_w(C, col);
|
||||
o.write_shift(-4, C);
|
||||
o.write_shift(-4, C);
|
||||
o.write_shift(4, p.width * 256);
|
||||
o.write_shift(4, 0/*ixfe*/); // style
|
||||
o.write_shift(1, 2); // bit flag
|
||||
o.write_shift(1, 0); // bit flag
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.61 Worksheet */
|
||||
function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ {
|
||||
if(!data) return data;
|
||||
@ -521,9 +535,15 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ {
|
||||
/* TODO: something useful -- this is a stub */
|
||||
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
|
||||
if(cell.v === undefined) return "";
|
||||
var vv = "";
|
||||
var vv = ""; var olddate = null;
|
||||
switch(cell.t) {
|
||||
case 'b': vv = cell.v ? "1" : "0"; break;
|
||||
case 'd': // no BrtCellDate :(
|
||||
cell.z = cell.z || SSF._table[14];
|
||||
olddate = cell.v;
|
||||
cell.v = datenum((cell.v/*:any*/)); cell.t = 'n';
|
||||
break;
|
||||
/* falls through */
|
||||
case 'n': case 'e': vv = ''+cell.v; break;
|
||||
default: vv = cell.v; break;
|
||||
}
|
||||
@ -533,7 +553,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
|
||||
switch(cell.t) {
|
||||
case 's': case 'str':
|
||||
if(opts.bookSST) {
|
||||
vv = get_sst_id(opts.Strings, cell.v);
|
||||
vv = get_sst_id(opts.Strings, (cell.v/*:any*/));
|
||||
o.t = "s"; o.v = vv;
|
||||
write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
|
||||
} else {
|
||||
@ -545,6 +565,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
|
||||
/* TODO: determine threshold for Real vs RK */
|
||||
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
|
||||
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
|
||||
if(olddate) { cell.t = 'd'; cell.v = olddate; }
|
||||
return;
|
||||
case 'b':
|
||||
o.t = "b";
|
||||
@ -555,7 +576,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
|
||||
write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
|
||||
}
|
||||
|
||||
function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
||||
function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
|
||||
write_record(ba, 'BrtBeginSheetData');
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
@ -582,6 +603,13 @@ function write_MERGECELLS(ba, ws/*:Worksheet*/) {
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_COLINFOS(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
if(!ws || !ws['!cols']) return;
|
||||
write_record(ba, 'BrtBeginColInfos');
|
||||
ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
|
||||
write_record(ba, 'BrtEndColInfos');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
@ -591,7 +619,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
write_record(ba, "BrtWsDim", write_BrtWsDim(r));
|
||||
/* [WSVIEWS2] */
|
||||
/* [WSFMTINFO] */
|
||||
/* *COLINFOS */
|
||||
write_COLINFOS(ba, ws, idx, opts, wb);
|
||||
write_CELLTABLE(ba, ws, idx, opts, wb);
|
||||
/* [BrtSheetCalcProp] */
|
||||
/* [[BrtSheetProtectionIso] BrtSheetProtection] */
|
||||
|
@ -199,8 +199,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
if(comments.length > 0) cell.c = comments;
|
||||
if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) cursheet[encode_col(c) + encode_row(r)] = cell;
|
||||
if(cell.HRef) {
|
||||
cell.l = {Target:cell.HRef, tooltip:cell.HRefScreenTip};
|
||||
cell.HRef = cell.HRefScreenTip = undefined;
|
||||
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
|
||||
delete cell.HRef; delete cell.HRefScreenTip;
|
||||
}
|
||||
if(cell.MergeAcross || cell.MergeDown) {
|
||||
var cc = c + (parseInt(cell.MergeAcross,10)|0);
|
||||
@ -787,6 +787,11 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
|
||||
}
|
||||
|
||||
if(cell.l && cell.l.Target) {
|
||||
attr["ss:HRef"] = escapexml(cell.l.Target);
|
||||
if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
|
||||
}
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
@ -822,6 +827,10 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
|
||||
var p = col_obj_w(i, n);
|
||||
o.push(writextag("Column",null, {"ss:Index":i+1, "ss:Width":width2px(p.width)}));
|
||||
});
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
|
@ -432,7 +432,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
|
||||
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC)
|
||||
if(out[encode_cell({c:rngC,r:rngR})])
|
||||
out[encode_cell({c:rngC,r:rngR})].l.tooltip = val[1];
|
||||
out[encode_cell({c:rngC,r:rngR})].l.Tooltip = val[1];
|
||||
} break;
|
||||
|
||||
/* Comments */
|
||||
|
1
dist/jszip.js
vendored
1
dist/jszip.js
vendored
@ -13,7 +13,6 @@ https://github.com/nodeca/pako/blob/master/LICENSE
|
||||
if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();
|
||||
else if("function"==typeof define&&define.amd){JSZip=e();define([],e);}
|
||||
else{
|
||||
if(typeof self == 'undefined' && typeof app != 'undefined') self = app;
|
||||
var f;
|
||||
"undefined"!=typeof window?f=window:
|
||||
"undefined"!=typeof global?f=global:
|
||||
|
30
dist/xlsx.core.min.js
vendored
30
dist/xlsx.core.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.core.min.map
vendored
2
dist/xlsx.core.min.map
vendored
File diff suppressed because one or more lines are too long
41
dist/xlsx.full.min.js
vendored
41
dist/xlsx.full.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.full.min.map
vendored
2
dist/xlsx.full.min.map
vendored
File diff suppressed because one or more lines are too long
637
dist/xlsx.js
vendored
637
dist/xlsx.js
vendored
File diff suppressed because it is too large
Load Diff
24
dist/xlsx.min.js
vendored
24
dist/xlsx.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.min.map
vendored
2
dist/xlsx.min.map
vendored
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@
|
||||
| `h` | HTML rendering of the rich text (if applicable) |
|
||||
| `c` | comments associated with the cell |
|
||||
| `z` | number format string associated with the cell (if requested) |
|
||||
| `l` | cell hyperlink object (.Target holds link, .tooltip is tooltip) |
|
||||
| `l` | cell hyperlink object (.Target holds link, .Tooltip is tooltip) |
|
||||
| `s` | the style/theme of the cell (if applicable) |
|
||||
|
||||
Built-in export utilities (such as the CSV exporter) will use the `w` text if it
|
||||
|
17
docbits/64_cellprops.md
Normal file
17
docbits/64_cellprops.md
Normal file
@ -0,0 +1,17 @@
|
||||
#### Hyperlinks
|
||||
|
||||
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
|
||||
hyperlink object is the target of the link, including the URI fragment. Tooltips
|
||||
are stored in the `Tooltip` field and are displayed when you move your mouse
|
||||
over the text.
|
||||
|
||||
For example, the following snippet creates a link from cell `A3` to
|
||||
<http://sheetjs.com> with the tip `"Find us @ SheetJS.com!"`:
|
||||
|
||||
```js
|
||||
ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
|
||||
```
|
||||
|
||||
Note that Excel does not automatically style hyperlinks -- they will generally
|
||||
be displayed as normal text.
|
||||
|
1
jszip.js
1
jszip.js
@ -13,7 +13,6 @@ https://github.com/nodeca/pako/blob/master/LICENSE
|
||||
if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();
|
||||
else if("function"==typeof define&&define.amd){JSZip=e();define([],e);}
|
||||
else{
|
||||
if(typeof self == 'undefined' && typeof app != 'undefined') self = app;
|
||||
var f;
|
||||
"undefined"!=typeof window?f=window:
|
||||
"undefined"!=typeof global?f=global:
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.9.6",
|
||||
"version": "0.9.7",
|
||||
"author": "sheetjs",
|
||||
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS (ODS/FODS/UOS) spreadsheet parser and writer",
|
||||
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
|
||||
|
41
test.js
41
test.js
@ -602,6 +602,19 @@ function diffsty(ws, r1,r2) {
|
||||
});
|
||||
}
|
||||
|
||||
function hlink(wb) {
|
||||
var ws = wb.Sheets.Sheet1;
|
||||
assert.equal(ws.A1.l.Target, "http://www.sheetjs.com");
|
||||
assert.equal(ws.A2.l.Target, "http://oss.sheetjs.com");
|
||||
assert.equal(ws.A3.l.Target, "http://oss.sheetjs.com#foo");
|
||||
assert.equal(ws.A4.l.Target, "mailto:dev@sheetjs.com");
|
||||
assert.equal(ws.A5.l.Target, "mailto:dev@sheetjs.com?subject=hyperlink");
|
||||
assert.equal(ws.A6.l.Target, "../../sheetjs/Documents/Test.xlsx");
|
||||
assert.equal(ws.A7.l.Target, "http://sheetjs.com");
|
||||
assert.equal(ws.A7.l.Tooltip, "foo bar baz");
|
||||
}
|
||||
|
||||
|
||||
describe('parse features', function() {
|
||||
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
|
||||
var X = require(modp);
|
||||
@ -760,17 +773,6 @@ describe('parse features', function() {
|
||||
if(typeof before != 'undefined') before(bef);
|
||||
else it('before', bef);
|
||||
|
||||
function hlink(wb) {
|
||||
var ws = wb.Sheets.Sheet1;
|
||||
assert.equal(ws.A1.l.Target, "http://www.sheetjs.com");
|
||||
assert.equal(ws.A2.l.Target, "http://oss.sheetjs.com");
|
||||
assert.equal(ws.A3.l.Target, "http://oss.sheetjs.com#foo");
|
||||
assert.equal(ws.A4.l.Target, "mailto:dev@sheetjs.com");
|
||||
assert.equal(ws.A5.l.Target, "mailto:dev@sheetjs.com?subject=hyperlink");
|
||||
assert.equal(ws.A6.l.Target, "../../sheetjs/Documents/Test.xlsx");
|
||||
assert.equal(ws.A7.l.Target, "http://sheetjs.com");
|
||||
}
|
||||
|
||||
it(N1, function() { hlink(wb1); });
|
||||
it(N2, function() { hlink(wb2); });
|
||||
it(N3, function() { hlink(wb3); });
|
||||
@ -977,14 +979,27 @@ describe('roundtrip features', function() {
|
||||
].forEach(function(w) {
|
||||
it(w[0], function() {
|
||||
var wb1 = X.readFile(w[1], {cellFormula:true});
|
||||
if(w[0] == 'ods') X.writeFile(wb1, "./tmp/_.ods", {bookType:"ods"});
|
||||
var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"buffer"}), {cellFormula:true, type:"buffer"});
|
||||
var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"buffer"}), {type:"buffer"});
|
||||
wb1.SheetNames.forEach(function(n) {
|
||||
assert.equal( X.utils.sheet_to_formulae(wb1.Sheets[n]).sort().join("\n"), X.utils.sheet_to_formulae(wb2.Sheets[n]).sort().join("\n") );
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should preserve hyperlink', function() { [
|
||||
['xlml', paths.hlxml],
|
||||
//['xlsx', paths.hlxlsx], // TODO
|
||||
//['xlsb', paths.hlxlsb] // TODO
|
||||
].forEach(function(w) {
|
||||
it(w[0], function() {
|
||||
var wb1 = X.readFile(w[1]);
|
||||
var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"buffer"}), {type:"buffer"});
|
||||
hlink(wb1);
|
||||
hlink(wb2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function password_file(x){return x.match(/^password.*\.xls$/); }
|
||||
|
@ -444,6 +444,19 @@ function diffsty(ws, r1,r2) {
|
||||
});
|
||||
}
|
||||
|
||||
function hlink(wb) {
|
||||
var ws = wb.Sheets.Sheet1;
|
||||
assert.equal(ws.A1.l.Target, "http://www.sheetjs.com");
|
||||
assert.equal(ws.A2.l.Target, "http://oss.sheetjs.com");
|
||||
assert.equal(ws.A3.l.Target, "http://oss.sheetjs.com#foo");
|
||||
assert.equal(ws.A4.l.Target, "mailto:dev@sheetjs.com");
|
||||
assert.equal(ws.A5.l.Target, "mailto:dev@sheetjs.com?subject=hyperlink");
|
||||
assert.equal(ws.A6.l.Target, "../../sheetjs/Documents/Test.xlsx");
|
||||
assert.equal(ws.A7.l.Target, "http://sheetjs.com");
|
||||
assert.equal(ws.A7.l.Tooltip, "foo bar baz");
|
||||
}
|
||||
|
||||
|
||||
describe('parse features', function() {
|
||||
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
|
||||
var X = require(modp);
|
||||
@ -602,17 +615,6 @@ describe('parse features', function() {
|
||||
if(typeof before != 'undefined') before(bef);
|
||||
else it('before', bef);
|
||||
|
||||
function hlink(wb) {
|
||||
var ws = wb.Sheets.Sheet1;
|
||||
assert.equal(ws.A1.l.Target, "http://www.sheetjs.com");
|
||||
assert.equal(ws.A2.l.Target, "http://oss.sheetjs.com");
|
||||
assert.equal(ws.A3.l.Target, "http://oss.sheetjs.com#foo");
|
||||
assert.equal(ws.A4.l.Target, "mailto:dev@sheetjs.com");
|
||||
assert.equal(ws.A5.l.Target, "mailto:dev@sheetjs.com?subject=hyperlink");
|
||||
assert.equal(ws.A6.l.Target, "../../sheetjs/Documents/Test.xlsx");
|
||||
assert.equal(ws.A7.l.Target, "http://sheetjs.com");
|
||||
}
|
||||
|
||||
it(N1, function() { hlink(wb1); });
|
||||
it(N2, function() { hlink(wb2); });
|
||||
it(N3, function() { hlink(wb3); });
|
||||
@ -825,6 +827,20 @@ describe('roundtrip features', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should preserve hyperlink', function() { [
|
||||
['xlml', paths.hlxml],
|
||||
//['xlsx', paths.hlxlsx], // TODO
|
||||
//['xlsb', paths.hlxlsb] // TODO
|
||||
].forEach(function(w) {
|
||||
it(w[0], function() {
|
||||
var wb1 = X.read(fs.readFileSync(w[1]), {type:"binary"});
|
||||
var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"binary"}), {type:"binary"});
|
||||
hlink(wb1);
|
||||
hlink(wb2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function password_file(x){return x.match(/^password.*\.xls$/); }
|
||||
|
@ -12,10 +12,10 @@ var data = [
|
||||
var ws_name = "SheetJS";
|
||||
|
||||
var wscols = [
|
||||
{wch:6},
|
||||
{wch:7},
|
||||
{wch:6}, // "characters"
|
||||
{wpx:50}, // "pixels"
|
||||
{wch:10},
|
||||
{wch:20}
|
||||
{wpx:125}
|
||||
];
|
||||
|
||||
|
||||
@ -28,52 +28,11 @@ console.log("Columns :"); for(i=0; i!=wscols.length;++i) console.log(wscols[i]);
|
||||
/* require XLSX */
|
||||
if(typeof XLSX === "undefined") { try { XLSX = require('./'); } catch(e) { XLSX = require('../'); } }
|
||||
|
||||
/* dummy workbook constructor */
|
||||
function Workbook() {
|
||||
if(!(this instanceof Workbook)) return new Workbook();
|
||||
this.SheetNames = [];
|
||||
this.Sheets = {};
|
||||
}
|
||||
var wb = new Workbook();
|
||||
|
||||
|
||||
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
|
||||
var epoch = v.getTime();
|
||||
if(date1904) epoch += 1462*24*60*60*1000;
|
||||
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
/* blank workbook constructor */
|
||||
var wb = { SheetNames: [], Sheets: {} };
|
||||
|
||||
/* convert an array of arrays in JS to a CSF spreadsheet */
|
||||
function sheet_from_array_of_arrays(data, opts) {
|
||||
var ws = {};
|
||||
var range = {s: {c:10000000, r:10000000}, e: {c:0, r:0 }};
|
||||
for(var R = 0; R != data.length; ++R) {
|
||||
for(var C = 0; C != data[R].length; ++C) {
|
||||
if(range.s.r > R) range.s.r = R;
|
||||
if(range.s.c > C) range.s.c = C;
|
||||
if(range.e.r < R) range.e.r = R;
|
||||
if(range.e.c < C) range.e.c = C;
|
||||
var cell = {v: data[R][C] };
|
||||
if(cell.v == null) continue;
|
||||
var cell_ref = XLSX.utils.encode_cell({c:C,r:R});
|
||||
|
||||
/* TEST: proper cell types and value handling */
|
||||
if(typeof cell.v === 'number') cell.t = 'n';
|
||||
else if(typeof cell.v === 'boolean') cell.t = 'b';
|
||||
else if(cell.v instanceof Date) {
|
||||
cell.t = 'n'; cell.z = XLSX.SSF._table[14];
|
||||
cell.v = datenum(cell.v);
|
||||
}
|
||||
else cell.t = 's';
|
||||
ws[cell_ref] = cell;
|
||||
}
|
||||
}
|
||||
|
||||
/* TEST: proper range */
|
||||
if(range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
|
||||
return ws;
|
||||
}
|
||||
var ws = sheet_from_array_of_arrays(data);
|
||||
var ws = XLSX.utils.aoa_to_sheet(data, {cellDates:true});
|
||||
|
||||
/* TEST: add worksheet to workbook */
|
||||
wb.SheetNames.push(ws_name);
|
||||
@ -96,8 +55,18 @@ ws["!ref"] = "A1:E4";
|
||||
/* TEST: column widths */
|
||||
ws['!cols'] = wscols;
|
||||
|
||||
/* TEST: hyperlink note: Excel does not automatically style hyperlinks */
|
||||
ws['A3'].l = { Target: "http://sheetjs.com", Tooltip: "Visit us <SheetJS.com!>" };
|
||||
|
||||
/* TEST: built-in format */
|
||||
//ws['A1'].z = "0%"; wb.SSF[9] = "0%"; // Format Code 9
|
||||
|
||||
/* TEST: custom format */
|
||||
//ws['B2'].z = "0.0"; wb.SSF[60] = "0.0"; // Custom
|
||||
console.log("JSON Data: "); console.log(XLSX.utils.sheet_to_json(ws, {header:1}));
|
||||
|
||||
console.log("Worksheet Model:")
|
||||
console.log(ws);
|
||||
|
||||
/* write file */
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsx', {bookSST:true});
|
||||
|
106
xlsx.flow.js
106
xlsx.flow.js
@ -5,7 +5,7 @@
|
||||
/*exported XLSX */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.9.6';
|
||||
XLSX.version = '0.9.7';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
/*:: declare var cptable:any; */
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
@ -1830,7 +1830,7 @@ function ReadShift(size/*:number*/, t/*:?string*/) {
|
||||
case 'cstr': size = 0; o = "";
|
||||
while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
|
||||
o = oo.join(""); break;
|
||||
case 'wstr': size = 0; o = "";
|
||||
case '_wstr': size = 0; o = "";
|
||||
while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
|
||||
size+=2; o = oo.join(""); break;
|
||||
|
||||
@ -2780,6 +2780,15 @@ var CTYPE_XML_ROOT = writextag('Types', null, {
|
||||
var CTYPE_DEFAULTS = [
|
||||
['xml', 'application/xml'],
|
||||
['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
|
||||
/* from test files */
|
||||
['bmp', 'image/bmp'],
|
||||
['png', 'image/png'],
|
||||
['gif', 'image/gif'],
|
||||
['emf', 'image/x-emf'],
|
||||
['wmf', 'image/x-wmf'],
|
||||
['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
|
||||
['tif', 'image/tiff'], ['tiff', 'image/tiff'],
|
||||
['pdf', 'application/pdf'],
|
||||
['rels', type2ct.rels[0]]
|
||||
].map(function(x) {
|
||||
return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
|
||||
@ -2821,6 +2830,7 @@ function write_ct(ct, opts)/*:string*/ {
|
||||
['strs', 'styles'].forEach(f1);
|
||||
['coreprops', 'extprops', 'custprops'].forEach(f3);
|
||||
f3('vba');
|
||||
f3('comments');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
@ -3128,7 +3138,7 @@ function parse_cust_props(data/*:string*/, opts) {
|
||||
var type = toks[0].substring(4), text = toks[1];
|
||||
/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
|
||||
switch(type) {
|
||||
case 'lpstr': case 'lpwstr': case 'bstr': case 'lpwstr':
|
||||
case 'lpstr': case 'bstr': case 'lpwstr':
|
||||
p[name] = unescapexml(text);
|
||||
break;
|
||||
case 'bool':
|
||||
@ -5393,7 +5403,7 @@ function rgb_tint(hex, tint) {
|
||||
|
||||
/* 18.3.1.13 width calculations */
|
||||
/* [MS-OI29500] 2.1.595 Column Width & Formatting */
|
||||
var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
|
||||
function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
|
||||
function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
|
||||
@ -5527,8 +5537,8 @@ function parse_fills(t, styles, themes, opts) {
|
||||
case '</fill>': styles.Fills.push(fill); fill = {}; break;
|
||||
|
||||
/* 18.8.24 gradientFill CT_GradientFill */
|
||||
case '<fill>': break;
|
||||
case '</fill>': styles.Fills.push(fill); fill = {}; break;
|
||||
case '<gradientFill>': break;
|
||||
case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
|
||||
|
||||
/* 18.8.32 patternFill CT_PatternFill */
|
||||
case '<patternFill': case '<patternFill>':
|
||||
@ -8812,6 +8822,18 @@ function get_sst_id(sst/*:SST*/, str/*:string*/)/*:number*/ {
|
||||
sst[len] = {t:str}; sst.Count ++; sst.Unique ++; return len;
|
||||
}
|
||||
|
||||
function col_obj_w(C/*:number*/, col) {
|
||||
var p = ({min:C+1,max:C+1}/*:any*/);
|
||||
/* wch (chars), wpx (pixels) */
|
||||
var width = -1;
|
||||
if(col.MDW) MDW = col.MDW;
|
||||
if(col.width != null) p.customWidth = 1;
|
||||
else if(col.wpx != null) width = px2char(col.wpx);
|
||||
else if(col.wch != null) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth = 1; }
|
||||
return p;
|
||||
}
|
||||
|
||||
function get_cell_style(styles, cell, opts) {
|
||||
var z = opts.revssf[cell.z != null ? cell.z : "General"];
|
||||
for(var i = 0, len = styles.length; i != len; ++i) if(styles[i].numFmtId === z) return i;
|
||||
@ -8932,7 +8954,7 @@ function write_ws_xml_merges(merges) {
|
||||
return o + '</mergeCells>';
|
||||
}
|
||||
|
||||
function parse_ws_xml_hlinks(s, data, rels) {
|
||||
function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
|
||||
for(var i = 0; i != data.length; ++i) {
|
||||
var val = parsexmltag(data[i], true);
|
||||
if(!val.ref) return;
|
||||
@ -8946,6 +8968,7 @@ function parse_ws_xml_hlinks(s, data, rels) {
|
||||
rel = {Target: val.location, TargetMode: 'Internal'};
|
||||
val.Rel = rel;
|
||||
}
|
||||
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
|
||||
var rng = safe_decode_range(val.ref);
|
||||
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
|
||||
var addr = encode_cell({c:C,r:R});
|
||||
@ -8971,15 +8994,7 @@ function write_ws_xml_cols(ws, cols)/*:string*/ {
|
||||
var o = ["<cols>"], col, width;
|
||||
for(var i = 0; i != cols.length; ++i) {
|
||||
if(!(col = cols[i])) continue;
|
||||
var p = ({min:i+1,max:i+1}/*:any*/);
|
||||
/* wch (chars), wpx (pixels) */
|
||||
width = -1;
|
||||
if(col.MDW) MDW = col.MDW;
|
||||
if(col.width);
|
||||
else if(col.wpx) width = px2char(col.wpx);
|
||||
else if(col.wch) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth= 1; }
|
||||
o[o.length] = (writextag('col', null, p));
|
||||
o[o.length] = (writextag('col', null, col_obj_w(i, col)));
|
||||
}
|
||||
o[o.length] = "</cols>";
|
||||
return o.join("");
|
||||
@ -9190,15 +9205,17 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
|
||||
|
||||
if(ws['!cols'] !== undefined && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
|
||||
o[sidx = o.length] = '<sheetData/>';
|
||||
if(ws['!ref'] !== undefined) {
|
||||
if(ws['!ref'] != null) {
|
||||
rdata = write_ws_xml_data(ws, opts, idx, wb);
|
||||
if(rdata.length > 0) o[o.length] = (rdata);
|
||||
}
|
||||
if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
|
||||
|
||||
if(ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
|
||||
if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
|
||||
|
||||
delete ws['!links'];
|
||||
return o.join("");
|
||||
}
|
||||
|
||||
@ -9429,7 +9446,7 @@ function parse_BrtHLink(data, length, opts) {
|
||||
var tooltip = parse_XLWideString(data);
|
||||
var display = parse_XLWideString(data);
|
||||
data.l = end;
|
||||
return {rfx:rfx, relId:relId, loc:loc, tooltip:tooltip, display:display};
|
||||
return {rfx:rfx, relId:relId, loc:loc, Tooltip:tooltip, display:display};
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.6 BrtArrFmla */
|
||||
@ -9458,6 +9475,20 @@ function parse_BrtShrFmla(data, length, opts) {
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.323 BrtColInfo */
|
||||
/* TODO: once XLS ColInfo is set, combine the functions */
|
||||
function write_BrtColInfo(C/*:number*/, col, o) {
|
||||
if(o == null) o = new_buf(18);
|
||||
var p = col_obj_w(C, col);
|
||||
o.write_shift(-4, C);
|
||||
o.write_shift(-4, C);
|
||||
o.write_shift(4, p.width * 256);
|
||||
o.write_shift(4, 0/*ixfe*/); // style
|
||||
o.write_shift(1, 2); // bit flag
|
||||
o.write_shift(1, 0); // bit flag
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.61 Worksheet */
|
||||
function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ {
|
||||
if(!data) return data;
|
||||
@ -9724,9 +9755,15 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ {
|
||||
/* TODO: something useful -- this is a stub */
|
||||
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
|
||||
if(cell.v === undefined) return "";
|
||||
var vv = "";
|
||||
var vv = ""; var olddate = null;
|
||||
switch(cell.t) {
|
||||
case 'b': vv = cell.v ? "1" : "0"; break;
|
||||
case 'd': // no BrtCellDate :(
|
||||
cell.z = cell.z || SSF._table[14];
|
||||
olddate = cell.v;
|
||||
cell.v = datenum((cell.v/*:any*/)); cell.t = 'n';
|
||||
break;
|
||||
/* falls through */
|
||||
case 'n': case 'e': vv = ''+cell.v; break;
|
||||
default: vv = cell.v; break;
|
||||
}
|
||||
@ -9736,7 +9773,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
|
||||
switch(cell.t) {
|
||||
case 's': case 'str':
|
||||
if(opts.bookSST) {
|
||||
vv = get_sst_id(opts.Strings, cell.v);
|
||||
vv = get_sst_id(opts.Strings, (cell.v/*:any*/));
|
||||
o.t = "s"; o.v = vv;
|
||||
write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
|
||||
} else {
|
||||
@ -9748,6 +9785,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
|
||||
/* TODO: determine threshold for Real vs RK */
|
||||
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
|
||||
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
|
||||
if(olddate) { cell.t = 'd'; cell.v = olddate; }
|
||||
return;
|
||||
case 'b':
|
||||
o.t = "b";
|
||||
@ -9758,7 +9796,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
|
||||
write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
|
||||
}
|
||||
|
||||
function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
||||
function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
|
||||
write_record(ba, 'BrtBeginSheetData');
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
@ -9785,6 +9823,13 @@ function write_MERGECELLS(ba, ws/*:Worksheet*/) {
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_COLINFOS(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
if(!ws || !ws['!cols']) return;
|
||||
write_record(ba, 'BrtBeginColInfos');
|
||||
ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
|
||||
write_record(ba, 'BrtEndColInfos');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
@ -9794,7 +9839,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
write_record(ba, "BrtWsDim", write_BrtWsDim(r));
|
||||
/* [WSVIEWS2] */
|
||||
/* [WSFMTINFO] */
|
||||
/* *COLINFOS */
|
||||
write_COLINFOS(ba, ws, idx, opts, wb);
|
||||
write_CELLTABLE(ba, ws, idx, opts, wb);
|
||||
/* [BrtSheetCalcProp] */
|
||||
/* [[BrtSheetProtectionIso] BrtSheetProtection] */
|
||||
@ -10674,8 +10719,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
if(comments.length > 0) cell.c = comments;
|
||||
if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) cursheet[encode_col(c) + encode_row(r)] = cell;
|
||||
if(cell.HRef) {
|
||||
cell.l = {Target:cell.HRef, tooltip:cell.HRefScreenTip};
|
||||
cell.HRef = cell.HRefScreenTip = undefined;
|
||||
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
|
||||
delete cell.HRef; delete cell.HRefScreenTip;
|
||||
}
|
||||
if(cell.MergeAcross || cell.MergeDown) {
|
||||
var cc = c + (parseInt(cell.MergeAcross,10)|0);
|
||||
@ -11262,6 +11307,11 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
|
||||
}
|
||||
|
||||
if(cell.l && cell.l.Target) {
|
||||
attr["ss:HRef"] = escapexml(cell.l.Target);
|
||||
if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
|
||||
}
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
@ -11297,6 +11347,10 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
|
||||
var p = col_obj_w(i, n);
|
||||
o.push(writextag("Column",null, {"ss:Index":i+1, "ss:Width":width2px(p.width)}));
|
||||
});
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
@ -11780,7 +11834,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
|
||||
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC)
|
||||
if(out[encode_cell({c:rngC,r:rngR})])
|
||||
out[encode_cell({c:rngC,r:rngR})].l.tooltip = val[1];
|
||||
out[encode_cell({c:rngC,r:rngR})].l.Tooltip = val[1];
|
||||
} break;
|
||||
|
||||
/* Comments */
|
||||
|
102
xlsx.js
102
xlsx.js
@ -5,7 +5,7 @@
|
||||
/*exported XLSX */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.9.6';
|
||||
XLSX.version = '0.9.7';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
|
||||
@ -1781,7 +1781,7 @@ function ReadShift(size, t) {
|
||||
case 'cstr': size = 0; o = "";
|
||||
while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
|
||||
o = oo.join(""); break;
|
||||
case 'wstr': size = 0; o = "";
|
||||
case '_wstr': size = 0; o = "";
|
||||
while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
|
||||
size+=2; o = oo.join(""); break;
|
||||
|
||||
@ -2728,6 +2728,15 @@ var CTYPE_XML_ROOT = writextag('Types', null, {
|
||||
var CTYPE_DEFAULTS = [
|
||||
['xml', 'application/xml'],
|
||||
['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
|
||||
/* from test files */
|
||||
['bmp', 'image/bmp'],
|
||||
['png', 'image/png'],
|
||||
['gif', 'image/gif'],
|
||||
['emf', 'image/x-emf'],
|
||||
['wmf', 'image/x-wmf'],
|
||||
['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
|
||||
['tif', 'image/tiff'], ['tiff', 'image/tiff'],
|
||||
['pdf', 'application/pdf'],
|
||||
['rels', type2ct.rels[0]]
|
||||
].map(function(x) {
|
||||
return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
|
||||
@ -2769,6 +2778,7 @@ function write_ct(ct, opts) {
|
||||
['strs', 'styles'].forEach(f1);
|
||||
['coreprops', 'extprops', 'custprops'].forEach(f3);
|
||||
f3('vba');
|
||||
f3('comments');
|
||||
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
@ -3076,7 +3086,7 @@ function parse_cust_props(data, opts) {
|
||||
var type = toks[0].substring(4), text = toks[1];
|
||||
/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
|
||||
switch(type) {
|
||||
case 'lpstr': case 'lpwstr': case 'bstr': case 'lpwstr':
|
||||
case 'lpstr': case 'bstr': case 'lpwstr':
|
||||
p[name] = unescapexml(text);
|
||||
break;
|
||||
case 'bool':
|
||||
@ -5339,7 +5349,7 @@ function rgb_tint(hex, tint) {
|
||||
|
||||
/* 18.3.1.13 width calculations */
|
||||
/* [MS-OI29500] 2.1.595 Column Width & Formatting */
|
||||
var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
|
||||
function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
|
||||
function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
|
||||
@ -5473,8 +5483,8 @@ function parse_fills(t, styles, themes, opts) {
|
||||
case '</fill>': styles.Fills.push(fill); fill = {}; break;
|
||||
|
||||
/* 18.8.24 gradientFill CT_GradientFill */
|
||||
case '<fill>': break;
|
||||
case '</fill>': styles.Fills.push(fill); fill = {}; break;
|
||||
case '<gradientFill>': break;
|
||||
case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
|
||||
|
||||
/* 18.8.32 patternFill CT_PatternFill */
|
||||
case '<patternFill': case '<patternFill>':
|
||||
@ -8757,6 +8767,18 @@ function get_sst_id(sst, str) {
|
||||
sst[len] = {t:str}; sst.Count ++; sst.Unique ++; return len;
|
||||
}
|
||||
|
||||
function col_obj_w(C, col) {
|
||||
var p = ({min:C+1,max:C+1});
|
||||
/* wch (chars), wpx (pixels) */
|
||||
var width = -1;
|
||||
if(col.MDW) MDW = col.MDW;
|
||||
if(col.width != null) p.customWidth = 1;
|
||||
else if(col.wpx != null) width = px2char(col.wpx);
|
||||
else if(col.wch != null) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth = 1; }
|
||||
return p;
|
||||
}
|
||||
|
||||
function get_cell_style(styles, cell, opts) {
|
||||
var z = opts.revssf[cell.z != null ? cell.z : "General"];
|
||||
for(var i = 0, len = styles.length; i != len; ++i) if(styles[i].numFmtId === z) return i;
|
||||
@ -8891,6 +8913,7 @@ function parse_ws_xml_hlinks(s, data, rels) {
|
||||
rel = {Target: val.location, TargetMode: 'Internal'};
|
||||
val.Rel = rel;
|
||||
}
|
||||
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
|
||||
var rng = safe_decode_range(val.ref);
|
||||
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
|
||||
var addr = encode_cell({c:C,r:R});
|
||||
@ -8916,15 +8939,7 @@ function write_ws_xml_cols(ws, cols) {
|
||||
var o = ["<cols>"], col, width;
|
||||
for(var i = 0; i != cols.length; ++i) {
|
||||
if(!(col = cols[i])) continue;
|
||||
var p = ({min:i+1,max:i+1});
|
||||
/* wch (chars), wpx (pixels) */
|
||||
width = -1;
|
||||
if(col.MDW) MDW = col.MDW;
|
||||
if(col.width);
|
||||
else if(col.wpx) width = px2char(col.wpx);
|
||||
else if(col.wch) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth= 1; }
|
||||
o[o.length] = (writextag('col', null, p));
|
||||
o[o.length] = (writextag('col', null, col_obj_w(i, col)));
|
||||
}
|
||||
o[o.length] = "</cols>";
|
||||
return o.join("");
|
||||
@ -9135,15 +9150,17 @@ function write_ws_xml(idx, opts, wb) {
|
||||
|
||||
if(ws['!cols'] !== undefined && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
|
||||
o[sidx = o.length] = '<sheetData/>';
|
||||
if(ws['!ref'] !== undefined) {
|
||||
if(ws['!ref'] != null) {
|
||||
rdata = write_ws_xml_data(ws, opts, idx, wb);
|
||||
if(rdata.length > 0) o[o.length] = (rdata);
|
||||
}
|
||||
if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
|
||||
|
||||
if(ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
|
||||
if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
|
||||
|
||||
delete ws['!links'];
|
||||
return o.join("");
|
||||
}
|
||||
|
||||
@ -9374,7 +9391,7 @@ function parse_BrtHLink(data, length, opts) {
|
||||
var tooltip = parse_XLWideString(data);
|
||||
var display = parse_XLWideString(data);
|
||||
data.l = end;
|
||||
return {rfx:rfx, relId:relId, loc:loc, tooltip:tooltip, display:display};
|
||||
return {rfx:rfx, relId:relId, loc:loc, Tooltip:tooltip, display:display};
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.6 BrtArrFmla */
|
||||
@ -9403,6 +9420,20 @@ function parse_BrtShrFmla(data, length, opts) {
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.323 BrtColInfo */
|
||||
/* TODO: once XLS ColInfo is set, combine the functions */
|
||||
function write_BrtColInfo(C, col, o) {
|
||||
if(o == null) o = new_buf(18);
|
||||
var p = col_obj_w(C, col);
|
||||
o.write_shift(-4, C);
|
||||
o.write_shift(-4, C);
|
||||
o.write_shift(4, p.width * 256);
|
||||
o.write_shift(4, 0/*ixfe*/); // style
|
||||
o.write_shift(1, 2); // bit flag
|
||||
o.write_shift(1, 0); // bit flag
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.61 Worksheet */
|
||||
function parse_ws_bin(data, opts, rels, wb, themes, styles) {
|
||||
if(!data) return data;
|
||||
@ -9669,9 +9700,15 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles) {
|
||||
/* TODO: something useful -- this is a stub */
|
||||
function write_ws_bin_cell(ba, cell, R, C, opts) {
|
||||
if(cell.v === undefined) return "";
|
||||
var vv = "";
|
||||
var vv = ""; var olddate = null;
|
||||
switch(cell.t) {
|
||||
case 'b': vv = cell.v ? "1" : "0"; break;
|
||||
case 'd': // no BrtCellDate :(
|
||||
cell.z = cell.z || SSF._table[14];
|
||||
olddate = cell.v;
|
||||
cell.v = datenum((cell.v)); cell.t = 'n';
|
||||
break;
|
||||
/* falls through */
|
||||
case 'n': case 'e': vv = ''+cell.v; break;
|
||||
default: vv = cell.v; break;
|
||||
}
|
||||
@ -9681,7 +9718,7 @@ function write_ws_bin_cell(ba, cell, R, C, opts) {
|
||||
switch(cell.t) {
|
||||
case 's': case 'str':
|
||||
if(opts.bookSST) {
|
||||
vv = get_sst_id(opts.Strings, cell.v);
|
||||
vv = get_sst_id(opts.Strings, (cell.v));
|
||||
o.t = "s"; o.v = vv;
|
||||
write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
|
||||
} else {
|
||||
@ -9693,6 +9730,7 @@ function write_ws_bin_cell(ba, cell, R, C, opts) {
|
||||
/* TODO: determine threshold for Real vs RK */
|
||||
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
|
||||
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
|
||||
if(olddate) { cell.t = 'd'; cell.v = olddate; }
|
||||
return;
|
||||
case 'b':
|
||||
o.t = "b";
|
||||
@ -9730,6 +9768,13 @@ function write_MERGECELLS(ba, ws) {
|
||||
write_record(ba, 'BrtEndMergeCells');
|
||||
}
|
||||
|
||||
function write_COLINFOS(ba, ws, idx, opts, wb) {
|
||||
if(!ws || !ws['!cols']) return;
|
||||
write_record(ba, 'BrtBeginColInfos');
|
||||
ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
|
||||
write_record(ba, 'BrtEndColInfos');
|
||||
}
|
||||
|
||||
function write_ws_bin(idx, opts, wb) {
|
||||
var ba = buf_array();
|
||||
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
|
||||
@ -9739,7 +9784,7 @@ function write_ws_bin(idx, opts, wb) {
|
||||
write_record(ba, "BrtWsDim", write_BrtWsDim(r));
|
||||
/* [WSVIEWS2] */
|
||||
/* [WSFMTINFO] */
|
||||
/* *COLINFOS */
|
||||
write_COLINFOS(ba, ws, idx, opts, wb);
|
||||
write_CELLTABLE(ba, ws, idx, opts, wb);
|
||||
/* [BrtSheetCalcProp] */
|
||||
/* [[BrtSheetProtectionIso] BrtSheetProtection] */
|
||||
@ -10617,8 +10662,8 @@ function parse_xlml_xml(d, opts) {
|
||||
if(comments.length > 0) cell.c = comments;
|
||||
if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) cursheet[encode_col(c) + encode_row(r)] = cell;
|
||||
if(cell.HRef) {
|
||||
cell.l = {Target:cell.HRef, tooltip:cell.HRefScreenTip};
|
||||
cell.HRef = cell.HRefScreenTip = undefined;
|
||||
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
|
||||
delete cell.HRef; delete cell.HRefScreenTip;
|
||||
}
|
||||
if(cell.MergeAcross || cell.MergeDown) {
|
||||
var cc = c + (parseInt(cell.MergeAcross,10)|0);
|
||||
@ -11203,6 +11248,11 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
|
||||
attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
|
||||
}
|
||||
|
||||
if(cell.l && cell.l.Target) {
|
||||
attr["ss:HRef"] = escapexml(cell.l.Target);
|
||||
if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
|
||||
}
|
||||
|
||||
if(ws['!merges']) {
|
||||
var marr = ws['!merges'];
|
||||
for(var mi = 0; mi != marr.length; ++mi) {
|
||||
@ -11238,6 +11288,10 @@ function write_ws_xlml_table(ws, opts, idx, wb) {
|
||||
var range = safe_decode_range(ws['!ref']);
|
||||
var marr = ws['!merges'] || [], mi = 0;
|
||||
var o = [];
|
||||
if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
|
||||
var p = col_obj_w(i, n);
|
||||
o.push(writextag("Column",null, {"ss:Index":i+1, "ss:Width":width2px(p.width)}));
|
||||
});
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = ['<Row ss:Index="' + (R+1) + '">'];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
@ -11721,7 +11775,7 @@ function parse_workbook(blob, options) {
|
||||
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
|
||||
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC)
|
||||
if(out[encode_cell({c:rngC,r:rngR})])
|
||||
out[encode_cell({c:rngC,r:rngR})].l.tooltip = val[1];
|
||||
out[encode_cell({c:rngC,r:rngR})].l.Tooltip = val[1];
|
||||
} break;
|
||||
|
||||
/* Comments */
|
||||
|
Loading…
Reference in New Issue
Block a user