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
commit 0b29aa4c0f
11 changed files with 433 additions and 0 deletions

2
.gitignore vendored Normal file

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

22
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
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
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
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
pages/.gitignore vendored Normal file

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

26
pages/index.js Normal file

@ -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
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
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
screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

139
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