forked from sheetjs/sheetjs
		
	updates to react demo
- bump react and babel - converted to functional components removed preact demo renamed jsx to js for next make instruction removed image component added pod install for pod linking
This commit is contained in:
		
							parent
							
								
									333deae63f
								
							
						
					
					
						commit
						58e59dcfd5
					
				@ -5,7 +5,7 @@ react: init ## Simple server for react and clones
 | 
			
		||||
.PHONY: next
 | 
			
		||||
next: init ## next.js demo
 | 
			
		||||
	mkdir -p pages static
 | 
			
		||||
	cat nexthdr.js sheetjs.jsx > pages/sheetjs.js
 | 
			
		||||
	cat nexthdr.js sheetjs.js > pages/sheetjs.js
 | 
			
		||||
	cp ../../shim.js static/shim.js
 | 
			
		||||
	next
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ native: ## Build react-native project
 | 
			
		||||
 | 
			
		||||
.PHONY: ios
 | 
			
		||||
ios: native ## react-native ios sim
 | 
			
		||||
	cd SheetJS; react-native run-ios --simulator="iPhone X"; cd -
 | 
			
		||||
	cd SheetJS; cd ios; pod install; cd -; react-native run-ios --simulator="iPhone X"; cd -
 | 
			
		||||
 | 
			
		||||
.PHONY: android
 | 
			
		||||
android: native ## react-native android sim
 | 
			
		||||
 | 
			
		||||
@ -13,19 +13,19 @@ The library can also be imported directly from JSX code with:
 | 
			
		||||
import XLSX from 'xlsx';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This demo shows a simple JSX component transpiled in the browser using the babel
 | 
			
		||||
This demo shows a simple React 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
 | 
			
		||||
 | 
			
		||||
## How to run
 | 
			
		||||
 | 
			
		||||
Run `make react` to run the browser demo for React, or run `make next` to run
 | 
			
		||||
the server-rendered demo using `next.js`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Internal State
 | 
			
		||||
 | 
			
		||||
The simplest state representation is an array of arrays.  To avoid having the
 | 
			
		||||
@ -116,15 +116,6 @@ set in the iOS project `Info.plist` file.
 | 
			
		||||
To run the React Native demo, run either `make ios` or `make android` while
 | 
			
		||||
connected to a device or emulator.
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
@ -6,9 +6,9 @@
 | 
			
		||||
<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/@babel/standalone/babel.min.js"></script>
 | 
			
		||||
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
 | 
			
		||||
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
 | 
			
		||||
<script src="node_modules/xlsx/dist/shim.min.js"></script>
 | 
			
		||||
<script src="node_modules/xlsx/dist/xlsx.full.min.js"></script>
 | 
			
		||||
<style>body, #app { height: 100%; };</style>
 | 
			
		||||
@ -21,18 +21,7 @@
 | 
			
		||||
<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" src="sheetjs.js"></script>
 | 
			
		||||
<script type="text/babel">
 | 
			
		||||
	ReactDOM.render( <SheetJSApp />, document.getElementById('app') );
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,42 +0,0 @@
 | 
			
		||||
<!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 Preact 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="node_modules/xlsx/dist/shim.min.js"></script>
 | 
			
		||||
<script src="node_modules/xlsx/dist/xlsx.full.min.js"></script>
 | 
			
		||||
<style>body, #app { height: 100%; };</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<div class="container-fluid">
 | 
			
		||||
<h1><a href="http://sheetjs.com">SheetJS Preact 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>
 | 
			
		||||
							
								
								
									
										65
									
								
								demos/react/react-native.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										65
									
								
								demos/react/react-native.js
									
									
									
									
										vendored
									
									
								
							@ -1,8 +1,17 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
 | 
			
		||||
import XLSX from 'xlsx';
 | 
			
		||||
 | 
			
		||||
import React, { Component } from 'react';
 | 
			
		||||
import { AppRegistry, StyleSheet, Text, View, Button, Alert, Image, ScrollView, TouchableWithoutFeedback } from 'react-native';
 | 
			
		||||
import { 
 | 
			
		||||
	AppRegistry, 
 | 
			
		||||
	StyleSheet, 
 | 
			
		||||
	Text, 
 | 
			
		||||
	View, 
 | 
			
		||||
	Button, 
 | 
			
		||||
	Alert, 
 | 
			
		||||
	Image, 
 | 
			
		||||
	ScrollView, 
 | 
			
		||||
	TouchableWithoutFeedback 
 | 
			
		||||
} from 'react-native';
 | 
			
		||||
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
 | 
			
		||||
 | 
			
		||||
// react-native-fs
 | 
			
		||||
@ -68,34 +77,36 @@ export default class SheetJS extends Component {
 | 
			
		||||
				Alert.alert("exportFile success", "Exported to " + file);
 | 
			
		||||
		}).catch((err) => { Alert.alert("exportFile Error", "Error " + err.message); });
 | 
			
		||||
	};
 | 
			
		||||
	render() { return (
 | 
			
		||||
<ScrollView contentContainerStyle={styles.container} vertical={true}>
 | 
			
		||||
	<Text style={styles.welcome}> </Text>
 | 
			
		||||
	<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>
 | 
			
		||||
	render() { 
 | 
			
		||||
		return (
 | 
			
		||||
			<ScrollView contentContainerStyle={styles.container} vertical={true}>
 | 
			
		||||
				<Text style={styles.welcome}> </Text>
 | 
			
		||||
				<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" />
 | 
			
		||||
 | 
			
		||||
	<ScrollView style={styles.table} horizontal={true} >
 | 
			
		||||
		<Table style={styles.table}>
 | 
			
		||||
			<TableWrapper>
 | 
			
		||||
				<Row data={this.state.cols} style={styles.thead} textStyle={styles.text} widthArr={this.state.widthArr}/>
 | 
			
		||||
			</TableWrapper>
 | 
			
		||||
			<TouchableWithoutFeedback>
 | 
			
		||||
				<ScrollView vertical={true}>
 | 
			
		||||
					<TableWrapper>
 | 
			
		||||
						<Rows data={this.state.data} style={styles.tr} textStyle={styles.text} widthArr={this.state.widthArr}/>
 | 
			
		||||
					</TableWrapper>
 | 
			
		||||
				<Text style={styles.instructions}>Current Data</Text>
 | 
			
		||||
 | 
			
		||||
				<ScrollView style={styles.table} horizontal={true} >
 | 
			
		||||
					<Table style={styles.table}>
 | 
			
		||||
						<TableWrapper>
 | 
			
		||||
							<Row data={this.state.cols} style={styles.thead} textStyle={styles.text} widthArr={this.state.widthArr}/>
 | 
			
		||||
						</TableWrapper>
 | 
			
		||||
						<TouchableWithoutFeedback>
 | 
			
		||||
							<ScrollView vertical={true}>
 | 
			
		||||
								<TableWrapper>
 | 
			
		||||
									<Rows data={this.state.data} style={styles.tr} textStyle={styles.text} widthArr={this.state.widthArr}/>
 | 
			
		||||
								</TableWrapper>
 | 
			
		||||
							</ScrollView>
 | 
			
		||||
						</TouchableWithoutFeedback>
 | 
			
		||||
					</Table>
 | 
			
		||||
				</ScrollView>
 | 
			
		||||
			</TouchableWithoutFeedback>
 | 
			
		||||
		</Table>
 | 
			
		||||
	</ScrollView>
 | 
			
		||||
</ScrollView>
 | 
			
		||||
	); };
 | 
			
		||||
			</ScrollView>
 | 
			
		||||
		); 
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const styles = StyleSheet.create({
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										145
									
								
								demos/react/sheetjs.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										145
									
								
								demos/react/sheetjs.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,145 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* 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
 | 
			
		||||
*/
 | 
			
		||||
function SheetJSApp() {
 | 
			
		||||
	const [data, setData] = React.useState([]);
 | 
			
		||||
	const [cols, setCols] = React.useState([]);
 | 
			
		||||
 | 
			
		||||
	const handleFile = (file) => {
 | 
			
		||||
		const reader = new FileReader();
 | 
			
		||||
		const rABS = !!reader.readAsBinaryString;
 | 
			
		||||
		reader.onload = (e) => {
 | 
			
		||||
			/* Parse data */
 | 
			
		||||
			const bstr = e.target.result;
 | 
			
		||||
			const wb = XLSX.read(bstr, {type:rABS ? 'binary' : 'array'});
 | 
			
		||||
			/* 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 */
 | 
			
		||||
			setData(data);
 | 
			
		||||
			setCols(make_cols(ws['!ref']))
 | 
			
		||||
		};
 | 
			
		||||
		if(rABS) reader.readAsBinaryString(file); else reader.readAsArrayBuffer(file);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const exportFile = () => {
 | 
			
		||||
		/* convert state to workbook */
 | 
			
		||||
		const ws = XLSX.utils.aoa_to_sheet(data);
 | 
			
		||||
		const wb = XLSX.utils.book_new();
 | 
			
		||||
		XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
 | 
			
		||||
		/* generate XLSX file and send to client */
 | 
			
		||||
		XLSX.writeFile(wb, "sheetjs.xlsx")
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
	<DragDropFile handleFile={handleFile}>
 | 
			
		||||
		<div className="row"><div className="col-xs-12">
 | 
			
		||||
			<DataInput handleFile={handleFile} />
 | 
			
		||||
		</div></div>
 | 
			
		||||
		<div className="row"><div className="col-xs-12">
 | 
			
		||||
			<button disabled={!data.length} className="btn btn-success" onClick={exportFile}>Export</button>
 | 
			
		||||
		</div></div>
 | 
			
		||||
		<div className="row"><div className="col-xs-12">
 | 
			
		||||
			<OutTable data={data} cols={cols} />
 | 
			
		||||
		</div></div>
 | 
			
		||||
	</DragDropFile>
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if(typeof module !== 'undefined') module.exports = SheetJSApp
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  Simple HTML5 file drag-and-drop wrapper
 | 
			
		||||
  usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
 | 
			
		||||
    handleFile(file:File):void;
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function DragDropFile({ handleFile, children }) {
 | 
			
		||||
	const suppress = (e) => { e.stopPropagation(); e.preventDefault(); };
 | 
			
		||||
	const handleDrop = (e) => { e.stopPropagation(); e.preventDefault();
 | 
			
		||||
		const files = e.dataTransfer.files;
 | 
			
		||||
		if(files && files[0]) handleFile(files[0]);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<div 
 | 
			
		||||
			onDrop={handleDrop} 
 | 
			
		||||
			onDragEnter={suppress} 
 | 
			
		||||
			onDragOver={suppress}
 | 
			
		||||
		>
 | 
			
		||||
		{children}
 | 
			
		||||
		</div>
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  Simple HTML5 file input wrapper
 | 
			
		||||
  usage: <DataInput handleFile={callback} />
 | 
			
		||||
    handleFile(file:File):void;
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function DataInput({ handleFile }) {
 | 
			
		||||
	const handleChange = (e) => {
 | 
			
		||||
		const files = e.target.files;
 | 
			
		||||
		if(files && files[0]) handleFile(files[0]);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<form className="form-inline">
 | 
			
		||||
			<div className="form-group">
 | 
			
		||||
				<label htmlFor="file">Drag or choose a spreadsheet file</label>
 | 
			
		||||
				<br />
 | 
			
		||||
				<input 
 | 
			
		||||
					type="file" 
 | 
			
		||||
					className="form-control" 
 | 
			
		||||
					id="file" 
 | 
			
		||||
					accept={SheetJSFT} 
 | 
			
		||||
					onChange={handleChange} 
 | 
			
		||||
				/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</form>
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  Simple HTML Table
 | 
			
		||||
  usage: <OutTable data={data} cols={cols} />
 | 
			
		||||
    data:Array<Array<any> >;
 | 
			
		||||
    cols:Array<{name:string, key:number|string}>;
 | 
			
		||||
*/
 | 
			
		||||
function OutTable({ data, cols }) {
 | 
			
		||||
	return (
 | 
			
		||||
		<div className="table-responsive">
 | 
			
		||||
			<table className="table table-striped">
 | 
			
		||||
				<thead>
 | 
			
		||||
					<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
 | 
			
		||||
				</thead>
 | 
			
		||||
				<tbody>
 | 
			
		||||
					{data.map((r,i) => <tr key={i}>
 | 
			
		||||
						{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(x => `.${x}`).join(",");
 | 
			
		||||
 | 
			
		||||
/* generate an array of column objects */
 | 
			
		||||
const make_cols = refstr => {
 | 
			
		||||
	let o = [], C = XLSX.utils.decode_range(refstr).e.c + 1;
 | 
			
		||||
	for(var i = 0; i < C; ++i) o[i] = {name:XLSX.utils.encode_col(i), key:i}
 | 
			
		||||
	return o;
 | 
			
		||||
};
 | 
			
		||||
@ -1,143 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present  SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* 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 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", K: 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();
 | 
			
		||||
		const rABS = !!reader.readAsBinaryString;
 | 
			
		||||
		reader.onload = (e) => {
 | 
			
		||||
			/* Parse data */
 | 
			
		||||
			const bstr = e.target.result;
 | 
			
		||||
			const wb = XLSX.read(bstr, {type:rABS ? 'binary' : 'array'});
 | 
			
		||||
			/* 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']) });
 | 
			
		||||
		};
 | 
			
		||||
		if(rABS) reader.readAsBinaryString(file); else reader.readAsArrayBuffer(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 and send to client */
 | 
			
		||||
		XLSX.writeFile(wb, "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
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  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(",");
 | 
			
		||||
 | 
			
		||||
/* generate an array of column objects */
 | 
			
		||||
const make_cols = refstr => {
 | 
			
		||||
	let o = [], C = XLSX.utils.decode_range(refstr).e.c + 1;
 | 
			
		||||
	for(var i = 0; i < C; ++i) o[i] = {name:XLSX.utils.encode_col(i), key:i}
 | 
			
		||||
	return o;
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user