merge from beta
This commit is contained in:
commit
8198744d58
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",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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)
|
||||
|
|
@ -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)
|
|
@ -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" }
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -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));
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -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