2017-03-12 18:02:43 +00:00
|
|
|
function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
2017-02-03 20:50:45 +00:00
|
|
|
if(opts.bookType == "ods") return write_ods(wb, opts);
|
2022-03-14 06:51:33 +00:00
|
|
|
if(opts.bookType == "xlsb") return write_zip_xlsxb(wb, opts);
|
|
|
|
return write_zip_xlsx(wb, opts);
|
2022-02-14 01:28:13 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 06:51:33 +00:00
|
|
|
/* XLSX and XLSB writing are very similar. Originally they were unified in one
|
|
|
|
export function. This is horrible for tree shaking in the common case (most
|
|
|
|
applications need to export files in one format) so this function supports
|
|
|
|
both formats while write_zip_xlsx only handles XLSX */
|
2022-02-14 01:28:13 +00:00
|
|
|
function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|
|
|
_shapeid = 1024;
|
2014-05-22 12:16:51 +00:00
|
|
|
if(wb && !wb.SSF) {
|
2022-03-20 01:54:41 +00:00
|
|
|
wb.SSF = dup(table_fmt);
|
2014-05-22 12:16:51 +00:00
|
|
|
}
|
2014-05-16 00:33:34 +00:00
|
|
|
if(wb && wb.SSF) {
|
2022-03-20 01:54:41 +00:00
|
|
|
make_ssf(); SSF_load_table(wb.SSF);
|
2017-03-12 18:02:43 +00:00
|
|
|
// $FlowIgnore
|
2014-06-29 18:29:45 +00:00
|
|
|
opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
|
2017-05-09 18:07:57 +00:00
|
|
|
opts.ssf = wb.SSF;
|
2014-05-16 00:33:34 +00:00
|
|
|
}
|
|
|
|
opts.rels = {}; opts.wbrels = {};
|
2017-03-12 18:02:43 +00:00
|
|
|
opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0;
|
2018-06-22 21:40:01 +00:00
|
|
|
if(browser_has_Map) opts.revStrings = new Map();
|
|
|
|
else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
|
2014-05-16 00:33:34 +00:00
|
|
|
var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
|
2017-12-30 05:40:35 +00:00
|
|
|
var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
|
2017-07-27 20:07:51 +00:00
|
|
|
var ct = new_ct();
|
2014-05-16 00:33:34 +00:00
|
|
|
fix_write_opts(opts = opts || {});
|
2019-08-04 19:50:49 +00:00
|
|
|
var zip = zip_new();
|
2014-05-16 00:33:34 +00:00
|
|
|
var f = "", rId = 0;
|
|
|
|
|
|
|
|
opts.cellXfs = [];
|
2014-05-22 12:16:51 +00:00
|
|
|
get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
|
2014-05-16 00:33:34 +00:00
|
|
|
|
2017-02-10 19:23:01 +00:00
|
|
|
if(!wb.Props) wb.Props = {};
|
|
|
|
|
2014-05-16 00:33:34 +00:00
|
|
|
f = "docProps/core.xml";
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_core_props(wb.Props, opts));
|
2014-05-16 00:33:34 +00:00
|
|
|
ct.coreprops.push(f);
|
2014-05-22 12:16:51 +00:00
|
|
|
add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
|
2014-05-16 00:33:34 +00:00
|
|
|
|
2017-03-12 18:02:43 +00:00
|
|
|
/*::if(!wb.Props) throw "unreachable"; */
|
2014-05-16 00:33:34 +00:00
|
|
|
f = "docProps/app.xml";
|
2017-05-09 18:07:57 +00:00
|
|
|
if(wb.Props && wb.Props.SheetNames){/* empty */}
|
2017-04-03 00:16:03 +00:00
|
|
|
else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
|
2018-02-28 10:41:49 +00:00
|
|
|
else {
|
|
|
|
var _sn = [];
|
|
|
|
for(var _i = 0; _i < wb.SheetNames.length; ++_i)
|
|
|
|
if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
|
|
|
|
wb.Props.SheetNames = _sn;
|
|
|
|
}
|
2017-03-31 18:46:42 +00:00
|
|
|
wb.Props.Worksheets = wb.Props.SheetNames.length;
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_ext_props(wb.Props, opts));
|
2014-05-16 00:33:34 +00:00
|
|
|
ct.extprops.push(f);
|
2014-05-22 12:16:51 +00:00
|
|
|
add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
|
2014-05-16 00:33:34 +00:00
|
|
|
|
2014-05-29 22:30:03 +00:00
|
|
|
if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
|
2014-05-16 00:33:34 +00:00
|
|
|
f = "docProps/custom.xml";
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
|
2014-05-16 00:33:34 +00:00
|
|
|
ct.custprops.push(f);
|
2014-05-22 12:16:51 +00:00
|
|
|
add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
|
2014-05-16 00:33:34 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 18:29:45 +00:00
|
|
|
for(rId=1;rId <= wb.SheetNames.length; ++rId) {
|
2017-03-31 00:47:35 +00:00
|
|
|
var wsrels = {'!id':{}};
|
2017-04-02 06:47:25 +00:00
|
|
|
var ws = wb.Sheets[wb.SheetNames[rId-1]];
|
2017-04-08 06:55:35 +00:00
|
|
|
var _type = (ws || {})["!type"] || "sheet";
|
|
|
|
switch(_type) {
|
2019-11-15 01:46:49 +00:00
|
|
|
case "chart":
|
2017-04-08 06:55:35 +00:00
|
|
|
/* falls through */
|
|
|
|
default:
|
|
|
|
f = "xl/worksheets/sheet" + rId + "." + wbext;
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels));
|
2017-04-08 06:55:35 +00:00
|
|
|
ct.sheets.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
|
|
|
|
}
|
|
|
|
|
2017-04-02 06:47:25 +00:00
|
|
|
if(ws) {
|
|
|
|
var comments = ws['!comments'];
|
2019-04-01 14:25:15 +00:00
|
|
|
var need_vml = false;
|
2022-03-16 03:18:09 +00:00
|
|
|
var cf = "";
|
2017-04-02 06:47:25 +00:00
|
|
|
if(comments && comments.length > 0) {
|
2022-03-16 03:18:09 +00:00
|
|
|
cf = "xl/comments" + rId + "." + wbext;
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, cf, write_cmnt(comments, cf, opts));
|
2017-04-02 06:47:25 +00:00
|
|
|
ct.comments.push(cf);
|
|
|
|
add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
|
2019-04-01 14:25:15 +00:00
|
|
|
need_vml = true;
|
2017-04-02 06:47:25 +00:00
|
|
|
}
|
|
|
|
if(ws['!legacy']) {
|
2019-08-04 19:50:49 +00:00
|
|
|
if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
|
2017-04-02 06:47:25 +00:00
|
|
|
}
|
|
|
|
delete ws['!comments'];
|
|
|
|
delete ws['!legacy'];
|
|
|
|
}
|
|
|
|
|
2019-08-04 19:50:49 +00:00
|
|
|
if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
|
2014-06-29 18:29:45 +00:00
|
|
|
}
|
2014-05-16 00:33:34 +00:00
|
|
|
|
2014-06-29 18:29:45 +00:00
|
|
|
if(opts.Strings != null && opts.Strings.length > 0) {
|
2014-05-16 00:33:34 +00:00
|
|
|
f = "xl/sharedStrings." + wbext;
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_sst(opts.Strings, f, opts));
|
2014-05-16 00:33:34 +00:00
|
|
|
ct.strs.push(f);
|
2017-04-02 06:47:25 +00:00
|
|
|
add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
|
2014-05-16 00:33:34 +00:00
|
|
|
}
|
|
|
|
|
2018-06-22 21:40:01 +00:00
|
|
|
f = "xl/workbook." + wbext;
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_wb(wb, f, opts));
|
2018-06-22 21:40:01 +00:00
|
|
|
ct.workbooks.push(f);
|
|
|
|
add_rels(opts.rels, 1, f, RELS.WB);
|
|
|
|
|
2014-05-16 00:33:34 +00:00
|
|
|
/* TODO: something more intelligent with themes */
|
2014-05-16 00:50:55 +00:00
|
|
|
|
2014-05-22 12:16:51 +00:00
|
|
|
f = "xl/theme/theme1.xml";
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_theme(wb.Themes, opts));
|
2014-05-16 00:33:34 +00:00
|
|
|
ct.themes.push(f);
|
2017-04-02 06:47:25 +00:00
|
|
|
add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
|
2014-05-16 00:33:34 +00:00
|
|
|
|
|
|
|
/* TODO: something more intelligent with styles */
|
|
|
|
|
2014-05-29 22:30:03 +00:00
|
|
|
f = "xl/styles." + wbext;
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, write_sty(wb, f, opts));
|
2014-05-16 00:33:34 +00:00
|
|
|
ct.styles.push(f);
|
2017-04-02 06:47:25 +00:00
|
|
|
add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
|
2014-05-16 00:33:34 +00:00
|
|
|
|
2017-03-28 04:41:01 +00:00
|
|
|
if(wb.vbaraw && vbafmt) {
|
|
|
|
f = "xl/vbaProject.bin";
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, f, wb.vbaraw);
|
2017-03-28 04:41:01 +00:00
|
|
|
ct.vba.push(f);
|
2017-04-02 06:47:25 +00:00
|
|
|
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
2017-03-28 04:41:01 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 08:35:39 +00:00
|
|
|
f = "xl/metadata." + wbext;
|
|
|
|
zip_add_file(zip, f, write_xlmeta(f));
|
|
|
|
ct.metadata.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
|
|
|
|
2019-08-04 19:50:49 +00:00
|
|
|
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
|
|
|
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
|
|
|
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
2017-05-09 18:07:57 +00:00
|
|
|
|
|
|
|
delete opts.revssf; delete opts.ssf;
|
2014-05-16 00:33:34 +00:00
|
|
|
return zip;
|
|
|
|
}
|
2022-02-14 01:28:13 +00:00
|
|
|
|
|
|
|
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
|
|
|
_shapeid = 1024;
|
|
|
|
if(wb && !wb.SSF) {
|
2022-03-20 01:54:41 +00:00
|
|
|
wb.SSF = dup(table_fmt);
|
2022-02-14 01:28:13 +00:00
|
|
|
}
|
|
|
|
if(wb && wb.SSF) {
|
2022-03-20 01:54:41 +00:00
|
|
|
make_ssf(); SSF_load_table(wb.SSF);
|
2022-02-14 01:28:13 +00:00
|
|
|
// $FlowIgnore
|
|
|
|
opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
|
|
|
|
opts.ssf = wb.SSF;
|
|
|
|
}
|
|
|
|
opts.rels = {}; opts.wbrels = {};
|
|
|
|
opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0;
|
|
|
|
if(browser_has_Map) opts.revStrings = new Map();
|
|
|
|
else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
|
|
|
|
var wbext = "xml";
|
|
|
|
var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
|
|
|
|
var ct = new_ct();
|
|
|
|
fix_write_opts(opts = opts || {});
|
|
|
|
var zip = zip_new();
|
|
|
|
var f = "", rId = 0;
|
|
|
|
|
|
|
|
opts.cellXfs = [];
|
|
|
|
get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
|
|
|
|
|
|
|
|
if(!wb.Props) wb.Props = {};
|
|
|
|
|
|
|
|
f = "docProps/core.xml";
|
|
|
|
zip_add_file(zip, f, write_core_props(wb.Props, opts));
|
|
|
|
ct.coreprops.push(f);
|
|
|
|
add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
|
|
|
|
|
|
|
|
/*::if(!wb.Props) throw "unreachable"; */
|
|
|
|
f = "docProps/app.xml";
|
|
|
|
if(wb.Props && wb.Props.SheetNames){/* empty */}
|
|
|
|
else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
|
|
|
|
else {
|
|
|
|
var _sn = [];
|
|
|
|
for(var _i = 0; _i < wb.SheetNames.length; ++_i)
|
|
|
|
if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
|
|
|
|
wb.Props.SheetNames = _sn;
|
|
|
|
}
|
|
|
|
wb.Props.Worksheets = wb.Props.SheetNames.length;
|
|
|
|
zip_add_file(zip, f, write_ext_props(wb.Props, opts));
|
|
|
|
ct.extprops.push(f);
|
|
|
|
add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
|
|
|
|
|
|
|
|
if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
|
|
|
|
f = "docProps/custom.xml";
|
|
|
|
zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
|
|
|
|
ct.custprops.push(f);
|
|
|
|
add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
|
|
|
|
}
|
|
|
|
|
2022-03-14 06:51:33 +00:00
|
|
|
var people = ["SheetJ5"];
|
|
|
|
opts.tcid = 0;
|
|
|
|
|
2022-02-14 01:28:13 +00:00
|
|
|
for(rId=1;rId <= wb.SheetNames.length; ++rId) {
|
|
|
|
var wsrels = {'!id':{}};
|
|
|
|
var ws = wb.Sheets[wb.SheetNames[rId-1]];
|
|
|
|
var _type = (ws || {})["!type"] || "sheet";
|
|
|
|
switch(_type) {
|
|
|
|
case "chart":
|
|
|
|
/* falls through */
|
|
|
|
default:
|
|
|
|
f = "xl/worksheets/sheet" + rId + "." + wbext;
|
|
|
|
zip_add_file(zip, f, write_ws_xml(rId-1, opts, wb, wsrels));
|
|
|
|
ct.sheets.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ws) {
|
|
|
|
var comments = ws['!comments'];
|
|
|
|
var need_vml = false;
|
2022-03-16 03:18:09 +00:00
|
|
|
var cf = "";
|
2022-02-14 01:28:13 +00:00
|
|
|
if(comments && comments.length > 0) {
|
2022-03-14 06:51:33 +00:00
|
|
|
var needtc = false;
|
|
|
|
comments.forEach(function(carr) {
|
|
|
|
carr[1].forEach(function(c) { if(c.T == true) needtc = true; });
|
|
|
|
});
|
|
|
|
if(needtc) {
|
|
|
|
cf = "xl/threadedComments/threadedComment" + rId + "." + wbext;
|
|
|
|
zip_add_file(zip, cf, write_tcmnt_xml(comments, people, opts));
|
|
|
|
ct.threadedcomments.push(cf);
|
|
|
|
add_rels(wsrels, -1, "../threadedComments/threadedComment" + rId + "." + wbext, RELS.TCMNT);
|
|
|
|
}
|
|
|
|
|
2022-03-16 03:18:09 +00:00
|
|
|
cf = "xl/comments" + rId + "." + wbext;
|
2022-02-14 01:28:13 +00:00
|
|
|
zip_add_file(zip, cf, write_comments_xml(comments, opts));
|
|
|
|
ct.comments.push(cf);
|
|
|
|
add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
|
|
|
|
need_vml = true;
|
|
|
|
}
|
|
|
|
if(ws['!legacy']) {
|
|
|
|
if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
|
|
|
|
}
|
|
|
|
delete ws['!comments'];
|
|
|
|
delete ws['!legacy'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(opts.Strings != null && opts.Strings.length > 0) {
|
|
|
|
f = "xl/sharedStrings." + wbext;
|
|
|
|
zip_add_file(zip, f, write_sst_xml(opts.Strings, opts));
|
|
|
|
ct.strs.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
|
|
|
|
}
|
|
|
|
|
|
|
|
f = "xl/workbook." + wbext;
|
|
|
|
zip_add_file(zip, f, write_wb_xml(wb, opts));
|
|
|
|
ct.workbooks.push(f);
|
|
|
|
add_rels(opts.rels, 1, f, RELS.WB);
|
|
|
|
|
|
|
|
/* TODO: something more intelligent with themes */
|
|
|
|
|
|
|
|
f = "xl/theme/theme1.xml";
|
|
|
|
zip_add_file(zip, f, write_theme(wb.Themes, opts));
|
|
|
|
ct.themes.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
|
|
|
|
|
|
|
|
/* TODO: something more intelligent with styles */
|
|
|
|
|
|
|
|
f = "xl/styles." + wbext;
|
|
|
|
zip_add_file(zip, f, write_sty_xml(wb, opts));
|
|
|
|
ct.styles.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
|
|
|
|
|
|
|
|
if(wb.vbaraw && vbafmt) {
|
|
|
|
f = "xl/vbaProject.bin";
|
|
|
|
zip_add_file(zip, f, wb.vbaraw);
|
|
|
|
ct.vba.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
|
|
|
|
}
|
|
|
|
|
2022-03-03 08:35:39 +00:00
|
|
|
f = "xl/metadata." + wbext;
|
|
|
|
zip_add_file(zip, f, write_xlmeta_xml());
|
|
|
|
ct.metadata.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
|
|
|
|
2022-03-14 06:51:33 +00:00
|
|
|
if(people.length > 1) {
|
|
|
|
f = "xl/persons/person.xml";
|
|
|
|
zip_add_file(zip, f, write_people_xml(people, opts));
|
|
|
|
ct.people.push(f);
|
|
|
|
add_rels(opts.wbrels, -1, "persons/person.xml", RELS.PEOPLE);
|
|
|
|
}
|
|
|
|
|
2022-02-14 01:28:13 +00:00
|
|
|
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
|
|
|
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
|
|
|
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
|
|
|
|
|
|
|
delete opts.revssf; delete opts.ssf;
|
|
|
|
return zip;
|
|
|
|
}
|
|
|
|
|