Skip to content

Commit e98f511

Browse files
committed
- Add toHtml method to convert data to HTML table format
- Applies `mso-number-format:'\@'` style to cells to prevent Excel from changing formats - Supports configurable table class, cell styling, and header row options - Properly escapes HTML special characters in cell content - Add new format options to `toBlob` and `download` methods: - `format: 'html'` - outputs HTML table with MIME type `text/html` and `.html` extension - `format: 'xls-html'` - outputs HTML table with BOM and MIME type `application/vnd.ms-excel` for Excel compatibility with `.xls` extension - HTML options can be passed via `options.html` object - bump version
1 parent 0fce622 commit e98f511

13 files changed

Lines changed: 313 additions & 85 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Change Logs
22

3+
## v0.4.1
4+
5+
- Add `toHtml` method to convert data to HTML table format
6+
- Applies `mso-number-format:'\@'` style to cells to prevent Excel from changing formats
7+
- Supports configurable table class, cell styling, and header row options
8+
- Properly escapes HTML special characters in cell content
9+
- Add new format options to `toBlob` and `download` methods:
10+
- `format: 'html'` - outputs HTML table with MIME type `text/html` and `.html` extension
11+
- `format: 'xls-html'` - outputs HTML table with BOM and MIME type `application/vnd.ms-excel` for Excel compatibility with `.xls` extension
12+
- HTML options can be passed via `options.html` object
13+
14+
315
## v0.4.0
416

517
- **BREAKING CHANGE**: Add option to choose between comma and tab as delimiter

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,27 @@ csv4xls provides following APIs:
3131
- `toXlsx(data)` - convert given 2D array to XLSX workbook (requires XLSX library).
3232
- `toBlob(data, options = {delimiter: '\t', format: 'auto'})` - convert data to blob with specified format.
3333
- If `format` is `'xlsx'`, returns XLSX blob (requires XLSX library)
34+
- If `format` is `'html'`, returns HTML table as blob with MIME type `text/html`
35+
- If `format` is `'xls-html'`, returns HTML table with BOM as blob with MIME type `application/vnd.ms-excel`
36+
- Uses `mso-number-format:'\@'` style to prevent Excel from changing formats
3437
- If `format` is `'auto'` (default), uses XLSX if available, otherwise falls back to CSV/TSV
3538
- If XLSX is not available or fails, falls back to CSV/TSV based on delimiter
39+
- HTML options can be passed via `options.html` object (see `toHtml` for available options)
3640
- `toHref(data, options = {delimiter: '\t', format: 'auto'})` - same as `toBlob` but return a corresponding object url.
41+
- `toHtml(data, options = {})` - convert given 2D array to HTML table format.
42+
- `options.tableClass` - CSS class for the table (default: 'csv4xls-table')
43+
- `options.cellStyle` - Whether to apply `mso-number-format:'\@'` style to cells to prevent Excel from changing formats (default: true)
44+
- `options.headerRow` - Whether to treat the first row as a header row using `<th>` tags (default: false)
3745
- `download(data, name = "data", options = {delimiter: '\t', format: 'auto'})` - trigger file download
3846
- If `format` is `'xlsx'`, file extension will be `.xlsx` (requires XLSX library)
47+
- If `format` is `'html'`, file extension will be `.html`
48+
- If `format` is `'xls-html'`, file extension will be `.xls` (HTML with BOM that Excel can open)
3949
- If `format` is `'auto'` (default), uses XLSX if available, otherwise falls back to CSV/TSV
4050
- If using CSV/TSV: delimiter `','``.csv`, delimiter `'\t'``.tsv`
4151

4252

4353
## Limitation
54+
4455
- CSV/TSV format only works with Excel if file is opened directly. Doesn't work when importing with text import wizard.
4556
- Default delimiter is tab (`'\t'`), which creates TSV files.
4657
- File extension and MIME type are automatically set based on the format and delimiter:

dist/index.js

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
(function(){
2-
var hasXlsx, obj, csv4xls;
2+
var hasXlsx, parseOption, obj, csv4xls;
33
hasXlsx = function(){
44
var e;
55
try {
@@ -9,6 +9,16 @@
99
return false;
1010
}
1111
};
12+
parseOption = function(opt){
13+
opt == null && (opt = {});
14+
return {
15+
format: opt.format || 'auto',
16+
delimiter: opt.delimiter || ({
17+
csv: ',',
18+
tsv: 't'
19+
}[opt.format] || 't')
20+
};
21+
};
1222
obj = {
1323
toString: function(data, delimiter){
1424
var str;
@@ -49,13 +59,12 @@
4959
return workbook;
5060
},
5161
toBlob: function(data, options){
52-
var delimiter, format, workbook, buffer, e, ba, mimeType;
62+
var ref$, format, delimiter, workbook, buffer, e, html, ba, i$, to$, i, mimeType;
5363
options == null && (options = {
54-
delimiter: '\t',
64+
delimiter: undefined,
5565
format: 'auto'
5666
});
57-
delimiter = options.delimiter || '\t';
58-
format = options.format || 'auto';
67+
ref$ = parseOption(options), format = ref$.format, delimiter = ref$.delimiter;
5968
if (format === 'xlsx' || (format === 'auto' && hasXlsx())) {
6069
try {
6170
workbook = obj.toXlsx(data);
@@ -71,6 +80,26 @@
7180
console.warn("Failed to create XLSX. Falling back to CSV/TSV format.", e);
7281
}
7382
}
83+
if (format === 'html') {
84+
html = obj.toHtml(data, options.html || {});
85+
return new Blob([html], {
86+
type: "text/html"
87+
});
88+
}
89+
if (format === 'xls-html') {
90+
html = obj.toHtml(data, options.html || {});
91+
ba = new Uint8Array(2 + html.length * 2);
92+
ba[0] = 0xff;
93+
ba[1] = 0xfe;
94+
for (i$ = 0, to$ = html.length; i$ < to$; ++i$) {
95+
i = i$;
96+
ba[i * 2 + 2] = html.charCodeAt(i);
97+
ba[i * 2 + 3] = html.charCodeAt(i) >> 8;
98+
}
99+
return new Blob([ba], {
100+
type: "application/vnd.ms-excel"
101+
});
102+
}
74103
ba = obj.toArray(data, delimiter);
75104
mimeType = delimiter === ',' ? "text/csv" : "text/tab-separated-values";
76105
return new Blob([ba], {
@@ -80,35 +109,27 @@
80109
toHref: function(data, options){
81110
var blob;
82111
options == null && (options = {
83-
delimiter: '\t',
112+
delimiter: undefined,
84113
format: 'auto'
85114
});
86115
blob = obj.toBlob(data, options);
87116
return URL.createObjectURL(blob);
88117
},
89118
download: function(data, name, options){
90-
var delimiter, format, extension, e, href, a;
119+
var ref$, format, delimiter, extension, href, a;
91120
name == null && (name = "data");
92121
options == null && (options = {
93-
delimiter: '\t',
122+
delimiter: undefined,
94123
format: 'auto'
95124
});
96-
delimiter = options.delimiter || '\t';
97-
format = options.format || 'auto';
125+
ref$ = parseOption(options), format = ref$.format, delimiter = ref$.delimiter;
98126
extension = format === 'xlsx' || (format === 'auto' && hasXlsx())
99-
? (function(){
100-
try {
101-
return '.xlsx';
102-
} catch (e$) {
103-
e = e$;
104-
if (delimiter === ',') {
105-
return '.csv';
106-
} else {
107-
return '.tsv';
108-
}
109-
}
110-
}())
111-
: delimiter === ',' ? '.csv' : '.tsv';
127+
? '.xlsx'
128+
: format === 'html'
129+
? '.html'
130+
: format === 'xls-html'
131+
? '.xls'
132+
: delimiter === ',' ? '.csv' : '.tsv';
112133
href = this.toHref(data, options);
113134
a = document.createElement('a');
114135
a.setAttribute('href', href);
@@ -118,11 +139,37 @@
118139
document.body.appendChild(a);
119140
a.click();
120141
return document.body.removeChild(a);
142+
},
143+
toHtml: function(data, options){
144+
var opts, html, i$, len$, i, row, isHeader, tag, j$, len1$, cell, style, safeCell;
145+
options == null && (options = {});
146+
opts = {
147+
tableClass: options.tableClass || 'csv4xls-table',
148+
cellStyle: options.cellStyle || true,
149+
headerRow: options.headerRow || false
150+
};
151+
html = "<table class=\"" + opts.tableClass + "\">";
152+
for (i$ = 0, len$ = data.length; i$ < len$; ++i$) {
153+
i = i$;
154+
row = data[i$];
155+
isHeader = opts.headerRow && i === 0;
156+
tag = isHeader ? 'th' : 'td';
157+
html += "<tr>";
158+
for (j$ = 0, len1$ = row.length; j$ < len1$; ++j$) {
159+
cell = row[j$];
160+
style = opts.cellStyle ? ' style="mso-number-format:\'\\@\';"' : '';
161+
safeCell = ('' + cell).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
162+
html += "<" + tag + style + ">" + safeCell + "</" + tag + ">";
163+
}
164+
html += "</tr>";
165+
}
166+
html += "</table>";
167+
return html;
121168
}
122169
};
123170
csv4xls = function(data, options){
124171
options == null && (options = {
125-
delimiter: '\t',
172+
delimiter: undefined,
126173
format: 'auto'
127174
});
128175
return obj.toHref(data, options);

dist/index.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 29 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dist/**/*"
99
],
1010
"description": "csv generator friendly for Microsoft Excel",
11-
"version": "0.4.0",
11+
"version": "0.4.1",
1212
"homepage": "https://github.com/plotdb/csv4xls",
1313
"repository": {
1414
"type": "git",
@@ -19,10 +19,14 @@
1919
},
2020
"devDependencies": {
2121
"@loadingio/bootstrap.ext": "^0.0.12",
22+
"@loadingio/debounce.js": "^1.0.1",
23+
"@loadingio/ldquery": "^3.0.6",
2224
"@zbryikt/template": "^2.4.1",
2325
"bootstrap": "^4.6.1",
2426
"fedep": "^1.4.1",
27+
"ldview": "^1.5.1",
2528
"livescript": ">=1.6.0",
29+
"proxise": "^1.0.1",
2630
"uglify-js": "^3.13.1",
2731
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
2832
},
@@ -31,6 +35,10 @@
3135
"modules": [
3236
"bootstrap",
3337
"@loadingio/bootstrap.ext",
38+
"proxise",
39+
"@loadingio/debounce.js",
40+
"@loadingio/ldquery",
41+
"ldview",
3442
"xlsx"
3543
]
3644
}

0 commit comments

Comments
 (0)