diff --git a/bits/39_xlsbiff.js b/bits/39_xlsbiff.js
index 755b5de..683ae20 100644
--- a/bits/39_xlsbiff.js
+++ b/bits/39_xlsbiff.js
@@ -223,7 +223,7 @@ function write_WriteAccess(s/*:string*/, opts) {
/* [MS-XLS] 2.4.351 */
function parse_WsBool(blob, length, opts) {
var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
- return { fDialog: flags & 0x10 };
+ return { fDialog: flags & 0x10, fBelow: flags & 0x40, fRight: flags & 0x80 };
}
/* [MS-XLS] 2.4.28 */
diff --git a/bits/66_wscommon.js b/bits/66_wscommon.js
index d62e348..ce038f8 100644
--- a/bits/66_wscommon.js
+++ b/bits/66_wscommon.js
@@ -45,6 +45,7 @@ function col_obj_w(C/*:number*/, col) {
if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
else if(col.width != null) p.width = col.width;
if(col.hidden) p.hidden = true;
+ if(col.level != null) { p.outlineLevel = p.level = col.level; }
return p;
}
diff --git a/bits/67_wsxml.js b/bits/67_wsxml.js
index 46cbc55..1ff5ded 100644
--- a/bits/67_wsxml.js
+++ b/bits/67_wsxml.js
@@ -10,6 +10,7 @@ var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
+var sheetprregex2= /<(?:\w:)?sheetPr[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetPr)>/;
var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
/* 18.3 Worksheets */
@@ -32,6 +33,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
/* 18.3.1.82 sheetPr CT_SheetPr */
var sheetPr = data1.match(sheetprregex);
if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
+ else if((sheetPr = data1.match(sheetprregex2))) parse_ws_xml_sheetpr2(sheetPr[0], sheetPr[1]||"", s, wb, idx, styles, themes);
/* 18.3.1.35 dimension CT_SheetDimension */
var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
@@ -104,6 +106,9 @@ function parse_ws_xml_sheetpr(sheetPr/*:string*/, s, wb/*:WBWBProps*/, idx/*:num
if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
if(data.codeName) wb.Sheets[idx].CodeName = unescapexml(utf8read(data.codeName));
}
+function parse_ws_xml_sheetpr2(sheetPr/*:string*/, body/*:string*/, s, wb/*:WBWBProps*/, idx/*:number*/, styles, themes) {
+ parse_ws_xml_sheetpr(sheetPr.slice(0, sheetPr.indexOf(">")), s, wb, idx);
+}
function write_ws_xml_sheetpr(ws, wb, idx, opts, o) {
var needed = false;
var props = {}, payload = null;
@@ -191,6 +196,7 @@ function parse_ws_xml_cols(columns, cols) {
var coll = parsexmltag(cols[coli], true);
if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
+ if(coll.outlineLevel) coll.level = (+coll.outlineLevel || 0);
delete coll.min; delete coll.max; coll.width = +coll.width;
if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
process_col(coll);
@@ -280,6 +286,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
case 'e': o.t = "e"; break;
case 'z': break;
default: if(cell.v == null) { delete cell.t; break; }
+ if(cell.v.length > 32767) throw new Error("Text length must not exceed 32767 characters");
if(opts && opts.bookSST) {
v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
o.t = "s"; break;
diff --git a/bits/68_wsbin.js b/bits/68_wsbin.js
index 83c0c61..0adf921 100644
--- a/bits/68_wsbin.js
+++ b/bits/68_wsbin.js
@@ -79,14 +79,23 @@ function parse_BrtWsFmtInfo(/*::data, length*/) {
/* [MS-XLSB] 2.4.823 BrtWsProp */
function parse_BrtWsProp(data, length) {
var z = {};
+ var f = data[data.l]; ++data.l;
+ z.above = !(f & 0x40);
+ z.left = !(f & 0x80);
/* TODO: pull flags */
- data.l += 19;
+ data.l += 18;
z.name = parse_XLSBCodeName(data, length - 19);
return z;
}
-function write_BrtWsProp(str, o) {
+function write_BrtWsProp(str, outl, o) {
if(o == null) o = new_buf(84+4*str.length);
- for(var i = 0; i < 3; ++i) o.write_shift(1,0);
+ var f = 0xC0;
+ if(outl) {
+ if(outl.above) f &= ~0x40;
+ if(outl.left) f &= ~0x80;
+ }
+ o.write_shift(1, f);
+ for(var i = 1; i < 3; ++i) o.write_shift(1,0);
write_BrtColor({auto:1}, o);
o.write_shift(-4,-1);
o.write_shift(-4,-1);
@@ -660,6 +669,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
case 0x0093: /* 'BrtWsProp' */
if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
if(val.name) wb.Sheets[idx].CodeName = val.name;
+ if(val.above || val.left) s['!outline'] = { above: val.above, left: val.left };
break;
case 0x0089: /* 'BrtBeginWsView' */
@@ -956,7 +966,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
/* passed back to write_zip and removed there */
ws['!comments'] = [];
write_record(ba, "BrtBeginSheet");
- if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
+ if(wb.vbaraw || ws['!outline']) write_record(ba, "BrtWsProp", write_BrtWsProp(c, ws['!outline']));
write_record(ba, "BrtWsDim", write_BrtWsDim(r));
write_WSVIEWS2(ba, ws, wb.Workbook);
write_WSFMTINFO(ba, ws);
diff --git a/bits/75_xlml.js b/bits/75_xlml.js
index c2eee20..08aac77 100644
--- a/bits/75_xlml.js
+++ b/bits/75_xlml.js
@@ -618,6 +618,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
case 'unsynced' /*case 'Unsynced'*/: break;
case 'print' /*case 'Print'*/: break;
+ case 'printerrors' /*case 'PrintErrors'*/: break;
case 'panes' /*case 'Panes'*/: break;
case 'scale' /*case 'Scale'*/: break;
case 'pane' /*case 'Pane'*/: break;
@@ -657,11 +658,17 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
case 'allowformatcells' /*case 'AllowFormatCells'*/: break;
case 'allowsizecols' /*case 'AllowSizeCols'*/: break;
case 'allowsizerows' /*case 'AllowSizeRows'*/: break;
- case 'nosummaryrowsbelowdetail' /*case 'NoSummaryRowsBelowDetail'*/: break;
+ case 'nosummaryrowsbelowdetail' /*case 'NoSummaryRowsBelowDetail'*/:
+ if(!cursheet["!outline"]) cursheet["!outline"] = {};
+ cursheet["!outline"].above = true;
+ break;
case 'tabcolorindex' /*case 'TabColorIndex'*/: break;
case 'donotdisplayheadings' /*case 'DoNotDisplayHeadings'*/: break;
case 'showpagelayoutzoom' /*case 'ShowPageLayoutZoom'*/: break;
- case 'nosummarycolumnsrightdetail' /*case 'NoSummaryColumnsRightDetail'*/: break;
+ case 'nosummarycolumnsrightdetail' /*case 'NoSummaryColumnsRightDetail'*/:
+ if(!cursheet["!outline"]) cursheet["!outline"] = {};
+ cursheet["!outline"].left = true;
+ break;
case 'blackandwhite' /*case 'BlackAndWhite'*/: break;
case 'donotdisplayzeros' /*case 'DoNotDisplayZeros'*/: break;
case 'displaypagebreak' /*case 'DisplayPageBreak'*/: break;
diff --git a/bits/76_xls.js b/bits/76_xls.js
index 31937b4..fbbb938 100644
--- a/bits/76_xls.js
+++ b/bits/76_xls.js
@@ -272,6 +272,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
case 'WsBool':
if(val.fDialog) out["!type"] = "dialog";
+ if(!val.fBelow) (out["!outline"] || (out["!outline"] = {})).above = true;
+ if(!val.fRight) (out["!outline"] || (out["!outline"] = {})).left = true;
break; // TODO
case 'XF':
XFs.push(val); break;
diff --git a/docbits/10_install.md b/docbits/10_install.md
index a981bcf..ef0f6ac 100644
--- a/docbits/10_install.md
+++ b/docbits/10_install.md
@@ -13,7 +13,7 @@ In the browser, just add a script tag:
|-----------:|:-------------------------------------------|
| `unpkg` | |
| `jsDelivr` | |
-| `CDNjs` | |
+| `CDNjs` | |
| `packd` | |
`unpkg` makes the latest version available at:
diff --git a/docbits/62_colrow.md b/docbits/62_colrow.md
index 3aae32e..f366831 100644
--- a/docbits/62_colrow.md
+++ b/docbits/62_colrow.md
@@ -14,6 +14,7 @@ type ColInfo = {
wch?: number; // width in characters
/* other fields for preserving features from files */
+ level?: number; // 0-indexed outline / group level
MDW?: number; // Excel's "Max Digit Width" unit, always integral
};
```
diff --git a/types/index.d.ts b/types/index.d.ts
index a2174d2..ae0aa9c 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -340,6 +340,9 @@ export interface ColInfo {
/** width in "characters" */
wch?: number;
+ /** outline / group level */
+ level?: number;
+
/** Excel's "Max Digit Width" unit, always integral */
MDW?: number;
}