diff --git a/README.md b/README.md
index ba7c48d..18ee067 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,8 @@ enhancements and additional features by request.
[**Commercial Support**](http://sheetjs.com/support)
+[**Rendered Documentation**](https://sheetjs.gitbooks.io/docs/)
+
[**In-Browser Demos**](http://sheetjs.com/demos)
[**Source Code**](http://git.io/xlsx)
@@ -634,8 +636,9 @@ In addition to the base sheet keys, worksheets also add:
the first cell (upper-left) in the range is set.
- `ws['protect']`: object of write sheet protection properties. The `password`
- key specifies the password. The writer uses the XOR obfuscation method. The
- following keys control the sheet protection (same as ECMA-376 18.3.1.85):
+ key specifies the password for formats that support password-protected sheets
+ (XLSX/XLSB/XLS). The writer uses the XOR obfuscation method. The following
+ keys control the sheet protection (same as ECMA-376 18.3.1.85):
| key | functionality disabled if value is true |
|:----------------------|:-----------------------------------------------------|
@@ -659,7 +662,7 @@ In addition to the base sheet keys, worksheets also add:
```typescript
type AutoFilter = {
- ref:string; // A-1 based range representing the AutoFilter table range
+ ref:string; // A-1 based range representing the AutoFilter table range
}
```
diff --git a/bits/36_xlsprops.js b/bits/36_xlsprops.js
index 617acf8..02a491d 100644
--- a/bits/36_xlsprops.js
+++ b/bits/36_xlsprops.js
@@ -1,25 +1,35 @@
/* Common Name -> XLML Name */
var XLMLDocPropsMap = {
- Category: 'Category',
- ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
- Keywords: 'Keywords',
- LastAuthor: 'LastAuthor',
- LastPrinted: 'LastPrinted',
- RevNumber: 'Revision',
- Author: 'Author',
- Comments: 'Description',
- Identifier: 'Identifier', /* NOTE: missing from schema */
- Language: 'Language', /* NOTE: missing from schema */
- Subject: 'Subject',
Title: 'Title',
+ Subject: 'Subject',
+ Author: 'Author',
+ Keywords: 'Keywords',
+ Comments: 'Description',
+ LastAuthor: 'LastAuthor',
+ RevNumber: 'Revision',
+ Application: 'AppName',
+ /* TotalTime: 'TotalTime', */
+ LastPrinted: 'LastPrinted',
CreatedDate: 'Created',
ModifiedDate: 'LastSaved',
-
- Application: 'AppName',
- AppVersion: 'Version',
- TotalTime: 'TotalTime',
+ /* Pages */
+ /* Words */
+ /* Characters */
+ Category: 'Category',
+ /* PresentationFormat */
Manager: 'Manager',
- Company: 'Company'
+ Company: 'Company',
+ /* Guid */
+ /* HyperlinkBase */
+ /* Bytes */
+ /* Lines */
+ /* Paragraphs */
+ /* CharactersWithSpaces */
+ AppVersion: 'Version',
+
+ ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
+ Identifier: 'Identifier', /* NOTE: missing from schema */
+ Language: 'Language' /* NOTE: missing from schema */
};
var evert_XLMLDPM = evert(XLMLDocPropsMap);
@@ -28,19 +38,21 @@ function xlml_set_prop(Props, tag/*:string*/, val) {
Props[tag] = val;
}
-
-/* TODO: verify */
function xlml_write_docprops(Props, opts) {
var o = [];
- CORE_PROPS.concat(EXT_PROPS).forEach(function(p) {
+ keys(XLMLDocPropsMap).map(function(m) {
+ for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
+ for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
+ throw m;
+ }).forEach(function(p) {
if(Props[p[1]] == null) return;
var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
switch(p[2]) {
- case 'date': m = new Date(m).toISOString(); break;
+ case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
}
if(typeof m == 'number') m = String(m);
else if(m === true || m === false) { m = m ? "1" : "0"; }
- else if(m instanceof Date) m = new Date(m).toISOString();
+ else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
});
return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
diff --git a/bits/67_wsxml.js b/bits/67_wsxml.js
index 01d4f5a..9038e83 100644
--- a/bits/67_wsxml.js
+++ b/bits/67_wsxml.js
@@ -244,8 +244,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
/* 18.3.1.73 row CT_Row */
for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
tag = parsexmltag(x.substr(0,ri), true);
- /* SpreadSheetGear uses implicit r/c */
- tagr = typeof tag.r !== 'undefined' ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
+ tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
if(opts.sheetRows && opts.sheetRows < tagr) continue;
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
@@ -297,7 +296,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
p.F = arrayf[i][1];
}
- if(tag.t === undefined && p.v === undefined) {
+ if(tag.t == null && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "z";
}
@@ -335,7 +334,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
break;
/* error string in .w, number in .v */
case 'e':
- if(opts && opts.cellText === false) p.w = p.v;
+ if(!opts || opts.cellText !== false) p.w = p.v;
p.v = RBErr[p.v]; break;
}
/* formatting */
diff --git a/bits/68_wsbin.js b/bits/68_wsbin.js
index b073512..3b30a40 100644
--- a/bits/68_wsbin.js
+++ b/bits/68_wsbin.js
@@ -400,7 +400,7 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ {
case 'n': p.v = val[1]; break;
case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
case 'b': p.v = val[1] ? true : false; break;
- case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
+ case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts, themes, styles);
diff --git a/bits/75_xlml.js b/bits/75_xlml.js
index 2bec86a..9e90060 100644
--- a/bits/75_xlml.js
+++ b/bits/75_xlml.js
@@ -121,11 +121,11 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a
if(cell.v === undefined) cell.v=+xml;
if(!cell.t) cell.t = 'n';
break;
- case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; cell.w = xml; break;
+ case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
}
safe_format_xlml(cell, nf, o);
- if(o.cellFormula != null) {
+ if(o.cellFormula !== false) {
if(cell.Formula) {
var fstr = unescapexml(cell.Formula);
/* strictly speaking, the leading = is required but some writers omit */
@@ -837,17 +837,107 @@ function write_sty_xlml(wb, opts)/*:string*/ {
}
/* WorksheetOptions */
function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
+ if(!ws) return "";
var o = [];
+ /* NOTE: spec technically allows any order, but stick with implied order */
+
+ /* FitToPage */
+ /* DoNotDisplayColHeaders */
+ /* DoNotDisplayRowHeaders */
+ /* ViewableRange */
+ /* Selection */
+ /* GridlineColor */
+ /* Name */
+ /* ExcelWorksheetType */
+ /* IntlMacro */
+ /* Unsynced */
+ /* Selected */
+ /* CodeName */
+
+ if(ws['!margins']) {
+ o.push("");
+ if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
+ if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
+ o.push(writextag("PageMargins", null, {
+ 'x:Bottom': ws['!margins'].bottom || "0.75",
+ 'x:Left': ws['!margins'].left || "0.7",
+ 'x:Right': ws['!margins'].right || "0.7",
+ 'x:Top': ws['!margins'].top || "0.75"
+ }));
+ o.push("");
+ }
+
/* PageSetup */
+ /* DisplayPageBreak */
+ /* TransitionExpressionEvaluation */
+ /* TransitionFormulaEntry */
+ /* Print */
+ /* Zoom */
+ /* PageLayoutZoom */
+ /* PageBreakZoom */
+ /* ShowPageBreakZoom */
+ /* DefaultRowHeight */
+ /* DefaultColumnWidth */
+ /* StandardWidth */
+
if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
/* Visible */
- if(!!wb.Workbook.Sheets[idx].Hidden) o.push("" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "");
+ if(!!wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
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("");
}
}
+
+ /* LeftColumnVisible */
+ /* DisplayRightToLeft */
+ /* GridlineColorIndex */
+ /* DisplayFormulas */
+ /* DoNotDisplayGridlines */
+ /* DoNotDisplayHeadings */
+ /* DoNotDisplayOutline */
+ /* ApplyAutomaticOutlineStyles */
+ /* NoSummaryRowsBelowDetail */
+ /* NoSummaryColumnsRightDetail */
+ /* DoNotDisplayZeros */
+ /* ActiveRow */
+ /* ActiveColumn */
+ /* FilterOn */
+ /* RangeSelection */
+ /* TopRowVisible */
+ /* TopRowBottomPane */
+ /* LeftColumnRightPane */
+ /* ActivePane */
+ /* SplitHorizontal */
+ /* SplitVertical */
+ /* FreezePanes */
+ /* FrozenNoSplit */
+ /* TabColorIndex */
+ /* Panes */
+
+ /* NOTE: Password not supported in XLML Format */
+ if(ws['!protect']) {
+ o.push(writetag("ProtectContents", "True"));
+ if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
+ if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
+ if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
+ else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
+ [
+ [ "formatColumns", "AllowFormatCells" ],
+ [ "formatRows", "AllowSizeCols" ],
+ [ "formatCells", "AllowSizeRows" ],
+ [ "insertColumns", "AllowInsertCols" ],
+ [ "insertRows", "AllowInsertRows" ],
+ [ "insertHyperlinks", "AllowInsertHyperlinks" ],
+ [ "deleteColumns", "AllowDeleteCols" ],
+ [ "deleteRows", "AllowDeleteRows" ],
+ [ "sort", "AllowSort" ],
+ [ "autoFilter", "AllowFilter" ],
+ [ "pivotTables", "AllowUsePivotTables" ]
+ ].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
+ }
+
if(o.length == 0) return "";
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
}
diff --git a/bits/76_xls.js b/bits/76_xls.js
index 539c850..a8318a0 100644
--- a/bits/76_xls.js
+++ b/bits/76_xls.js
@@ -54,12 +54,13 @@ function slurp(R, blob, length/*:number*/, opts) {
function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
if(p.t === 'z') return;
- if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
if(!p.XF) return;
try {
var fmtid = p.XF.ifmt||0;
if(opts.cellNF) p.z = SSF._table[fmtid];
- if(p.t === 'e'){}
+ } catch(e) { if(opts.WTF) throw e; }
+ if(!opts || opts.cellText !== false) try {
+ if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
diff --git a/bits/80_parseods.js b/bits/80_parseods.js
index 3f52438..9b38b18 100644
--- a/bits/80_parseods.js
+++ b/bits/80_parseods.js
@@ -135,7 +135,7 @@ var parse_content_xml = (function() {
isstub = textpidx == 0;
}
if(comments.length > 0) { q.c = comments; comments = []; }
- if(textp) q.w = textp;
+ if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
if(opts.dense) {
diff --git a/book.json b/book.json
index f1e3a11..dd01ccb 100644
--- a/book.json
+++ b/book.json
@@ -3,7 +3,7 @@
"title": "SheetJS js-xlsx",
"author": "sheetjs",
"gitbook": "3.2.2",
- "plugins": ["anchorjs", "ga", "sidebar-ad", "-sharing", "advanced-emoji"],
+ "plugins": ["anchorjs", "ga", "sidebar-ad", "-sharing", "-search", "advanced-emoji"],
"pluginsConfig": {
"anchorjs": {
"icon": "#",
diff --git a/docbits/00_intro.md b/docbits/00_intro.md
index eab25b2..511a855 100644
--- a/docbits/00_intro.md
+++ b/docbits/00_intro.md
@@ -12,6 +12,8 @@ enhancements and additional features by request.
[**Commercial Support**](http://sheetjs.com/support)
+[**Rendered Documentation**](https://sheetjs.gitbooks.io/docs/)
+
[**In-Browser Demos**](http://sheetjs.com/demos)
[**Source Code**](http://git.io/xlsx)
diff --git a/docbits/54_shobject.md b/docbits/54_shobject.md
index a860e10..4f82199 100644
--- a/docbits/54_shobject.md
+++ b/docbits/54_shobject.md
@@ -14,8 +14,9 @@ In addition to the base sheet keys, worksheets also add:
the first cell (upper-left) in the range is set.
- `ws['protect']`: object of write sheet protection properties. The `password`
- key specifies the password. The writer uses the XOR obfuscation method. The
- following keys control the sheet protection (same as ECMA-376 18.3.1.85):
+ key specifies the password for formats that support password-protected sheets
+ (XLSX/XLSB/XLS). The writer uses the XOR obfuscation method. The following
+ keys control the sheet protection (same as ECMA-376 18.3.1.85):
| key | functionality disabled if value is true |
|:----------------------|:-----------------------------------------------------|
@@ -39,7 +40,7 @@ In addition to the base sheet keys, worksheets also add:
```typescript
type AutoFilter = {
- ref:string; // A-1 based range representing the AutoFilter table range
+ ref:string; // A-1 based range representing the AutoFilter table range
}
```
diff --git a/test.js b/test.js
index f0f7d37..4883ba5 100644
--- a/test.js
+++ b/test.js
@@ -284,6 +284,7 @@ describe('parse options', function() {
if(typeof before != 'undefined') before(bef);
else it('before', bef);
describe('cell', function() {
+ var FSTPaths = [paths.fstxls, paths.fstxml, paths.fstxlsx, paths.fstxlsb, paths.fstods];
it('XLSX should generate HTML by default', function() {
var wb = X.readFile(paths.cstxlsx);
var ws = wb.Sheets.Sheet1;
@@ -299,7 +300,7 @@ describe('parse options', function() {
});
});
it('should generate formulae by default', function() {
- [paths.fstxls, paths.fstxlsb].forEach(function(p) {
+ FSTPaths.forEach(function(p) {
var wb = X.readFile(p);
var found = false;
wb.SheetNames.forEach(function(s) {
@@ -312,7 +313,7 @@ describe('parse options', function() {
});
});
it('should not generate formulae when requested', function() {
- [paths.fstxls, paths.fstxlsb].forEach(function(p) {
+ FSTPaths.forEach(function(p) {
var wb =X.readFile(p,{cellFormula:false});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
@@ -322,6 +323,30 @@ describe('parse options', function() {
});
});
});
+ it('should generate formatted text by default', function() {
+ FSTPaths.forEach(function(p) {
+ var wb = X.readFile(p);
+ var found = false;
+ wb.SheetNames.forEach(function(s) {
+ var ws = wb.Sheets[s];
+ each_cell(ws, function(cell) {
+ if(typeof cell.w !== 'undefined') return (found = true);
+ });
+ });
+ assert(found);
+ });
+ });
+ it('should not generate formatted text when requested', function() {
+ FSTPaths.forEach(function(p) {
+ var wb =X.readFile(p,{cellText:false});
+ wb.SheetNames.forEach(function(s) {
+ var ws = wb.Sheets[s];
+ each_cell(ws, function(cell) {
+ assert(typeof cell.w === 'undefined');
+ });
+ });
+ });
+ });
it('should not generate number formats by default', function() {
[paths.nfxls, paths.nfxlsx, paths.nfxlsb].forEach(function(p) {
var wb = X.readFile(p);
@@ -1218,7 +1243,7 @@ describe('roundtrip features', function() {
if(m[0].t === 'n' && m[1].t === 'n') assert.equal(m[0].v, m[1].v);
else if(m[0].t === 'd' && m[1].t === 'd') assert.equal(m[0].v.toString(), m[1].v.toString());
- else if(m[1].t === 'n') assert(Math.abs(datenum(new Date(m[0].v)) - m[1].v) < 0.01); /* TODO: 1sec adjustment */
+ else if(m[1].t === 'n') assert(Math.abs(datenum(new Date(m[0].v)) - m[1].v) < 0.01);
});
});
});
@@ -1253,7 +1278,7 @@ describe('roundtrip features', function() {
});
(fs.existsSync(paths.pmxlsx) ? describe : describe.skip)('should preserve page margins', function() {[
- //['xlml', paths.pmxml],
+ ['xlml', paths.pmxml],
['xlsx', paths.pmxlsx],
['xlsb', paths.pmxlsb]
].forEach(function(w) { it(w[0], function() {
diff --git a/xlsx.flow.js b/xlsx.flow.js
index 785100f..e4e47d9 100644
--- a/xlsx.flow.js
+++ b/xlsx.flow.js
@@ -3330,26 +3330,36 @@ function write_cust_props(cp, opts)/*:string*/ {
}
/* Common Name -> XLML Name */
var XLMLDocPropsMap = {
- Category: 'Category',
- ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
- Keywords: 'Keywords',
- LastAuthor: 'LastAuthor',
- LastPrinted: 'LastPrinted',
- RevNumber: 'Revision',
- Author: 'Author',
- Comments: 'Description',
- Identifier: 'Identifier', /* NOTE: missing from schema */
- Language: 'Language', /* NOTE: missing from schema */
- Subject: 'Subject',
Title: 'Title',
+ Subject: 'Subject',
+ Author: 'Author',
+ Keywords: 'Keywords',
+ Comments: 'Description',
+ LastAuthor: 'LastAuthor',
+ RevNumber: 'Revision',
+ Application: 'AppName',
+ /* TotalTime: 'TotalTime', */
+ LastPrinted: 'LastPrinted',
CreatedDate: 'Created',
ModifiedDate: 'LastSaved',
-
- Application: 'AppName',
- AppVersion: 'Version',
- TotalTime: 'TotalTime',
+ /* Pages */
+ /* Words */
+ /* Characters */
+ Category: 'Category',
+ /* PresentationFormat */
Manager: 'Manager',
- Company: 'Company'
+ Company: 'Company',
+ /* Guid */
+ /* HyperlinkBase */
+ /* Bytes */
+ /* Lines */
+ /* Paragraphs */
+ /* CharactersWithSpaces */
+ AppVersion: 'Version',
+
+ ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
+ Identifier: 'Identifier', /* NOTE: missing from schema */
+ Language: 'Language' /* NOTE: missing from schema */
};
var evert_XLMLDPM = evert(XLMLDocPropsMap);
@@ -3358,19 +3368,21 @@ function xlml_set_prop(Props, tag/*:string*/, val) {
Props[tag] = val;
}
-
-/* TODO: verify */
function xlml_write_docprops(Props, opts) {
var o = [];
- CORE_PROPS.concat(EXT_PROPS).forEach(function(p) {
+ keys(XLMLDocPropsMap).map(function(m) {
+ for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
+ for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
+ throw m;
+ }).forEach(function(p) {
if(Props[p[1]] == null) return;
var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
switch(p[2]) {
- case 'date': m = new Date(m).toISOString(); break;
+ case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
}
if(typeof m == 'number') m = String(m);
else if(m === true || m === false) { m = m ? "1" : "0"; }
- else if(m instanceof Date) m = new Date(m).toISOString();
+ else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
});
return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
@@ -10228,8 +10240,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
/* 18.3.1.73 row CT_Row */
for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
tag = parsexmltag(x.substr(0,ri), true);
- /* SpreadSheetGear uses implicit r/c */
- tagr = typeof tag.r !== 'undefined' ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
+ tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
if(opts.sheetRows && opts.sheetRows < tagr) continue;
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
@@ -10281,7 +10292,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
p.F = arrayf[i][1];
}
- if(tag.t === undefined && p.v === undefined) {
+ if(tag.t == null && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "z";
}
@@ -10319,7 +10330,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
break;
/* error string in .w, number in .v */
case 'e':
- if(opts && opts.cellText === false) p.w = p.v;
+ if(!opts || opts.cellText !== false) p.w = p.v;
p.v = RBErr[p.v]; break;
}
/* formatting */
@@ -10881,7 +10892,7 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ {
case 'n': p.v = val[1]; break;
case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
case 'b': p.v = val[1] ? true : false; break;
- case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
+ case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts, themes, styles);
@@ -12145,11 +12156,11 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a
if(cell.v === undefined) cell.v=+xml;
if(!cell.t) cell.t = 'n';
break;
- case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; cell.w = xml; break;
+ case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
}
safe_format_xlml(cell, nf, o);
- if(o.cellFormula != null) {
+ if(o.cellFormula !== false) {
if(cell.Formula) {
var fstr = unescapexml(cell.Formula);
/* strictly speaking, the leading = is required but some writers omit */
@@ -12861,17 +12872,107 @@ function write_sty_xlml(wb, opts)/*:string*/ {
}
/* WorksheetOptions */
function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
+ if(!ws) return "";
var o = [];
+ /* NOTE: spec technically allows any order, but stick with implied order */
+
+ /* FitToPage */
+ /* DoNotDisplayColHeaders */
+ /* DoNotDisplayRowHeaders */
+ /* ViewableRange */
+ /* Selection */
+ /* GridlineColor */
+ /* Name */
+ /* ExcelWorksheetType */
+ /* IntlMacro */
+ /* Unsynced */
+ /* Selected */
+ /* CodeName */
+
+ if(ws['!margins']) {
+ o.push("");
+ if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
+ if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
+ o.push(writextag("PageMargins", null, {
+ 'x:Bottom': ws['!margins'].bottom || "0.75",
+ 'x:Left': ws['!margins'].left || "0.7",
+ 'x:Right': ws['!margins'].right || "0.7",
+ 'x:Top': ws['!margins'].top || "0.75"
+ }));
+ o.push("");
+ }
+
/* PageSetup */
+ /* DisplayPageBreak */
+ /* TransitionExpressionEvaluation */
+ /* TransitionFormulaEntry */
+ /* Print */
+ /* Zoom */
+ /* PageLayoutZoom */
+ /* PageBreakZoom */
+ /* ShowPageBreakZoom */
+ /* DefaultRowHeight */
+ /* DefaultColumnWidth */
+ /* StandardWidth */
+
if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
/* Visible */
- if(!!wb.Workbook.Sheets[idx].Hidden) o.push("" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "");
+ if(!!wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
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("");
}
}
+
+ /* LeftColumnVisible */
+ /* DisplayRightToLeft */
+ /* GridlineColorIndex */
+ /* DisplayFormulas */
+ /* DoNotDisplayGridlines */
+ /* DoNotDisplayHeadings */
+ /* DoNotDisplayOutline */
+ /* ApplyAutomaticOutlineStyles */
+ /* NoSummaryRowsBelowDetail */
+ /* NoSummaryColumnsRightDetail */
+ /* DoNotDisplayZeros */
+ /* ActiveRow */
+ /* ActiveColumn */
+ /* FilterOn */
+ /* RangeSelection */
+ /* TopRowVisible */
+ /* TopRowBottomPane */
+ /* LeftColumnRightPane */
+ /* ActivePane */
+ /* SplitHorizontal */
+ /* SplitVertical */
+ /* FreezePanes */
+ /* FrozenNoSplit */
+ /* TabColorIndex */
+ /* Panes */
+
+ /* NOTE: Password not supported in XLML Format */
+ if(ws['!protect']) {
+ o.push(writetag("ProtectContents", "True"));
+ if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
+ if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
+ if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
+ else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
+ [
+ [ "formatColumns", "AllowFormatCells" ],
+ [ "formatRows", "AllowSizeCols" ],
+ [ "formatCells", "AllowSizeRows" ],
+ [ "insertColumns", "AllowInsertCols" ],
+ [ "insertRows", "AllowInsertRows" ],
+ [ "insertHyperlinks", "AllowInsertHyperlinks" ],
+ [ "deleteColumns", "AllowDeleteCols" ],
+ [ "deleteRows", "AllowDeleteRows" ],
+ [ "sort", "AllowSort" ],
+ [ "autoFilter", "AllowFilter" ],
+ [ "pivotTables", "AllowUsePivotTables" ]
+ ].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
+ }
+
if(o.length == 0) return "";
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
}
@@ -13048,12 +13149,13 @@ function slurp(R, blob, length/*:number*/, opts) {
function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
if(p.t === 'z') return;
- if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
if(!p.XF) return;
try {
var fmtid = p.XF.ifmt||0;
if(opts.cellNF) p.z = SSF._table[fmtid];
- if(p.t === 'e'){}
+ } catch(e) { if(opts.WTF) throw e; }
+ if(!opts || opts.cellText !== false) try {
+ if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
@@ -15436,7 +15538,7 @@ var parse_content_xml = (function() {
isstub = textpidx == 0;
}
if(comments.length > 0) { q.c = comments; comments = []; }
- if(textp) q.w = textp;
+ if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
if(opts.dense) {
diff --git a/xlsx.js b/xlsx.js
index 4efc39f..08a9047 100644
--- a/xlsx.js
+++ b/xlsx.js
@@ -3271,26 +3271,36 @@ function write_cust_props(cp, opts) {
}
/* Common Name -> XLML Name */
var XLMLDocPropsMap = {
- Category: 'Category',
- ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
- Keywords: 'Keywords',
- LastAuthor: 'LastAuthor',
- LastPrinted: 'LastPrinted',
- RevNumber: 'Revision',
- Author: 'Author',
- Comments: 'Description',
- Identifier: 'Identifier', /* NOTE: missing from schema */
- Language: 'Language', /* NOTE: missing from schema */
- Subject: 'Subject',
Title: 'Title',
+ Subject: 'Subject',
+ Author: 'Author',
+ Keywords: 'Keywords',
+ Comments: 'Description',
+ LastAuthor: 'LastAuthor',
+ RevNumber: 'Revision',
+ Application: 'AppName',
+ /* TotalTime: 'TotalTime', */
+ LastPrinted: 'LastPrinted',
CreatedDate: 'Created',
ModifiedDate: 'LastSaved',
-
- Application: 'AppName',
- AppVersion: 'Version',
- TotalTime: 'TotalTime',
+ /* Pages */
+ /* Words */
+ /* Characters */
+ Category: 'Category',
+ /* PresentationFormat */
Manager: 'Manager',
- Company: 'Company'
+ Company: 'Company',
+ /* Guid */
+ /* HyperlinkBase */
+ /* Bytes */
+ /* Lines */
+ /* Paragraphs */
+ /* CharactersWithSpaces */
+ AppVersion: 'Version',
+
+ ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
+ Identifier: 'Identifier', /* NOTE: missing from schema */
+ Language: 'Language' /* NOTE: missing from schema */
};
var evert_XLMLDPM = evert(XLMLDocPropsMap);
@@ -3299,19 +3309,21 @@ function xlml_set_prop(Props, tag, val) {
Props[tag] = val;
}
-
-/* TODO: verify */
function xlml_write_docprops(Props, opts) {
var o = [];
- CORE_PROPS.concat(EXT_PROPS).forEach(function(p) {
+ keys(XLMLDocPropsMap).map(function(m) {
+ for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
+ for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
+ throw m;
+ }).forEach(function(p) {
if(Props[p[1]] == null) return;
var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
switch(p[2]) {
- case 'date': m = new Date(m).toISOString(); break;
+ case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
}
if(typeof m == 'number') m = String(m);
else if(m === true || m === false) { m = m ? "1" : "0"; }
- else if(m instanceof Date) m = new Date(m).toISOString();
+ else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
});
return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
@@ -10166,8 +10178,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
/* 18.3.1.73 row CT_Row */
for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
tag = parsexmltag(x.substr(0,ri), true);
- /* SpreadSheetGear uses implicit r/c */
- tagr = typeof tag.r !== 'undefined' ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
+ tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
if(opts.sheetRows && opts.sheetRows < tagr) continue;
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
@@ -10219,7 +10230,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
p.F = arrayf[i][1];
}
- if(tag.t === undefined && p.v === undefined) {
+ if(tag.t == null && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "z";
}
@@ -10257,7 +10268,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
break;
/* error string in .w, number in .v */
case 'e':
- if(opts && opts.cellText === false) p.w = p.v;
+ if(!opts || opts.cellText !== false) p.w = p.v;
p.v = RBErr[p.v]; break;
}
/* formatting */
@@ -10819,7 +10830,7 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles) {
case 'n': p.v = val[1]; break;
case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
case 'b': p.v = val[1] ? true : false; break;
- case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
+ case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts, themes, styles);
@@ -12081,11 +12092,11 @@ function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o
if(cell.v === undefined) cell.v=+xml;
if(!cell.t) cell.t = 'n';
break;
- case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; cell.w = xml; break;
+ case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
}
safe_format_xlml(cell, nf, o);
- if(o.cellFormula != null) {
+ if(o.cellFormula !== false) {
if(cell.Formula) {
var fstr = unescapexml(cell.Formula);
/* strictly speaking, the leading = is required but some writers omit */
@@ -12795,17 +12806,107 @@ function write_sty_xlml(wb, opts) {
}
/* WorksheetOptions */
function write_ws_xlml_wsopts(ws, opts, idx, wb) {
+ if(!ws) return "";
var o = [];
+ /* NOTE: spec technically allows any order, but stick with implied order */
+
+ /* FitToPage */
+ /* DoNotDisplayColHeaders */
+ /* DoNotDisplayRowHeaders */
+ /* ViewableRange */
+ /* Selection */
+ /* GridlineColor */
+ /* Name */
+ /* ExcelWorksheetType */
+ /* IntlMacro */
+ /* Unsynced */
+ /* Selected */
+ /* CodeName */
+
+ if(ws['!margins']) {
+ o.push("");
+ if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
+ if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
+ o.push(writextag("PageMargins", null, {
+ 'x:Bottom': ws['!margins'].bottom || "0.75",
+ 'x:Left': ws['!margins'].left || "0.7",
+ 'x:Right': ws['!margins'].right || "0.7",
+ 'x:Top': ws['!margins'].top || "0.75"
+ }));
+ o.push("");
+ }
+
/* PageSetup */
+ /* DisplayPageBreak */
+ /* TransitionExpressionEvaluation */
+ /* TransitionFormulaEntry */
+ /* Print */
+ /* Zoom */
+ /* PageLayoutZoom */
+ /* PageBreakZoom */
+ /* ShowPageBreakZoom */
+ /* DefaultRowHeight */
+ /* DefaultColumnWidth */
+ /* StandardWidth */
+
if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
/* Visible */
- if(!!wb.Workbook.Sheets[idx].Hidden) o.push("" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "");
+ if(!!wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
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("");
}
}
+
+ /* LeftColumnVisible */
+ /* DisplayRightToLeft */
+ /* GridlineColorIndex */
+ /* DisplayFormulas */
+ /* DoNotDisplayGridlines */
+ /* DoNotDisplayHeadings */
+ /* DoNotDisplayOutline */
+ /* ApplyAutomaticOutlineStyles */
+ /* NoSummaryRowsBelowDetail */
+ /* NoSummaryColumnsRightDetail */
+ /* DoNotDisplayZeros */
+ /* ActiveRow */
+ /* ActiveColumn */
+ /* FilterOn */
+ /* RangeSelection */
+ /* TopRowVisible */
+ /* TopRowBottomPane */
+ /* LeftColumnRightPane */
+ /* ActivePane */
+ /* SplitHorizontal */
+ /* SplitVertical */
+ /* FreezePanes */
+ /* FrozenNoSplit */
+ /* TabColorIndex */
+ /* Panes */
+
+ /* NOTE: Password not supported in XLML Format */
+ if(ws['!protect']) {
+ o.push(writetag("ProtectContents", "True"));
+ if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
+ if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
+ if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
+ else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
+ [
+ [ "formatColumns", "AllowFormatCells" ],
+ [ "formatRows", "AllowSizeCols" ],
+ [ "formatCells", "AllowSizeRows" ],
+ [ "insertColumns", "AllowInsertCols" ],
+ [ "insertRows", "AllowInsertRows" ],
+ [ "insertHyperlinks", "AllowInsertHyperlinks" ],
+ [ "deleteColumns", "AllowDeleteCols" ],
+ [ "deleteRows", "AllowDeleteRows" ],
+ [ "sort", "AllowSort" ],
+ [ "autoFilter", "AllowFilter" ],
+ [ "pivotTables", "AllowUsePivotTables" ]
+ ].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
+ }
+
if(o.length == 0) return "";
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
}
@@ -12982,12 +13083,13 @@ function slurp(R, blob, length, opts) {
function safe_format_xf(p, opts, date1904) {
if(p.t === 'z') return;
- if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
if(!p.XF) return;
try {
var fmtid = p.XF.ifmt||0;
if(opts.cellNF) p.z = SSF._table[fmtid];
- if(p.t === 'e'){}
+ } catch(e) { if(opts.WTF) throw e; }
+ if(!opts || opts.cellText !== false) try {
+ if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
@@ -15370,7 +15472,7 @@ var parse_content_xml = (function() {
isstub = textpidx == 0;
}
if(comments.length > 0) { q.c = comments; comments = []; }
- if(textp) q.w = textp;
+ if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
if(opts.dense) {