updated demos [ci skip]

- frameworks: react, react-native, preact, next.js, weex, nuxt.js
- deployments: nodejs server, duktape, chakra, electron, nw.js
This commit is contained in:
SheetJS 2017-09-12 16:02:06 -04:00
parent ad47cb433c
commit f03e32fc9a
58 changed files with 1730 additions and 71 deletions

@ -167,21 +167,25 @@ CDNjs automatically pulls the latest version and makes all versions available at
The `demos` directory includes sample projects for:
**JS Frameworks and APIs**
**Frameworks and APIs**
- [`angular 1.x`](demos/angular/)
- [`angular 2.x / 4.x`](demos/angular2/)
- [`meteor`](demos/meteor/)
- [`vue 2.x`](demos/vue/)
- [`react and react-native`](demos/react/)
- [`vue 2.x and weex`](demos/vue/)
- [`XMLHttpRequest and fetch`](demos/xhr/)
- [`nodejs server`](demos/server/)
**JS Bundlers and Tooling**
**Bundlers and Tooling**
- [`browserify`](demos/browserify/)
- [`requirejs`](demos/requirejs/)
- [`rollup`](demos/rollup/)
- [`systemjs`](demos/systemjs/)
- [`webpack 2.x`](demos/webpack/)
**JS Platforms and Integrations**
**Platforms and Integrations**
- [`electron application`](demos/electron/)
- [`nw.js application`](demos/nwjs/)
- [`Adobe ExtendScript`](demos/extendscript/)
- [`Headless Browsers`](demos/headless/)
- [`canvas-datagrid`](demos/datagrid/)

@ -89,8 +89,14 @@ function wb_fmt() {
opts.cellNF = true;
if(program.output) sheetname = program.output;
}
workbook_formats.forEach(function(m) { if(program[m]) { wb_fmt(); } });
wb_formats_2.forEach(function(m) { if(program[m[0]]) { wb_fmt(); } });
function isfmt(m) {
if(!program.output) return false;
var t = m.charAt(0) == "." ? m : "." + m;
console.log(m);
return program.output.slice(-m.length) == m;
}
workbook_formats.forEach(function(m) { if(program[m] || isfmt(m)) { wb_fmt(); } });
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
if(seen) {
} else if(program.formulae) opts.cellFormula = true;
else opts.cellFormula = false;
@ -129,14 +135,14 @@ var wopts = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
if(program.compress) wopts.compression = true;
/* full workbook formats */
workbook_formats.forEach(function(m) { if(program[m]) {
X.writeFile(wb, sheetname || ((filename || "") + "." + m), wopts);
workbook_formats.forEach(function(m) { if(program[m] || isfmt(m)) {
X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m), wopts);
process.exit(0);
} });
wb_formats_2.forEach(function(m) { if(program[m[0]]) {
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
wopts.bookType = m[1];
X.writeFile(wb, sheetname || ((filename || "") + "." + m[2]), wopts);
X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
process.exit(0);
} });
@ -168,9 +174,9 @@ if(program.readOnly) process.exit(0);
['prn', '.prn'],
['txt', '.txt'],
['dif', '.dif']
].forEach(function(m) { if(program[m[0]]) {
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {
wopts.bookType = m[0];
X.writeFile(wb, sheetname || ((filename || "") + m[1]), wopts);
X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts);
process.exit(0);
} });

@ -1,6 +1,8 @@
jvm-npm.js
sheetjs.*
duk*
*.class
*.jar
rhino
xlsx.swift.js
xlsx.*.js
payload.js

@ -6,8 +6,11 @@ base:
if [ ! -e sheetjs.xlsx ]; then node ../../tests/write.js; fi
.PHONY: duktape
duktape: base ## duktape / skookum demo
sjs skookum.js
duktape: base ## duktape demo
bash ./duktape.sh
gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm
if [ ! -e xlsx.duktape.js ]; then cp ../../dist/xlsx.full.min.js xlsx.duktape.js; fi
./sheetjs.duk
.PHONY: nashorn
nashorn: base ## nashorn demo
@ -19,6 +22,12 @@ swift: base ## swift demo
if [ ! -e xlsx.swift.js ]; then cp ../../dist/xlsx.full.min.js xlsx.swift.js; fi
./SheetJSCore.swift
.PHONY: chakra
chakra: base ## Chakra demo
node -pe "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('sheetjs.xlsx').toString('base64') + '\";')"
cat global.js ../../dist/xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
chakra ./xlsx.chakra.js
.PHONY: rhinojs ## rhino demo
rhinojs: base SheetJSRhino.class
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xlsx

@ -50,14 +50,30 @@ context.setOptimizationLevel(-1);
```
## duktape and skookum
## ChakraCore
ChakraCore is an embeddable JS engine written in C++. The library and binary
distributions include a command-line tool `chakra` for running JS scripts.
The simplest way to interop with the engine is to pass Base64 strings. The make
target builds a very simple payload with the data.
## Duktape
[Duktape](http://duktape.org/) is an embeddable JS engine written in C. The
amalgamation makes integration extremely simple! Duktape understands the source
code and can process binary strings out the box, but does not provide I/O or
other standard library features.
amalgamation makes integration extremely simple! It supports `Buffer` natively:
To demonstrate compatibility with duktape, this demo uses the JS runtime from
[Skookum JS](https://github.com/saghul/sjs). Built upon the duktape engine, it
adds a simple I/O interface to enable reading from files.
```C
/* parse a C char array as a workbook object */
duk_push_external_buffer(ctx);
duk_config_buffer(ctx, -1, buf, len);
duk_put_global_string(ctx, "buf");
duk_eval_string_noresult("workbook = XLSX.read(buf, {type:'buffer'});");
/* write a workbook object to a C char array */
duk_eval_string(ctx, "XLSX.write(workbook, {type:'buffer', bookType:'xlsx'})");
duk_size_t sz;
char *buf = (char *)duk_get_buffer_data(ctx, -1, sz);
duk_pop(ctx);
```

3
demos/altjs/chakra.js Normal file

@ -0,0 +1,3 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var wb = XLSX.read(payload, {type:'base64'});
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));

17
demos/altjs/duktape.sh Executable file

@ -0,0 +1,17 @@
#!/bin/bash
DUKTAPE_VER=2.1.1
if [ ! -e duktape-$DUKTAPE_VER ]; then
if [ ! -e duktape-$DUKTAPE_VER.tar ]; then
if [ ! -e duktape-$DUKTAPE_VER.tar.xz ]; then
curl -O http://duktape.org/duktape-$DUKTAPE_VER.tar.xz
fi
xz -d duktape-$DUKTAPE_VER.tar.xz
fi
tar -xf duktape-$DUKTAPE_VER.tar
fi
for f in duktape.{c,h} duk_config.h; do
cp duktape-$DUKTAPE_VER/src/$f .
done

3
demos/altjs/global.js Normal file

@ -0,0 +1,3 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var global = (function(){ return this; }).call(null);

101
demos/altjs/sheetjs.duk.c Normal file

@ -0,0 +1,101 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "duktape.h"
#define FAIL_LOAD { \
duk_push_undefined(ctx); \
perror("Error in load_file"); \
return 1; \
}
static char *read_file(const char *filename, size_t *sz) {
FILE *f = fopen(filename, "rb");
if(!f) return NULL;
long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
char *buf = (char *)malloc(fsize * sizeof(char));
*sz = fread((void *) buf, 1, fsize, f);
fclose(f);
return buf;
}
static duk_int_t eval_file(duk_context *ctx, const char *filename) {
size_t len; char *buf = read_file(filename, &len);
if(!buf) FAIL_LOAD
duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len);
duk_int_t retval = duk_peval(ctx);
duk_pop(ctx);
return retval;
}
static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) {
size_t len; char *buf = read_file(filename, &len);
if(!buf) FAIL_LOAD
duk_push_external_buffer(ctx);
duk_config_buffer(ctx, -1, buf, len);
duk_put_global_string(ctx, var);
return 0;
}
static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) {
duk_get_global_string(ctx, var);
duk_size_t sz;
char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz);
if(!buf) return 1;
FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f);
return 0;
}
#define FAIL(cmd) { \
printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \
duk_destroy_heap(ctx); \
return res; \
}
#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd);
int main(int argc, char *argv[]) {
duk_int_t res = 0;
/* initialize */
duk_context *ctx = duk_create_heap_default();
/* duktape does not expose a standard "global" by default */
DOIT("var global = (function(){ return this; }).call(null);");
/* load library */
res = eval_file(ctx, "xlsx.duktape.js");
if(res != 0) FAIL("library load")
/* get version string */
duk_eval_string(ctx, "XLSX.version");
printf("SheetJS library version %s\n", duk_get_string(ctx, -1));
duk_pop(ctx);
/* read file */
res = load_file(ctx, "sheetjs.xlsx", "buf");
if(res != 0) FAIL("load sheetjs.xlsx")
/* parse workbook */
DOIT("wb = XLSX.read(buf, {type:'buffer'});");
DOIT("ws = wb.Sheets[wb.SheetNames[0]]");
/* print CSV */
duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)");
printf("%s\n", duk_get_string(ctx, -1));
duk_pop(ctx);
/* change cell A1 to 3 */
DOIT("ws['A1'].v = 3; delete ws['A1'].w;");
/* write file */
DOIT("newbuf = XLSX.write(wb, {type:'buffer', bookType:'xlsx'})");
res = save_file(ctx, "sheetjsw.xlsx", "newbuf");
if(res != 0) FAIL("save sheetjsw.xlsx")
/* cleanup */
duk_destroy_heap(ctx);
return res;
}

@ -1,13 +0,0 @@
#!/usr/bin/env sjs
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('../../xlsx.js');
var io = require('io');
var file = io.open("sheetjs.xlsx", "rb");
var strs = [], str = "";
while((str = file.read()).length > 0) strs.push(str);
var data = (Buffer.concat(strs.map(function(x) { return new Buffer(x); })));
var wb = XLSX.read(data, {type:"buffer"});
console.log(wb.Sheets[wb.SheetNames[0]]);

@ -6,9 +6,9 @@ The library can be imported directly from TS code with:
import * as XLSX from 'xlsx';
```
This demo uses an array of arrays as the core data structure. The component
template includes a file input element, a table that updates based on the data,
and a button to export the data.
This demo uses an array of arrays (type `Array<Array<any>>`) as the core state.
The component template includes a file input element, a table that updates with
the data, and a button to export the data.
## Switching between Angular versions

@ -24,8 +24,8 @@ function s2ab(s: string): ArrayBuffer {
<table class="sjs-table">
<tr *ngFor="let row of data">
<td *ngFor="let val of row">
{{val}}
</td>
{{val}}
</td>
</tr>
</table>
<button (click)="export()">Export!</button>

8
demos/electron/Makefile Normal file

@ -0,0 +1,8 @@
.PHONY: init
init:
mkdir -p node_modules
cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx ; fi; cd -
.PHONY: run
run:
electron .

19
demos/electron/README.md Normal file

@ -0,0 +1,19 @@
# Electron
This library is compatible with Electron and should just work out of the box.
The demonstration uses Electron v1.7.5. The library is added via `require` from
the render process. It can also be required from the main process, as shown in
this demo to render a version string in the About dialog on OSX.
The standard HTML5 `FileReader` techniques from the browser apply to Electron.
This demo includes a drag-and-drop box as well as a file input box, mirroring
the [SheetJS Data Preview Live Demo](http://oss.sheetjs.com/js-xlsx/)
Since electron provides an `fs` implementation, `readFile` and `writeFile` can
be used in conjunction with the standard dialogs. For example:
```js
var dialog = require('electron').remote.dialog;
var o = (dialog.showOpenDialog({ properties: ['openFile'] })||[''])[0];
var workbook = X.readFile(o);
```

37
demos/electron/index.html Normal file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>SheetJS Electron Demo</title>
<style>
#drop{
border:2px dashed #bbb;
-moz-border-radius:5px;
-webkit-border-radius:5px;
border-radius:5px;
padding:25px;
text-align:center;
font:20pt bold,"Vollkorn";color:#bbb
}
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Electron Demo</a></b>
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a>
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a>
<br />
<button id="readf">Click here to select a file from your computer</button><br />
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
</pre>
<div id="htmlout"></div>
<br />
<script src="index.js"></script>
</body>
</html>

79
demos/electron/index.js Normal file

@ -0,0 +1,79 @@
var X = require('xlsx');
var electron = require('electron').remote;
var process_wb = (function() {
var HTMLOUT = document.getElementById('htmlout');
return function process_wb(wb) {
HTMLOUT.innerHTML = "";
wb.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(wb, {sheet:sheetName, type:'binary', bookType:'html'});
HTMLOUT.innerHTML += htmlstr;
});
};
})();
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
var do_file = (function() {
return function do_file(files) {
var f = files[0];
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
data = new Uint8Array(data);
process_wb(X.read(data, {type: 'array'}));
};
reader.readAsArrayBuffer(f);
};
})();
(function() {
var drop = document.getElementById('drop');
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
do_file(e.dataTransfer.files);
}
function handleDragover(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}
drop.addEventListener('dragenter', handleDragover, false);
drop.addEventListener('dragover', handleDragover, false);
drop.addEventListener('drop', handleDrop, false);
})();
(function() {
var readf = document.getElementById('readf');
function handleF(e) {
var o = electron.dialog.showOpenDialog({
title: 'Select a file',
filters: [{
name: "Spreadsheets",
extensions: "xls|xlsx|xlsm|xlsb|xml|xlw|xlc|csv|txt|dif|sylk|slk|prn|ods|fods|uos|dbf|wks|123|wq1|qpw|htm|html".split("|")
}],
properties: ['openFile']
});
if(o.length > 0) process_wb(X.readFile(o[0]));
}
readf.addEventListener('click', handleF, false);
})();
(function() {
var xlf = document.getElementById('xlf');
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();

19
demos/electron/main.js Normal file

@ -0,0 +1,19 @@
/* from the electron quick-start */
var electron = require('electron');
var XLSX = require('xlsx');
var app = electron.app;
var win = null;
function createWindow() {
if(win) return;
win = new electron.BrowserWindow({width:800, height:600});
win.loadURL("file://" + __dirname + "/index.html");
win.webContents.openDevTools();
win.on('closed', function() { win = null; });
}
if(app.setAboutPanelOptions) app.setAboutPanelOptions({ applicationName: 'sheetjs-electron', applicationVersion: "XLSX " + XLSX.version, copyright: "(C) 2017-present SheetJS LLC" });
app.on('open-file', function() { console.log(arguments); });
app.on('ready', createWindow);
app.on('activate', createWindow);
app.on('window-all-closed', function() { if(process.platform !== 'darwin') app.quit(); });

@ -0,0 +1,10 @@
{
"name": "sheetjs-electron",
"author": "sheetjs",
"version": "0.0.0",
"main": "main.js",
"dependencies": {
"electron": "~1.7.x",
"xlsx": "*"
}
}

7
demos/nwjs/Makefile Normal file

@ -0,0 +1,7 @@
.PHONY: init
init:
if [ ! -e xlsx.full.min.js ]; then ln -s ../../dist/xlsx.full.min.js . ; fi
.PHONY: run
run:
nw .

10
demos/nwjs/README.md Normal file

@ -0,0 +1,10 @@
# NW.js
This library is compatible with NW.js and should just work out of the box.
The demonstration uses NW.js 0.24 with the dist script.
The standard HTML5 `FileReader` techniques from the browser apply to NW.js.
This demo includes a drag-and-drop box as well as a file input box, mirroring
the [SheetJS Data Preview Live Demo](http://oss.sheetjs.com/js-xlsx/)

37
demos/nwjs/index.html Normal file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>SheetJS NW.js Demo</title>
<style>
#drop{
border:2px dashed #bbb;
-moz-border-radius:5px;
-webkit-border-radius:5px;
border-radius:5px;
padding:25px;
text-align:center;
font:20pt bold,"Vollkorn";color:#bbb
}
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS NW.js Demo</a></b>
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a>
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a>
<br />
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
</pre>
<div id="htmlout"></div>
<br />
<script src="xlsx.full.min.js"></script>
<script src="index.js"></script>
</body>
</html>

62
demos/nwjs/index.js Normal file

@ -0,0 +1,62 @@
var X = XLSX;
var process_wb = (function() {
var HTMLOUT = document.getElementById('htmlout');
return function process_wb(wb) {
HTMLOUT.innerHTML = "";
wb.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(wb, {sheet:sheetName, type:'binary', bookType:'html'});
HTMLOUT.innerHTML += htmlstr;
});
};
})();
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
var do_file = (function() {
return function do_file(files) {
var f = files[0];
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
data = new Uint8Array(data);
process_wb(X.read(data, {type: 'array'}));
};
reader.readAsArrayBuffer(f);
};
})();
(function() {
var drop = document.getElementById('drop');
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
do_file(e.dataTransfer.files);
}
function handleDragover(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}
drop.addEventListener('dragenter', handleDragover, false);
drop.addEventListener('dragover', handleDragover, false);
drop.addEventListener('drop', handleDrop, false);
})();
(function() {
var xlf = document.getElementById('xlf');
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();

10
demos/nwjs/package.json Normal file

@ -0,0 +1,10 @@
{
"name": "sheetjs-nwjs",
"author": "sheetjs",
"version": "0.0.0",
"main": "index.html",
"dependencies": {
"nw": "~0.24.4",
"xlsx": "*"
}
}

1
demos/nwjs/xlsx.full.min.js vendored Symbolic link

@ -0,0 +1 @@
../../dist/xlsx.full.min.js

2
demos/react/.gitignore vendored Normal file

@ -0,0 +1,2 @@
SheetJS
.next

22
demos/react/Makefile Normal file

@ -0,0 +1,22 @@
.PHONY: react
react: ## Simple server for react and clones
python -mSimpleHTTPServer
.PHONY: next
next: ## next.js demo
# next doesn't support jsx extension
mkdir -p pages
cp sheetjs.jsx pages/sheetjs.js
next
.PHONY: native
native: ## Build react-native project
bash ./native.sh
.PHONY: ios
ios: native ## react-native ios sim
cd SheetJS; react-native run-ios; cd -
.PHONY: android
android: native ## react-native android sim
cd SheetJS; react-native run-android; cd -

68
demos/react/README.md Normal file

@ -0,0 +1,68 @@
# React
The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped
into web pages with script tags e.g.
```html
<script src="xlsx.full.min.js"></script>
```
The library can also be imported directly from JSX code with:
```js
import * as XLSX from 'xlsx';
```
This demo shows a simple JSX component transpiled in the browser using the babel
standalone library. Since there is no standard React table model, this demo
settles on the array of arrays approach.
Other scripts in this demo show:
- server-rendered React component (with `next.js`)
- `preact` using the react compatibility library
- `react-native` deployment for iOS and android
## Internal State
The simplest state representation is an array of arrays. To avoid having the
table component depend on the library, the column labels are precomputed. The
state in this demo is shaped like the following object:
```js
{
cols: [
{ name: "A", key: 0 },
{ name: "B", key: 1 },
{ name: "C", key: 2 },
],
data: [
[ "id", "name", "value" ],
[ 1, "sheetjs", 7262 ]
[ 2, "js-xlsx", 6969 ]
]
}
```
The appropriate state model is application-specific.
## React Native
<img src="screen.png" width="400px"/>
Reproducing the full project is straightforward:
```bash
react-native init SheetJS
cd SheetJS
npm i -S xlsx react react-native react-native-table-component react-native-fs
cp ../react-native.js index.ios.js
cp ../react-native.js index.android.js
react-native link
```
This uses `react-native-fs` to read and write files on devices. The app will
prompt before reading and after writing data. The printed location will be:
- android: path in the device filesystem
- iOS simulator: local path to file
- iOS device: a path accessible from iTunes App Documents view

40
demos/react/index.html Normal file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html lang="en" style="height: 100%">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>SheetJS React Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<script src="https://unpkg.com/file-saver/FileSaver.js"></script>
<style>body, #app { height: 100%; };</style>
</head>
<body>
<div class="container-fluid">
<h1><a href="http://sheetjs.com">SheetJS React Demo</a></h1>
<br />
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a><br />
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a><br /><br />
</div>
<div id="app" class="container-fluid"></div>
<script type="text/babel" src="sheetjs.jsx"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<script type="text/babel">
ReactDOM.render( <SheetJSApp />, document.getElementById('app') );
</script>
</body>
</html>

17
demos/react/native.sh Executable file

@ -0,0 +1,17 @@
#!/bin/bash
if [ ! -e SheetJS ]; then
react-native init SheetJS
cd SheetJS
npm i -S xlsx react react-native react-native-table-component react-native-fs
cd -
fi
if [ ! -e SheetJS/logo.png ]; then
curl -O http://oss.sheetjs.com/assets/img/logo.png
mv logo.png SheetJS/logo.png
fi
cp react-native.js SheetJS/index.ios.js
cp react-native.js SheetJS/index.android.js
cd SheetJS;
react-native link
cd -;

1
demos/react/pages/.gitignore vendored Normal file

@ -0,0 +1 @@
sheetjs.js

@ -0,0 +1,26 @@
import Head from 'next/head'
import SheetJSApp from './sheetjs.js'
export default () => (
<div>
<Head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>SheetJS React Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<script src="https://unpkg.com/file-saver/FileSaver.js"></script>
<style jsx>{`
body, #app { height: 100%; };
`}</style>
</Head>
<div class="container-fluid">
<h1><a href="http://sheetjs.com">SheetJS React Demo</a></h1>
<br />
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a><br />
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a><br /><br />
</div>
<SheetJSApp />
</div>
)

42
demos/react/preact.html Normal file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html lang="en" style="height: 100%">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>SheetJS React Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="//unpkg.com/preact"></script>
<script src="//unpkg.com/proptypes"></script>
<script src="//unpkg.com/preact-compat"></script>
<script>var React = preactCompat, ReactDOM = preactCompat;</script>
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<script src="https://unpkg.com/file-saver/FileSaver.js"></script>
<style>body, #app { height: 100%; };</style>
</head>
<body>
<div class="container-fluid">
<h1><a href="http://sheetjs.com">SheetJS React Demo</a></h1>
<br />
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a><br />
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a><br /><br />
</div>
<div id="app" class="container-fluid"></div>
<script type="text/babel" src="sheetjs.jsx"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<script type="text/babel">
ReactDOM.render( <SheetJSApp />, document.getElementById('app') );
</script>
</body>
</html>

76
demos/react/react-native.js vendored Normal file

@ -0,0 +1,76 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import * as XLSX from 'xlsx';
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, Button, Alert, Image } from 'react-native';
import { Table, Row, Rows } from 'react-native-table-component';
import { writeFile, readFile, DocumentDirectoryPath } from 'react-native-fs'
const DDP = DocumentDirectoryPath + "/";
const make_cols = refstr => Array.from({length: XLSX.utils.decode_range(refstr).e.c + 1}, (x,i) => XLSX.utils.encode_col(i));
export default class SheetJS extends Component {
constructor(props) {
super(props);
this.state = {
data: [[1,2,3],[4,5,6]],
cols: make_cols("A1:C2")
};
this.importFile = this.importFile.bind(this);
this.exportFile = this.exportFile.bind(this);
};
importFile() {
Alert.alert("Rename file to sheetjs.xlsx", "Copy to " + DDP, [
{text: 'Cancel', onPress: () => {}, style: 'cancel' },
{text: 'Import', onPress: () => {
readFile(DDP + "sheetjs.xlsx", 'ascii').then((res) => {
const wb = XLSX.read(res, {type:'binary'});
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = XLSX.utils.sheet_to_json(ws, {header:1});
this.setState({ data: data, cols: make_cols(ws['!ref']) });
}).catch((err) => { Alert.alert("importFile Error", "Error " + err.message); });
}}
]);
}
exportFile() {
const ws = XLSX.utils.aoa_to_sheet(this.state.data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
const wbout = XLSX.write(wb, {type:"binary", bookType:"xlsx"});
const file = DDP + "sheetjsw.xlsx";
writeFile(file, wbout, 'ascii').then((res) =>{
Alert.alert("exportFile success", "Exported to " + file);
}).catch((err) => { Alert.alert("exportFile Error", "Error " + err.message); });
};
render() { return (
<View style={styles.container}>
<Image style={{width: 128, height: 128}} source={require('./logo.png')} />
<Text style={styles.welcome}>SheetJS React Native Demo</Text>
<Text style={styles.instructions}>Import Data</Text>
<Button onPress={this.importFile} title="Import data from a spreadsheet" color="#841584" />
<Text style={styles.instructions}>Export Data</Text>
<Button disabled={!this.state.data.length} onPress={this.exportFile} title="Export data to XLSX" color="#841584" />
<Text style={styles.instructions}>Current Data</Text>
<Table style={styles.table}>
<Row data={this.state.cols} style={styles.thead} textStyle={styles.text}/>
<Rows data={this.state.data} style={styles.tr} textStyle={styles.text}/>
</Table>
</View>
); };
};
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF' },
welcome: { fontSize: 20, textAlign: 'center', margin: 10 },
instructions: { textAlign: 'center', color: '#333333', marginBottom: 5 },
thead: { height: 40, backgroundColor: '#f1f8ff' },
tr: { height: 30 },
text: { marginLeft: 5 },
table: { width: "100%" }
});
AppRegistry.registerComponent('SheetJS', () => SheetJS);

BIN
demos/react/screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

139
demos/react/sheetjs.jsx Normal file

@ -0,0 +1,139 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
const SheetJSFT = [
"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm"
].map(function(x) { return "." + x; }).join(",");
/*
Simple HTML5 file drag-and-drop wrapper
usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
handleFile(file:File):void;
*/
class DragDropFile extends React.Component {
constructor(props) {
super(props);
this.onDrop = this.onDrop.bind(this);
};
suppress(evt) { evt.stopPropagation(); evt.preventDefault(); };
onDrop(evt) { evt.stopPropagation(); evt.preventDefault();
const files = evt.dataTransfer.files;
if(files && files[0]) this.props.handleFile(files[0]);
};
render() { return (
<div onDrop={this.onDrop} onDragEnter={this.suppress} onDragOver={this.suppress}>
{this.props.children}
</div>
); };
};
/*
Simple HTML5 file input wrapper
usage: <DataInput handleFile={callback} />
handleFile(file:File):void;
*/
class DataInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
};
handleChange(e) {
const files = e.target.files;
if(files && files[0]) this.props.handleFile(files[0]);
};
render() { return (
<form className="form-inline">
<div className="form-group">
<label htmlFor="file">Spreadsheet</label>
<input type="file" className="form-control" id="file" accept={SheetJSFT} onChange={this.handleChange} />
</div>
</form>
); };
}
/* generate an array of column objects */
const make_cols = refstr => Array(XLSX.utils.decode_range(refstr).e.c + 1).fill(0).map((x,i) => ({name:XLSX.utils.encode_col(i), key:i}));
/*
Simple HTML Table
usage: <OutTable data={data} cols={cols} />
data:Array<Array<any> >;
cols:Array<{name:string, key:number|string}>;
*/
class OutTable extends React.Component {
constructor(props) { super(props); };
render() { return (
<div className="table-responsive">
<table className="table table-striped">
<thead>
<tr>{this.props.cols.map((c) => <th>{c.name}</th>)}</tr>
</thead>
<tbody>
{this.props.data.map(r => <tr>
{this.props.cols.map(c => <td key={c.key}>{ r[c.key] }</td>)}
</tr>)}
</tbody>
</table>
</div>
); };
};
/* see Browser download file example in docs */
function s2ab(s) {
const buf = new ArrayBuffer(s.length);
const view = new Uint8Array(buf);
for (let i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
class SheetJSApp extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [], /* Array of Arrays e.g. [["a","b"],[1,2]] */
cols: [] /* Array of column objects e.g. { name: "C", key: 2 } */
};
this.handleFile = this.handleFile.bind(this);
this.exportFile = this.exportFile.bind(this);
};
handleFile(file/*:File*/) {
/* Boilerplate to set up FileReader */
const reader = new FileReader();
reader.onload = (e) => {
/* Parse data */
const bstr = e.target.result;
const wb = XLSX.read(bstr, {type:'binary'});
/* Get first worksheet */
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
/* Convert array of arrays */
const data = XLSX.utils.sheet_to_json(ws, {header:1});
/* Update state */
this.setState({ data: data, cols: make_cols(ws['!ref']) });
};
reader.readAsBinaryString(file);
};
exportFile() {
/* convert state to workbook */
const ws = XLSX.utils.aoa_to_sheet(this.state.data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
/* generate XLSX file */
const wbout = XLSX.write(wb, {type:"binary", bookType:"xlsx"});
/* send to client */
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "sheetjs.xlsx");
};
render() { return (
<DragDropFile handleFile={this.handleFile}>
<div className="row"><div className="col-xs-12">
<DataInput handleFile={this.handleFile} />
</div></div>
<div className="row"><div className="col-xs-12">
<button disabled={!this.state.data.length} className="btn btn-success" onClick={this.exportFile}>Export</button>
</div></div>
<div className="row"><div className="col-xs-12">
<OutTable data={this.state.data} cols={this.state.cols} />
</div></div>
</DragDropFile>
); };
};
if(typeof module !== 'undefined') module.exports = SheetJSApp

21
demos/server/Makefile Normal file

@ -0,0 +1,21 @@
.PHONY: init
init:
if [ ! -e sheetjs.xlsx ]; then ln -s ../../sheetjs.xlsx; fi
mkdir -p node_modules
cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd -
.PHONY: request
request: init ## request demo
node _request.js
.PHONY: express
express: init ## express demo
node express.js
.PHONY: micro
micro: init ## micro demo
micro -p 7262 micro.js
.PHONY: koa
koa: init ## koa demo
node koa.js

96
demos/server/README.md Normal file

@ -0,0 +1,96 @@
# NodeJS Server Deployments
This library is 100% pure JS. This is great for compatibility but tends to lock
up long-running processes. In the web browser, Web Workers are used to offload
work from the main browser thread. In NodeJS, there are other strategies. This
demo shows a few different strategies applied to different server frameworks.
NOTE: these examples merely demonstrate the core concepts and do not include
appropriate error checking or other production-level features.
### Node Buffer
The `read` and `write` functions can handle `Buffer` data with `type:"buffer"`.
For example, the `request` library returns data in a buffer:
```js
var XLSX = require('xlsx'), request = require('request');
request(url, {encoding: null}, function(err, res, data) {
if(err || res.statusCode !== 200) return;
/* data is a node Buffer that can be passed to XLSX.read */
var workbook = XLSX.read(data, {type:'buffer'});
/* DO SOMETHING WITH workbook HERE */
});
```
### Example servers
Each example server is expected to hold an array-of-arrays in memory. They are
expected to handle:
- `POST / ` accepts an encoded `file` and updates the internal storage
- `GET /?t=<type>` returns the internal storage in the specified type
- `POST /?f=<name>` reads the local file and updates the internal storage
- `GET /?f=<name>` writes the file to the specified name
Testing with cURL is straightforward:
```bash
# upload test.xls and update data
curl -X POST -F "data=@test.xls" http://localhost:7262/
# download data in SYLK format
curl -X GET http://localhost:7262/?t=slk
# read sheetjs.xlsx from the server directory
curl -X POST http://localhost:7262/?f=sheetjs.xlsx
# write sheetjs.xlsb in the XLSB format
curl -X GET http://localhost:7262/?f=sheetjs.xlsb
```
## Main-process logic with express
The most straightforward approach is to handle the data directly in HTTP event
handlers. The `buffer` type for `XLSX.read` and `XLSX.write` work with `http`
module and with express directly. The following snippet generates a workbook
based on an array of arrays and sends it to the client:
```js
function send_aoa_to_client(req, res, data, bookType) {
/* generate workbook */
var ws = XLSX.utils.aoa_to_sheet(data);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
/* generate buffer */
var buf = XLSX.write(wb, {type:'buffer', bookType:bookType || "xlsx"});
/* send to client */
res.status(200).send(buf);
}
```
## fork with koa
`child_process.fork` provides a light-weight and customizable way to offload
work from the main server process. This demo passes commands to a custom child
process and the child passes back buffers of data.
The main server script is `koa.js` and the worker script is `koasub.js`. State
is maintained in the worker script.
## xlsx script with micro
The node module ships with the `xlsx` bin script. For global installs, symlinks
are configured to enable running `xlsx` from anywhere. For local installs, the
appropriate symlink is set up in `node_modules/.bin/`.
The `--arrays` option directs `xlsx` to generate an array of arrays that can be
parsed by the server. To generate files, the `json2csv` module exports the JS
array of arrays to a CSV, the server writes the file, and the `xlsx` command is
used to generate files of different formats.

4
demos/server/_cors.js Normal file

@ -0,0 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var cors = function(req, res) { res.header('Access-Control-Allow-Origin', '*'); };
cors.mw = function(req, res, next) { cors(req, res); next(); };
module.exports = cors;

7
demos/server/_logit.js Normal file

@ -0,0 +1,7 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var sprintf = require('printj').sprintf;
var logit = function(req, res) {
console.log(sprintf("%s %s %d", req.method, req.url, res.statusCode));
};
logit.mw = function(req, res, next) { logit(req, res); next(); }
module.exports = logit;

9
demos/server/_request.js Normal file

@ -0,0 +1,9 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('xlsx'), request = require('request');
var url = 'http://www.freddiemac.com/pmms/2017/historicalweeklydata.xls'
request(url, {encoding: null}, function(err, res, data) {
if(err || res.statusCode !== 200) return;
var wb = XLSX.read(data, {type:'buffer'});
var ws = wb.Sheets[wb.SheetNames[0]];
console.log(XLSX.utils.sheet_to_csv(ws, {blankrows:false}));
});

65
demos/server/express.js Normal file

@ -0,0 +1,65 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var fs = require('fs'), path = require('path'), URL = require('url');
var express = require('express'), app = express();
var sprintf = require('printj').sprintf;
var logit = require('./_logit');
var cors = require('./_cors');
var data = "a,b,c\n1,2,3".split("\n").map(function(x) { return x.split(","); });
var XLSX = require('xlsx');
/* helper to generate the workbook object */
function make_book() {
var ws = XLSX.utils.aoa_to_sheet(data);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
return wb;
}
function get_data(req, res, type) {
var wb = make_book();
/* send buffer back */
res.status(200).send(XLSX.write(wb, {type:'buffer', bookType:type}));
}
function get_file(req, res, file) {
var wb = make_book();
/* write using XLSX.writeFile */
XLSX.writeFile(wb, file);
res.status(200).send("wrote to " + file + "\n");
}
function load_data(file) {
var wb = XLSX.readFile(file);
/* generate array of arrays */
data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1});
console.log(data);
}
function post_data(req, res) {
var keys = Object.keys(req.files), k = keys[0];
load_data(req.files[k].path);
res.status(200).send("ok\n");
}
function post_file(req, res, file) {
load_data(file);
res.status(200).send("ok\n");
}
app.use(logit.mw);
app.use(cors.mw);
app.use(require('express-formidable')());
app.get('/', function(req, res, next) {
var url = URL.parse(req.url, true);
if(url.query.t) return get_data(req, res, url.query.t);
else if(url.query.f) return get_file(req, res, url.query.f);
res.status(403).end("Forbidden");
});
app.post('/', function(req, res, next) {
var url = URL.parse(req.url, true);
if(url.query.f) return post_file(req, res, url.query.f);
return post_data(req, res);
});
var port = +process.argv[2] ||