version bump 0.11.19: browser writeFile
- IE6-9 ActiveX + VBScript shim - `writeFile` supported in browser - `oldie` demo for IE write strategies
This commit is contained in:
parent
edf7150ca8
commit
75845a0ca7
@ -36,7 +36,6 @@ CDNjs
|
||||
CommonJS
|
||||
Ethercalc
|
||||
ExtendScript
|
||||
FileSaver
|
||||
IndexedDB
|
||||
JavaScriptCore
|
||||
LocalStorage
|
||||
@ -58,6 +57,7 @@ webpack
|
||||
weex
|
||||
|
||||
# Other terms
|
||||
ActiveX
|
||||
APIs
|
||||
ArrayBuffer
|
||||
Base64
|
||||
@ -66,6 +66,7 @@ JS
|
||||
NoSQL
|
||||
README
|
||||
UTF-16
|
||||
VBScript
|
||||
XHR
|
||||
XMLHttpRequest
|
||||
bundler
|
||||
|
@ -4,6 +4,10 @@ This log is intended to keep track of backwards-incompatible changes, including
|
||||
but not limited to API changes and file location changes. Minor behavioral
|
||||
changes may not be included if they are not expected to break existing code.
|
||||
|
||||
## 0.11.19
|
||||
|
||||
* Error on empty workbook
|
||||
|
||||
## 0.11.16 (2017-12-30)
|
||||
|
||||
* XLS ANSI/CP separation
|
||||
|
94
README.md
94
README.md
@ -215,6 +215,7 @@ The [`demos` directory](demos/) includes sample projects for:
|
||||
- [`Headless Browsers`](demos/headless/)
|
||||
- [`canvas-datagrid`](demos/datagrid/)
|
||||
- [`Swift JSC and other engines`](demos/altjs/)
|
||||
- [`internet explorer`](demos/oldie/)
|
||||
|
||||
### Optional Modules
|
||||
|
||||
@ -339,7 +340,7 @@ var worksheet = XLSX.read(htmlstr, {type:'string'});
|
||||
<summary><b>Browser download file (ajax)</b> (click to show)</summary>
|
||||
|
||||
Note: for a more complete example that works in older browsers, check the demo
|
||||
at <http://oss.sheetjs.com/js-xlsx/ajax.html>). The <demos/xhr/> directory also
|
||||
at <http://oss.sheetjs.com/js-xlsx/ajax.html>). The [`xhr` demo](demos/xhr/)
|
||||
includes more examples with `XMLHttpRequest` and `fetch`.
|
||||
|
||||
```js
|
||||
@ -414,6 +415,8 @@ input_dom_element.addEventListener('change', handleFile, false);
|
||||
|
||||
</details>
|
||||
|
||||
More specialized cases, including mobile app file processing, are covered in the
|
||||
[included demos](demos/)
|
||||
|
||||
### Parsing Examples
|
||||
|
||||
@ -590,8 +593,7 @@ Assuming `workbook` is a workbook object:
|
||||
<details>
|
||||
<summary><b>nodejs write a file</b> (click to show)</summary>
|
||||
|
||||
`writeFile` is only available in server environments. Browsers have no API for
|
||||
writing arbitrary files given a path, so another strategy must be used.
|
||||
`XLSX.writeFile` uses `fs.writeFileSync` in server environments:
|
||||
|
||||
```js
|
||||
if(typeof require !== 'undefined') XLSX = require('xlsx');
|
||||
@ -603,7 +605,7 @@ XLSX.writeFile(workbook, 'out.xlsb');
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Browser add to web page</b> (click to show)</summary>
|
||||
<summary><b>Browser add TABLE element to page</b> (click to show)</summary>
|
||||
|
||||
The `sheet_to_html` utility function generates HTML code that can be added to
|
||||
any DOM element.
|
||||
@ -614,29 +616,10 @@ var container = document.getElementById('tableau');
|
||||
container.innerHTML = XLSX.utils.sheet_to_html(worksheet);
|
||||
```
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Browser save file</b> (click to show)</summary>
|
||||
|
||||
Note: browser generates binary blob and forces a "download" to client. This
|
||||
example uses [FileSaver](https://github.com/eligrey/FileSaver.js/):
|
||||
|
||||
```js
|
||||
/* bookType can be any supported output type */
|
||||
var wopts = { bookType:'xlsx', bookSST:false, type:'array' };
|
||||
|
||||
var wbout = XLSX.write(workbook,wopts);
|
||||
|
||||
/* the saveAs call downloads a file on the local machine */
|
||||
saveAs(new Blob([wbout],{type:"application/octet-stream"}), "test.xlsx");
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Browser upload to server</b> (click to show)</summary>
|
||||
<summary><b>Browser upload file (ajax)</b> (click to show)</summary>
|
||||
|
||||
A complete example using XHR is [included in the XHR demo](demos/xhr/), along
|
||||
with examples for fetch and wrapper libraries. This example assumes the server
|
||||
@ -658,6 +641,65 @@ req.send(formdata);
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Browser save file</b> (click to show)</summary>
|
||||
|
||||
`XLSX.writeFile` wraps a few techniques for triggering a file save:
|
||||
|
||||
- `URL` browser API creates an object URL for the file, which the library uses
|
||||
by creating a link and forcing a click. It is supported in modern browsers.
|
||||
- `msSaveBlob` is an IE10+ API for triggering a file save.
|
||||
- `IE_FileSave` uses VBScript and ActiveX to write a file in IE6+ for Windows
|
||||
XP and Windows 7. The shim must be included in the containing HTML page.
|
||||
|
||||
There is no standard way to determine if the actual file has been downloaded.
|
||||
|
||||
```js
|
||||
/* output format determined by filename */
|
||||
XLSX.writeFile(workbook, 'out.xlsb');
|
||||
/* at this point, out.xlsb will have been downloaded */
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Browser save file (compatibility)</b> (click to show)</summary>
|
||||
|
||||
`XLSX.writeFile` techniques work for most modern browsers as well as older IE.
|
||||
For much older browsers, there are workarounds implemented by wrapper libraries.
|
||||
|
||||
[`FileSaver.js`](https://github.com/eligrey/FileSaver.js/) implements `saveAs`.
|
||||
Note: `XLSX.writeFile` will automatically call `saveAs` if available.
|
||||
|
||||
```js
|
||||
/* bookType can be any supported output type */
|
||||
var wopts = { bookType:'xlsx', bookSST:false, type:'array' };
|
||||
|
||||
var wbout = XLSX.write(workbook,wopts);
|
||||
|
||||
/* the saveAs call downloads a file on the local machine */
|
||||
saveAs(new Blob([wbout],{type:"application/octet-stream"}), "test.xlsx");
|
||||
```
|
||||
|
||||
[`Downloadify`](https://github.com/dcneiner/downloadify) uses a Flash SWF button
|
||||
to generate local files, suitable for environments where ActiveX is unavailable:
|
||||
|
||||
```js
|
||||
Downloadify.create(id,{
|
||||
/* other options are required! read the downloadify docs for more info */
|
||||
filename: "test.xlsx",
|
||||
data: function() { return XLSX.write(wb, {bookType:"xlsx", type:'base64'}); },
|
||||
append: false,
|
||||
dataType: 'base64'
|
||||
});
|
||||
```
|
||||
|
||||
The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
|
||||
|
||||
</details>
|
||||
|
||||
The [included demos](demos/) cover mobile apps and other special deployments.
|
||||
|
||||
### Writing Examples
|
||||
|
||||
- <http://sheetjs.com/demos/table.html> exporting an HTML table
|
||||
@ -705,7 +747,8 @@ Parse options are described in the [Parsing Options](#parsing-options) section.
|
||||
|
||||
`XLSX.write(wb, write_opts)` attempts to write the workbook `wb`
|
||||
|
||||
`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`
|
||||
`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`.
|
||||
In browser-based environments, it will attempt to force a client-side download.
|
||||
|
||||
`XLSX.writeFileAsync(filename, wb, o, cb)` attempts to write `wb` to `filename`.
|
||||
If `o` is omitted, the writer will use the third argument as the callback.
|
||||
@ -2015,6 +2058,7 @@ produces HTML output. The function takes an options argument:
|
||||
|
||||
| Option Name | Default | Description |
|
||||
| :---------- | :------: | :-------------------------------------------------- |
|
||||
|`id` | | Specify the `id` attribute for the `TABLE` element |
|
||||
|`editable` | false | If true, set `contenteditable="true"` for every TD |
|
||||
|`header` | | Override header (default `html body`) |
|
||||
|`footer` | | Override footer (default `/body /html`) |
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.11.18';
|
||||
XLSX.version = '0.11.19';
|
||||
|
@ -19,11 +19,16 @@ function s2ab(s/*:string*/) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
function arr2str(data/*:any*/)/*:string*/ {
|
||||
function a2s(data/*:any*/)/*:string*/ {
|
||||
if(Array.isArray(data)) return data.map(_chr).join("");
|
||||
var o/*:Array<string>*/ = []; for(var i = 0; i < data.length; ++i) o[i] = _chr(data[i]); return o.join("");
|
||||
}
|
||||
|
||||
function a2u(data/*:Array<number>*/)/*:Uint8Array*/ {
|
||||
if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
|
||||
function ab2a(data/*:ArrayBuffer|Uint8Array*/)/*:Array<number>*/ {
|
||||
if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
|
||||
if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
|
||||
|
37
bits/19_fsutils.js
Normal file
37
bits/19_fsutils.js
Normal file
@ -0,0 +1,37 @@
|
||||
var _fs;
|
||||
if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
|
||||
|
||||
/* normalize data for blob ctor */
|
||||
function blobify(data) {
|
||||
if(typeof data === "string") return s2ab(data);
|
||||
if(Array.isArray(data)) return a2u(data);
|
||||
return data;
|
||||
}
|
||||
/* write or download file */
|
||||
function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
||||
/*global IE_SaveFile, Blob, navigator, saveAs, URL, document */
|
||||
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
|
||||
var data = (enc == "utf8") ? utf8write(payload) : payload;
|
||||
/*:: declare var IE_SaveFile: any; */
|
||||
if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
|
||||
if(typeof Blob !== 'undefined') {
|
||||
var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
|
||||
/*:: declare var navigator: any; */
|
||||
if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
|
||||
/*:: declare var saveAs: any; */
|
||||
if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
|
||||
if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
|
||||
var a = document.createElement("a");
|
||||
if(a.download != null) {
|
||||
var url = URL.createObjectURL(blob);
|
||||
/*:: if(document.body == null) throw new Error("unreachable"); */
|
||||
a.download = fname; a.href = url; document.body.appendChild(a); a.click();
|
||||
/*:: if(document.body == null) throw new Error("unreachable"); */ document.body.removeChild(a);
|
||||
if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error("cannot initiate download");
|
||||
}
|
||||
|
@ -51,14 +51,13 @@ function getzipstr(zip, file/*:string*/, safe/*:?boolean*/)/*:?string*/ {
|
||||
try { return getzipstr(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
var _fs, jszip;
|
||||
var jszip;
|
||||
/*:: declare var JSZip:any; */
|
||||
/*global JSZip:true */
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
if(typeof exports !== 'undefined') {
|
||||
if(typeof module !== 'undefined' && module.exports) {
|
||||
if(typeof jszip === 'undefined') jszip = require('./jszip.js');
|
||||
try { _fs = require('fs'); } catch(e) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,7 @@ function check_wb_names(N) {
|
||||
}
|
||||
function check_wb(wb) {
|
||||
if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
|
||||
if(!wb.SheetNames.length) throw new Error("Workbook is empty");
|
||||
check_wb_names(wb.SheetNames);
|
||||
/* TODO: validate workbook */
|
||||
}
|
||||
|
@ -833,7 +833,7 @@ function parse_xlml(data/*:RawBytes|string*/, opts)/*:Workbook*/ {
|
||||
switch(opts.type||"base64") {
|
||||
case "base64": return parse_xlml_xml(Base64.decode(data), opts);
|
||||
case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
|
||||
case "array": return parse_xlml_xml(arr2str(data), opts);
|
||||
case "array": return parse_xlml_xml(a2s(data), opts);
|
||||
}
|
||||
/*:: throw new Error("unsupported type " + opts.type); */
|
||||
}
|
||||
|
@ -84,9 +84,9 @@ var HTML_ = (function() {
|
||||
var preamble = "<tr>";
|
||||
return preamble + oo.join("") + "</tr>";
|
||||
}
|
||||
function make_html_preamble(/*::ws:Worksheet, R:Range, o:Sheet2HTMLOpts*/)/*:string*/ {
|
||||
function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)/*:string*/ {
|
||||
var out/*:Array<string>*/ = [];
|
||||
return out.join("") + '<table>';
|
||||
return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
|
||||
}
|
||||
var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
|
||||
var _END = '</body></html>';
|
||||
|
@ -100,7 +100,6 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
||||
case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
|
||||
}
|
||||
if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
|
||||
if(0x20>n[0]||n[0]>0x7F) throw new Error("Unsupported file " + n.join("|"));
|
||||
return read_prn(data, d, o, str);
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,12 @@ function write_zip_type(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
|
||||
switch(o.type) {
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + ' files');
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
case "buffer":
|
||||
case "file": oopts.type = "nodebuffer"; break;
|
||||
case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(o.type === "file") return _fs.writeFileSync(o.file, z.generate(oopts));
|
||||
if(o.type === "file") return write_dl(o.file, z.generate(oopts));
|
||||
var out = z.generate(oopts);
|
||||
// $FlowIgnore
|
||||
return o.type == "string" ? utf8read(out) : out;
|
||||
@ -23,8 +23,8 @@ function write_cfb_type(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
|
||||
switch(o.type) {
|
||||
case "base64": case "binary": break;
|
||||
case "buffer": case "array": o.type = ""; break;
|
||||
case "file": return _fs.writeFileSync(o.file, CFB.write(cfb, {type:'buffer'}));
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + ' files');
|
||||
case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
|
||||
case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
return CFB.write(cfb, o);
|
||||
@ -37,7 +37,7 @@ function write_string_type(out/*:string*/, opts/*:WriteOpts*/, bom/*:?string*/)/
|
||||
case "base64": return Base64.encode(utf8write(o));
|
||||
case "binary": return utf8write(o);
|
||||
case "string": return out;
|
||||
case "file": return _fs.writeFileSync(opts.file, o, 'utf8');
|
||||
case "file": return write_dl(opts.file, o, 'utf8');
|
||||
case "buffer": {
|
||||
if(has_buf) return new Buffer(o, 'utf8');
|
||||
else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
|
||||
@ -51,7 +51,7 @@ function write_stxt_type(out/*:string*/, opts/*:WriteOpts*/)/*:any*/ {
|
||||
case "base64": return Base64.encode(out);
|
||||
case "binary": return out;
|
||||
case "string": return out; /* override in sheet_to_txt */
|
||||
case "file": return _fs.writeFileSync(opts.file, out, 'binary');
|
||||
case "file": return write_dl(opts.file, out, 'binary');
|
||||
case "buffer": {
|
||||
if(has_buf) return new Buffer(out, 'binary');
|
||||
else return out.split("").map(function(c) { return c.charCodeAt(0); });
|
||||
@ -70,7 +70,7 @@ function write_binary_type(out, opts/*:WriteOpts*/)/*:any*/ {
|
||||
// $FlowIgnore
|
||||
for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
|
||||
return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
|
||||
case "file": return _fs.writeFileSync(opts.file, out);
|
||||
case "file": return write_dl(opts.file, out);
|
||||
case "buffer": return out;
|
||||
default: throw new Error("Unrecognized type " + opts.type);
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
|
||||
var s = sheet_to_csv(sheet, opts);
|
||||
if(typeof cptable == 'undefined' || opts.type == 'string') return s;
|
||||
var o = cptable.utils.encode(1200, s, 'str');
|
||||
return "\xff\xfe" + o;
|
||||
return String.fromCharCode(255) + String.fromCharCode(254) + o;
|
||||
}
|
||||
|
||||
function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
|
||||
|
@ -44,5 +44,6 @@ can be installed with Bash on Windows or with `cygwin`.
|
||||
- [`Headless Browsers`](headless/)
|
||||
- [`canvas-datagrid`](datagrid/)
|
||||
- [`Swift JSC and other engines`](altjs/)
|
||||
- [`internet explorer`](oldie/)
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -81,18 +81,15 @@ var ws = XLSX.utils.json_to_sheet(data);
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
|
||||
|
||||
/* write workbook (use type 'array' for ArrayBuffer) */
|
||||
var wbout = XLSX.write(wb, {bookType:'xlsx', type:'array'});
|
||||
|
||||
/* generate a download */
|
||||
saveAs(new Blob([wbout],{type:"application/octet-stream"}), "sheetjs.xlsx");
|
||||
/* write workbook and force a download */
|
||||
XLSX.writeFile(wb, "sheetjs.xlsx");
|
||||
```
|
||||
|
||||
|
||||
`SheetJSExportService` exposes export functions for `XLSB` and `XLSX`. Other
|
||||
formats are easily supported by changing the `bookType` variable. It grabs
|
||||
values from the grid, builds an array of arrays, generates a workbook and uses
|
||||
FileSaver to generate a download. By setting the `filename` and `sheetname`
|
||||
options in the ui-grid options, the output can be controlled.
|
||||
values from the grid, builds an array of arrays, generates a workbook and forces
|
||||
a download. By setting the `filename` and `sheetname` options in the ui-grid
|
||||
options, the output can be controlled.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
3
demos/angular/SheetJS-angular.js
vendored
3
demos/angular/SheetJS-angular.js
vendored
@ -12,8 +12,7 @@ function SheetJSExportService(uiGridExporterService) {
|
||||
|
||||
var wb = XLSX.utils.book_new(), ws = uigrid_to_sheet(data, columns);
|
||||
XLSX.utils.book_append_sheet(wb, ws, sheetName);
|
||||
var wbout = XLSX.write(wb, wopts);
|
||||
saveAs(new Blob([wbout], { type: 'application/octet-stream' }), fileName);
|
||||
XLSX.writeFile(wb, fileName);
|
||||
}
|
||||
|
||||
var service = {};
|
||||
|
@ -13,10 +13,8 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.0/ui-grid.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.0/ui-grid.css"/>
|
||||
|
||||
<!-- FileSaver shim for exporting files -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
|
||||
|
||||
<!-- SheetJS js-xlsx library -->
|
||||
<script src="shim.js"></script>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
|
||||
<!-- SheetJS Service -->
|
||||
|
1
demos/angular/shim.js
vendored
Symbolic link
1
demos/angular/shim.js
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
../../shim.js
|
@ -2,24 +2,27 @@
|
||||
angular:
|
||||
# Test Angular2 build
|
||||
cp package.json-angular2 package.json
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
if [ ! -e node_modules ]; then mkdir node_modules; fi
|
||||
if [ ! -e node_modules/xlsx ]; then cd node_modules; ln -s ../../../ xlsx; cd -; fi
|
||||
ng build
|
||||
npm run build
|
||||
|
||||
# Test Angular4 build
|
||||
cp package.json-angular4 package.json
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
if [ ! -e node_modules ]; then mkdir node_modules; fi
|
||||
if [ ! -e node_modules/xlsx ]; then cd node_modules; ln -s ../../../ xlsx; cd -; fi
|
||||
ng build
|
||||
npm run build
|
||||
|
||||
# Test Angular5 build
|
||||
cp package.json-angular5 package.json
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
if [ ! -e node_modules ]; then mkdir node_modules; fi
|
||||
if [ ! -e node_modules/xlsx ]; then cd node_modules; ln -s ../../../ xlsx; cd -; fi
|
||||
ng build
|
||||
npm run build
|
||||
|
||||
.PHONY: ionic
|
||||
ionic:
|
||||
|
@ -38,8 +38,7 @@ const wb: XLSX.WorkBook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
|
||||
|
||||
/* save to file */
|
||||
const wbout: string = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
saveAs(new Blob([wbout]), 'SheetJS.xlsx');
|
||||
XLSX.writeFile(wb, 'SheetJS.xlsx');
|
||||
```
|
||||
|
||||
`sheet_to_json` with the option `header:1` makes importing simple:
|
||||
|
@ -5,7 +5,7 @@ if [ ! -e SheetJSIonic ]; then
|
||||
ionic cordova platform add browser </dev/null
|
||||
ionic cordova platform add ios </dev/null
|
||||
ionic cordova plugin add cordova-plugin-file </dev/null
|
||||
npm install --save @ionic-native/file file-saver
|
||||
npm install --save @ionic-native/file
|
||||
npm install --save xlsx
|
||||
|
||||
cp src/app/app.module.ts{,.bak}
|
||||
|
@ -5,7 +5,6 @@ import { Component } from '@angular/core';
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
import { File } from '@ionic-native/file';
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
type AOA = any[][];
|
||||
|
||||
@ -48,7 +47,7 @@ export class HomePage {
|
||||
this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header: 1}));
|
||||
};
|
||||
|
||||
write(): ArrayBuffer {
|
||||
write(): XLSX.WorkBook {
|
||||
/* generate worksheet */
|
||||
const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
|
||||
|
||||
@ -56,9 +55,7 @@ export class HomePage {
|
||||
const wb: XLSX.WorkBook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
|
||||
|
||||
/* save to ArrayBuffer */
|
||||
const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
return wbout;
|
||||
return wb;
|
||||
};
|
||||
|
||||
/* File Input element for browser */
|
||||
@ -91,17 +88,26 @@ export class HomePage {
|
||||
|
||||
/* Export button */
|
||||
async export() {
|
||||
const wbout: ArrayBuffer = this.write();
|
||||
const wb: XLSX.WorkBook = this.write();
|
||||
const filename: string = "SheetJSIonic.xlsx";
|
||||
const blob: Blob = new Blob([wbout], {type: 'application/octet-stream'});
|
||||
try {
|
||||
/* generate Blob */
|
||||
const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
const blob: Blob = new Blob([wbout], {type: 'application/octet-stream'});
|
||||
|
||||
/* find appropriate path for mobile */
|
||||
const target: string = this.file.documentsDirectory || this.file.externalDataDirectory || this.file.dataDirectory || '';
|
||||
const dentry = await this.file.resolveDirectoryUrl(target);
|
||||
const url: string = dentry.nativeURL || '';
|
||||
|
||||
/* attempt to save blob to file */
|
||||
await this.file.writeFile(url, filename, blob, {replace: true});
|
||||
alert(`Wrote to SheetJSIonic.xlsx in ${url}`);
|
||||
} catch(e) {
|
||||
if(e.message.match(/It was determined/)) saveAs(blob, filename);
|
||||
if(e.message.match(/It was determined/)) {
|
||||
/* in the browser, use writeFile */
|
||||
XLSX.writeFile(wb, filename);
|
||||
}
|
||||
else alert(`Error: ${e.message}`);
|
||||
}
|
||||
};
|
||||
|
@ -24,11 +24,10 @@
|
||||
|
||||
"rxjs": "^5.5.2",
|
||||
|
||||
"zone.js": "^0.8.14",
|
||||
"file-saver": "^1.3.3"
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.5.0",
|
||||
"@angular/cli": "^1.5.3",
|
||||
"@angular/compiler-cli": "^5.0.0",
|
||||
"@angular/language-service": "^5.0.0",
|
||||
"@types/node": "~6.0.60",
|
||||
|
@ -24,8 +24,7 @@
|
||||
"reflect-metadata": "^0.1.8",
|
||||
"rxjs": "^5.0.2",
|
||||
"systemjs": "0.19.40",
|
||||
"zone.js": "^0.7.4",
|
||||
"file-saver": "^1.3.3"
|
||||
"zone.js": "^0.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.1.2",
|
||||
|
@ -24,8 +24,7 @@
|
||||
|
||||
"rxjs": "^5.1.0",
|
||||
|
||||
"zone.js": "^0.8.4",
|
||||
"file-saver": "^1.3.3"
|
||||
"zone.js": "^0.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.1.2",
|
||||
|
@ -24,11 +24,10 @@
|
||||
|
||||
"rxjs": "^5.5.2",
|
||||
|
||||
"zone.js": "^0.8.14",
|
||||
"file-saver": "^1.3.3"
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.5.0",
|
||||
"@angular/cli": "^1.5.3",
|
||||
"@angular/compiler-cli": "^5.0.0",
|
||||
"@angular/language-service": "^5.0.0",
|
||||
"@types/node": "~6.0.60",
|
||||
|
@ -4,8 +4,6 @@ import { Component } from '@angular/core';
|
||||
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
type AOA = any[][];
|
||||
|
||||
@Component({
|
||||
@ -57,7 +55,6 @@ export class SheetJSComponent {
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
|
||||
|
||||
/* save to file */
|
||||
const wbout: ArrayBuffer = XLSX.write(wb, this.wopts);
|
||||
saveAs(new Blob([wbout], { type: 'application/octet-stream' }), this.fileName);
|
||||
XLSX.writeFile(wb, this.fileName);
|
||||
}
|
||||
}
|
||||
|
@ -9,42 +9,42 @@ var client = redis.createClient();
|
||||
|
||||
/* Sample data */
|
||||
var init = [
|
||||
["FLUSHALL", []],
|
||||
["SADD", ["birdpowers", "flight", "pecking"]],
|
||||
["SET", ["foo", "bar"]],
|
||||
["SET", ["baz", 0]],
|
||||
["RPUSH", ["friends", "sam", "alice", "bob"]],
|
||||
["ZADD", ["hackers", 1906, 'Grace Hopper', 1912, 'Alan Turing', 1916, 'Claude Shannon', 1940, 'Alan Kay', 1953, 'Richard Stallman', 1957, 'Sophie Wilson', 1965, 'Yukihiro Matsumoto', 1969, 'Linus Torvalds']],
|
||||
["SADD", ["superpowers", "flight", 'x-ray vision']],
|
||||
["HMSET", ["user:1000", "name", 'John Smith', "email", 'john.smith@example.com', "password", "s3cret", "visits", 1]],
|
||||
["HMSET", ["user:1001", "name", 'Mary Jones', "email", 'mjones@example.com', "password", "hidden"]]
|
||||
["FLUSHALL", []],
|
||||
["SADD", ["birdpowers", "flight", "pecking"]],
|
||||
["SET", ["foo", "bar"]],
|
||||
["SET", ["baz", 0]],
|
||||
["RPUSH", ["friends", "sam", "alice", "bob"]],
|
||||
["ZADD", ["hackers", 1906, 'Grace Hopper', 1912, 'Alan Turing', 1916, 'Claude Shannon', 1940, 'Alan Kay', 1953, 'Richard Stallman', 1957, 'Sophie Wilson', 1965, 'Yukihiro Matsumoto', 1969, 'Linus Torvalds']],
|
||||
["SADD", ["superpowers", "flight", 'x-ray vision']],
|
||||
["HMSET", ["user:1000", "name", 'John Smith', "email", 'john.smith@example.com', "password", "s3cret", "visits", 1]],
|
||||
["HMSET", ["user:1001", "name", 'Mary Jones', "email", 'mjones@example.com', "password", "hidden"]]
|
||||
];
|
||||
|
||||
const R = (()=>{
|
||||
const Rcache = {};
|
||||
const R_ = (n) => Rcache[n] || (Rcache[n] = util.promisify(client[n]).bind(client));
|
||||
return (n) => R_(n.toLowerCase());
|
||||
const Rcache = {};
|
||||
const R_ = (n) => Rcache[n] || (Rcache[n] = util.promisify(client[n]).bind(client));
|
||||
return (n) => R_(n.toLowerCase());
|
||||
})();
|
||||
|
||||
(async () => {
|
||||
for(var i = 0; i < init.length; ++i) await R(init[i][0])(init[i][1]);
|
||||
for(var i = 0; i < init.length; ++i) await R(init[i][0])(init[i][1]);
|
||||
|
||||
/* Export database to XLSX */
|
||||
var wb = await SheetJSRedis.redis_to_wb(R);
|
||||
var wb = await SheetJSRedis.redis_to_wb(R);
|
||||
XLSX.writeFile(wb, "redis.xlsx");
|
||||
|
||||
/* Import XLSX to database */
|
||||
await R("flushall")();
|
||||
await R("flushall")();
|
||||
var wb2 = XLSX.readFile("redis.xlsx");
|
||||
await SheetJSRedis.wb_to_redis(wb2, R);
|
||||
await SheetJSRedis.wb_to_redis(wb2, R);
|
||||
|
||||
/* Verify */
|
||||
assert.equal(await R("get")("foo"), "bar");
|
||||
assert.equal(await R("lindex")("friends", 1), "alice");
|
||||
assert.equal(await R("zscore")("hackers", "Claude Shannon"), 1916);
|
||||
assert.equal(await R("hget")("user:1000", "name"), "John Smith");
|
||||
assert.equal(await R("sismember")("superpowers", "flight"), "1");
|
||||
assert.equal(await R("sismember")("birdpowers", "pecking"), "1");
|
||||
/* Verify */
|
||||
assert.equal(await R("get")("foo"), "bar");
|
||||
assert.equal(await R("lindex")("friends", 1), "alice");
|
||||
assert.equal(await R("zscore")("hackers", "Claude Shannon"), 1916);
|
||||
assert.equal(await R("hget")("user:1000", "name"), "John Smith");
|
||||
assert.equal(await R("sismember")("superpowers", "flight"), "1");
|
||||
assert.equal(await R("sismember")("birdpowers", "pecking"), "1");
|
||||
|
||||
client.quit();
|
||||
client.quit();
|
||||
})();
|
||||
|
@ -6,68 +6,68 @@ const pair = (arr) => arr.map((x,i)=>!(i%2)&&[x,+arr[i+1]]).filter(x=>x);
|
||||
const keyify = (obj) => Object.keys(obj).map(x => [x, obj[x]]);
|
||||
|
||||
async function redis_to_wb(R) {
|
||||
var wb = XLSX.utils.book_new();
|
||||
var manifest = [], strs = [];
|
||||
var wb = XLSX.utils.book_new();
|
||||
var manifest = [], strs = [];
|
||||
|
||||
/* store strings in strs and keep note of other objects in manifest */
|
||||
var keys = await R("keys")("*"), type = "";
|
||||
for(var i = 0; i < keys.length; ++i) {
|
||||
type = await R("type")(keys[i]);
|
||||
switch(type) {
|
||||
case "string": strs.push({key:keys[i], value: await R("get")(keys[i])}); break;
|
||||
case "list": case "zset": case "set": case "hash": manifest.push({key:keys[i], type:type}); break;
|
||||
default: throw new Error("bad type " + type);
|
||||
}
|
||||
}
|
||||
/* store strings in strs and keep note of other objects in manifest */
|
||||
var keys = await R("keys")("*"), type = "";
|
||||
for(var i = 0; i < keys.length; ++i) {
|
||||
type = await R("type")(keys[i]);
|
||||
switch(type) {
|
||||
case "string": strs.push({key:keys[i], value: await R("get")(keys[i])}); break;
|
||||
case "list": case "zset": case "set": case "hash": manifest.push({key:keys[i], type:type}); break;
|
||||
default: throw new Error("bad type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/* add worksheets if relevant */
|
||||
if(strs.length > 0) {
|
||||
var wss = XLSX.utils.json_to_sheet(strs, {header: ["key", "value"], skipHeader:1});
|
||||
XLSX.utils.book_append_sheet(wb, wss, "_strs");
|
||||
}
|
||||
if(manifest.length > 0) {
|
||||
var wsm = XLSX.utils.json_to_sheet(manifest, {header: ["key", "type"]});
|
||||
XLSX.utils.book_append_sheet(wb, wsm, "_manifest");
|
||||
}
|
||||
for(i = 0; i < manifest.length; ++i) {
|
||||
var sn = "obj" + i;
|
||||
var aoa, key = manifest[i].key;
|
||||
switch((type=manifest[i].type)) {
|
||||
case "list":
|
||||
aoa = (await R("lrange")(key, 0, -1)).map(x => [x]); break;
|
||||
case "set":
|
||||
aoa = (await R("smembers")(key)).map(x => [x]); break;
|
||||
case "zset":
|
||||
aoa = pair(await R("zrange")(key, 0, -1, "withscores")); break;
|
||||
case "hash":
|
||||
aoa = keyify(await R("hgetall")(key)); break;
|
||||
default: throw new Error("bad type " + type);
|
||||
}
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(aoa), sn);
|
||||
}
|
||||
return wb;
|
||||
/* add worksheets if relevant */
|
||||
if(strs.length > 0) {
|
||||
var wss = XLSX.utils.json_to_sheet(strs, {header: ["key", "value"], skipHeader:1});
|
||||
XLSX.utils.book_append_sheet(wb, wss, "_strs");
|
||||
}
|
||||
if(manifest.length > 0) {
|
||||
var wsm = XLSX.utils.json_to_sheet(manifest, {header: ["key", "type"]});
|
||||
XLSX.utils.book_append_sheet(wb, wsm, "_manifest");
|
||||
}
|
||||
for(i = 0; i < manifest.length; ++i) {
|
||||
var sn = "obj" + i;
|
||||
var aoa, key = manifest[i].key;
|
||||
switch((type=manifest[i].type)) {
|
||||
case "list":
|
||||
aoa = (await R("lrange")(key, 0, -1)).map(x => [x]); break;
|
||||
case "set":
|
||||
aoa = (await R("smembers")(key)).map(x => [x]); break;
|
||||
case "zset":
|
||||
aoa = pair(await R("zrange")(key, 0, -1, "withscores")); break;
|
||||
case "hash":
|
||||
aoa = keyify(await R("hgetall")(key)); break;
|
||||
default: throw new Error("bad type " + type);
|
||||
}
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(aoa), sn);
|
||||
}
|
||||
return wb;
|
||||
}
|
||||
|
||||
/* convert worksheet aoa to specific redis type */
|
||||
const aoa_to_redis = {
|
||||
list: async (aoa, R, key) => await R("RPUSH")([key].concat(aoa.map(x=>x[0]))),
|
||||
zset: async (aoa, R, key) => await R("ZADD" )([key].concat(aoa.reduce((acc,x)=>acc.concat([+x[1], x[0]]), []))),
|
||||
hash: async (aoa, R, key) => await R("HMSET")([key].concat(aoa.reduce((acc,x)=>acc.concat(x), []))),
|
||||
set: async (aoa, R, key) => await R("SADD" )([key].concat(aoa.map(x=>x[0])))
|
||||
list: async (aoa, R, key) => await R("RPUSH")([key].concat(aoa.map(x=>x[0]))),
|
||||
zset: async (aoa, R, key) => await R("ZADD" )([key].concat(aoa.reduce((acc,x)=>acc.concat([+x[1], x[0]]), []))),
|
||||
hash: async (aoa, R, key) => await R("HMSET")([key].concat(aoa.reduce((acc,x)=>acc.concat(x), []))),
|
||||
set: async (aoa, R, key) => await R("SADD" )([key].concat(aoa.map(x=>x[0])))
|
||||
};
|
||||
async function wb_to_redis(wb, R) {
|
||||
if(wb.Sheets._strs) {
|
||||
var strs = XLSX.utils.sheet_to_json(wb.Sheets._strs, {header:1});
|
||||
for(var i = 0; i < strs.length; ++i) await R("SET")(strs[i]);
|
||||
}
|
||||
if(!wb.Sheets._manifest) return;
|
||||
var M = XLSX.utils.sheet_to_json(wb.Sheets._manifest);
|
||||
for(i = 0; i < M.length; ++i) {
|
||||
var aoa = XLSX.utils.sheet_to_json(wb.Sheets["obj" + i], {header:1});
|
||||
await aoa_to_redis[M[i].type](aoa, R, M[i].key);
|
||||
}
|
||||
if(wb.Sheets._strs) {
|
||||
var strs = XLSX.utils.sheet_to_json(wb.Sheets._strs, {header:1});
|
||||
for(var i = 0; i < strs.length; ++i) await R("SET")(strs[i]);
|
||||
}
|
||||
if(!wb.Sheets._manifest) return;
|
||||
var M = XLSX.utils.sheet_to_json(wb.Sheets._manifest);
|
||||
for(i = 0; i < M.length; ++i) {
|
||||
var aoa = XLSX.utils.sheet_to_json(wb.Sheets["obj" + i], {header:1});
|
||||
await aoa_to_redis[M[i].type](aoa, R, M[i].key);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
redis_to_wb,
|
||||
wb_to_redis
|
||||
redis_to_wb,
|
||||
wb_to_redis
|
||||
};
|
||||
|
@ -49,9 +49,9 @@ function sheet_to_sql(ws, sname, mode) {
|
||||
|
||||
var out = [];
|
||||
|
||||
var BT = mode == "PGSQL" ? "" : "`";
|
||||
var Q = mode == "PGSQL" ? "'" : '"';
|
||||
var R = mode == "PGSQL" ? /'/g : /"/g;
|
||||
var BT = mode == "PGSQL" ? "" : "`";
|
||||
var Q = mode == "PGSQL" ? "'" : '"';
|
||||
var R = mode == "PGSQL" ? /'/g : /"/g;
|
||||
out.push("DROP TABLE IF EXISTS " + BT + sname + BT );
|
||||
out.push("CREATE TABLE " + BT + sname + BT + " (" + names.map(function(n, i) { return BT + n + BT + " " + (types[i]||"TEXT"); }).join(", ") + ");" );
|
||||
|
||||
|
@ -82,7 +82,8 @@ var ws = XLSX.utils.aoa_to_sheet(prep(grid.data));
|
||||
var wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
|
||||
|
||||
/* .. generate download (see documentation for examples) .. */
|
||||
/* generate download */
|
||||
XLSX.writeFile(wb, "SheetJS.xlsx");
|
||||
```
|
||||
|
||||
## Additional Features
|
||||
|
@ -40,8 +40,7 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
|
||||
<div id="htmlout"></div>
|
||||
<br />
|
||||
<script src="https://unpkg.com/canvas-datagrid/dist/canvas-datagrid.js"></script>
|
||||
<script type="text/javascript" src="https://rawgit.com/eligrey/Blob.js/master/Blob.js"></script>
|
||||
<script type="text/javascript" src="https://rawgit.com/eligrey/FileSaver.js/master/FileSaver.js"></script>
|
||||
<script src="shim.js"></script>
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
<script>
|
||||
/*jshint browser:true */
|
||||
@ -151,11 +150,7 @@ var export_xlsx = (function() {
|
||||
XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS');
|
||||
|
||||
/* write file and trigger a download */
|
||||
var wbout = XLSX.write(new_wb, {bookType:'xlsx', bookSST:true, type:'array'});
|
||||
var fname = 'sheetjs.xlsx';
|
||||
try {
|
||||
saveAs(new Blob([wbout],{type:"application/octet-stream"}), fname);
|
||||
} catch(e) { if(typeof console != 'undefined') console.log(e, wbout); }
|
||||
XLSX.writeFile(new_wb, 'sheetjs.xlsx', {bookSST:true});
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
|
1
demos/datagrid/shim.js
Symbolic link
1
demos/datagrid/shim.js
Symbolic link
@ -0,0 +1 @@
|
||||
../../shim.js
|
@ -6,9 +6,9 @@ start:
|
||||
init:
|
||||
if [ ! -e .meteor ]; then meteor create .; fi;
|
||||
@npm install babel-runtime meteor-node-stubs
|
||||
@meteor add pfafman:filesaver check
|
||||
@meteor add check
|
||||
@mkdir -p node_modules; cd node_modules; ln -s ../../../ xlsx; cd -
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@meteor npm run lint
|
||||
@meteor npm run lint
|
||||
|
@ -61,13 +61,9 @@ const html = document.getElementById('out').innerHTML;
|
||||
// SERVER SIDE
|
||||
const wb = XLSX.read(html, { type: 'binary' });
|
||||
// CLIENT SIDE
|
||||
const o = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
saveAs(new Blob([o], {type:'application/octet-stream'}), 'sheetjs.xlsx');
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsx');
|
||||
```
|
||||
|
||||
This demo uses the FileSaver library for writing files, installed through the
|
||||
[`pfafman:filesaver` wrapper](https://atmospherejs.com/pfafman/filesaver).
|
||||
|
||||
|
||||
## Setup
|
||||
|
||||
@ -76,7 +72,6 @@ This tree does not include the `.meteor` structure. Rebuild the project with:
|
||||
```bash
|
||||
meteor create .
|
||||
npm install babel-runtime meteor-node-stubs xlsx
|
||||
meteor add pfafman:filesaver
|
||||
meteor
|
||||
```
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
import XLSX from 'xlsx';
|
||||
/* note: saveAs is made available via the smart package */
|
||||
/* global saveAs */
|
||||
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
@ -13,11 +11,12 @@ Template.sheetjs.events({
|
||||
/* "Browser file upload form element" from SheetJS README */
|
||||
const file = event.currentTarget.files[0];
|
||||
const reader = new FileReader();
|
||||
const rABS = !!reader.readAsBinaryString;
|
||||
reader.onload = function(e) {
|
||||
const data = e.target.result;
|
||||
const name = file.name;
|
||||
/* Meteor magic */
|
||||
Meteor.call('upload', data, name, function(err, wb) {
|
||||
Meteor.call(rABS ? 'uploadS' : 'uploadU', rABS ? data : new Uint8Array(data), name, function(err, wb) {
|
||||
if (err) throw err;
|
||||
/* load the first worksheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
@ -27,15 +26,14 @@ Template.sheetjs.events({
|
||||
document.getElementById('dnload').disabled = false;
|
||||
});
|
||||
};
|
||||
reader.readAsBinaryString(file);
|
||||
if(rABS) reader.readAsBinaryString(file); else reader.readAsArrayBuffer(file);
|
||||
},
|
||||
'click button' () {
|
||||
const html = document.getElementById('out').innerHTML;
|
||||
Meteor.call('download', html, function(err, wb) {
|
||||
if (err) throw err;
|
||||
/* "Browser download file" from SheetJS README */
|
||||
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'sheetjs.xlsx');
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsx');
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -4,12 +4,17 @@ import { check } from 'meteor/check';
|
||||
import XLSX from 'xlsx';
|
||||
|
||||
Meteor.methods({
|
||||
upload: (bstr, name) => {
|
||||
/* read the data and return the workbook object to the frontend */
|
||||
/* read the data and return the workbook object to the frontend */
|
||||
uploadS: (bstr, name) => {
|
||||
check(bstr, String);
|
||||
check(name, String);
|
||||
return XLSX.read(bstr, { type: 'binary' });
|
||||
},
|
||||
uploadU: (ab, name) => {
|
||||
check(ab, Uint8Array);
|
||||
check(name, String);
|
||||
return XLSX.read(ab, { type: 'array' });
|
||||
},
|
||||
download: (html) => {
|
||||
check(html, String);
|
||||
let wb;
|
||||
|
70
demos/oldie/README.md
Normal file
70
demos/oldie/README.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Internet Explorer
|
||||
|
||||
Despite the efforts to deprecate the pertinent operating systems, IE is still
|
||||
very popular, required for various government and corporate websites throughout
|
||||
the world. The modern download strategies are not available in older versions
|
||||
of IE, but there are alternative approaches.
|
||||
|
||||
## Strategies
|
||||
|
||||
#### IE10 and IE11 File API
|
||||
|
||||
As part of the File API implementation, IE10 and IE11 provide the `msSaveBlob`
|
||||
and `msSaveOrOpenBlob` functions to save blobs to the client computer. This
|
||||
approach is embedded in `XLSX.writeFile` and no additional shims are necessary.
|
||||
|
||||
#### Flash-based Download
|
||||
|
||||
It is possible to write to the file system using a SWF. `Downloadify` library
|
||||
implements one solution. Since a genuine click is required, there is no way to
|
||||
force a download. The demo generates a button for each desired output format.
|
||||
|
||||
#### ActiveX-based Download
|
||||
|
||||
Through the `Scripting.FileSystemObject` object model, a script in the VBScript
|
||||
scripting language can write to an arbitrary path on the filesystem. The shim
|
||||
includes a special `IE_SaveFile` function to write binary strings to file. It
|
||||
attempts to write to the Downloads folder or Documents folder or Desktop.
|
||||
|
||||
This approach can be triggered, but it requires the user to enable ActiveX. It
|
||||
is embedded as a strategy in `writeFile` and used only if the shim script is
|
||||
included in the page and the relevant features are enabled on the target system.
|
||||
|
||||
## Demo
|
||||
|
||||
The included demo starts from an array of arrays, generating an editable HTML
|
||||
table with `aoa_to_sheet` and adding it to the page:
|
||||
|
||||
```js
|
||||
var ws = XLSX.utils.aoa_to_sheet(aoa);
|
||||
var html_string = XLSX.utils.sheet_to_html(ws, { id: "table", editable: true });
|
||||
document.getElementById("container").innerHTML = html_string;
|
||||
```
|
||||
|
||||
The included download buttons use `table_to_book` to construct a new workbook
|
||||
based on the table and `writeFile` to force a download:
|
||||
|
||||
|
||||
```js
|
||||
var elt = document.getElementById('table');
|
||||
var wb = XLSX.utils.table_to_book(elt, { sheet: "Sheet JS" });
|
||||
XLSX.writeFile(wb, filename);
|
||||
```
|
||||
|
||||
The shim is included in the HTML page, unlocking the ActiveX pathway if enabled
|
||||
in browser settings.
|
||||
|
||||
The corresponding SWF buttons are displayed in environments where Flash is
|
||||
available and `Downloadify` is supported. The easiest solution involves writing
|
||||
to a Base64 string and passing to the library:
|
||||
|
||||
```js
|
||||
Downloadify.create(element_id, {
|
||||
/* the demo includes the other options required by Downloadify */
|
||||
filename: "test.xlsx",
|
||||
data: function() { return XLSX.write(wb, {bookType:"xlsx", type:'base64'}); },
|
||||
dataType: 'base64'
|
||||
});
|
||||
```
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
1
demos/oldie/base64.min.js
vendored
Normal file
1
demos/oldie/base64.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(){function t(t){this.message=t}var r="undefined"!=typeof exports?exports:self,e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=new Error,t.prototype.name="InvalidCharacterError",r.btoa||(r.btoa=function(r){for(var o,n,a=String(r),i=0,c=e,d="";a.charAt(0|i)||(c="=",i%1);d+=c.charAt(63&o>>8-i%1*8)){if(n=a.charCodeAt(i+=.75),n>255)throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");o=o<<8|n}return d}),r.atob||(r.atob=function(r){var o=String(r).replace(/=+$/,"");if(o.length%4==1)throw new t("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,a,i=0,c=0,d="";a=o.charAt(c++);~a&&(n=i%4?64*n+a:a,i++%4)?d+=String.fromCharCode(255&n>>(-2*i&6)):0)a=e.indexOf(a);return d})}();
|
BIN
demos/oldie/download.png
Executable file
BIN
demos/oldie/download.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
3
demos/oldie/downloadify.min.js
vendored
Executable file
3
demos/oldie/downloadify.min.js
vendored
Executable file
@ -0,0 +1,3 @@
|
||||
/* Downloadify 0.2 (c) 2009 by Douglas Neiner. Licensed under the MIT license */
|
||||
/* See http://github.com/dcneiner/Downloadify for license and more info */
|
||||
(function(){Downloadify=window.Downloadify={queue:{},uid:new Date().getTime(),getTextForSave:function(a){var b=Downloadify.queue[a];if(b)return b.getData();return""},getFileNameForSave:function(a){var b=Downloadify.queue[a];if(b)return b.getFilename();return""},getDataTypeForSave:function(a){var b=Downloadify.queue[a];if(b)return b.getDataType();return""},saveComplete:function(a){var b=Downloadify.queue[a];if(b)b.complete();return true},saveCancel:function(a){var b=Downloadify.queue[a];if(b)b.cancel();return true},saveError:function(a){var b=Downloadify.queue[a];if(b)b.error();return true},addToQueue:function(a){Downloadify.queue[a.queue_name]=a},getUID:function(a){if(a.id=="")a.id='downloadify_'+Downloadify.uid++;return a.id}};Downloadify.create=function(a,b){var c=(typeof(a)=="string"?document.getElementById(a):a);return new Downloadify.Container(c,b)};Downloadify.Container=function(d,e){var f=this;f.el=d;f.enabled=true;f.dataCallback=null;f.filenameCallback=null;f.data=null;f.filename=null;var g=function(){f.options=e;if(!f.options.append)f.el.innerHTML="";f.flashContainer=document.createElement('span');f.el.appendChild(f.flashContainer);f.queue_name=Downloadify.getUID(f.flashContainer);if(typeof(f.options.filename)==="function")f.filenameCallback=f.options.filename;else if(f.options.filename)f.filename=f.options.filename;if(typeof(f.options.data)==="function")f.dataCallback=f.options.data;else if(f.options.data)f.data=f.options.data;var a={queue_name:f.queue_name,width:f.options.width,height:f.options.height};var b={allowScriptAccess:'always'};var c={id:f.flashContainer.id,name:f.flashContainer.id};if(f.options.enabled===false)f.enabled=false;if(f.options.transparent===true)b.wmode="transparent";if(f.options.downloadImage)a.downloadImage=f.options.downloadImage;swfobject.embedSWF(f.options.swf,f.flashContainer.id,f.options.width,f.options.height,"10",null,a,b,c);Downloadify.addToQueue(f)};f.enable=function(){var a=document.getElementById(f.flashContainer.id);a.setEnabled(true);f.enabled=true};f.disable=function(){var a=document.getElementById(f.flashContainer.id);a.setEnabled(false);f.enabled=false};f.getData=function(){if(!f.enabled)return"";if(f.dataCallback)return f.dataCallback();else if(f.data)return f.data;else return""};f.getFilename=function(){if(f.filenameCallback)return f.filenameCallback();else if(f.filename)return f.filename;else return""};f.getDataType=function(){if(f.options.dataType)return f.options.dataType;return"string"};f.complete=function(){if(typeof(f.options.onComplete)==="function")f.options.onComplete()};f.cancel=function(){if(typeof(f.options.onCancel)==="function")f.options.onCancel()};f.error=function(){if(typeof(f.options.onError)==="function")f.options.onError()};g()};Downloadify.defaultOptions={swf:'media/downloadify.swf',downloadImage:'images/download.png',width:100,height:30,transparent:true,append:false,dataType:"string"}})();if(typeof(jQuery)!="undefined"){(function($){$.fn.downloadify=function(b){return this.each(function(){b=$.extend({},Downloadify.defaultOptions,b);var a=Downloadify.create(this,b);$(this).data('Downloadify',a)})}})(jQuery)};if(typeof(MooTools)!='undefined'){Element.implement({downloadify:function(a){a=$merge(Downloadify.defaultOptions,a);return this.store('Downloadify',Downloadify.create(this,a))}})};
|
BIN
demos/oldie/downloadify.swf
Executable file
BIN
demos/oldie/downloadify.swf
Executable file
Binary file not shown.
122
122