forked from sheetjs/sheetjs
merge from beta
This commit is contained in:
commit
8198744d58
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
37
README.md
37
README.md
@ -1,10 +1,9 @@
|
||||
# xlsx-style
|
||||
|
||||
Parser and writer for various spreadsheet formats. Pure-JS cleanroom
|
||||
implementation from official specifications and related documents.
|
||||
Parser and writer for various spreadsheet formats. Pure-JS cleanroom implementation from official specifications and related documents.
|
||||
|
||||
## About this fork
|
||||
[This project](https://github.com/SheetJS/js-xlsx/tree/beta) is a fork of the original (and awesome) [SheetJS/xlsx](https://github.com/SheetJS/js-xlsx) project.
|
||||
# About this fork
|
||||
**NOTE:** [This project](https://github.com/SheetJS/js-xlsx/tree/beta) is a fork of the original (and awesome) [SheetJS/xlsx](https://github.com/SheetJS/js-xlsx) project.
|
||||
It is extended to enable cell formats to be read from and written to .xlsx workbooks.
|
||||
The intent is to provide a temporary means of using these features in practice, and ultimately to merge this into the primary project.
|
||||
Report any issues to https://github.com/protobi/js-xlsx/issues.
|
||||
@ -13,7 +12,7 @@ For those contributing to this fork:
|
||||
* `master` is the main branch, which follows the original repo to enable a future pull request.
|
||||
* `beta` branch is published to npm and bower to make this fork available for use.
|
||||
|
||||
## Supported formats
|
||||
# Supported formats
|
||||
|
||||
Supported read formats:
|
||||
|
||||
@ -258,20 +257,7 @@ XLSX.writeFile(workbook, 'out.xlsx');
|
||||
|
||||
```js
|
||||
/* bookType can be 'xlsx' or 'xlsm' or 'xlsb' */
|
||||
var wopts = {
|
||||
bookType:'xlsx',
|
||||
bookSST:false,
|
||||
type:'binary',
|
||||
showGridLines: false,
|
||||
defaultCellStyle: { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}},
|
||||
Props: {
|
||||
title: "Goldilocks",
|
||||
description: "Girl discovers mysterious cottage in forest ",
|
||||
creator:"Traditional folk tale",
|
||||
keywords: "Bears; porridge; property rights; iterative optimization",
|
||||
subject: "subject"
|
||||
}
|
||||
};
|
||||
var wopts = { bookType:'xlsx', bookSST:false, type:'binary' };
|
||||
|
||||
var wbout = XLSX.write(workbook,wopts);
|
||||
|
||||
@ -444,6 +430,8 @@ Special worksheet keys (accessible as `worksheet[key]`, each starting with `!`):
|
||||
will write all cells in the merge range if they exist, so be sure that only
|
||||
the first cell (upper-left) in the range is set.
|
||||
|
||||
- `ws['!printHeader']`: array of row indices for repeating row headers on print, e.g. `[1:1]` to repeat just the first row.
|
||||
|
||||
The following properties are currently used when generating an XLSX file, but not yet parsed:
|
||||
|
||||
- `ws['!rowBreaks']`: array of row break points, e.g. `[16,32]`
|
||||
@ -517,8 +505,12 @@ The exported `write` and `writeFile` functions accept an options argument:
|
||||
| cellDates | false | Store dates as type `d` (default is `n`) |
|
||||
| bookSST | false | Generate Shared String Table ** |
|
||||
| bookType | 'xlsx' | Type of Workbook ("xlsx" or "xlsm" or "xlsb") |
|
||||
| showGridLines | true | Show grid lines on all pages (note capital L) |
|
||||
| showGridLines | true | Show gridlines on all pages |
|
||||
| tabSelected | '1' | Initial tab selected |
|
||||
| Props | null | Workbook properties |
|
||||
|
||||
|
||||
|
||||
|
||||
- `bookSST` is slower and more memory intensive, but has better compatibility
|
||||
with older versions of iOS Numbers
|
||||
@ -529,6 +521,9 @@ The exported `write` and `writeFile` functions accept an options argument:
|
||||
third-party readers. Excel itself does not usually write cells with type `d`
|
||||
so non-Excel tools may ignore the data or blow up in the presence of dates.
|
||||
- showGridLines and tabSelected are currently used when generating an XLSX file but not yet parse.
|
||||
- Props specifies workbook properties
|
||||
|
||||
|
||||
|
||||
|
||||
## Cell Styles
|
||||
@ -558,7 +553,7 @@ top-level attributes: `fill`, `font`, `numFmt`, `alignment`, and `border`.
|
||||
| | | `"0.00%;\\(0.00%\\);\\-;@"` // string specifying a custom format, escaping special characters
|
||||
| | | `"m/dd/yy"` // string a date format using Excel's format notation
|
||||
| alignment | vertical | `"bottom"||"center"||"top"`
|
||||
| | horizontal | `"left"||"center"||"right"`
|
||||
| | horizontal | `"bottom"||"center"||"top"`
|
||||
| | wrapText | `true || false`
|
||||
| | readingOrder | `2` // for right-to-left
|
||||
| | textRotation | Number from `0` to `180` or `255` (default is `0`)
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.8.0';
|
||||
XLSX.version = '0.8.11';
|
||||
|
@ -77,20 +77,9 @@ function write_ws_xml_pagesetup(setup) {
|
||||
horizontalDpi : setup.horizontalDpi || '4294967292',
|
||||
verticalDpi : setup.verticalDpi || '4294967292'
|
||||
})
|
||||
console.log(pageSetup);
|
||||
return pageSetup;
|
||||
}
|
||||
|
||||
//<pageSetup scale="90" orientation="portrait" horizontalDpi="4294967292" verticalDpi="4294967292"/>
|
||||
//<rowBreaks count="1" manualBreakCount="1">
|
||||
// <brk id="8" max="16383" man="1"/>
|
||||
//</rowBreaks>
|
||||
//<colBreaks count="1" manualBreakCount="1">
|
||||
// <brk id="8" max="1048575" man="1"/>
|
||||
//</colBreaks>
|
||||
|
||||
|
||||
|
||||
|
||||
function parse_ws_xml_hlinks(s, data, rels) {
|
||||
for(var i = 0; i != data.length; ++i) {
|
||||
@ -335,10 +324,9 @@ function write_ws_xml(idx, opts, wb) {
|
||||
|
||||
if(ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
|
||||
if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup'])
|
||||
if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks'])
|
||||
if (ws['!colBreaks'] !== undefined) o[o.length] = write_ws_xml_col_breaks(ws['!colBreaks'])
|
||||
|
||||
if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup']);
|
||||
if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks']);
|
||||
if (ws['!colBreaks'] !== undefined) o[o.length] = write_ws_xml_col_breaks(ws['!colBreaks']);
|
||||
|
||||
if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
|
@ -134,6 +134,44 @@ function write_wb_xml(wb, opts) {
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i)
|
||||
o[o.length] = (writextag('sheet',null,{name:wb.SheetNames[i].substr(0,31), sheetId:""+(i+1), "r:id":"rId"+(i+1)}));
|
||||
o[o.length] = "</sheets>";
|
||||
|
||||
var hasPrintHeaders = false;
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) {
|
||||
var sheetName = wb.SheetNames[i];
|
||||
var sheet = wb.Sheets[sheetName]
|
||||
if (sheet['!printHeader']) {
|
||||
if (sheet['!printHeader'].length !== 2) {
|
||||
throw "!printHeaders must be an array of length 2: "+sheet['!printHeader'];
|
||||
|
||||
}
|
||||
hasPrintHeaders = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hasPrintHeaders) {
|
||||
o[o.length] = '<definedNames>';
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) {
|
||||
var sheetName = wb.SheetNames[i];
|
||||
var sheet = wb.Sheets[sheetName]
|
||||
if (sheet['!printHeader'])
|
||||
var range = "'" + sheetName + "'!" + sheet['!printHeader'];
|
||||
console.log("!!!!"+range)
|
||||
o[o.length] = (writextag('definedName', range, {
|
||||
"name":"_xlnm.Print_Titles",
|
||||
localSheetId : ''+i
|
||||
}))
|
||||
}
|
||||
o[o.length] = '</definedNames>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
// <definedNames>
|
||||
// <definedName name="_xlnm.Print_Titles" localSheetId="0">Sheet1!$1:$1</definedName>
|
||||
// <definedName name="_xlnm.Print_Titles" localSheetId="1">Sheet2!$1:$2</definedName>
|
||||
// </definedNames>
|
||||
|
||||
if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
|
@ -265,12 +265,10 @@
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
|
||||
|
||||
var $numFmt = XmlNode('numFmt')
|
||||
.attr('numFmtId', (++customNumFmtId))
|
||||
.attr('formatCode', numFmt);
|
||||
|
||||
|
||||
this.$numFmts.append($numFmt);
|
||||
|
||||
var count = this.$numFmts.children().length;
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "js-xlsx",
|
||||
"homepage": "https://github.com/SheetJS/js-xlsx",
|
||||
"main": "dist/xlsx.js",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.11",
|
||||
"ignore": [
|
||||
"bin",
|
||||
"bits",
|
||||
|
1773
cell_style_simple.json
Normal file
1773
cell_style_simple.json
Normal file
File diff suppressed because it is too large
Load Diff
86
color.js
Normal file
86
color.js
Normal file
@ -0,0 +1,86 @@
|
||||
function hex2RGB(h) {
|
||||
var o = h.substr(h[0]==="#"?1:0,6);
|
||||
var R = o.substr(0,2);
|
||||
var G = o.substr(2,2);
|
||||
var B = o.substr(4,2);
|
||||
return [parseInt(R,16),parseInt(G,16),parseInt(B,16)];
|
||||
}
|
||||
function rgb2Hex(rgb) {
|
||||
for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
|
||||
return o.toString(16).toUpperCase().substr(1);
|
||||
}
|
||||
|
||||
function rgb2HSL(rgb) {
|
||||
var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
|
||||
var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
|
||||
if(C === 0) return [0, 0, R];
|
||||
|
||||
var H6 = 0, S = 0, L2 = (M + m);
|
||||
S = C / (L2 > 1 ? 2 - L2 : L2);
|
||||
switch(M){
|
||||
case R: H6 = ((G - B) / C + 6)%6; break;
|
||||
case G: H6 = ((B - R) / C + 2); break;
|
||||
case B: H6 = ((R - G) / C + 4); break;
|
||||
}
|
||||
return [H6 / 6, S, L2 / 2];
|
||||
}
|
||||
|
||||
function hsl2RGB(hsl){
|
||||
var H = hsl[0], S = hsl[1], L = hsl[2];
|
||||
var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
|
||||
var rgb = [m,m,m], h6 = 6*H;
|
||||
|
||||
var X;
|
||||
if(S !== 0) switch(h6|0) {
|
||||
case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
|
||||
case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
|
||||
case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
|
||||
case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
|
||||
case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
|
||||
case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
|
||||
}
|
||||
for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
|
||||
return rgb;
|
||||
}
|
||||
/* 18.8.3 bgColor tint algorithm */
|
||||
function rgb_tint(hex, tint) {
|
||||
if(tint === 0) return hex;
|
||||
var hsl = rgb2HSL(hex2RGB(hex));
|
||||
if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
|
||||
else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
|
||||
return rgb2Hex(hsl2RGB(hsl));
|
||||
}
|
||||
|
||||
var exp = [
|
||||
{ patternType: 'darkHorizontal',
|
||||
fgColor: { theme: 9, "tint":-0.249977111117893, rgb: 'F79646' },
|
||||
bgColor: { theme: 5, "tint":0.3999755851924192, rgb: 'C0504D' } },
|
||||
{ patternType: 'darkUp',
|
||||
fgColor: { theme: 3, "tint":-0.249977111117893, rgb: 'EEECE1' },
|
||||
bgColor: { theme: 7, "tint":0.3999755851924192, rgb: '8064A2' } },
|
||||
{ patternType: 'darkGray',
|
||||
fgColor: { theme: 3, rgb: 'EEECE1' },
|
||||
bgColor: { theme: 1, rgb: 'FFFFFF' } },
|
||||
{ patternType: 'lightGray',
|
||||
fgColor: { theme: 6, "tint":0.3999755851924192, rgb: '9BBB59' },
|
||||
bgColor: { theme: 2, "tint":-0.499984740745262, rgb: '1F497D' } },
|
||||
{ patternType: 'lightDown',
|
||||
fgColor: { theme: 4, rgb: '4F81BD' },
|
||||
bgColor: { theme: 7, rgb: '8064A2' } },
|
||||
{ patternType: 'lightGrid',
|
||||
fgColor: { theme: 6, "tint":-0.249977111117893, rgb: '9BBB59' },
|
||||
bgColor: { theme: 9, "tint":-0.249977111117893, rgb: 'F79646' } },
|
||||
{ patternType: 'lightGrid',
|
||||
fgColor: { theme: 4, rgb: '4F81BD' },
|
||||
bgColor: { theme: 2, "tint":-0.749992370372631, rgb: '1F497D' } },
|
||||
{ patternType: 'lightVertical',
|
||||
fgColor: { theme: 3, "tint":0.3999755851924192, rgb: 'EEECE1' },
|
||||
bgColor: { theme: 7, "tint":0.3999755851924192, rgb: '8064A2' } }
|
||||
];
|
||||
var map = [];
|
||||
exp.forEach(function(e) {
|
||||
e.fgColor.new = rgb_tint( e.fgColor.rgb, e.fgColor.tint || 0);
|
||||
console.log(e.fgColor.rgb, e.fgColor.new);
|
||||
e.bgColor.new = rgb_tint( e.bgColor.rgb, e.bgColor.tint || 0);
|
||||
console.log(e.bgColor.rgb, e.bgColor.new);
|
||||
});
|
24
dist/xlsx.core.min.js
vendored
24
dist/xlsx.core.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.core.min.map
vendored
2
dist/xlsx.core.min.map
vendored
File diff suppressed because one or more lines are too long
24
dist/xlsx.full.min.js
vendored
24
dist/xlsx.full.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.full.min.map
vendored
2
dist/xlsx.full.min.map
vendored
File diff suppressed because one or more lines are too long
1194
dist/xlsx.js
vendored
1194
dist/xlsx.js
vendored
File diff suppressed because one or more lines are too long
18
dist/xlsx.min.js
vendored
18
dist/xlsx.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.min.map
vendored
2
dist/xlsx.min.map
vendored
File diff suppressed because one or more lines are too long
642
example-style.js
Normal file
642
example-style.js
Normal file
@ -0,0 +1,642 @@
|
||||
var XLSX = require('xlsx');
|
||||
var OUTFILE = '/tmp/example-style.xlsx';
|
||||
|
||||
function JSDateToExcelDate(inDate) {
|
||||
return 25569.0 + ((inDate.getTime() - (inDate.getTimezoneOffset() * 60 * 1000)) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
var defaultCellStyle = { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}};
|
||||
|
||||
// test to see if everything on the left equals its counterpart on the right
|
||||
// but the right hand object may have other attributes which we might not care about
|
||||
function basicallyEquals(left, right) {
|
||||
if (Array.isArray(left) && Array.isArray(right)) {
|
||||
for (var i = 0; i < left.length; i++) {
|
||||
if (!basicallyEquals(left[i], right[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (typeof left == 'object' && typeof right == 'object') {
|
||||
for (var key in left) {
|
||||
if (key != 'bgColor') {
|
||||
if (!basicallyEquals(left[key], right[key])) {
|
||||
if (JSON.stringify(left[key]) == "{}" && right[key] == undefined) return true;
|
||||
if (JSON.stringify(right[key]) == "{}" && left[key] == undefined) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (left != right) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var workbook, wbout, wbin;
|
||||
|
||||
workbook = {
|
||||
"SheetNames": [
|
||||
"Main"
|
||||
],
|
||||
"Sheets": {
|
||||
"Main": {
|
||||
"!merges": [
|
||||
{
|
||||
"s": {
|
||||
"c": 0,
|
||||
"r": 0
|
||||
},
|
||||
"e": {
|
||||
"c": 2,
|
||||
"r": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"A1": {
|
||||
"v": "This is a submerged cell",
|
||||
"s": {
|
||||
"border": {
|
||||
"left": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B1": {
|
||||
"v": "Pirate ship",
|
||||
"s": {
|
||||
"border": {
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C1": {
|
||||
"v": "Sunken treasure",
|
||||
"s": {
|
||||
"border": {
|
||||
"right": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A2": {
|
||||
"v": "Blank",
|
||||
"t": "s"
|
||||
},
|
||||
"B2": {
|
||||
"v": "Red",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFF0000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C2": {
|
||||
"v": "Green",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FF00FF00"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D2": {
|
||||
"v": "Blue",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FF0000FF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E2": {
|
||||
"v": "Theme 5",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"theme": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"F2": {
|
||||
"v": "Theme 5 Tint -0.5",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"theme": 5,
|
||||
"tint": -0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A3": {
|
||||
"v": "Default",
|
||||
"t": "s"
|
||||
},
|
||||
"B3": {
|
||||
"v": "Arial",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Arial",
|
||||
"sz": 24,
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C3": {
|
||||
"v": "Times New Roman",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Times New Roman",
|
||||
bold: true,
|
||||
underline: true,
|
||||
italic: true,
|
||||
strike: true,
|
||||
outline: true,
|
||||
shadow: true,
|
||||
vertAlign: "superscript",
|
||||
"sz": 16,
|
||||
"color": {
|
||||
"rgb": "FF2222FF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D3": {
|
||||
"v": "Courier New",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Courier New",
|
||||
"sz": 14
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"B4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"C4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"D4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%"
|
||||
}
|
||||
},
|
||||
"E4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%",
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFFCC00"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"A5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0%"
|
||||
}
|
||||
},
|
||||
"B5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.0%"
|
||||
}
|
||||
},
|
||||
"C5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%"
|
||||
}
|
||||
},
|
||||
"D5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.000%"
|
||||
}
|
||||
},
|
||||
"E5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.0000%"
|
||||
}
|
||||
},
|
||||
"F5": {
|
||||
"v": 0,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%;\\(0.00%\\);\\-;@",
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFFCC00"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"A6": {
|
||||
"v": "Sat Mar 21 2015 23:47:34 GMT-0400 (EDT)",
|
||||
"t": "s"
|
||||
},
|
||||
"B6": {
|
||||
"v": 42084.99137416667,
|
||||
"t": "n"
|
||||
},
|
||||
"C6": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "d-mmm-yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"A7": {
|
||||
"v": "left",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "left"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B7": {
|
||||
"v": "center",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "center"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C7": {
|
||||
"v": "right",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "right"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "top"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "center"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "bottom"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "1"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "2"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "3"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A10": {
|
||||
"v": "In publishing and graphic design, lorem ipsum is a filler text commonly used to demonstrate the graphic elements of a document or visual presentation. ",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"wrapText": 1,
|
||||
"horizontal": "right",
|
||||
"vertical": "center",
|
||||
"indent": 1
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"B11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "d-mmm-yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"C11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "h:mm:ss AM/PM"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"D11": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"E11": {
|
||||
"v": 42065.02247239584,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"F11": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy h:mm:ss AM/PM"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"A12": {
|
||||
"v": "Apple",
|
||||
"s": {
|
||||
"border": {
|
||||
"top": {
|
||||
"style": "thin"
|
||||
},
|
||||
"left": {
|
||||
"style": "thin"
|
||||
},
|
||||
"right": {
|
||||
"style": "thin"
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C12": {
|
||||
"v": "Apple",
|
||||
"s": {
|
||||
"border": {
|
||||
"diagonalUp": 1,
|
||||
"diagonalDown": 1,
|
||||
"top": {
|
||||
"style": "dashed",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"style": "medium",
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "hair",
|
||||
"color": {
|
||||
"theme": 5,
|
||||
"tint": "-0.3"
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"style": "thin",
|
||||
"color": {
|
||||
"rgb": "FFFFAA00"
|
||||
}
|
||||
},
|
||||
"diagonal": {
|
||||
"style": "dotted",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E12": {
|
||||
"v": "Pear",
|
||||
"s": {
|
||||
"border": {
|
||||
"diagonalUp": 1,
|
||||
"diagonalDown": 1,
|
||||
"top": {
|
||||
"style": "dashed",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"style": "dotted",
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "mediumDashed",
|
||||
"color": {
|
||||
"theme": 5,
|
||||
"tint": "-0.3"
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"style": "double",
|
||||
"color": {
|
||||
"rgb": "FFFFAA00"
|
||||
}
|
||||
},
|
||||
"diagonal": {
|
||||
"style": "hair",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A13": {
|
||||
"v": "Up 90",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 90
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B13": {
|
||||
"v": "Up 45",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 45
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C13": {
|
||||
"v": "Horizontal",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 0
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D13": {
|
||||
"v": "Down 45",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 135
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E13": {
|
||||
"v": "Down 90",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 180
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"F13": {
|
||||
"v": "Vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 255
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A14": {
|
||||
"v": "Font color test",
|
||||
"s": {
|
||||
"font": {
|
||||
"color": {
|
||||
"rgb": "FFC6EFCE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"!ref": "A1:F14"
|
||||
}
|
||||
}
|
||||
}
|
||||
XLSX.writeFile(workbook, OUTFILE, { defaultCellStyle: defaultCellStyle });
|
||||
console.log("open " + OUTFILE)
|
||||
|
89
example1.js
Normal file
89
example1.js
Normal file
@ -0,0 +1,89 @@
|
||||
var XLSX = require('./');
|
||||
var sheetName = 'test & debug';
|
||||
|
||||
|
||||
var ATTRIBUTE_VALUE_STYLE={
|
||||
font: {
|
||||
name: "Arial",
|
||||
sz: 10
|
||||
}
|
||||
};
|
||||
|
||||
var Workbook = function(){
|
||||
this.SheetNames = [];
|
||||
this.Sheets = {};
|
||||
};
|
||||
|
||||
var range = {s: {c:10000000, r:10000000}, e:{c:0, r:0}};
|
||||
|
||||
function updateRange(row, col) {
|
||||
if (range.s.r > row) { range.s.r = row;}
|
||||
if (range.s.c > col) { range.s.c = col; }
|
||||
if (range.e.r < row) { range.e.r = row; }
|
||||
if (range.e.c < col) { range.e.c = col; }
|
||||
}
|
||||
|
||||
function addCell(wb, ws, value, type, row, col, styles) {
|
||||
|
||||
updateRange(row, col);
|
||||
|
||||
var cell = {t: type, v: value, s:styles};
|
||||
|
||||
// i use d to recognize that the format is a date, and if it is, i use z attribute to format it
|
||||
if (cell.t === 'd') {
|
||||
cell.t = 'n';
|
||||
cell.z = XLSX.SSF._table[14];
|
||||
}
|
||||
|
||||
var cell_ref = XLSX.utils.encode_cell({c: col, r:row});
|
||||
|
||||
ws[cell_ref] = cell;
|
||||
}
|
||||
|
||||
function s2ab(s) {
|
||||
var buf = new ArrayBuffer(s.length);
|
||||
var view = new Uint8Array(buf);
|
||||
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
|
||||
return buf;
|
||||
}
|
||||
|
||||
function datenum(v, date1904) {
|
||||
if(date1904) v+=1462;
|
||||
var epoch = Date.parse(v);
|
||||
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
var wb = new Workbook();
|
||||
var ws = {};
|
||||
|
||||
/* Here i add a cell with format number with value 10*/
|
||||
addCell(wb, ws, 10, 'n', 0, 0, ATTRIBUTE_VALUE_STYLE);
|
||||
|
||||
/* Here i add a cell with format number that is current date*/
|
||||
addCell(wb, ws, datenum(new Date()), 'd', 0, 1, ATTRIBUTE_VALUE_STYLE);
|
||||
|
||||
/* Here i add a cell with format number with value 10, again another number*/
|
||||
addCell(wb, ws, 10, 'd', 0, 2, ATTRIBUTE_VALUE_STYLE);
|
||||
|
||||
/* Here i add a cell with format number with value 10, again another number*/
|
||||
addCell(wb, ws, "Hello null\u0000world", 's', 0, 3);
|
||||
|
||||
|
||||
ws['!ref'] = XLSX.utils.encode_range(range);
|
||||
|
||||
wb.SheetNames.push(sheetName);
|
||||
wb.Sheets[sheetName] = ws;
|
||||
|
||||
|
||||
ws['!rowBreaks'] = [12,24];
|
||||
ws['!colBreaks'] = [3,6];
|
||||
ws['!pageSetup'] = {scale: '140'};
|
||||
|
||||
/* bookType can be 'xszlsx' or 'xlsm' or 'xlsb' */
|
||||
var defaultCellStyle = { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}};
|
||||
var wopts = { bookType:'xlsx', bookSST:false, type:'binary', defaultCellStyle: defaultCellStyle, showGridLines: false};
|
||||
|
||||
//console.log(JSON.stringify(wb, null,4))
|
||||
var OUTFILE = '/tmp/wb.xlsx';
|
||||
XLSX.writeFile(wb, OUTFILE, wopts);
|
||||
console.log("Results written to " + OUTFILE)
|
42
example3.js
Normal file
42
example3.js
Normal file
@ -0,0 +1,42 @@
|
||||
var XLSX = require('./');
|
||||
|
||||
var wb = {};
|
||||
wb.Sheets = {};
|
||||
wb.Props = {};
|
||||
wb.SSF = {};
|
||||
wb.SheetNames = [];
|
||||
|
||||
var ws = {
|
||||
"!cols": []
|
||||
};
|
||||
|
||||
var range = {
|
||||
s: {c: 0, r: 0},
|
||||
e: {c: 0, r: 0}
|
||||
};
|
||||
|
||||
var cell;
|
||||
for (var r = 0; r < 6; r++) {
|
||||
ws["!cols"].push({wch: 6});
|
||||
if (range.e.r < r + 1) range.e.r = r + 1;
|
||||
for (var c = 0; c < 6; c++) {
|
||||
if (range.e.c < c) range.e.c = c;
|
||||
cell_ref = XLSX.utils.encode_cell({c: c, r: r});
|
||||
cell = {v: cell_ref};
|
||||
ws[cell_ref] = cell;
|
||||
}
|
||||
}
|
||||
|
||||
ws["!ref"] = XLSX.utils.encode_range(range);
|
||||
wb.SheetNames.push("Sheet1");
|
||||
wb.Sheets["Sheet1"] = ws;
|
||||
wb.SheetNames.push("Sheet2");
|
||||
wb.Sheets["Sheet2"] = JSON.parse(JSON.stringify(ws))
|
||||
// workbook options
|
||||
var wopts = {bookType: "xlsx"};
|
||||
|
||||
|
||||
//console.log(JSON.stringify(wb, null,4))
|
||||
var OUTFILE = '/tmp/example.xlsx';
|
||||
XLSX.writeFile(wb, OUTFILE, wopts);
|
||||
console.log("Results written to " + OUTFILE)
|
10
package.json
10
package.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.8.0",
|
||||
"name": "xlsx-style",
|
||||
"version": "0.8.11",
|
||||
"author": "sheetjs",
|
||||
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS spreadsheet parser and writer",
|
||||
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS spreadsheet parser and writer (extended to enable read/write of cell formats with xlsx files)",
|
||||
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
|
||||
"bin": {
|
||||
"xlsx": "./bin/xlsx.njs"
|
||||
@ -23,7 +23,7 @@
|
||||
"xlsjs":"",
|
||||
"uglify-js":""
|
||||
},
|
||||
"repository": { "type":"git", "url":"git://github.com/SheetJS/js-xlsx.git" },
|
||||
"repository": { "type":"git", "url":"git://github.com/protobi/js-xlsx.git#beta" },
|
||||
"scripts": {
|
||||
"pretest": "git submodule init && git submodule update",
|
||||
"test": "make test"
|
||||
@ -33,7 +33,7 @@
|
||||
"pattern": "xlsx.js"
|
||||
}
|
||||
},
|
||||
"bugs": { "url": "https://github.com/SheetJS/js-xlsx/issues" },
|
||||
"bugs": { "url": "https://github.com/protobi/js-xlsx/issues" },
|
||||
"license": "Apache-2.0",
|
||||
"engines": { "node": ">=0.8" }
|
||||
}
|
||||
|
715
tests/test-ampersand.js
Normal file
715
tests/test-ampersand.js
Normal file
@ -0,0 +1,715 @@
|
||||
var XLSX = require('../.');
|
||||
|
||||
var JSZip = require('jszip');
|
||||
var fs = require('fs');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
function JSDateToExcelDate(inDate) {
|
||||
return 25569.0 + ((inDate.getTime() - (inDate.getTimezoneOffset() * 60 * 1000)) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
var defaultCellStyle = { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}};
|
||||
|
||||
// test to see if everything on the left equals its counterpart on the right
|
||||
// but the right hand object may have other attributes which we might not care about
|
||||
function basicallyEquals(left, right) {
|
||||
if (Array.isArray(left) && Array.isArray(right)) {
|
||||
for (var i=0; i<left.length; i++) {
|
||||
if (!basicallyEquals(left[i], right[i] )) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (typeof left == 'object' && typeof right == 'object') {
|
||||
for (var key in left) {
|
||||
if (key != 'bgColor') {
|
||||
if (!basicallyEquals(left[key], right[key] )) {
|
||||
if (JSON.stringify(left[key])=="{}" && right[key] == undefined) return true;
|
||||
if (JSON.stringify(right[key])=="{}" && left[key] == undefined) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (left != right) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
describe('styles with blank cells', function () {
|
||||
it ('retains styles with blank cells', function() {
|
||||
|
||||
|
||||
var OUTFILE = '/tmp/ex1.xlsx';
|
||||
var OUTFILE2 = '/tmp/ex1a.xlsx';
|
||||
|
||||
var workbook = {
|
||||
SheetNames : ["Sheet1"],
|
||||
Sheets: {
|
||||
"Sheet1": {
|
||||
"B2": {v: "Top left", s: { border: { top: { style: 'medium', color: { rgb: "FFFFAA00"}}, left: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"C2": {v: "Top right", s: { border: { top: { style: 'medium', color: { rgb: "FFFFAA00"}}, right: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"B3": {v: "Bottom left", s: { border: { bottom: { style: 'medium', color: { rgb: "FFFFAA00"}}, left: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"C3": {v: "", s: { border: { bottom: { style: 'medium', color: { rgb: "FFFFAA00"}}, right: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"!ref":"B2:C3"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// write the file and read it back...
|
||||
XLSX.writeFile(workbook, OUTFILE, {bookType: 'xlsx', bookSST: false});
|
||||
var workbook2 = XLSX.readFile(OUTFILE, {cellStyles: true});
|
||||
assert(basicallyEquals(workbook.Sheets, workbook2.Sheets));
|
||||
|
||||
XLSX.writeFile(workbook2, OUTFILE2, {bookType: 'xlsx', bookSST: false});
|
||||
var workbook3 = XLSX.readFile(OUTFILE2, {cellStyles: true});
|
||||
assert(basicallyEquals(workbook.Sheets, workbook3.Sheets))
|
||||
});
|
||||
});
|
||||
|
||||
describe("Export styles", function () {
|
||||
var workbook, wbout, wbin;
|
||||
|
||||
before(function () {
|
||||
workbook = {
|
||||
"SheetNames": [
|
||||
"Main"
|
||||
],
|
||||
"Sheets": {
|
||||
"Main": {
|
||||
"!merges": [
|
||||
{
|
||||
"s": {
|
||||
"c": 0,
|
||||
"r": 0
|
||||
},
|
||||
"e": {
|
||||
"c": 2,
|
||||
"r": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"A1": {
|
||||
"v": "This is a submerged cell",
|
||||
"s": {
|
||||
"border": {
|
||||
"left": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B1": {
|
||||
"v": "Pirate ship",
|
||||
"s": {
|
||||
"border": {
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C1": {
|
||||
"v": "Sunken treasure",
|
||||
"s": {
|
||||
"border": {
|
||||
"right": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A2": {
|
||||
"v": "Blank",
|
||||
"t": "s"
|
||||
},
|
||||
"B2": {
|
||||
"v": "Red",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFF0000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C2": {
|
||||
"v": "Green",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FF00FF00"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D2": {
|
||||
"v": "Blue",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FF0000FF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E2": {
|
||||
"v": "Theme 5",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"theme": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"F2": {
|
||||
"v": "Theme 5 Tint -0.5",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"theme": 5,
|
||||
"tint": -0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A3": {
|
||||
"v": "Default",
|
||||
"t": "s"
|
||||
},
|
||||
"B3": {
|
||||
"v": "Arial",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Arial",
|
||||
"sz": 24,
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C3": {
|
||||
"v": "Times New Roman",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Times New Roman",
|
||||
bold:true,
|
||||
underline: true,
|
||||
italic: true,
|
||||
strike: true,
|
||||
outline: true,
|
||||
shadow: true,
|
||||
vertAlign: "superscript",
|
||||
"sz": 16,
|
||||
"color": {
|
||||
"rgb": "FF2222FF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D3": {
|
||||
"v": "Courier New",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Courier New",
|
||||
"sz": 14
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"B4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"C4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"D4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%"
|
||||
}
|
||||
},
|
||||
"E4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%",
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFFCC00"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"A5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0%"
|
||||
}
|
||||
},
|
||||
"B5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.0%"
|
||||
}
|
||||
},
|
||||
"C5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%"
|
||||
}
|
||||
},
|
||||
"D5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.000%"
|
||||
}
|
||||
},
|
||||
"E5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.0000%"
|
||||
}
|
||||
},
|
||||
"F5": {
|
||||
"v": 0,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%;\\(0.00%\\);\\-;@",
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFFCC00"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"A6": {
|
||||
"v": "Sat Mar 21 2015 23:47:34 GMT-0400 (EDT)",
|
||||
"t": "s"
|
||||
},
|
||||
"B6": {
|
||||
"v": 42084.99137416667,
|
||||
"t": "n"
|
||||
},
|
||||
"C6": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "d-mmm-yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"A7": {
|
||||
"v": "left",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "left"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B7": {
|
||||
"v": "center",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "center"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C7": {
|
||||
"v": "right",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "right"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "top"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "center"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "bottom"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "1"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "2"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "3"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A10": {
|
||||
"v": "In publishing and graphic design, lorem ipsum is a filler text commonly used to demonstrate the graphic elements of a document or visual presentation. ",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"wrapText": 1,
|
||||
"horizontal": "right",
|
||||
"vertical": "center",
|
||||
"indent": 1
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"B11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "d-mmm-yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"C11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "h:mm:ss AM/PM"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"D11": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"E11": {
|
||||
"v": 42065.02247239584,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"F11": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy h:mm:ss AM/PM"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"A12": {
|
||||
"v": "Apple",
|
||||
"s": {
|
||||
"border": {
|
||||
"top": {
|
||||
"style": "thin"
|
||||
},
|
||||
"left": {
|
||||
"style": "thin"
|
||||
},
|
||||
"right": {
|
||||
"style": "thin"
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C12": {
|
||||
"v": "Apple",
|
||||
"s": {
|
||||
"border": {
|
||||
"diagonalUp": 1,
|
||||
"diagonalDown": 1,
|
||||
"top": {
|
||||
"style": "dashed",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"style": "medium",
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "hair",
|
||||
"color": {
|
||||
"theme": 5,
|
||||
"tint": "-0.3"
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"style": "thin",
|
||||
"color": {
|
||||
"rgb": "FFFFAA00"
|
||||
}
|
||||
},
|
||||
"diagonal": {
|
||||
"style": "dotted",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E12": {
|
||||
"v": "Pear",
|
||||
"s": {
|
||||
"border": {
|
||||
"diagonalUp": 1,
|
||||
"diagonalDown": 1,
|
||||
"top": {
|
||||
"style": "dashed",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"style": "dotted",
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "mediumDashed",
|
||||
"color": {
|
||||
"theme": 5,
|
||||
"tint": "-0.3"
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"style": "double",
|
||||
"color": {
|
||||
"rgb": "FFFFAA00"
|
||||
}
|
||||
},
|
||||
"diagonal": {
|
||||
"style": "hair",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A13": {
|
||||
"v": "Up 90",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 90
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B13": {
|
||||
"v": "Up 45",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 45
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C13": {
|
||||
"v": "Horizontal",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 0
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D13": {
|
||||
"v": "Down 45",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 135
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E13": {
|
||||
"v": "Down 90",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 180
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"F13": {
|
||||
"v": "Vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 255
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A14": {
|
||||
"v": "Font color test",
|
||||
"s": {
|
||||
"font": {
|
||||
"color": {
|
||||
"rgb": "FFC6EFCE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"!ref": "A1:F14"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it('can write to a file and read the file back', function () {
|
||||
XLSX.writeFile(workbook, '/tmp/wb.xlsx', { defaultCellStyle: defaultCellStyle });
|
||||
var wb1 = XLSX.readFile('/tmp/wb.xlsx', {type: "xlsx", cellStyles: true, cellNF: true, WTF:true});
|
||||
assert(basicallyEquals(workbook.Sheets.Main,wb1.Sheets.Main));
|
||||
});
|
||||
|
||||
it('can write to a buffer and read the file back', function () {
|
||||
var wb2 = XLSX.read(XLSX.write(workbook, {type:"buffer", bookType: 'xlsx'}), {cellStyles: true, cellNF: true})
|
||||
XLSX.writeFile(wb2, '/tmp/wb2.xlsx', { defaultCellStyle: defaultCellStyle });
|
||||
assert(basicallyEquals(workbook.Sheets.Main,wb2.Sheets.Main));
|
||||
});
|
||||
|
||||
it('should edit style of one cell without applie modification on other cell', function () {
|
||||
var wb2 = XLSX.read(XLSX.write(workbook, {type:"buffer", bookType: 'xlsx'}), {cellStyles: true, cellNF: true})
|
||||
|
||||
var A6s = wb2.Sheets.Main.A6.s;
|
||||
var B6s = wb2.Sheets.Main.B6.s;
|
||||
|
||||
Object.keys(A6s).forEach(function(key) {
|
||||
if(A6s[key])
|
||||
assert(A6s[key] !== B6s[key]);
|
||||
});
|
||||
|
||||
assert(A6s.border.top === undefined);
|
||||
assert(B6s.border.top === undefined);
|
||||
|
||||
A6s.border.top = {};
|
||||
assert(B6s.border.top === undefined);
|
||||
|
||||
XLSX.writeFile(wb2, '/tmp/wb2.xlsx', { defaultCellStyle: defaultCellStyle });
|
||||
assert(basicallyEquals(workbook.Sheets.Main,wb2.Sheets.Main));
|
||||
});
|
||||
|
||||
});
|
||||
|
715
tests/test-freeze.js
Normal file
715
tests/test-freeze.js
Normal file
@ -0,0 +1,715 @@
|
||||
var XLSX = require('../.');
|
||||
|
||||
var JSZip = require('jszip');
|
||||
var fs = require('fs');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
function JSDateToExcelDate(inDate) {
|
||||
return 25569.0 + ((inDate.getTime() - (inDate.getTimezoneOffset() * 60 * 1000)) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
var defaultCellStyle = { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}};
|
||||
|
||||
// test to see if everything on the left equals its counterpart on the right
|
||||
// but the right hand object may have other attributes which we might not care about
|
||||
function basicallyEquals(left, right) {
|
||||
if (Array.isArray(left) && Array.isArray(right)) {
|
||||
for (var i=0; i<left.length; i++) {
|
||||
if (!basicallyEquals(left[i], right[i] )) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (typeof left == 'object' && typeof right == 'object') {
|
||||
for (var key in left) {
|
||||
if (key != 'bgColor') {
|
||||
if (!basicallyEquals(left[key], right[key] )) {
|
||||
if (JSON.stringify(left[key])=="{}" && right[key] == undefined) return true;
|
||||
if (JSON.stringify(right[key])=="{}" && left[key] == undefined) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (left != right) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
describe('styles with blank cells', function () {
|
||||
it ('retains styles with blank cells', function() {
|
||||
|
||||
|
||||
var OUTFILE = '/tmp/ex1.xlsx';
|
||||
var OUTFILE2 = '/tmp/ex1a.xlsx';
|
||||
|
||||
var workbook = {
|
||||
SheetNames : ["Sheet1"],
|
||||
Sheets: {
|
||||
"Sheet1": {
|
||||
"B2": {v: "Top left", s: { border: { top: { style: 'medium', color: { rgb: "FFFFAA00"}}, left: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"C2": {v: "Top right", s: { border: { top: { style: 'medium', color: { rgb: "FFFFAA00"}}, right: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"B3": {v: "Bottom left", s: { border: { bottom: { style: 'medium', color: { rgb: "FFFFAA00"}}, left: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"C3": {v: "", s: { border: { bottom: { style: 'medium', color: { rgb: "FFFFAA00"}}, right: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
"!ref":"B2:C3"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// write the file and read it back...
|
||||
XLSX.writeFile(workbook, OUTFILE, {bookType: 'xlsx', bookSST: false});
|
||||
var workbook2 = XLSX.readFile(OUTFILE, {cellStyles: true});
|
||||
assert(basicallyEquals(workbook.Sheets, workbook2.Sheets));
|
||||
|
||||
XLSX.writeFile(workbook2, OUTFILE2, {bookType: 'xlsx', bookSST: false});
|
||||
var workbook3 = XLSX.readFile(OUTFILE2, {cellStyles: true});
|
||||
assert(basicallyEquals(workbook.Sheets, workbook3.Sheets))
|
||||
});
|
||||
});
|
||||
|
||||
describe("Export styles", function () {
|
||||
var workbook, wbout, wbin;
|
||||
|
||||
before(function () {
|
||||
workbook = {
|
||||
"SheetNames": [
|
||||
"Main"
|
||||
],
|
||||
"Sheets": {
|
||||
"Main": {
|
||||
"!merges": [
|
||||
{
|
||||
"s": {
|
||||
"c": 0,
|
||||
"r": 0
|
||||
},
|
||||
"e": {
|
||||
"c": 2,
|
||||
"r": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"A1": {
|
||||
"v": "This is a submerged cell",
|
||||
"s": {
|
||||
"border": {
|
||||
"left": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B1": {
|
||||
"v": "Pirate ship",
|
||||
"s": {
|
||||
"border": {
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C1": {
|
||||
"v": "Sunken treasure",
|
||||
"s": {
|
||||
"border": {
|
||||
"right": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"top": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thick",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A2": {
|
||||
"v": "Blank",
|
||||
"t": "s"
|
||||
},
|
||||
"B2": {
|
||||
"v": "Red",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFF0000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C2": {
|
||||
"v": "Green",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FF00FF00"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D2": {
|
||||
"v": "Blue",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FF0000FF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E2": {
|
||||
"v": "Theme 5",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"theme": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"F2": {
|
||||
"v": "Theme 5 Tint -0.5",
|
||||
"s": {
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"theme": 5,
|
||||
"tint": -0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A3": {
|
||||
"v": "Default",
|
||||
"t": "s"
|
||||
},
|
||||
"B3": {
|
||||
"v": "Arial",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Arial",
|
||||
"sz": 24,
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C3": {
|
||||
"v": "Times New Roman",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Times New Roman",
|
||||
bold:true,
|
||||
underline: true,
|
||||
italic: true,
|
||||
strike: true,
|
||||
outline: true,
|
||||
shadow: true,
|
||||
vertAlign: "superscript",
|
||||
"sz": 16,
|
||||
"color": {
|
||||
"rgb": "FF2222FF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D3": {
|
||||
"v": "Courier New",
|
||||
"s": {
|
||||
"font": {
|
||||
"name": "Courier New",
|
||||
"sz": 14
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"B4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"C4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n"
|
||||
},
|
||||
"D4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%"
|
||||
}
|
||||
},
|
||||
"E4": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%",
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFFCC00"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"A5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0%"
|
||||
}
|
||||
},
|
||||
"B5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.0%"
|
||||
}
|
||||
},
|
||||
"C5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%"
|
||||
}
|
||||
},
|
||||
"D5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.000%"
|
||||
}
|
||||
},
|
||||
"E5": {
|
||||
"v": 0.618033989,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.0000%"
|
||||
}
|
||||
},
|
||||
"F5": {
|
||||
"v": 0,
|
||||
"t": "n",
|
||||
"s": {
|
||||
"numFmt": "0.00%;\\(0.00%\\);\\-;@",
|
||||
"fill": {
|
||||
"fgColor": {
|
||||
"rgb": "FFFFCC00"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"A6": {
|
||||
"v": "Sat Mar 21 2015 23:47:34 GMT-0400 (EDT)",
|
||||
"t": "s"
|
||||
},
|
||||
"B6": {
|
||||
"v": 42084.99137416667,
|
||||
"t": "n"
|
||||
},
|
||||
"C6": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "d-mmm-yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"A7": {
|
||||
"v": "left",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "left"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B7": {
|
||||
"v": "center",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "center"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C7": {
|
||||
"v": "right",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"horizontal": "right"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "top"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "center"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C8": {
|
||||
"v": "vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"vertical": "bottom"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "1"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "2"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C9": {
|
||||
"v": "indent",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"indent": "3"
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A10": {
|
||||
"v": "In publishing and graphic design, lorem ipsum is a filler text commonly used to demonstrate the graphic elements of a document or visual presentation. ",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"wrapText": 1,
|
||||
"horizontal": "right",
|
||||
"vertical": "center",
|
||||
"indent": 1
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"B11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "d-mmm-yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"C11": {
|
||||
"v": 41684.35264774306,
|
||||
"s": {
|
||||
"numFmt": "h:mm:ss AM/PM"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"D11": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"E11": {
|
||||
"v": 42065.02247239584,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"F11": {
|
||||
"v": 42084.99137416667,
|
||||
"s": {
|
||||
"numFmt": "m/d/yy h:mm:ss AM/PM"
|
||||
},
|
||||
"t": "n"
|
||||
},
|
||||
"A12": {
|
||||
"v": "Apple",
|
||||
"s": {
|
||||
"border": {
|
||||
"top": {
|
||||
"style": "thin"
|
||||
},
|
||||
"left": {
|
||||
"style": "thin"
|
||||
},
|
||||
"right": {
|
||||
"style": "thin"
|
||||
},
|
||||
"bottom": {
|
||||
"style": "thin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C12": {
|
||||
"v": "Apple",
|
||||
"s": {
|
||||
"border": {
|
||||
"diagonalUp": 1,
|
||||
"diagonalDown": 1,
|
||||
"top": {
|
||||
"style": "dashed",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"style": "medium",
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "hair",
|
||||
"color": {
|
||||
"theme": 5,
|
||||
"tint": "-0.3"
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"style": "thin",
|
||||
"color": {
|
||||
"rgb": "FFFFAA00"
|
||||
}
|
||||
},
|
||||
"diagonal": {
|
||||
"style": "dotted",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E12": {
|
||||
"v": "Pear",
|
||||
"s": {
|
||||
"border": {
|
||||
"diagonalUp": 1,
|
||||
"diagonalDown": 1,
|
||||
"top": {
|
||||
"style": "dashed",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
},
|
||||
"right": {
|
||||
"style": "dotted",
|
||||
"color": {
|
||||
"theme": "5"
|
||||
}
|
||||
},
|
||||
"bottom": {
|
||||
"style": "mediumDashed",
|
||||
"color": {
|
||||
"theme": 5,
|
||||
"tint": "-0.3"
|
||||
}
|
||||
},
|
||||
"left": {
|
||||
"style": "double",
|
||||
"color": {
|
||||
"rgb": "FFFFAA00"
|
||||
}
|
||||
},
|
||||
"diagonal": {
|
||||
"style": "hair",
|
||||
"color": {
|
||||
"auto": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A13": {
|
||||
"v": "Up 90",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 90
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"B13": {
|
||||
"v": "Up 45",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 45
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"C13": {
|
||||
"v": "Horizontal",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 0
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"D13": {
|
||||
"v": "Down 45",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 135
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"E13": {
|
||||
"v": "Down 90",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 180
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"F13": {
|
||||
"v": "Vertical",
|
||||
"s": {
|
||||
"alignment": {
|
||||
"textRotation": 255
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"A14": {
|
||||
"v": "Font color test",
|
||||
"s": {
|
||||
"font": {
|
||||
"color": {
|
||||
"rgb": "FFC6EFCE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": "s"
|
||||
},
|
||||
"!ref": "A1:F14"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it('can write to a file and read the file back', function () {
|
||||
XLSX.writeFile(workbook, '/tmp/wb.xlsx', { defaultCellStyle: defaultCellStyle });
|
||||
var wb1 = XLSX.readFile('/tmp/wb.xlsx', {type: "xlsx", cellStyles: true, cellNF: true, WTF:true});
|
||||
assert(basicallyEquals(workbook.Sheets.Main,wb1.Sheets.Main));
|
||||
});
|
||||
|
||||
it('can write to a buffer and read the file back', function () {
|
||||
var wb2 = XLSX.read(XLSX.write(workbook, {type:"buffer", bookType: 'xlsx'}), {cellStyles: true, cellNF: true})
|
||||
XLSX.writeFile(wb2, '/tmp/wb2.xlsx', { defaultCellStyle: defaultCellStyle });
|
||||
assert(basicallyEquals(workbook.Sheets.Main,wb2.Sheets.Main));
|
||||
});
|
||||
|
||||
it('should edit style of one cell without applie modification on other cell', function () {
|
||||
var wb2 = XLSX.read(XLSX.write(workbook, {type:"buffer", bookType: 'xlsx'}), {cellStyles: true, cellNF: true})
|
||||
|
||||
var A6s = wb2.Sheets.Main.A6.s;
|
||||
var B6s = wb2.Sheets.Main.B6.s;
|
||||
|
||||
Object.keys(A6s).forEach(function(key) {
|
||||
if(A6s[key])
|
||||
assert(A6s[key] !== B6s[key]);
|
||||
});
|
||||
|
||||
assert(A6s.border.top === undefined);
|
||||
assert(B6s.border.top === undefined);
|
||||
|
||||
A6s.border.top = {};
|
||||
assert(B6s.border.top === undefined);
|
||||
|
||||
XLSX.writeFile(wb2, '/tmp/wb2.xlsx', { defaultCellStyle: defaultCellStyle });
|
||||
assert(basicallyEquals(workbook.Sheets.Main,wb2.Sheets.Main));
|
||||
});
|
||||
|
||||
});
|
||||
|
98
tests/test-header.js
Normal file
98
tests/test-header.js
Normal file
@ -0,0 +1,98 @@
|
||||
var XLSX = require('../.');
|
||||
|
||||
var JSZip = require('jszip');
|
||||
var fs = require('fs');
|
||||
var cheerio = require('cheerio');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
function JSDateToExcelDate(inDate) {
|
||||
return 25569.0 + ((inDate.getTime() - (inDate.getTimezoneOffset() * 60 * 1000)) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
var defaultCellStyle = { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}};
|
||||
//"A1": {v: "Header", s: { border: { top: { style: 'medium', color: { rgb: "FFFFAA00"}}, left: { style: 'medium', color: { rgb: "FFFFAA00"}} }}},
|
||||
|
||||
|
||||
var workbook = {
|
||||
SheetNames : ["Sheet1"],
|
||||
Sheets: {
|
||||
"Sheet1": {
|
||||
"A1": {v: "Header"},
|
||||
"A2": {v: "Anchorage"},
|
||||
"A3": {v: "Anchorage"},
|
||||
"A4": {v: "Boston"},
|
||||
"A5": {v: "Chicago"},
|
||||
"A6": {v: "Dayton"},
|
||||
"A7": {v: "East Lansing"},
|
||||
"A8": {v: "Fargo"},
|
||||
"A9": {v: "Galena"},
|
||||
"A10": {v: "Iowa City"},
|
||||
"A11": {v: "Jacksonville"},
|
||||
"A12": {v: "Jacksonville"},
|
||||
"A13": {v: "Jacksonville"},
|
||||
"A14": {v: "Jacksonville"},
|
||||
"A15": {v: "Jacksonville"},
|
||||
"A16": {v: "Jacksonville"},
|
||||
"A17": {v: "Jacksonville"},
|
||||
"A18": {v: "Jacksonville"},
|
||||
"A19": {v: "Jacksonville"},
|
||||
"A20": {v: "Jacksonville"},
|
||||
"A21": {v: "Jacksonville"},
|
||||
"A22": {v: "Jacksonville"},
|
||||
"A23": {v: "Jacksonville"},
|
||||
"A24": {v: "Jacksonville"},
|
||||
"A25": {v: "Jacksonville"},
|
||||
"A26": {v: "Jacksonville"},
|
||||
"A27": {v: "Jacksonville"},
|
||||
"A28": {v: "Jacksonville"},
|
||||
"A29": {v: "Jacksonville"},
|
||||
"A30": {v: "Jacksonville"},
|
||||
"A31": {v: "Jacksonville"},
|
||||
"A32": {v: "Jacksonville"},
|
||||
"A33": {v: "Jacksonville"},
|
||||
"A34": {v: "Jacksonville"},
|
||||
"A35": {v: "Jacksonville"},
|
||||
"A36": {v: "Jacksonville"},
|
||||
"A37": {v: "Jacksonville"},
|
||||
"A38": {v: "Jacksonville"},
|
||||
"A39": {v: "Jacksonville"},
|
||||
"A40": {v: "Jacksonville"},
|
||||
"A41": {v: "Jacksonville"},
|
||||
"A42": {v: "Jacksonville"},
|
||||
"A43": {v: "Jacksonville"},
|
||||
"A44": {v: "Jacksonville"},
|
||||
"A45": {v: "Jacksonville"},
|
||||
"A46": {v: "Jacksonville"},
|
||||
"A47": {v: "Jacksonville"},
|
||||
"A48": {v: "Jacksonville"},
|
||||
"A49": {v: "Jacksonville"},
|
||||
"A50": {v: "Jacksonville"},
|
||||
"A51": {v: "Jacksonville"},
|
||||
"A52": {v: "Jacksonville"},
|
||||
"A53": {v: "Jacksonville"},
|
||||
"A54": {v: "Jacksonville"},
|
||||
"A55": {v: "Jacksonville"},
|
||||
"A56": {v: "Jacksonville"},
|
||||
"A57": {v: "Jacksonville"},
|
||||
"A58": {v: "Jacksonville"},
|
||||
"A59": {v: "Jacksonville"},
|
||||
"!ref":"A1:A59",
|
||||
"!printHeader":[1,1]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe('repeats header', function () {
|
||||
it ('repeats header', function() {
|
||||
|
||||
|
||||
var OUTFILE = '/tmp/header.xlsx';
|
||||
|
||||
|
||||
// write the file and read it back...
|
||||
XLSX.writeFile(workbook, OUTFILE, {bookType: 'xlsx', bookSST: false});
|
||||
console.log("open \""+OUTFILE+"\"")
|
||||
});
|
||||
});
|
||||
|
62
xlsx.js
62
xlsx.js
@ -4,7 +4,7 @@
|
||||
/*jshint funcscope:true, eqnull:true */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.8.0';
|
||||
XLSX.version = '0.8.11';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
@ -7609,20 +7609,9 @@ function write_ws_xml_pagesetup(setup) {
|
||||
horizontalDpi : setup.horizontalDpi || '4294967292',
|
||||
verticalDpi : setup.verticalDpi || '4294967292'
|
||||
})
|
||||
console.log(pageSetup);
|
||||
return pageSetup;
|
||||
}
|
||||
|
||||
//<pageSetup scale="90" orientation="portrait" horizontalDpi="4294967292" verticalDpi="4294967292"/>
|
||||
//<rowBreaks count="1" manualBreakCount="1">
|
||||
// <brk id="8" max="16383" man="1"/>
|
||||
//</rowBreaks>
|
||||
//<colBreaks count="1" manualBreakCount="1">
|
||||
// <brk id="8" max="1048575" man="1"/>
|
||||
//</colBreaks>
|
||||
|
||||
|
||||
|
||||
|
||||
function parse_ws_xml_hlinks(s, data, rels) {
|
||||
for(var i = 0; i != data.length; ++i) {
|
||||
@ -7852,7 +7841,7 @@ function write_ws_xml(idx, opts, wb) {
|
||||
|
||||
var sheetView = writextag('sheetView', null, {
|
||||
showGridLines: opts.showGridLines == false ? '0' : '1',
|
||||
tabSelected: opts.tabSelected === undefined ? '0' : opts.tabSelected, // see issue #26, need to set WorkbookViews if this is set
|
||||
tabSelected: opts.tabSelected === undefined ? '0' : opts.tabSelected,
|
||||
workbookViewId: opts.workbookViewId === undefined ? '0' : opts.workbookViewId
|
||||
});
|
||||
o[o.length] = writextag('sheetViews', sheetView);
|
||||
@ -7867,10 +7856,9 @@ function write_ws_xml(idx, opts, wb) {
|
||||
|
||||
if(ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
|
||||
|
||||
if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup'])
|
||||
if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks'])
|
||||
if (ws['!colBreaks'] !== undefined) o[o.length] = write_ws_xml_col_breaks(ws['!colBreaks'])
|
||||
|
||||
if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup']);
|
||||
if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks']);
|
||||
if (ws['!colBreaks'] !== undefined) o[o.length] = write_ws_xml_col_breaks(ws['!colBreaks']);
|
||||
|
||||
if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
@ -8571,6 +8559,44 @@ function write_wb_xml(wb, opts) {
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i)
|
||||
o[o.length] = (writextag('sheet',null,{name:wb.SheetNames[i].substr(0,31), sheetId:""+(i+1), "r:id":"rId"+(i+1)}));
|
||||
o[o.length] = "</sheets>";
|
||||
|
||||
var hasPrintHeaders = false;
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) {
|
||||
var sheetName = wb.SheetNames[i];
|
||||
var sheet = wb.Sheets[sheetName]
|
||||
if (sheet['!printHeader']) {
|
||||
if (sheet['!printHeader'].length !== 2) {
|
||||
throw "!printHeaders must be an array of length 2: "+sheet['!printHeader'];
|
||||
|
||||
}
|
||||
hasPrintHeaders = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hasPrintHeaders) {
|
||||
o[o.length] = '<definedNames>';
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) {
|
||||
var sheetName = wb.SheetNames[i];
|
||||
var sheet = wb.Sheets[sheetName]
|
||||
if (sheet['!printHeader'])
|
||||
var range = "'" + sheetName + "'!" + sheet['!printHeader'];
|
||||
console.log("!!!!"+range)
|
||||
o[o.length] = (writextag('definedName', range, {
|
||||
"name":"_xlnm.Print_Titles",
|
||||
localSheetId : ''+i
|
||||
}))
|
||||
}
|
||||
o[o.length] = '</definedNames>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
// <definedNames>
|
||||
// <definedName name="_xlnm.Print_Titles" localSheetId="0">Sheet1!$1:$1</definedName>
|
||||
// <definedName name="_xlnm.Print_Titles" localSheetId="1">Sheet2!$1:$2</definedName>
|
||||
// </definedNames>
|
||||
|
||||
if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
|
||||
return o.join("");
|
||||
}
|
||||
@ -12336,12 +12362,10 @@ var XmlNode = (function () {
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
|
||||
|
||||
var $numFmt = XmlNode('numFmt')
|
||||
.attr('numFmtId', (++customNumFmtId))
|
||||
.attr('formatCode', numFmt);
|
||||
|
||||
|
||||
this.$numFmts.append($numFmt);
|
||||
|
||||
var count = this.$numFmts.children().length;
|
||||
|
Loading…
Reference in New Issue
Block a user