sheet visibility
- XLSB read V H VH + write V H VH - XLSX read V H VH + write V H VH - XLML read V H VH + write V H VH - XLS read V H VH - fixes #123 h/t @rla-dev @Mior - fixes #464 h/t @enobufs @thowk - fixes #498 h/t @digity - fixes #503 h/t @digity
This commit is contained in:
parent
233eae2f4e
commit
97f7c1d4bf
32
README.md
32
README.md
@ -44,6 +44,7 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6.
|
||||
+ [Formulae](#formulae)
|
||||
+ [Column Properties](#column-properties)
|
||||
+ [Hyperlinks](#hyperlinks)
|
||||
+ [Sheet Visibility](#sheet-visibility)
|
||||
- [Parsing Options](#parsing-options)
|
||||
* [Input Type](#input-type)
|
||||
* [Guessing File Type](#guessing-file-type)
|
||||
@ -714,6 +715,37 @@ 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.
|
||||
|
||||
#### Sheet Visibility
|
||||
|
||||
Excel enables hiding sheets in the lower tab bar. The sheet data is stored in
|
||||
the file but the UI does not readily make it available. Standard hidden sheets
|
||||
are revealed in the unhide menu. Excel also has "very hidden" sheets which
|
||||
cannot be revealed in the menu. It is only accessible in the VB Editor!
|
||||
|
||||
The visibility setting is stored in the `Hidden` property of the sheet props
|
||||
array. The values are:
|
||||
|
||||
| Value | Definition |
|
||||
|:-----:|:------------|
|
||||
| 0 | Visible |
|
||||
| 1 | Hidden |
|
||||
| 2 | Very Hidden |
|
||||
|
||||
With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>:
|
||||
|
||||
```js
|
||||
> wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] })
|
||||
[ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ]
|
||||
```
|
||||
|
||||
Non-Excel formats do not support the Very Hidden state. The best way to test
|
||||
if a sheet is visible is to check if the `Hidden` property is logical negation:
|
||||
|
||||
```js
|
||||
> wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] })
|
||||
[ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ]
|
||||
```
|
||||
|
||||
## Parsing Options
|
||||
|
||||
The exported `read` and `readFile` functions accept an options argument:
|
||||
|
@ -179,6 +179,7 @@ function prep_blob(blob, pos/*:number*/) {
|
||||
}
|
||||
|
||||
function parsenoop(blob, length/*:number*/) { blob.l += length; }
|
||||
function parsenooplog(blob, length/*:number*/) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; }
|
||||
|
||||
function writenoop(blob, length/*:number*/) { blob.l += length; }
|
||||
|
||||
|
@ -35,8 +35,8 @@ function parse_ext_props(data, p) {
|
||||
var v = parseVector(q.HeadingPairs);
|
||||
var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; });
|
||||
var idx = 0, len = 0;
|
||||
for(var i = 0; i !== v.length; ++i) {
|
||||
len = +(v[++i].v);
|
||||
for(var i = 0; i !== v.length; i+=2) {
|
||||
len = +(v[i+1].v);
|
||||
switch(v[i].v) {
|
||||
case "Worksheets":
|
||||
case "工作表":
|
||||
@ -69,6 +69,7 @@ function parse_ext_props(data, p) {
|
||||
idx += len;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -303,7 +303,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
|
||||
if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell);
|
||||
}
|
||||
if(r.length > 0) {
|
||||
var params = {r:rr}
|
||||
var params = ({r:rr}/*:any*/);
|
||||
if(rows && rows[R]) {
|
||||
var row = rows[R];
|
||||
if(row.hidden) params.hidden = 1;
|
||||
|
@ -37,7 +37,7 @@ var WBViewDef = [
|
||||
|
||||
/* 18.2.19 (CT_Sheet) Defaults */
|
||||
var SheetDef = [
|
||||
['state', 'visible']
|
||||
//['state', 'visible']
|
||||
];
|
||||
|
||||
/* 18.2.2 (CT_CalcPr) Defaults */
|
||||
|
@ -43,7 +43,15 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
|
||||
/* 18.2.20 sheets CT_Sheets 1 */
|
||||
case '<sheets>': case '</sheets>': break; // aggregate sheet
|
||||
/* 18.2.19 sheet CT_Sheet + */
|
||||
case '<sheet': delete y[0]; y.name = unescapexml(utf8read(y.name)); wb.Sheets.push(y); break;
|
||||
case '<sheet':
|
||||
switch(y.state) {
|
||||
case "hidden": y.Hidden = 1; break;
|
||||
case "veryHidden": y.Hidden = 2; break;
|
||||
default: y.Hidden = 0;
|
||||
}
|
||||
delete y.state;
|
||||
y.name = unescapexml(utf8read(y.name));
|
||||
delete y[0]; wb.Sheets.push(y); break;
|
||||
case '</sheet>': break;
|
||||
|
||||
/* 18.2.15 functionGroups CT_FunctionGroups ? */
|
||||
@ -153,8 +161,17 @@ function write_wb_xml(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:string*/ {
|
||||
o[o.length] = WB_XML_ROOT;
|
||||
o[o.length] = (writextag('workbookPr', null, {date1904:safe1904(wb), codeName:"ThisWorkbook"}));
|
||||
o[o.length] = "<sheets>";
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i)
|
||||
o[o.length] = (writextag('sheet',null,{name:escapexml(wb.SheetNames[i].substr(0,31)), sheetId:""+(i+1), "r:id":"rId"+(i+1)}));
|
||||
var sheets = wb.Workbook && wb.Workbook.Sheets || [];
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) {
|
||||
var sht = ({name:escapexml(wb.SheetNames[i].substr(0,31))}/*:any*/);
|
||||
sht.sheetId = ""+(i+1);
|
||||
sht["r:id"] = "rId"+(i+1);
|
||||
if(sheets[i]) switch(sheets[i].Hidden) {
|
||||
case 1: sht.state = "hidden"; break;
|
||||
case 2: sht.state = "veryHidden"; break;
|
||||
}
|
||||
o[o.length] = (writextag('sheet',null,sht));
|
||||
}
|
||||
o[o.length] = "</sheets>";
|
||||
if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* [MS-XLSB] 2.4.301 BrtBundleSh */
|
||||
function parse_BrtBundleSh(data, length/*:number*/) {
|
||||
var z = {};
|
||||
z.hsState = data.read_shift(4); //ST_SheetState
|
||||
z.Hidden = data.read_shift(4); //hsState ST_SheetState
|
||||
z.iTabID = data.read_shift(4);
|
||||
z.strRelID = parse_RelID(data,length-8);
|
||||
z.name = parse_XLWideString(data);
|
||||
@ -9,7 +9,7 @@ function parse_BrtBundleSh(data, length/*:number*/) {
|
||||
}
|
||||
function write_BrtBundleSh(data, o) {
|
||||
if(!o) o = new_buf(127);
|
||||
o.write_shift(4, data.hsState);
|
||||
o.write_shift(4, data.Hidden);
|
||||
o.write_shift(4, data.iTabID);
|
||||
write_RelID(data.strRelID, o);
|
||||
write_XLWideString(data.name.substr(0,31), o);
|
||||
@ -138,7 +138,8 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
|
||||
function write_BUNDLESHS(ba, wb, opts) {
|
||||
write_record(ba, "BrtBeginBundleShs");
|
||||
for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
|
||||
var d = { hsState: 0, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
|
||||
var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
|
||||
var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
|
||||
write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
|
||||
}
|
||||
write_record(ba, "BrtEndBundleShs");
|
||||
@ -156,9 +157,34 @@ function write_BrtFileVersion(data, o) {
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.298 BrtBookView */
|
||||
function write_BrtBookView(idx, o) {
|
||||
if(!o) o = new_buf(29);
|
||||
o.write_shift(-4, 0);
|
||||
o.write_shift(-4, 460);
|
||||
o.write_shift(4, 28800);
|
||||
o.write_shift(4, 17600);
|
||||
o.write_shift(4, 500);
|
||||
o.write_shift(4, idx);
|
||||
o.write_shift(4, idx);
|
||||
var flags = 0x78;
|
||||
o.write_shift(1, flags);
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.60 Workbook */
|
||||
function write_BOOKVIEWS(ba, wb, opts) {
|
||||
/* required if hidden tab appears before visible tab */
|
||||
if(!wb.Workbook || !wb.Workbook.Sheets) return;
|
||||
var sheets = wb.Workbook.Sheets;
|
||||
var i = 0, vistab = -1, hidden = -1;
|
||||
for(; i < sheets.length; ++i) {
|
||||
if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
|
||||
else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
|
||||
}
|
||||
if(hidden > vistab) return;
|
||||
write_record(ba, "BrtBeginBookViews");
|
||||
write_record(ba, "BrtBookView", write_BrtBookView(vistab));
|
||||
/* 1*(BrtBookView *FRT) */
|
||||
write_record(ba, "BrtEndBookViews");
|
||||
}
|
||||
@ -192,7 +218,7 @@ function write_wb_bin(wb, opts) {
|
||||
write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
/* [ACABSPATH] */
|
||||
/* [[BrtBookProtectionIso] BrtBookProtection] */
|
||||
/* write_BOOKVIEWS(ba, wb, opts); */
|
||||
write_BOOKVIEWS(ba, wb, opts);
|
||||
write_BUNDLESHS(ba, wb, opts);
|
||||
/* [FNGROUP] */
|
||||
/* [EXTERNALS] */
|
||||
|
@ -186,6 +186,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
var cstys = [], csty, seencol = false;
|
||||
var arrayf = [];
|
||||
var rowinfo = [];
|
||||
var Workbook = { Sheets:[] }, wsprops = {};
|
||||
xlmlregex.lastIndex = 0;
|
||||
str = str.replace(/<!--([^\u2603]*?)-->/mg,"");
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
@ -260,6 +261,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
mergecells = [];
|
||||
arrayf = [];
|
||||
rowinfo = [];
|
||||
wsprops = {name:sheetname, Hidden:0};
|
||||
Workbook.Sheets.push(wsprops);
|
||||
}
|
||||
break;
|
||||
case 'Table':
|
||||
@ -484,8 +487,15 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
|
||||
/* WorksheetOptions */
|
||||
case 'WorksheetOptions': switch(Rn[3]) {
|
||||
case 'Visible':
|
||||
if(Rn[0].slice(-2) === "/>"){}
|
||||
else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
|
||||
case "SheetHidden": wsprops.Hidden = 1; break;
|
||||
case "SheetVeryHidden": wsprops.Hidden = 2; break;
|
||||
}
|
||||
else pidx = Rn.index + Rn[0].length;
|
||||
break;
|
||||
case 'Unsynced': break;
|
||||
case 'Visible': break;
|
||||
case 'Print': break;
|
||||
case 'Panes': break;
|
||||
case 'Scale': break;
|
||||
@ -740,6 +750,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
var out = ({}/*:any*/);
|
||||
if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
|
||||
out.SheetNames = sheetnames;
|
||||
out.Workbook = Workbook;
|
||||
out.SSF = SSF.get_table();
|
||||
out.Props = Props;
|
||||
out.Custprops = Custprops;
|
||||
@ -776,6 +787,22 @@ function write_sty_xlml(wb, opts)/*:string*/ {
|
||||
/* Styles */
|
||||
return "";
|
||||
}
|
||||
/* WorksheetOptions */
|
||||
function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
|
||||
var o = [];
|
||||
/* PageSetup */
|
||||
if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
|
||||
/* Visible */
|
||||
if(!!wb.Workbook.Sheets[idx].Hidden) o.push("<Visible>" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "</Visible>");
|
||||
else {
|
||||
/* Selected */
|
||||
for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
|
||||
if(i == idx) o.push("<Selected/>");
|
||||
}
|
||||
}
|
||||
if(o.length == 0) return "";
|
||||
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
|
||||
}
|
||||
/* TODO */
|
||||
function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>";
|
||||
@ -861,7 +888,10 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
|
||||
/* Table */
|
||||
var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
|
||||
if(t.length > 0) o.push("<Table>" + t + "</Table>");
|
||||
|
||||
/* WorksheetOptions */
|
||||
o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
|
||||
|
||||
return o.join("");
|
||||
}
|
||||
function write_xlml(wb, opts)/*:string*/ {
|
||||
|
@ -98,6 +98,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
var cell_valid = true;
|
||||
var XFs = []; /* XF records */
|
||||
var palette = [];
|
||||
var Workbook = { Sheets:[] }, wsprops = {};
|
||||
var get_rgb = function getrgb(icv) {
|
||||
if(icv < 8) return XLSIcv[icv];
|
||||
if(icv < 64) return palette[icv-8] || XLSIcv[icv];
|
||||
@ -269,6 +270,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
if(objects.length > 0) out["!objects"] = objects;
|
||||
if(colinfo.length > 0) out["!cols"] = colinfo;
|
||||
if(rowinfo.length > 0) out["!rows"] = rowinfo;
|
||||
Workbook.Sheets.push(wsprops);
|
||||
}
|
||||
if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
|
||||
out = {};
|
||||
@ -285,6 +287,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
if(file_depth++) break;
|
||||
cell_valid = true;
|
||||
out = {};
|
||||
|
||||
if(opts.biff < 5) {
|
||||
if(cur_sheet === "") cur_sheet = "Sheet1";
|
||||
range = {s:{r:0,c:0},e:{r:0,c:0}};
|
||||
@ -301,6 +304,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
colinfo = []; rowinfo = [];
|
||||
defwidth = defheight = 0;
|
||||
seencol = false;
|
||||
wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
|
||||
} break;
|
||||
|
||||
case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
|
||||
@ -705,6 +709,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
if(opts.enc) wb.Encryption = opts.enc;
|
||||
wb.Metadata = {};
|
||||
if(country !== undefined) wb.Metadata.Country = country;
|
||||
wb.Workbook = Workbook;
|
||||
return wb;
|
||||
}
|
||||
|
||||
|
@ -114,14 +114,15 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
||||
var i=0;
|
||||
var sheetRels = ({}/*:any*/);
|
||||
var path, relsPath;
|
||||
if(!props.Worksheets) {
|
||||
|
||||
//if(!props.Worksheets) {
|
||||
var wbsheets = wb.Sheets;
|
||||
props.Worksheets = wbsheets.length;
|
||||
props.SheetNames = [];
|
||||
for(var j = 0; j != wbsheets.length; ++j) {
|
||||
props.SheetNames[j] = wbsheets[j].name;
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
var wbext = xlsb ? "bin" : "xml";
|
||||
var wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
|
@ -33,8 +33,10 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
|
||||
/*::if(!wb.Props) throw "unreachable"; */
|
||||
f = "docProps/app.xml";
|
||||
wb.Props.SheetNames = wb.SheetNames;
|
||||
wb.Props.Worksheets = wb.SheetNames.length;
|
||||
if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
|
||||
/*:: else if(!wb.Props) throw "unreachable"; */
|
||||
else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; });
|
||||
wb.Props.Worksheets = wb.Props.SheetNames.length;
|
||||
zip.file(f, write_ext_props(wb.Props, opts));
|
||||
ct.extprops.push(f);
|
||||
add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
|
||||
|
31
docbits/73_sheetprops.md
Normal file
31
docbits/73_sheetprops.md
Normal file
@ -0,0 +1,31 @@
|
||||
#### Sheet Visibility
|
||||
|
||||
Excel enables hiding sheets in the lower tab bar. The sheet data is stored in
|
||||
the file but the UI does not readily make it available. Standard hidden sheets
|
||||
are revealed in the unhide menu. Excel also has "very hidden" sheets which
|
||||
cannot be revealed in the menu. It is only accessible in the VB Editor!
|
||||
|
||||
The visibility setting is stored in the `Hidden` property of the sheet props
|
||||
array. The values are:
|
||||
|
||||
| Value | Definition |
|
||||
|:-----:|:------------|
|
||||
| 0 | Visible |
|
||||
| 1 | Hidden |
|
||||
| 2 | Very Hidden |
|
||||
|
||||
With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>:
|
||||
|
||||
```js
|
||||
> wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] })
|
||||
[ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ]
|
||||
```
|
||||
|
||||
Non-Excel formats do not support the Very Hidden state. The best way to test
|
||||
if a sheet is visible is to check if the `Hidden` property is logical negation:
|
||||
|
||||
```js
|
||||
> wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] })
|
||||
[ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ]
|
||||
```
|
||||
|
@ -24,6 +24,7 @@
|
||||
+ [Formulae](README.md#formulae)
|
||||
+ [Column Properties](README.md#column-properties)
|
||||
+ [Hyperlinks](README.md#hyperlinks)
|
||||
+ [Sheet Visibility](README.md#sheet-visibility)
|
||||
- [Parsing Options](README.md#parsing-options)
|
||||
* [Input Type](README.md#input-type)
|
||||
* [Guessing File Type](README.md#guessing-file-type)
|
||||
|
15
misc/flow.js
15
misc/flow.js
@ -17,10 +17,25 @@ type Workbook = {
|
||||
Custprops?: any;
|
||||
Themes?: any;
|
||||
|
||||
Workbook?: WBWBProps;
|
||||
|
||||
SSF?: {[n:number]:string};
|
||||
cfb?: any;
|
||||
};
|
||||
|
||||
type WorkbookProps = {
|
||||
SheetNames?: Array<string>;
|
||||
}
|
||||
|
||||
type WBWBProps = {
|
||||
Sheets: Array<WBWSProp>;
|
||||
};
|
||||
|
||||
type WBWSProp = {
|
||||
Hidden?: number;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface CellAddress {
|
||||
r:number;
|
||||
c:number;
|
||||
|
84
test.js
84
test.js
@ -73,6 +73,11 @@ var paths = {
|
||||
cwxml: dir + 'column_width.xml',
|
||||
cwxlsx: dir + 'column_width.xlsx',
|
||||
cwxlsb: dir + 'column_width.xlsx',
|
||||
svxls: dir + 'sheet_visibility.xls',
|
||||
svxls5: dir + 'sheet_visibility.xls',
|
||||
svxml: dir + 'sheet_visibility.xml',
|
||||
svxlsx: dir + 'sheet_visibility.xlsx',
|
||||
svxlsb: dir + 'sheet_visibility.xlsb',
|
||||
swcxls: dir + 'apachepoi_SimpleWithComments.xls',
|
||||
swcxml: dir + '2011/apachepoi_SimpleWithComments.xls.xml',
|
||||
swcxlsx: dir + 'apachepoi_SimpleWithComments.xlsx',
|
||||
@ -616,21 +621,54 @@ function hlink(wb) {
|
||||
|
||||
|
||||
describe('parse features', function() {
|
||||
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
|
||||
var X = require(modp);
|
||||
var sheet = 'Sheet1';
|
||||
var wb1=X.readFile(paths.swcxlsx);
|
||||
var wb2=X.readFile(paths.swcxlsb);
|
||||
var wb3=X.readFile(paths.swcxls);
|
||||
var wb4=X.readFile(paths.swcxml);
|
||||
describe('sheet visibility', function() {
|
||||
var wb1, wb2, wb3, wb4, wb5;
|
||||
var bef = (function() {
|
||||
wb1 = X.readFile(paths.svxls);
|
||||
wb2 = X.readFile(paths.svxls5);
|
||||
wb3 = X.readFile(paths.svxml);
|
||||
wb4 = X.readFile(paths.svxlsx);
|
||||
wb5 = X.readFile(paths.svxlsb);
|
||||
});
|
||||
if(typeof before != 'undefined') before(bef);
|
||||
else it('before', bef);
|
||||
|
||||
[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
|
||||
assert.equal(ws.B1.c.length, 1,"must have 1 comment");
|
||||
assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author");
|
||||
assert.equal(ws.B1.c[0].t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "Yegor Kozlov:\nfirst cell", "must have the concatenated texts");
|
||||
if(i > 0) return;
|
||||
assert.equal(ws.B1.c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation");
|
||||
assert.equal(ws.B1.c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation");
|
||||
it('should detect visible sheets', function() {
|
||||
[wb1, wb2, wb3, wb4, wb5].forEach(function(wb) {
|
||||
assert(!wb.Workbook.Sheets[0].Hidden);
|
||||
});
|
||||
});
|
||||
it('should detect all hidden sheets', function() {
|
||||
[wb1, wb2, wb3, wb4, wb5].forEach(function(wb) {
|
||||
assert(wb.Workbook.Sheets[1].Hidden);
|
||||
assert(wb.Workbook.Sheets[2].Hidden);
|
||||
});
|
||||
});
|
||||
it('should distinguish very hidden sheets', function() {
|
||||
[wb1, wb2, wb3, wb4, wb5].forEach(function(wb) {
|
||||
assert.equal(wb.Workbook.Sheets[1].Hidden,1);
|
||||
assert.equal(wb.Workbook.Sheets[2].Hidden,2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('comments', function() {
|
||||
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
|
||||
var X = require(modp);
|
||||
var sheet = 'Sheet1';
|
||||
var wb1=X.readFile(paths.swcxlsx);
|
||||
var wb2=X.readFile(paths.swcxlsb);
|
||||
var wb3=X.readFile(paths.swcxls);
|
||||
var wb4=X.readFile(paths.swcxml);
|
||||
|
||||
[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
|
||||
assert.equal(ws.B1.c.length, 1,"must have 1 comment");
|
||||
assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author");
|
||||
assert.equal(ws.B1.c[0].t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "Yegor Kozlov:\nfirst cell", "must have the concatenated texts");
|
||||
if(i > 0) return;
|
||||
assert.equal(ws.B1.c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation");
|
||||
assert.equal(ws.B1.c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1000,6 +1038,24 @@ describe('roundtrip features', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('should preserve sheet visibility', function() { [
|
||||
['xlml', paths.svxml],
|
||||
['xlsx', paths.svxlsx],
|
||||
['xlsb', paths.svxlsb]
|
||||
].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"});
|
||||
var wbs1 = wb1.Workbook.Sheets;
|
||||
var wbs2 = wb2.Workbook.Sheets;
|
||||
assert.equal(wbs1.length, wbs2.length);
|
||||
for(var i = 0; i < wbs1.length; ++i) {
|
||||
assert.equal(wbs1[i].name, wbs2[i].name);
|
||||
assert.equal(wbs1[i].Hidden, wbs2[i].Hidden);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function password_file(x){return x.match(/^password.*\.xls$/); }
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit cbafd3a184d0c668aaae1f9f8420ccaed74ad8e5
|
||||
Subproject commit 7926b8cd03370487edfa9476cad10b532ef22e99
|
19
tests.lst
19
tests.lst
@ -34,6 +34,7 @@ pivot_table_named_range.xlsb
|
||||
pivot_table_test.xlsb
|
||||
rich_text_stress.xlsb
|
||||
row_height.xlsb
|
||||
sheet_visibility.xlsb
|
||||
sized_boxen.xlsb
|
||||
smart_tags_2007.xlsb
|
||||
sushi.xlsb
|
||||
@ -199,7 +200,6 @@ apachepoi_DataTableCities.xlsx
|
||||
apachepoi_DataValidationEvaluations.xlsx
|
||||
apachepoi_DataValidations-49244.xlsx
|
||||
# apachepoi_DateFormatTests.xlsx # xlml
|
||||
apachepoi_DateFormatTests.xlsx.xlsx
|
||||
apachepoi_ElapsedFormatTests.xlsx
|
||||
apachepoi_ExcelTables.xlsx
|
||||
apachepoi_ForShifting.xlsx
|
||||
@ -288,6 +288,7 @@ apachepoi_workbookProtection_worksheet_protected.xlsx
|
||||
apachepoi_xlsx-jdbc.xlsx
|
||||
calendar_stress_test.xlsx.pending
|
||||
cell_style_simple.xlsx
|
||||
column_width.xlsx
|
||||
comments_stress_test.xlsx
|
||||
custom_properties.xlsx
|
||||
defined_names_simple.xlsx
|
||||
@ -407,6 +408,10 @@ roo_time-test.xlsx
|
||||
roo_whitespace.xlsx
|
||||
roo_x000D.xlsx
|
||||
roo_zero-padded-number.xlsx
|
||||
row_height.xlsx
|
||||
sheet_visibility.xlsx
|
||||
sheet_visibility_strict.xlsx
|
||||
sized_boxen.xlsx
|
||||
smart_tags_2007.xlsx
|
||||
spout-xlsx_attack_billion_laughs.xlsx
|
||||
spout-xlsx_attack_quadratic_blowup.xlsx
|
||||
@ -578,6 +583,7 @@ roo_time-test.ods
|
||||
roo_type_excel.ods
|
||||
roo_type_excelx.ods
|
||||
roo_whitespace.ods
|
||||
sheet_visibility.ods
|
||||
spout-ods_attack_billion_laughs.ods
|
||||
spout-ods_attack_quadratic_blowup.ods
|
||||
# spout-ods_file_corrupted.ods
|
||||
@ -1001,6 +1007,7 @@ apachepoi_xor-encryption-abc.xls.pending
|
||||
# apachepoi_yearfracExamples.xls # xlml
|
||||
calendar_stress_test.xls.pending
|
||||
cell_style_simple.xls
|
||||
column_width.xls
|
||||
comments_stress_test.xls
|
||||
custom_properties.xls
|
||||
defined_names_simple.xls
|
||||
@ -1233,6 +1240,10 @@ roo_time-test.xls
|
||||
roo_type_excelx.xls
|
||||
# roo_type_openoffice.xls # incorrect baseline
|
||||
roo_whitespace.xls
|
||||
row_height.xls
|
||||
sheet_visibility.xls
|
||||
sheet_visibility5.xls
|
||||
sized_boxen.xls
|
||||
smart_tags_2007.xls
|
||||
sushi.xls
|
||||
text_and_numbers.xls
|
||||
@ -1261,6 +1272,7 @@ RkNumber.xlsx.xml
|
||||
apachepoi_SampleSS.xml
|
||||
calendar_stress_test.xml.pending
|
||||
cell_style_simple.xml
|
||||
column_width.xml
|
||||
comments_stress_test.xls.xml
|
||||
comments_stress_test.xlsb.xml
|
||||
comments_stress_test.xlsx.xml
|
||||
@ -1327,12 +1339,15 @@ roo_formula_parse_error.xml
|
||||
# roo_numbers1.xml # SSF TODO
|
||||
roo_only_one_sheet.xml
|
||||
roo_paragraph.xml
|
||||
# roo_sheet1.xml
|
||||
# roo_simple_spreadsheet.xml # SSF TODO
|
||||
# roo_simple_spreadsheet_from_italo.xml # SSF TODO
|
||||
roo_style.xml
|
||||
# roo_time-test.xml # SSF TODO
|
||||
# roo_whitespace.xml # SSF TODO
|
||||
# roo_sheet1.xml
|
||||
row_height.xml
|
||||
sheet_visibility.xml
|
||||
sized_boxen.xml
|
||||
smart_tags_2007.xml
|
||||
sushi.xml
|
||||
text_and_numbers.xml
|
||||
|
@ -63,6 +63,11 @@ var paths = {
|
||||
cwxml: dir + 'column_width.xml',
|
||||
cwxlsx: dir + 'column_width.xlsx',
|
||||
cwxlsb: dir + 'column_width.xlsx',
|
||||
svxls: dir + 'sheet_visibility.xls',
|
||||
svxls5: dir + 'sheet_visibility.xls',
|
||||
svxml: dir + 'sheet_visibility.xml',
|
||||
svxlsx: dir + 'sheet_visibility.xlsx',
|
||||
svxlsb: dir + 'sheet_visibility.xlsb',
|
||||
swcxls: dir + 'apachepoi_SimpleWithComments.xls',
|
||||
swcxml: dir + '2011/apachepoi_SimpleWithComments.xls.xml',
|
||||
swcxlsx: dir + 'apachepoi_SimpleWithComments.xlsx',
|
||||
@ -458,21 +463,54 @@ function hlink(wb) {
|
||||
|
||||
|
||||
describe('parse features', function() {
|
||||
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
|
||||
var X = require(modp);
|
||||
var sheet = 'Sheet1';
|
||||
var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:"binary"});
|
||||
var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:"binary"});
|
||||
var wb3=X.read(fs.readFileSync(paths.swcxls), {type:"binary"});
|
||||
var wb4=X.read(fs.readFileSync(paths.swcxml), {type:"binary"});
|
||||
describe('sheet visibility', function() {
|
||||
var wb1, wb2, wb3, wb4, wb5;
|
||||
var bef = (function() {
|
||||
wb1 = X.read(fs.readFileSync(paths.svxls), {type:"binary"});
|
||||
wb2 = X.read(fs.readFileSync(paths.svxls5), {type:"binary"});
|
||||
wb3 = X.read(fs.readFileSync(paths.svxml), {type:"binary"});
|
||||
wb4 = X.read(fs.readFileSync(paths.svxlsx), {type:"binary"});
|
||||
wb5 = X.read(fs.readFileSync(paths.svxlsb), {type:"binary"});
|
||||
});
|
||||
if(typeof before != 'undefined') before(bef);
|
||||
else it('before', bef);
|
||||
|
||||
[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
|
||||
assert.equal(ws.B1.c.length, 1,"must have 1 comment");
|
||||
assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author");
|
||||
assert.equal(ws.B1.c[0].t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "Yegor Kozlov:\nfirst cell", "must have the concatenated texts");
|
||||
if(i > 0) return;
|
||||
assert.equal(ws.B1.c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation");
|
||||
assert.equal(ws.B1.c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation");
|
||||
it('should detect visible sheets', function() {
|
||||
[/*wb1, wb2, wb3, wb4,*/ wb5].forEach(function(wb) {
|
||||
assert(!wb.Workbook.Sheets[0].Hidden);
|
||||
});
|
||||
});
|
||||
it('should detect all hidden sheets', function() {
|
||||
[/*wb1, wb2, wb3, wb4,*/ wb5].forEach(function(wb) {
|
||||
assert(wb.Workbook.Sheets[1].Hidden);
|
||||
assert(wb.Workbook.Sheets[2].Hidden);
|
||||
});
|
||||
});
|
||||
it('should distinguish very hidden sheets', function() {
|
||||
[/*wb1, wb2, wb3, wb4,*/ wb5].forEach(function(wb) {
|
||||
assert.equal(wb.Workbook.Sheets[1].Hidden,1);
|
||||
assert.equal(wb.Workbook.Sheets[2].Hidden,2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('comments', function() {
|
||||
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
|
||||
var X = require(modp);
|
||||
var sheet = 'Sheet1';
|
||||
var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:"binary"});
|
||||
var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:"binary"});
|
||||
var wb3=X.read(fs.readFileSync(paths.swcxls), {type:"binary"});
|
||||
var wb4=X.read(fs.readFileSync(paths.swcxml), {type:"binary"});
|
||||
|
||||
[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
|
||||
assert.equal(ws.B1.c.length, 1,"must have 1 comment");
|
||||
assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author");
|
||||
assert.equal(ws.B1.c[0].t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "Yegor Kozlov:\nfirst cell", "must have the concatenated texts");
|
||||
if(i > 0) return;
|
||||
assert.equal(ws.B1.c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation");
|
||||
assert.equal(ws.B1.c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -841,6 +879,24 @@ describe('roundtrip features', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('should preserve sheet visibility', function() { [
|
||||
['xlml', paths.svxml],
|
||||
['xlsx', paths.svxlsx],
|
||||
['xlsb', paths.svxlsb]
|
||||
].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"});
|
||||
var wbs1 = wb1.Workbook.Sheets;
|
||||
var wbs2 = wb2.Workbook.Sheets;
|
||||
assert.equal(wbs1.length, wbs2.length);
|
||||
for(var i = 0; i < wbs1.length; ++i) {
|
||||
assert.equal(wbs1[i].name, wbs2[i].name);
|
||||
assert.equal(wbs1[i].Hidden, wbs2[i].Hidden);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function password_file(x){return x.match(/^password.*\.xls$/); }
|
||||
|
File diff suppressed because one or more lines are too long
@ -39,6 +39,11 @@
|
||||
./test_files/column_width.xml
|
||||
./test_files/column_width.xlsx
|
||||
./test_files/column_width.xlsx
|
||||
./test_files/sheet_visibility.xls
|
||||
./test_files/sheet_visibility.xls
|
||||
./test_files/sheet_visibility.xml
|
||||
./test_files/sheet_visibility.xlsx
|
||||
./test_files/sheet_visibility.xlsb
|
||||
./test_files/apachepoi_SimpleWithComments.xls
|
||||
./test_files/2011/apachepoi_SimpleWithComments.xls.xml
|
||||
./test_files/apachepoi_SimpleWithComments.xlsx
|
||||
|
@ -80,6 +80,13 @@ console.log("JSON Data: "); console.log(XLSX.utils.sheet_to_json(ws, {header:1})
|
||||
console.log("Worksheet Model:")
|
||||
console.log(ws);
|
||||
|
||||
/* TEST: hidden sheets */
|
||||
|
||||
wb.SheetNames.push("Hidden");
|
||||
wb.Sheets["Hidden"] = XLSX.utils.aoa_to_sheet(["Hidden".split(""), [1,2,3]]);
|
||||
wb.Workbook = {Sheets:[]};
|
||||
wb.Workbook.Sheets[1] = {Hidden:1};
|
||||
|
||||
/* write file */
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsx', {bookSST:true});
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsm');
|
||||
|
115
xlsx.flow.js
115
xlsx.flow.js
@ -1915,6 +1915,7 @@ function prep_blob(blob, pos/*:number*/) {
|
||||
}
|
||||
|
||||
function parsenoop(blob, length/*:number*/) { blob.l += length; }
|
||||
function parsenooplog(blob, length/*:number*/) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; }
|
||||
|
||||
function writenoop(blob, length/*:number*/) { blob.l += length; }
|
||||
|
||||
@ -3070,8 +3071,8 @@ function parse_ext_props(data, p) {
|
||||
var v = parseVector(q.HeadingPairs);
|
||||
var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; });
|
||||
var idx = 0, len = 0;
|
||||
for(var i = 0; i !== v.length; ++i) {
|
||||
len = +(v[++i].v);
|
||||
for(var i = 0; i !== v.length; i+=2) {
|
||||
len = +(v[i+1].v);
|
||||
switch(v[i].v) {
|
||||
case "Worksheets":
|
||||
case "工作表":
|
||||
@ -3104,6 +3105,7 @@ function parse_ext_props(data, p) {
|
||||
idx += len;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -9208,7 +9210,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
|
||||
if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell);
|
||||
}
|
||||
if(r.length > 0) {
|
||||
var params = {r:rr}
|
||||
var params = ({r:rr}/*:any*/);
|
||||
if(rows && rows[R]) {
|
||||
var row = rows[R];
|
||||
if(row.hidden) params.hidden = 1;
|
||||
@ -10086,7 +10088,7 @@ var WBViewDef = [
|
||||
|
||||
/* 18.2.19 (CT_Sheet) Defaults */
|
||||
var SheetDef = [
|
||||
['state', 'visible']
|
||||
//['state', 'visible']
|
||||
];
|
||||
|
||||
/* 18.2.2 (CT_CalcPr) Defaults */
|
||||
@ -10199,7 +10201,15 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
|
||||
/* 18.2.20 sheets CT_Sheets 1 */
|
||||
case '<sheets>': case '</sheets>': break; // aggregate sheet
|
||||
/* 18.2.19 sheet CT_Sheet + */
|
||||
case '<sheet': delete y[0]; y.name = unescapexml(utf8read(y.name)); wb.Sheets.push(y); break;
|
||||
case '<sheet':
|
||||
switch(y.state) {
|
||||
case "hidden": y.Hidden = 1; break;
|
||||
case "veryHidden": y.Hidden = 2; break;
|
||||
default: y.Hidden = 0;
|
||||
}
|
||||
delete y.state;
|
||||
y.name = unescapexml(utf8read(y.name));
|
||||
delete y[0]; wb.Sheets.push(y); break;
|
||||
case '</sheet>': break;
|
||||
|
||||
/* 18.2.15 functionGroups CT_FunctionGroups ? */
|
||||
@ -10309,8 +10319,17 @@ function write_wb_xml(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:string*/ {
|
||||
o[o.length] = WB_XML_ROOT;
|
||||
o[o.length] = (writextag('workbookPr', null, {date1904:safe1904(wb), codeName:"ThisWorkbook"}));
|
||||
o[o.length] = "<sheets>";
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i)
|
||||
o[o.length] = (writextag('sheet',null,{name:escapexml(wb.SheetNames[i].substr(0,31)), sheetId:""+(i+1), "r:id":"rId"+(i+1)}));
|
||||
var sheets = wb.Workbook && wb.Workbook.Sheets || [];
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) {
|
||||
var sht = ({name:escapexml(wb.SheetNames[i].substr(0,31))}/*:any*/);
|
||||
sht.sheetId = ""+(i+1);
|
||||
sht["r:id"] = "rId"+(i+1);
|
||||
if(sheets[i]) switch(sheets[i].Hidden) {
|
||||
case 1: sht.state = "hidden"; break;
|
||||
case 2: sht.state = "veryHidden"; break;
|
||||
}
|
||||
o[o.length] = (writextag('sheet',null,sht));
|
||||
}
|
||||
o[o.length] = "</sheets>";
|
||||
if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
@ -10318,7 +10337,7 @@ function write_wb_xml(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:string*/ {
|
||||
/* [MS-XLSB] 2.4.301 BrtBundleSh */
|
||||
function parse_BrtBundleSh(data, length/*:number*/) {
|
||||
var z = {};
|
||||
z.hsState = data.read_shift(4); //ST_SheetState
|
||||
z.Hidden = data.read_shift(4); //hsState ST_SheetState
|
||||
z.iTabID = data.read_shift(4);
|
||||
z.strRelID = parse_RelID(data,length-8);
|
||||
z.name = parse_XLWideString(data);
|
||||
@ -10326,7 +10345,7 @@ function parse_BrtBundleSh(data, length/*:number*/) {
|
||||
}
|
||||
function write_BrtBundleSh(data, o) {
|
||||
if(!o) o = new_buf(127);
|
||||
o.write_shift(4, data.hsState);
|
||||
o.write_shift(4, data.Hidden);
|
||||
o.write_shift(4, data.iTabID);
|
||||
write_RelID(data.strRelID, o);
|
||||
write_XLWideString(data.name.substr(0,31), o);
|
||||
@ -10455,7 +10474,8 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
|
||||
function write_BUNDLESHS(ba, wb, opts) {
|
||||
write_record(ba, "BrtBeginBundleShs");
|
||||
for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
|
||||
var d = { hsState: 0, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
|
||||
var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
|
||||
var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
|
||||
write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
|
||||
}
|
||||
write_record(ba, "BrtEndBundleShs");
|
||||
@ -10473,9 +10493,34 @@ function write_BrtFileVersion(data, o) {
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.298 BrtBookView */
|
||||
function write_BrtBookView(idx, o) {
|
||||
if(!o) o = new_buf(29);
|
||||
o.write_shift(-4, 0);
|
||||
o.write_shift(-4, 460);
|
||||
o.write_shift(4, 28800);
|
||||
o.write_shift(4, 17600);
|
||||
o.write_shift(4, 500);
|
||||
o.write_shift(4, idx);
|
||||
o.write_shift(4, idx);
|
||||
var flags = 0x78;
|
||||
o.write_shift(1, flags);
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.60 Workbook */
|
||||
function write_BOOKVIEWS(ba, wb, opts) {
|
||||
/* required if hidden tab appears before visible tab */
|
||||
if(!wb.Workbook || !wb.Workbook.Sheets) return;
|
||||
var sheets = wb.Workbook.Sheets;
|
||||
var i = 0, vistab = -1, hidden = -1;
|
||||
for(; i < sheets.length; ++i) {
|
||||
if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
|
||||
else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
|
||||
}
|
||||
if(hidden > vistab) return;
|
||||
write_record(ba, "BrtBeginBookViews");
|
||||
write_record(ba, "BrtBookView", write_BrtBookView(vistab));
|
||||
/* 1*(BrtBookView *FRT) */
|
||||
write_record(ba, "BrtEndBookViews");
|
||||
}
|
||||
@ -10509,7 +10554,7 @@ function write_wb_bin(wb, opts) {
|
||||
write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
/* [ACABSPATH] */
|
||||
/* [[BrtBookProtectionIso] BrtBookProtection] */
|
||||
/* write_BOOKVIEWS(ba, wb, opts); */
|
||||
write_BOOKVIEWS(ba, wb, opts);
|
||||
write_BUNDLESHS(ba, wb, opts);
|
||||
/* [FNGROUP] */
|
||||
/* [EXTERNALS] */
|
||||
@ -10790,6 +10835,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
var cstys = [], csty, seencol = false;
|
||||
var arrayf = [];
|
||||
var rowinfo = [];
|
||||
var Workbook = { Sheets:[] }, wsprops = {};
|
||||
xlmlregex.lastIndex = 0;
|
||||
str = str.replace(/<!--([^\u2603]*?)-->/mg,"");
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
@ -10864,6 +10910,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
mergecells = [];
|
||||
arrayf = [];
|
||||
rowinfo = [];
|
||||
wsprops = {name:sheetname, Hidden:0};
|
||||
Workbook.Sheets.push(wsprops);
|
||||
}
|
||||
break;
|
||||
case 'Table':
|
||||
@ -11088,8 +11136,15 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
|
||||
/* WorksheetOptions */
|
||||
case 'WorksheetOptions': switch(Rn[3]) {
|
||||
case 'Visible':
|
||||
if(Rn[0].slice(-2) === "/>"){}
|
||||
else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
|
||||
case "SheetHidden": wsprops.Hidden = 1; break;
|
||||
case "SheetVeryHidden": wsprops.Hidden = 2; break;
|
||||
}
|
||||
else pidx = Rn.index + Rn[0].length;
|
||||
break;
|
||||
case 'Unsynced': break;
|
||||
case 'Visible': break;
|
||||
case 'Print': break;
|
||||
case 'Panes': break;
|
||||
case 'Scale': break;
|
||||
@ -11344,6 +11399,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
|
||||
var out = ({}/*:any*/);
|
||||
if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
|
||||
out.SheetNames = sheetnames;
|
||||
out.Workbook = Workbook;
|
||||
out.SSF = SSF.get_table();
|
||||
out.Props = Props;
|
||||
out.Custprops = Custprops;
|
||||
@ -11380,6 +11436,22 @@ function write_sty_xlml(wb, opts)/*:string*/ {
|
||||
/* Styles */
|
||||
return "";
|
||||
}
|
||||
/* WorksheetOptions */
|
||||
function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
|
||||
var o = [];
|
||||
/* PageSetup */
|
||||
if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
|
||||
/* Visible */
|
||||
if(!!wb.Workbook.Sheets[idx].Hidden) o.push("<Visible>" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "</Visible>");
|
||||
else {
|
||||
/* Selected */
|
||||
for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
|
||||
if(i == idx) o.push("<Selected/>");
|
||||
}
|
||||
}
|
||||
if(o.length == 0) return "";
|
||||
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
|
||||
}
|
||||
/* TODO */
|
||||
function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
|
||||
if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>";
|
||||
@ -11465,7 +11537,10 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
|
||||
/* Table */
|
||||
var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
|
||||
if(t.length > 0) o.push("<Table>" + t + "</Table>");
|
||||
|
||||
/* WorksheetOptions */
|
||||
o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
|
||||
|
||||
return o.join("");
|
||||
}
|
||||
function write_xlml(wb, opts)/*:string*/ {
|
||||
@ -11584,6 +11659,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
var cell_valid = true;
|
||||
var XFs = []; /* XF records */
|
||||
var palette = [];
|
||||
var Workbook = { Sheets:[] }, wsprops = {};
|
||||
var get_rgb = function getrgb(icv) {
|
||||
if(icv < 8) return XLSIcv[icv];
|
||||
if(icv < 64) return palette[icv-8] || XLSIcv[icv];
|
||||
@ -11755,6 +11831,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
if(objects.length > 0) out["!objects"] = objects;
|
||||
if(colinfo.length > 0) out["!cols"] = colinfo;
|
||||
if(rowinfo.length > 0) out["!rows"] = rowinfo;
|
||||
Workbook.Sheets.push(wsprops);
|
||||
}
|
||||
if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
|
||||
out = {};
|
||||
@ -11771,6 +11848,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
if(file_depth++) break;
|
||||
cell_valid = true;
|
||||
out = {};
|
||||
|
||||
if(opts.biff < 5) {
|
||||
if(cur_sheet === "") cur_sheet = "Sheet1";
|
||||
range = {s:{r:0,c:0},e:{r:0,c:0}};
|
||||
@ -11787,6 +11865,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
colinfo = []; rowinfo = [];
|
||||
defwidth = defheight = 0;
|
||||
seencol = false;
|
||||
wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
|
||||
} break;
|
||||
|
||||
case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
|
||||
@ -12191,6 +12270,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
if(opts.enc) wb.Encryption = opts.enc;
|
||||
wb.Metadata = {};
|
||||
if(country !== undefined) wb.Metadata.Country = country;
|
||||
wb.Workbook = Workbook;
|
||||
return wb;
|
||||
}
|
||||
|
||||
@ -14340,14 +14420,15 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
||||
var i=0;
|
||||
var sheetRels = ({}/*:any*/);
|
||||
var path, relsPath;
|
||||
if(!props.Worksheets) {
|
||||
|
||||
//if(!props.Worksheets) {
|
||||
var wbsheets = wb.Sheets;
|
||||
props.Worksheets = wbsheets.length;
|
||||
props.SheetNames = [];
|
||||
for(var j = 0; j != wbsheets.length; ++j) {
|
||||
props.SheetNames[j] = wbsheets[j].name;
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
var wbext = xlsb ? "bin" : "xml";
|
||||
var wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
|
||||
@ -14428,8 +14509,10 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
|
||||
/*::if(!wb.Props) throw "unreachable"; */
|
||||
f = "docProps/app.xml";
|
||||
wb.Props.SheetNames = wb.SheetNames;
|
||||
wb.Props.Worksheets = wb.SheetNames.length;
|
||||
if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
|
||||
// $FlowIgnore
|
||||
else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; });
|
||||
wb.Props.Worksheets = wb.Props.SheetNames.length;
|
||||
zip.file(f, write_ext_props(wb.Props, opts));
|
||||
ct.extprops.push(f);
|
||||
add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
|
||||
|
115
xlsx.js
115
xlsx.js
@ -1864,6 +1864,7 @@ function prep_blob(blob, pos) {
|
||||
}
|
||||
|
||||
function parsenoop(blob, length) { blob.l += length; }
|
||||
function parsenooplog(blob, length) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; }
|
||||
|
||||
function writenoop(blob, length) { blob.l += length; }
|
||||
|
||||
@ -3018,8 +3019,8 @@ function parse_ext_props(data, p) {
|
||||
var v = parseVector(q.HeadingPairs);
|
||||
var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; });
|
||||
var idx = 0, len = 0;
|
||||
for(var i = 0; i !== v.length; ++i) {
|
||||
len = +(v[++i].v);
|
||||
for(var i = 0; i !== v.length; i+=2) {
|
||||
len = +(v[i+1].v);
|
||||
switch(v[i].v) {
|
||||
case "Worksheets":
|
||||
case "工作表":
|
||||
@ -3052,6 +3053,7 @@ function parse_ext_props(data, p) {
|
||||
idx += len;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -9153,7 +9155,7 @@ function write_ws_xml_data(ws, opts, idx, wb, rels) {
|
||||
if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) |