demo refresh [ci skip]
This commit is contained in:
parent
0b29aa4c0f
commit
2fbe7a711e
11
Makefile
11
Makefile
@ -3,10 +3,9 @@ react: ## Simple server for react and clones
|
||||
python -mSimpleHTTPServer
|
||||
|
||||
.PHONY: next
|
||||
next: ## next.js demo
|
||||
# next doesn't support jsx extension
|
||||
next: init ## next.js demo
|
||||
mkdir -p pages
|
||||
cp sheetjs.jsx pages/sheetjs.js
|
||||
cat nexthdr.js sheetjs.jsx > pages/sheetjs.js
|
||||
next
|
||||
|
||||
.PHONY: native
|
||||
@ -20,3 +19,9 @@ ios: native ## react-native ios sim
|
||||
.PHONY: android
|
||||
android: native ## react-native android sim
|
||||
cd SheetJS; react-native run-android; cd -
|
||||
|
||||
.PHONY: init
|
||||
init: ## set up node_modules and symlink
|
||||
mkdir -p node_modules
|
||||
cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd -
|
||||
if [ ! -e node_modules/file-saver ]; then npm install file-saver; fi
|
||||
|
75
README.md
75
README.md
@ -1,7 +1,7 @@
|
||||
# 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.
|
||||
into web pages with script tags:
|
||||
|
||||
```html
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
@ -30,11 +30,7 @@ state in this demo is shaped like the following object:
|
||||
|
||||
```js
|
||||
{
|
||||
cols: [
|
||||
{ name: "A", key: 0 },
|
||||
{ name: "B", key: 1 },
|
||||
{ name: "C", key: 2 },
|
||||
],
|
||||
cols: [{ name: "A", key: 0 }, { name: "B", key: 1 }, { name: "C", key: 2 }],
|
||||
data: [
|
||||
[ "id", "name", "value" ],
|
||||
[ 1, "sheetjs", 7262 ]
|
||||
@ -43,7 +39,32 @@ state in this demo is shaped like the following object:
|
||||
}
|
||||
```
|
||||
|
||||
The appropriate state model is application-specific.
|
||||
`sheet_to_json` and `aoa_to_sheet` utility functions can convert between arrays
|
||||
of arrays and worksheets:
|
||||
|
||||
```js
|
||||
/* convert from workbook to array of arrays */
|
||||
var first_worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
var data = XLSX.utils.sheet_to_json(first_worksheet, {header:1});
|
||||
|
||||
/* convert from array of arrays to workbook */
|
||||
var worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
var new_workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(new_workbook, worksheet, "SheetJS");
|
||||
```
|
||||
|
||||
The column objects can be generated with the `encode_col` utility function:
|
||||
|
||||
```js
|
||||
function make_cols(refstr/*:string*/) {
|
||||
var o = [];
|
||||
var range = XLSX.utils.decode_range(refstr);
|
||||
for(var i = 0; i <= range.e.c; ++i) {
|
||||
o.push({name: XLSX.utils.encode_col(i), key:i});
|
||||
}
|
||||
return o;
|
||||
}
|
||||
```
|
||||
|
||||
## React Native
|
||||
|
||||
@ -52,6 +73,7 @@ The appropriate state model is application-specific.
|
||||
Reproducing the full project is straightforward:
|
||||
|
||||
```bash
|
||||
# see native.sh
|
||||
react-native init SheetJS
|
||||
cd SheetJS
|
||||
npm i -S xlsx react react-native react-native-table-component react-native-fs
|
||||
@ -60,9 +82,44 @@ 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:
|
||||
`react-native-table-component` draws the data table. `react-native-fs` reads
|
||||
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
|
||||
|
||||
`react-native-fs` supports `"ascii"` encoding for `readFile` and `writeFile`.
|
||||
In practice, that encoding uses binary strings compatible with `"binary"` type:
|
||||
|
||||
```js
|
||||
import { writeFile, readFile } from 'react-native-fs';
|
||||
|
||||
/* read a workbook */
|
||||
readFile(file, 'ascii').then((res) => {
|
||||
const workbook = XLSX.read(res, {type:'binary'});
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
});
|
||||
|
||||
/* write a workbook */
|
||||
const wbout = XLSX.write(wb, {type:'binary', bookType:"xlsx"});
|
||||
writeFile(file, wbout, 'ascii').then((r)=>{/* :) */}).catch((e)=>{/* :( */});
|
||||
```
|
||||
|
||||
## Other Demos
|
||||
|
||||
#### Preact
|
||||
|
||||
`preact-compat` is an easy-to-use compatibility layer that provides equivalents
|
||||
for `React` and `ReactDOM`. The `preact` demo uses the same JSX component code!
|
||||
[The docs](https://npm.im/preact-compat#use-without-webpackbrowserify) explain
|
||||
how to convert the in-browser React demo to Preact.
|
||||
|
||||
#### Server-Rendered React Components with Next.js
|
||||
|
||||
The demo uses the same component code as the in-browser version, but the build
|
||||
step adds a small header that imports the library. The import is not needed in
|
||||
deployments that use script tags to include the library.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
if [ ! -e SheetJS ]; then
|
||||
react-native init SheetJS
|
||||
cd SheetJS
|
||||
@ -13,5 +13,5 @@ fi
|
||||
cp react-native.js SheetJS/index.ios.js
|
||||
cp react-native.js SheetJS/index.android.js
|
||||
cd SheetJS;
|
||||
react-native link
|
||||
RNFB_ANDROID_PERMISSIONS=true react-native link
|
||||
cd -;
|
||||
|
3
nexthdr.js
Normal file
3
nexthdr.js
Normal file
@ -0,0 +1,3 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
import * as XLSX from 'xlsx';
|
||||
import { saveAs } from 'file-saver';
|
@ -6,16 +6,11 @@ export default () => (
|
||||
<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">
|
||||
<div className="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 />
|
||||
|
31
react-native.js
vendored
31
react-native.js
vendored
@ -1,13 +1,24 @@
|
||||
/* 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'
|
||||
|
||||
// react-native-fs
|
||||
import { writeFile, readFile, DocumentDirectoryPath } from 'react-native-fs';
|
||||
const DDP = DocumentDirectoryPath + "/";
|
||||
const input = res => res;
|
||||
const output = str => str;
|
||||
|
||||
// react-native-fetch-blob
|
||||
/*
|
||||
import RNFetchBlob from 'react-native-fetch-blob';
|
||||
const { writeFile, readFile, dirs:{ DocumentDir } } = RNFetchBlob.fs;
|
||||
const DDP = DocumentDir + "/";
|
||||
const input = res => res.map(x => String.fromCharCode(x)).join("");
|
||||
const output = str => str.split("").map(x => x.charCodeAt(0));
|
||||
*/
|
||||
|
||||
const make_cols = refstr => Array.from({length: XLSX.utils.decode_range(refstr).e.c + 1}, (x,i) => XLSX.utils.encode_col(i));
|
||||
|
||||
@ -26,22 +37,32 @@ export default class SheetJS extends Component {
|
||||
{text: 'Cancel', onPress: () => {}, style: 'cancel' },
|
||||
{text: 'Import', onPress: () => {
|
||||
readFile(DDP + "sheetjs.xlsx", 'ascii').then((res) => {
|
||||
const wb = XLSX.read(res, {type:'binary'});
|
||||
/* parse file */
|
||||
const wb = XLSX.read(input(res), {type:'binary'});
|
||||
|
||||
/* convert first worksheet to AOA */
|
||||
const wsname = wb.SheetNames[0];
|
||||
const ws = wb.Sheets[wsname];
|
||||
const data = XLSX.utils.sheet_to_json(ws, {header:1});
|
||||
|
||||
/* update state */
|
||||
this.setState({ data: data, cols: make_cols(ws['!ref']) });
|
||||
}).catch((err) => { Alert.alert("importFile Error", "Error " + err.message); });
|
||||
}}
|
||||
]);
|
||||
}
|
||||
exportFile() {
|
||||
/* convert AOA back to worksheet */
|
||||
const ws = XLSX.utils.aoa_to_sheet(this.state.data);
|
||||
|
||||
/* build new workbook */
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
|
||||
const wbout = XLSX.write(wb, {type:"binary", bookType:"xlsx"});
|
||||
|
||||
/* write file */
|
||||
const wbout = XLSX.write(wb, {type:'binary', bookType:"xlsx"});
|
||||
const file = DDP + "sheetjsw.xlsx";
|
||||
writeFile(file, wbout, 'ascii').then((res) =>{
|
||||
writeFile(file, output(wbout), 'ascii').then((res) =>{
|
||||
Alert.alert("exportFile success", "Exported to " + file);
|
||||
}).catch((err) => { Alert.alert("exportFile Error", "Error " + err.message); });
|
||||
};
|
||||
|
179
sheetjs.jsx
179
sheetjs.jsx
@ -1,95 +1,16 @@
|
||||
/* 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;
|
||||
/* Notes:
|
||||
- usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );`
|
||||
- xlsx.full.min.js is loaded in the head of the HTML page
|
||||
- this script should be referenced with type="text/babel"
|
||||
- babel.js in-browser transpiler should be loaded before this script
|
||||
*/
|
||||
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 } */
|
||||
cols: [] /* Array of column objects e.g. { name: "C", K: 2 } */
|
||||
};
|
||||
this.handleFile = this.handleFile.bind(this);
|
||||
this.exportFile = this.exportFile.bind(this);
|
||||
@ -137,3 +58,91 @@ class SheetJSApp extends React.Component {
|
||||
};
|
||||
|
||||
if(typeof module !== 'undefined') module.exports = SheetJSApp
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
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>
|
||||
); };
|
||||
}
|
||||
|
||||
/*
|
||||
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 key={c.key}>{c.name}</th>)}</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{this.props.data.map((r,i) => <tr key={i}>
|
||||
{this.props.cols.map(c => <td key={c.key}>{ r[c.key] }</td>)}
|
||||
</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
); };
|
||||
};
|
||||
|
||||
/* list of supported file types */
|
||||
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(",");
|
||||
|
||||
/* see Browser download file example in docs */
|
||||
function s2ab(s/*:string*/)/*:ArrayBuffer*/ {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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}));
|
||||
|
Loading…
Reference in New Issue
Block a user