demo refresh [ci skip]

This commit is contained in:
SheetJS 2017-09-24 19:40:09 -04:00
parent d02650055d
commit 1a8f97269e
132 changed files with 3179 additions and 1906 deletions

109
.spelling Normal file

@ -0,0 +1,109 @@
# xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com
SheetJS
js-xlsx
xls
xlsb
xlsx
# Excel-related terms
A1-style
AutoFilter
ECMA-376
FoxPro
Multiplan
OData
OpenDocument
OpenFormula
PivotTable
Quattro
SpreadsheetML
Unhide
Visicalc
chartsheet
chartsheets
dBASE
tooltip
tooltips
# Third-party
Browserify
CDNjs
CommonJS
ExtendScript
FileSaver
JavaScriptCore
NPM
Nuxt.js
RequireJS
Rollup
SystemJS
VueJS
iOS
nodejs
npm
unpkg
webpack
weex
# Other terms
APIs
Base64
Booleans
JS
README
UTF-16
XHR
XMLHttpRequest
bundlers
cleanroom
config
customizable
datagrid
deduplication
embeddable
filesystem
javascript
metadata
natively
prepend
prepended
repo
runtime
submodule
transpiled
- demos/altjs/README.md
ChakraCore
Duktape
Nashorn
- demos/angular/README.md
angular-ui-grid
ui-grid
- demos/angular2/README.md
angular-cli
- demos/extendscript/README.md
Photoshop
minifier
- demos/headless/README.md
PhantomJS
SlimerJS
wkhtmltopdf
- demos/nwjs/README.md
NW.js
- demos/react/README.md
Next.js
Preact
- demos/server/README.md
hapi
- demos/xhr/README.md
axios
superagent

@ -209,6 +209,13 @@ book: readme graph ## Update summary for documentation
markdown-toc README.md | sed 's/(#/(README.md#/g'>> misc/docs/SUMMARY.md
<README.md grep -vE "(details|summary)>" > misc/docs/README.md
DEMOMDS=$(sort $(wildcard demos/*/README.md))
MDLINT=$(DEMODS) $(READEPS) demos/README.md
.PHONY: mdlint
mdlint: $(MDLINT) ## Check markdown documents
alex $^
mdspell -a -n -x -r --en-us $^
.PHONY: help
help:
@grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | bash misc/help.sh

795
README.md

File diff suppressed because it is too large Load Diff

@ -8,5 +8,37 @@ works extremely well in common use cases: script tag insertion and node require.
Systems like webpack try to be clever by performing simple static analysis to
pull in code. However, they do not support dynamic type tests, breaking
compatibility with traditional scripts. Configuration is required. The demos
cover basic configuration steps for various systems and should work as laid out.
cover basic configuration steps for various systems and should "just work".
Mobile app and other larger demos do not include the full build structure. The
demos have `Makefile` scripts that show how to reproduce the full projects. The
scripts have been tested against iOS and OSX. For Windows platforms, GNU make
can be installed with Bash on Windows or with `cygwin`.
### Included Demos
**Frameworks and APIs**
- [`angular 1.x`](angular/)
- [`angular 2.x / 4.x`](angular2/)
- [`meteor`](meteor/)
- [`react and react-native`](react/)
- [`vue 2.x and weex`](vue/)
- [`XMLHttpRequest and fetch`](xhr/)
- [`nodejs server`](server/)
**Bundlers and Tooling**
- [`browserify`](browserify/)
- [`requirejs`](requirejs/)
- [`rollup`](rollup/)
- [`systemjs`](systemjs/)
- [`webpack 2.x`](webpack/)
**Platforms and Integrations**
- [`electron application`](electron/)
- [`nw.js application`](nwjs/)
- [`Adobe ExtendScript`](extendscript/)
- [`Headless Browsers`](headless/)
- [`canvas-datagrid`](datagrid/)
- [`Swift JSC and other engines`](altjs/)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -17,9 +17,52 @@ var global = (function(){ return this; }).call(null);
iOS and OSX ship with the JavaScriptCore framework, enabling easy JS access from
Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
passing is straightforward.
passing is straightforward. The demo shows a standalone example for OSX. For
playgrounds, the library should be copied to shared playground data directory
(usually `~/Documents/Shared Playground Data`):
Binary strings can be passed back and forth using `String.Encoding.ascii`.
```swift
/* This only works in a playground, see SheetJSCore.swift for standalone use */
import JavaScriptCore;
import PlaygroundSupport;
/* build path variable for the library */
let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory;
let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js");
/* prepare JS context */
var context:JSContext! = JSContext();
var src = "var global = (function(){ return this; }).call(null);";
context.evaluateScript(src);
/* load library */
var lib = try? String(contentsOf: lib_path);
context.evaluateScript(lib);
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
/* to verify the library was loaded, get the version string */
let XLSXversion: JSValue! = XLSX.objectForKeyedSubscript("version")
var version = XLSXversion.toString();
```
Binary strings can be passed back and forth using `String.Encoding.isoLatin1`:
```swift
/* parse sheetjs.xls */
let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
let data:String! = try String(contentsOf: file_path, encoding:String.Encoding.isoLatin1);
context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
src = "var wb = XLSX.read(payload, {type:'binary'});";
context.evaluateScript(src);
/* write to sheetjs.xlsx */
let out_path = shared_dir.appendingPathComponent("sheetjs.xlsx");
src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})";
context.evaluateScript(src);
let outvalue: JSValue! = context.objectForKeyedSubscript("out");
var out:String! = outvalue.toString();
try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);
```
## Nashorn
@ -42,7 +85,7 @@ array and calls `XLSX.read` with type `"array"`.
`SheetJSRhino` class and `com.sheetjs` package show a complete JAR deployment,
including the full XLSX source.
Due to code generation errors, optimization must be disabled:
Due to code generation errors, optimization must be turned off:
```java
Context context = Context.enter();
@ -55,7 +98,7 @@ context.setOptimizationLevel(-1);
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
The simplest way to interact with the engine is to pass Base64 strings. The make
target builds a very simple payload with the data.
@ -77,3 +120,5 @@ duk_size_t sz;
char *buf = (char *)duk_get_buffer_data(ctx, -1, sz);
duk_pop(ctx);
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -0,0 +1,37 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* This only works in a playground, see SheetJSCore.swift for standalone use */
import JavaScriptCore;
import PlaygroundSupport;
/* build path variable for the library */
let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory;
let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js");
/* prepare JS context */
var context:JSContext! = JSContext();
var src = "var global = (function(){ return this; }).call(null);";
context.evaluateScript(src);
/* load library */
var lib = try? String(contentsOf: lib_path);
context.evaluateScript(lib);
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
/* to verify the library was loaded, get the version string */
let XLSXversion: JSValue! = XLSX.objectForKeyedSubscript("version")
var version = XLSXversion.toString();
/* parse sheetjs.xls */
let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
let data:String! = try String(contentsOf: file_path, encoding:String.Encoding.isoLatin1);
context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
src = "var wb = XLSX.read(payload, {type:'binary'});";
context.evaluateScript(src);
/* write to sheetjs.xlsx */
let out_path = shared_dir.appendingPathComponent("sheetjs.xlsx");
src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})";
context.evaluateScript(src);
let outvalue: JSValue! = context.objectForKeyedSubscript("out");
var out:String! = outvalue.toString();
try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);

@ -1,5 +1,5 @@
#!/usr/bin/env xcrun swift
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import JavaScriptCore;
class SheetJS {
@ -30,7 +30,7 @@ class SheetJS {
}
func readFileToCSV(file: String) throws -> String {
let data:String! = try String(contentsOfFile: file, encoding:String.Encoding.ascii);
let data:String! = try String(contentsOfFile: file, encoding:String.Encoding.isoLatin1);
self.context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
let src = [

@ -1,7 +1,7 @@
# Angular 1
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>
@ -12,21 +12,94 @@ as you would with any other browser-friendly library. To make this meaningful,
we chose to show an integration with a common angular table component.
This demo uses angular-ui-grid to display a data table. The ui-grid does not
provide any way to hook into the import button, so the demo includes a simple
provide any way to modify the import button, so the demo includes a simple
directive for a HTML File Input control. It also includes a sample service for
export which adds an item to the export menu.
## Import Directive
`SheetJSImportDirective` follows the prescription from the README for File input
controls using `readAsBinaryString`, converting to a suitable representation
and updating the scope.
A general import directive is fairly straightforward:
- Define the `importSheetJs` directive in the app:
```js
app.directive("importSheetJs", [SheetJSImportDirective]);
```
- Add the attribute `import-sheet-js=""` to the file input element:
```html
<input type="file" import-sheet-js="" multiple="false" />
```
- Define the directive:
```js
var SheetJSImportDirective = function() {
return {
scope: { },
link: function ($scope, $elm, $attrs) {
$elm.on('change', function (changeEvent) {
var reader = new FileReader();
reader.onload = function (e) {
/* read workbook */
var bstr = e.target.result;
var workbook = XLSX.read(bstr, {type:'binary'});
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsBinaryString(changeEvent.target.files[0]);
});
}
};
};
```
The demo `SheetJSImportDirective` follows the prescription from the README for
File input controls using `readAsBinaryString`, converting to a suitable
representation and updating the scope.
## Export Service
An export can be triggered at any point! Depending on how data is represented,
a workbook object can be built using the utility functions. For example, using
an array of objects:
```js
/* starting from this data */
var data = [
{ name: "Barack Obama", pres: 44 },
{ name: "Donald Trump", pres: 45 }
];
/* generate a worksheet */
var ws = XLSX.utils.json_to_sheet(data);
/* add to workbook */
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
/* write workbook (use type 'binary') */
var wbout = XLSX.write(wb, {bookType:'xlsx', type:'binary'});
/* generate a download */
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "sheetjs.xlsx");
```
`SheetJSExportService` exposes export functions for `XLSB` and `XLSX`. Other
formats are easily supported by changing the `bookType` variable. It grabs
values from the grid, builds an array of arrays, generates a workbook and uses
FileSaver to generate a download. By setting the `filename` and `sheetname`
options in the ui-grid options, the output can be controlled.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -103,5 +103,5 @@ var SheetJSImportDirective = function() {
reader.readAsBinaryString(changeEvent.target.files[0]);
});
}
}
}
};
};

@ -10,6 +10,61 @@ 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.
## Array of Arrays
`Array<Array<any>>` neatly maps to a table with `ngFor`:
```html
<table class="sjs-table">
<tr *ngFor="let row of data">
<td *ngFor="let val of row">
{{val}}
</td>
</tr>
</table>
```
The `aoa_to_sheet` utility function returns a worksheet. Exporting is simple:
```typescript
/* generate worksheet */
const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
/* generate workbook and add the worksheet */
const wb: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
/* save to file */
const wbout: string = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)]), 'SheetJS.xlsx');
```
`sheet_to_json` with the option `header:1` makes importing simple:
```typescript
/* <input type="file" (change)="onFileChange($event)" multiple="false" /> */
/* ... (within the component class definition) ... */
onFileChange(evt: any) {
/* wire up file reader */
const target: DataTransfer = <DataTransfer>(evt.target);
if (target.files.length !== 1) throw new Error('Cannot use multiple files');
const reader: FileReader = new FileReader();
reader.onload = (e: any) => {
/* read workbook */
const bstr: string = e.target.result;
const wb: XLSX.WorkBook = XLSX.read(bstr, {type: 'binary'});
/* grab first sheet */
const wsname: string = wb.SheetNames[0];
const ws: XLSX.WorkSheet = wb.Sheets[wsname];
/* save data */
this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header: 1}));
};
reader.readAsBinaryString(target.files[0]);
}
```
## Switching between Angular versions
Modules that work with Angular 2 largely work as-is with Angular 4. Switching
@ -33,15 +88,14 @@ $ npm install
$ ng serve
```
## XLSX Symlink
## XLSX Symbolic Link
In this tree, `node_modules/xlsx` is a symlink pointing back to the root. This
In this tree, `node_modules/xlsx` is a link pointing back to the root. This
enables testing the development version of the library. In order to use this
demo in other applications, add the `xlsx` dependency:
```bash
$ npm install --save xlsx
```
## SystemJS Configuration
@ -53,16 +107,18 @@ SystemJS example shows the required meta and map settings:
```js
SystemJS.config({
meta: {
'xlsx': {
exports: 'XLSX' // <-- tell SystemJS to expose the XLSX variable
}
},
map: {
'xlsx': 'xlsx.full.min.js', // <-- make sure xlsx.full.min.js is in same dir
'fs': '', // <--|
'crypto': '', // <--| suppress native node modules
'stream': '' // <--|
}
meta: {
'xlsx': {
exports: 'XLSX' // <-- tell SystemJS to expose the XLSX variable
}
},
map: {
'xlsx': 'xlsx.full.min.js', // <-- make sure xlsx.full.min.js is in same dir
'fs': '', // <--|
'crypto': '', // <--| suppress native node modules
'stream': '' // <--|
}
});
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -9,11 +9,9 @@ import { saveAs } from 'file-saver';
type AOA = Array<Array<any>>;
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;
};
const buf: ArrayBuffer = new ArrayBuffer(s.length);
const view: Uint8Array = new Uint8Array(buf);
for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
@ -33,41 +31,40 @@ function s2ab(s: string): ArrayBuffer {
})
export class SheetJSComponent {
data: AOA = [[1,2],[3,4]];
wopts: XLSX.WritingOptions = { bookType:'xlsx', type:'binary' };
fileName: string = "SheetJS.xlsx";
data: AOA = [ [1, 2], [3, 4] ];
wopts: XLSX.WritingOptions = { bookType: 'xlsx', type: 'binary' };
fileName: string = 'SheetJS.xlsx';
onFileChange(evt: any) {
/* wire up file reader */
const target: DataTransfer = <DataTransfer>(evt.target);
if(target.files.length != 1) { throw new Error("Cannot upload multiple files on the entry") };
const reader = new FileReader();
if (target.files.length !== 1) throw new Error('Cannot use multiple files');
const reader: FileReader = new FileReader();
reader.onload = (e: any) => {
/* read workbook */
const bstr = e.target.result;
const wb = XLSX.read(bstr, {type:'binary'});
const bstr: string = e.target.result;
const wb: XLSX.WorkBook = XLSX.read(bstr, {type: 'binary'});
/* grab first sheet */
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const wsname: string = wb.SheetNames[0];
const ws: XLSX.WorkSheet = wb.Sheets[wsname];
/* save data */
this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header:1}));
this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header: 1}));
};
reader.readAsBinaryString(target.files[0]);
}
export(): void {
/* generate worksheet */
const ws = XLSX.utils.aoa_to_sheet(this.data);
const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
/* generate workbook and add the worksheet */
const wb = XLSX.utils.book_new();
const wb: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
/* save to file */
const wbout = XLSX.write(wb, this.wopts);
console.log(this.fileName);
const wbout: string = XLSX.write(wb, this.wopts);
saveAs(new Blob([s2ab(wbout)]), this.fileName);
}
}

@ -1,3 +1,3 @@
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import 'zone.js/dist/zone';

@ -1,2 +1,4 @@
browserify.js
browserify.min.js
worker.js
worker.min.js

@ -1,10 +1,17 @@
TOOL=browserify
.PHONY: all
all: $(TOOL).min.js
all: $(TOOL).min.js worker.min.js
$(TOOL).min.js: $(TOOL).js
uglifyjs $< > $@
.PHONY: $(TOOL).js
$(TOOL).js:
browserify -r './main.js:xlsx' > $@
$(TOOL).js: app.js
browserify $< > $@
worker.min.js: worker.js
uglifyjs $< > $@
.PHONY: worker.js
worker.js: xlsxworker.js
browserify $< > $@

@ -1,6 +1,31 @@
# Browserify
The library is compatible with browserify and should just work out of the box.
The library is compatible with Browserify and should just work out of the box.
This demo uses the `require` form to expose the whole library, enabling client
code to just `require('xlsx')`. The included demo and Makefile do just that.
code to access the library with `var XLSX = require('xlsx')`. The JS code from
the root demo was moved to a separate `app.js` script. That script is bundled:
```bash
browserify app.js > browserify.js
uglifyjs browserify.js > browserify.min.js
```
### Worker Scripts
Browserify can also bundle worker scripts! Instead of using `importScripts`,
the worker script should require the module:
```diff
-importScripts('dist/xlsx.full.min.js');
+var XLSX = require('xlsx');
```
The same process generates the worker script:
```bash
browserify xlsxworker.js > worker.js
uglifyjs worker.js > worker.min.js
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

162
demos/browserify/app.js Normal file

@ -0,0 +1,162 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('../../'); // test against development version
//var XLSX = require('xlsx'); // use in production
/*jshint browser:true */
/*global require */
var X = require('xlsx');
var XW = {
/* worker message */
msg: 'xlsx',
/* worker scripts */
worker: './worker.min.js'
};
var global_wb;
var process_wb = (function() {
var OUT = document.getElementById('out');
var HTMLOUT = document.getElementById('htmlout');
var get_format = (function() {
var radios = document.getElementsByName( "format" );
return function() {
for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value;
};
})();
var to_json = function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length) result[sheetName] = roa;
});
return JSON.stringify(result, 2, 2);
};
var to_csv = function to_csv(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var csv = X.utils.sheet_to_csv(workbook.Sheets[sheetName]);
if(csv.length){
result.push("SHEET: " + sheetName);
result.push("");
result.push(csv);
}
});
return result.join("\n");
};
var to_fmla = function to_fmla(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var formulae = X.utils.get_formulae(workbook.Sheets[sheetName]);
if(formulae.length){
result.push("SHEET: " + sheetName);
result.push("");
result.push(formulae.join("\n"));
}
});
return result.join("\n");
};
var to_html = function to_html(workbook) {
HTMLOUT.innerHTML = "";
workbook.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(workbook, {sheet:sheetName, type:'binary', bookType:'html'});
HTMLOUT.innerHTML += htmlstr;
});
return "";
};
return function process_wb(wb) {
global_wb = wb;
var output = "";
switch(get_format()) {
case "form": output = to_fmla(wb); break;
case "html": output = to_html(wb); break;
case "json": output = to_json(wb); break;
default: output = to_csv(wb);
}
if(OUT.innerText === undefined) OUT.textContent = output;
else OUT.innerText = output;
if(typeof console !== 'undefined') console.log("output", new Date());
};
})();
var setfmt = window.setfmt = function setfmt() { if(global_wb) process_wb(global_wb); };
var b64it = window.b64it = (function() {
var tarea = document.getElementById('b64data');
return function b64it() {
if(typeof console !== 'undefined') console.log("onload", new Date());
var wb = X.read(tarea.value, {type:'base64', WTF:false});
process_wb(wb);
};
})();
var do_file = (function() {
var rABS = typeof FileReader !== "undefined" && (FileReader.prototype||{}).readAsBinaryString;
var domrabs = document.getElementsByName("userabs")[0];
if(!rABS) domrabs.disabled = !(domrabs.checked = false);
var use_worker = typeof Worker !== 'undefined';
var domwork = document.getElementsByName("useworker")[0];
if(!use_worker) domwork.disabled = !(domwork.checked = false);
var xw = function xw(data, cb) {
var worker = new Worker(XW.worker);
worker.onmessage = function(e) {
switch(e.data.t) {
case 'ready': break;
case 'e': console.error(e.data.d); break;
case XW.msg: cb(JSON.parse(e.data.d)); break;
}
};
worker.postMessage({d:data,b:rABS?'binary':'array'});
};
return function do_file(files) {
rABS = domrabs.checked;
use_worker = domwork.checked;
var f = files[0];
var reader = new FileReader();
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS, use_worker);
var data = e.target.result;
if(!rABS) data = new Uint8Array(data);
if(use_worker) xw(data, process_wb);
else process_wb(X.read(data, {type: rABS ? 'binary' : 'array'}));
};
if(rABS) reader.readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
};
})();
(function() {
var drop = document.getElementById('drop');
if(!drop.addEventListener) return;
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');
if(!xlf.addEventListener) return;
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();

@ -47,167 +47,8 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<div id="htmlout"></div>
<br />
<script src="browserify.min.js"></script>
<script>
/*jshint browser:true */
/*global require */
var X = require('xlsx');
var XW = {
/* worker message */
msg: 'xlsx',
/* worker scripts */
worker: './xlsxworker.js'
};
var global_wb;
var process_wb = (function() {
var OUT = document.getElementById('out');
var HTMLOUT = document.getElementById('htmlout');
var get_format = (function() {
var radios = document.getElementsByName( "format" );
return function() {
for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value;
};
})();
var to_json = function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length) result[sheetName] = roa;
});
return JSON.stringify(result, 2, 2);
};
var to_csv = function to_csv(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var csv = X.utils.sheet_to_csv(workbook.Sheets[sheetName]);
if(csv.length){
result.push("SHEET: " + sheetName);
result.push("");
result.push(csv);
}
});
return result.join("\n");
};
var to_fmla = function to_fmla(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var formulae = X.utils.get_formulae(workbook.Sheets[sheetName]);
if(formulae.length){
result.push("SHEET: " + sheetName);
result.push("");
result.push(formulae.join("\n"));
}
});
return result.join("\n");
};
var to_html = function to_html(workbook) {
HTMLOUT.innerHTML = "";
workbook.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(workbook, {sheet:sheetName, type:'binary', bookType:'html'});
HTMLOUT.innerHTML += htmlstr;
});
return "";
};
return function process_wb(wb) {
global_wb = wb;
var output = "";
switch(get_format()) {
case "form": output = to_fmla(wb); break;
case "html": output = to_html(wb); break;
case "json": output = to_json(wb); break;
default: output = to_csv(wb);
}
if(OUT.innerText === undefined) OUT.textContent = output;
else OUT.innerText = output;
if(typeof console !== 'undefined') console.log("output", new Date());
};
})();
var setfmt = window.setfmt = function setfmt() { if(global_wb) process_wb(global_wb); };
var b64it = window.b64it = (function() {
var tarea = document.getElementById('b64data');
return function b64it() {
if(typeof console !== 'undefined') console.log("onload", new Date());
var wb = X.read(tarea.value, {type:'base64', WTF:false});
process_wb(wb);
};
})();
var do_file = (function() {
var rABS = typeof FileReader !== "undefined" && (FileReader.prototype||{}).readAsBinaryString;
var domrabs = document.getElementsByName("userabs")[0];
if(!rABS) domrabs.disabled = !(domrabs.checked = false);
var use_worker = typeof Worker !== 'undefined';
var domwork = document.getElementsByName("useworker")[0];
if(!use_worker) domwork.disabled = !(domwork.checked = false);
var xw = function xw(data, cb) {
var worker = new Worker(XW.worker);
worker.onmessage = function(e) {
switch(e.data.t) {
case 'ready': break;
case 'e': console.error(e.data.d); break;
case XW.msg: cb(JSON.parse(e.data.d)); break;
}
};
worker.postMessage({d:data,b:rABS?'binary':'array'});
};
return function do_file(files) {
rABS = domrabs.checked;
use_worker = domwork.checked;
var f = files[0];
var reader = new FileReader();
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS, use_worker);
var data = e.target.result;
if(!rABS) data = new Uint8Array(data);
if(use_worker) xw(data, process_wb);
else process_wb(X.read(data, {type: rABS ? 'binary' : 'array'}));
};
if(rABS) reader.readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
};
})();
(function() {
var drop = document.getElementById('drop');
if(!drop.addEventListener) return;
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');
if(!xlf.addEventListener) return;
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();
</script>
<script type="text/javascript">
/* eslint no-use-before-define:0 */
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);

@ -1,4 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('../../'); // test against development version
//var XLSX = require('xlsx'); // use in production
module.exports = XLSX;

@ -1,12 +1,12 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
importScripts('browserify.min.js');
var XLSX = require('xlsx');
var XLSX = require('../../'); // test against development version
//var XLSX = require('xlsx'); // use in production
postMessage({t:"ready"});
onmessage = function (oEvent) {
onmessage = function (evt) {
var v;
try {
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b});
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

@ -5,6 +5,8 @@ with other JS libraries such as data grids for previewing data. After extensive
testing, [`canvas-datagrid`](https://tonygermaneri.github.io/canvas-datagrid/)
stood out as a very high-performance grid with an incredibly simple API.
This demo is available at <http://oss.sheetjs.com/js-xlsx/datagrid.html>
## Obtaining the Library
The [`canvas-datagrid` npm nodule](http://npm.im/canvas-datagrid) includes a
@ -27,8 +29,8 @@ Grid initialization is a one-liner:
```js
var grid = canvasDatagrid({
parentNode: document.getElementById('gridctr'),
data: []
parentNode: document.getElementById('gridctr'),
data: []
});
```
@ -44,15 +46,30 @@ features to support multiple worksheets.
## Editing
The library handles the whole edit cycle. No intervention is necessary.
`canvas-datagrid` handles the entire edit cycle. No intervention is necessary.
## Saving Data
`grid.data` is immediately readable and can be converted back to a worksheet:
`grid.data` is immediately readable and can be converted back to a worksheet.
Some versions return an array-like object without the length, so a little bit of
preparation may be needed:
```js
/* converts an array of array-like objects into an array of arrays */
function prep(arr) {
var out = [];
for(var i = 0; i < arr.length; ++i) {
if(!arr[i]) continue;
if(Array.isArray(arr[i])) { out[i] = arr[i]; continue };
var o = new Array();
Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] });
out[i] = o;
}
return out;
}
/* build worksheet from the grid data */
var ws = XLSX.utils.aoa_to_sheet(grid.data);
var ws = XLSX.utils.aoa_to_sheet(prep(grid.data));
/* build up workbook */
var wb = XLSX.utils.book_new();
@ -65,3 +82,5 @@ XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
This demo barely scratches the surface. The underlying grid component includes
many additional features including massive data streaming, sorting and styling.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -33,11 +33,10 @@ a { text-decoration: none }
<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
<textarea id="b64data">... or paste a base64-encoding here</textarea>
<input type="button" id="dotext" value="Click here to process the base64 text" onclick="b64it();"/><br />
<b>Advanced Demo Options:</b>
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked>
</pre>
<p><input type="submit" value="Export to XLSX!" id="xport" onclick="doit();" disabled="true"></p>
<p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();" disabled="true"></p>
<div id="htmlout"></div>
<br />
<script src="https://unpkg.com/canvas-datagrid/dist/canvas-datagrid.js"></script>
@ -52,147 +51,117 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
/*global XLSX */
var X = XLSX;
var rABS = typeof FileReader !== "undefined" && typeof FileReader.prototype !== "undefined" && typeof FileReader.prototype.readAsBinaryString !== "undefined";
if(!rABS) {
document.getElementsByName("userabs")[0].disabled = true;
document.getElementsByName("userabs")[0].checked = false;
}
var wtf_mode = false;
function fixdata(data) {
var o = "", l = 0, w = 10240;
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint8Array(data.slice(l*w,l*w+w)));
o+=String.fromCharCode.apply(null, new Uint8Array(data.slice(l*w)));
return o;
}
function ab2str(data) {
var o = "", l = 0, w = 10240;
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint16Array(data.slice(l*w,l*w+w)));
o+=String.fromCharCode.apply(null, new Uint16Array(data.slice(l*w)));
return o;
}
function s2ab(s) {
var b = new ArrayBuffer(s.length), v = new Uint8Array(b);
for (var i=0; i != s.length; ++i) v[i] = s.charCodeAt(i) & 0xFF;
return b;
}
function get_radio_value( radioName ) {
var radios = document.getElementsByName( radioName );
for( var i = 0; i < radios.length; i++ ) {
if( radios[i].checked || radios.length === 1 ) {
return radios[i].value;
}
}
}
var tarea = document.getElementById('b64data');
function b64it() {
if(typeof console !== 'undefined') console.log("onload", new Date());
var wb = X.read(tarea.value, {type: 'base64',WTF:wtf_mode});
process_wb(wb);
}
window.b64it = b64it;
var global_wb;
var cDg;
function process_wb(wb) {
global_wb = wb;
var ws = wb.Sheets[wb.SheetNames[0]];
var data = XLSX.utils.sheet_to_json(ws, {header:1});
if(!cDg) cDg = canvasDatagrid({ parentNode:document.getElementById('htmlout'), data:data });
else cDg.data = data;
var range = XLSX.utils.decode_range(ws['!ref']);
for(var i = range.s.c; i <= range.e.c; ++i) cDg.schema[i - range.s.c].title = XLSX.utils.encode_col(i);
document.getElementById('xport').disabled = false;
if(typeof console !== 'undefined') console.log("output", new Date());
}
function doit() {
var new_wb = XLSX.utils.book_new();
var new_ws = XLSX.utils.aoa_to_sheet(cDg.data);
XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS');
var wbout = XLSX.write(new_wb, {bookType:'xlsx', bookSST:true, type:'binary'});
var fname = 'sheetjs.xlsx';
try {
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), fname);
} catch(e) { if(typeof console != 'undefined') console.log(e, wbout); }
}
var drop = document.getElementById('drop');
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
rABS = document.getElementsByName("userabs")[0].checked;
var files = e.dataTransfer.files;
var f = files[0];
{
var process_wb = (function() {
var XPORT = document.getElementById('xport');
var HTMLOUT = document.getElementById('htmlout');
return function process_wb(wb) {
/* get data */
var ws = wb.Sheets[wb.SheetNames[0]];
var data = XLSX.utils.sheet_to_json(ws, {header:1});
/* update canvas-datagrid */
if(!cDg) cDg = canvasDatagrid({ parentNode:HTMLOUT, data:data });
cDg.data = data;
XPORT.disabled = false;
/* create schema (for A,B,C column headings) */
var range = XLSX.utils.decode_range(ws['!ref']);
for(var i = range.s.c; i <= range.e.c; ++i) cDg.schema[i - range.s.c].title = XLSX.utils.encode_col(i);
if(typeof console !== 'undefined') console.log("output", new Date());
};
})();
var do_file = (function() {
var rABS = typeof FileReader !== "undefined" && (FileReader.prototype||{}).readAsBinaryString;
var domrabs = document.getElementsByName("userabs")[0];
if(!rABS) domrabs.disabled = !(domrabs.checked = false);
return function do_file(files) {
rABS = domrabs.checked;
var f = files[0];
var reader = new FileReader();
//var name = f.name;
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS);
var data = e.target.result;
{
var wb;
if(rABS) {
wb = X.read(data, {type: 'binary'});
} else {
var arr = fixdata(data);
wb = X.read(btoa(arr), {type: 'base64'});
}
process_wb(wb);
}
if(!rABS) data = new Uint8Array(data);
process_wb(X.read(data, {type: rABS ? 'binary' : 'array'}));
};
if(rABS) reader.readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
};
})();
(function() {
var drop = document.getElementById('drop');
if(!drop.addEventListener) return;
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
do_file(e.dataTransfer.files);
}
}
function handleDragover(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}
function handleDragover(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}
if(drop.addEventListener) {
drop.addEventListener('dragenter', handleDragover, false);
drop.addEventListener('dragover', handleDragover, false);
drop.addEventListener('drop', handleDrop, false);
}
})();
(function() {
var xlf = document.getElementById('xlf');
if(!xlf.addEventListener) return;
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();
var xlf = document.getElementById('xlf');
function handleFile(e) {
rABS = document.getElementsByName("userabs")[0].checked;
var files = e.target.files;
var f = files[0];
{
var reader = new FileReader();
//var name = f.name;
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS);
var data = e.target.result;
{
var wb;
if(rABS) {
wb = X.read(data, {type: 'binary'});
} else {
var arr = fixdata(data);
wb = X.read(btoa(arr), {type: 'base64'});
}
process_wb(wb);
}
};
if(rABS) reader.readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
var export_xlsx = (function() {
function prep(arr) {
var out = [];
for(var i = 0; i < arr.length; ++i) {
if(!arr[i]) continue;
if(Array.isArray(arr[i])) { out[i] = arr[i]; continue };
var o = new Array();
Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] });
out[i] = o;
}
return out;
}
}
if(xlf.addEventListener) xlf.addEventListener('change', handleFile, false);
function s2ab(s) {
var b = new ArrayBuffer(s.length), v = new Uint8Array(b);
for (var i=0; i != s.length; ++i) v[i] = s.charCodeAt(i) & 0xFF;
return b;
}
return function export_xlsx() {
if(!cDg) return;
/* convert canvas-datagrid data to worksheet */
var new_ws = XLSX.utils.aoa_to_sheet(prep(cDg.data));
/* build workbook */
var new_wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS');
/* write file and trigger a download */
var wbout = XLSX.write(new_wb, {bookType:'xlsx', bookSST:true, type:'binary'});
var fname = 'sheetjs.xlsx';
try {
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), fname);
} catch(e) { if(typeof console != 'undefined') console.log(e, wbout); }
};
})();
</script>
<script type="text/javascript">
/* eslint no-use-before-define:0 */
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);

@ -1,7 +1,7 @@
# 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 demonstration uses Electron 1.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.
@ -9,11 +9,28 @@ 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/)
The core data in this demo is an editable HTML table. The readers build up the
table using `sheet_to_html` (with `editable:true` option) and the writers scrape
the table using `table_to_book`.
## Reading and Writing Files
Since electron provides an `fs` implementation, `readFile` and `writeFile` can
be used in conjunction with the standard dialogs. For example:
be used in conjunction with the standard dialog windows. For example:
```js
/* from app code, require('electron').remote calls back to main process */
var dialog = require('electron').remote.dialog;
var o = (dialog.showOpenDialog({ properties: ['openFile'] })||[''])[0];
var workbook = X.readFile(o);
/* show a file-open dialog and read the first selected file */
var o = dialog.showOpenDialog({ properties: ['openFile'] });
var workbook = X.readFile(o[0]);
/* show a file-save dialog and write the workbook */
var o = dialog.showSaveDialog();
XLSX.writeFile(workbook, o);
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -30,6 +30,7 @@ a { text-decoration: none }
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
</pre>
<p><input type="submit" value="Export Data!" id="xport" onclick="export_xlsx();" disabled="true"></p>
<div id="htmlout"></div>
<br />
<script src="index.js"></script>

@ -1,13 +1,15 @@
var X = require('xlsx');
var XLSX = require('xlsx');
var electron = require('electron').remote;
var process_wb = (function() {
var HTMLOUT = document.getElementById('htmlout');
var XPORT = document.getElementById('xport');
return function process_wb(wb) {
XPORT.disabled = false;
HTMLOUT.innerHTML = "";
wb.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(wb, {sheet:sheetName, type:'binary', bookType:'html'});
var htmlstr = XLSX.utils.sheet_to_html(wb.Sheets[sheetName],{editable:true});
HTMLOUT.innerHTML += htmlstr;
});
};
@ -30,7 +32,7 @@ var do_file = (function() {
reader.onload = function(e) {
var data = e.target.result;
data = new Uint8Array(data);
process_wb(X.read(data, {type: 'array'}));
process_wb(XLSX.read(data, {type: 'array'}));
};
reader.readAsArrayBuffer(f);
};
@ -67,7 +69,7 @@ var do_file = (function() {
}],
properties: ['openFile']
});
if(o.length > 0) process_wb(X.readFile(o[0]));
if(o.length > 0) process_wb(XLSX.readFile(o[0]));
}
readf.addEventListener('click', handleF, false);
})();
@ -77,3 +79,21 @@ var do_file = (function() {
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();
var export_xlsx = (function() {
var HTMLOUT = document.getElementById('htmlout');
var XTENSION = "xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html".split("|")
return function() {
var wb = XLSX.utils.table_to_book(HTMLOUT);
var o = electron.dialog.showSaveDialog({
title: 'Save file as',
filters: [{
name: "Spreadsheets",
extensions: XTENSION
}]
});
console.log(o);
XLSX.writeFile(wb, o);
electron.dialog.showMessageBox({ message: "Exported data to " + o, buttons: ["OK"] });
};
})();

@ -1,11 +1,34 @@
# ExtendScript demos
# Adobe ExtendScript
ExtendScript adds some features to a limited form of ECMAScript version 3. With
the included shim, the library can run within Photoshop and other Adobe apps!
The main file is `test.jsx`. Target-specific files prepend target directives.
Copy the `test.jsx` file as well as the `shim.js` and `xlsx.core.min.js` files
to wherever you want the scripts to reside. The demo shows opening a file and
converting to an array of arrays.
to wherever you want the scripts to reside.
The demo shows opening a file and converting to an array of arrays:
```js
/* include library */
#include "shim.js"
#include "xlsx.core.min.js"
/* get data as binary string */
var filename = "sheetjs.xlsx";
var base = new File($.fileName);
var infile = File(base.path + "/" + filename);
infile.open("r");
infile.encoding = "binary";
var data = infile.read();
/* parse data */
var workbook = XLSX.read(data, {type:"binary"});
/* DO SOMETHING WITH workbook HERE */
```
NOTE: [We forked the minifier](https://www.npmjs.com/package/@sheetjs/uglify-js)
and included a bugfix for ExtendScript's misparsing of switch statements.
and included a patch for ExtendScript's switch statement semicolon issue.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

1
demos/headless/.gitignore vendored Normal file

@ -0,0 +1 @@
*.pdf

@ -1,11 +1,11 @@
# Headless Browsers
The library, intentionally conservative in the use of ES5+ features, plays nicely
The library, eschewing unstable and nascent ECMAScript features, plays nicely
with most headless browsers. This demo shows a few common headless scenarios.
## PhantomJS
This was tested in phantomjs 2.1.1, installed using the node module:
This was tested in PhantomJS 2.1.1, installed using the node module:
```bash
$ npm install -g phantomjs
@ -17,12 +17,12 @@ $ phantomjs phantomjs.js
This was tested in wkhtmltopdf 0.12.4, installed using the official binaries:
```bash
$ wkhtmltopdf --javascript-delay 60000 http://localhost:8000/ test.pdf
```
$ wkhtmltopdf --javascript-delay 20000 http://oss.sheetjs.com/js-xlsx/tests/ test.pdf
```
## Puppeteer
This was tested in puppeteer 0.9.0 and Chromium r494755, installed using node:
This was tested in puppeteer 0.9.0 and Chromium revision 494755:
```bash
$ npm install puppeteer
@ -34,10 +34,11 @@ the webpage. The `dist` versions are suitable for web pages.
## SlimerJS
This was tested in slimerjs 0.10.3 and FF 52.0, installed using `brew` on OSX:
This was tested in SlimerJS 0.10.3 and FF 52.0, installed using `brew` on OSX:
```bash
$ brew install slimerjs
$ slimerjs slimerjs.js
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -3,7 +3,7 @@ var fs = require('fs');
var xlsx = require('../../xlsx');
var page = require('webpage').create();
page.open('http://www.google.com', function(status) {
page.open('http://oss.sheetjs.com/js-xlsx/tests/', function(status) {
var data = fs.read('sheetjs.xlsx', {mode: 'rb', charset: 'utf8'});
var workbook = xlsx.read(data, {type: 'binary'});

@ -5,7 +5,7 @@ const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:8000', {waitUntil: 'load'});
await page.goto('http://oss.sheetjs.com/js-xlsx/tests/', {waitUntil: 'load'});
await page.waitFor(30*1000);
await page.pdf({path: 'test.pdf', format: 'A4'});

@ -3,7 +3,7 @@ var fs = require('fs');
var xlsx = require('../../dist/xlsx.full.min');
var page = require('webpage').create();
page.open('http://www.google.com', function(status) {
page.open('http://oss.sheetjs.com/js-xlsx/tests/', function(status) {
var data = fs.read('sheetjs.xlsx', {mode: 'rb', charset: 'utf8'});
var workbook = xlsx.read(data, {type: 'binary'});

@ -1 +1,2 @@
.meteor
node_modules/

@ -4,6 +4,11 @@ start:
.PHONY: init
init:
if [ ! -e .meteor ]; then meteor create .; fi;
@npm install babel-runtime meteor-node-stubs
@meteor add pfafman:filesaver
@meteor add pfafman:filesaver check
@mkdir -p node_modules; cd node_modules; ln -s ../../../ xlsx; cd -
.PHONY: lint
lint:
@meteor npm run lint

@ -5,34 +5,70 @@ tables in the browser, streaming write in nodejs), the core is ES3/ES5 and can
be used in any reasonably compliant JS implementation. It should play nice with
meteor out of the box.
Using the npm module, the library can be imported from client or server side:
```js
import XLSX from 'xlsx'
```
All of the functions and utilities are available in both realms. Since the core
data representations are simple JS objects, the workbook object can be passed on
the wire, enabling hybrid workflows where the server processes data and client
finishes the work.
## This demonstration
You can split the work between the client and server side as you see fit. The
obvious extremes of pure-client code and pure-server code are straightforward.
This demo tries to split the work to demonstrate that the workbook object can be
passed on the wire.
Note: the obvious extremes of pure-client code and pure-server code are covered
in other demos.
The read demo:
### Reading Data
The parse demo:
- accepts files from the client side
- sends binary string to server
- processes data on server side
- sends workbook object to client
- renders HTML and adds to a DOM element
The write demo:
- generates workbook on server side
- sends workbook object to client
- generates file on client side
- triggers a download.
The logic from within the `FileReader` is split as follows:
This demo uses the FileSaver.js library for writing files, installed through the
[`pfafman:filesaver` wrapper](https://atmospherejs.com/pfafman/filesaver):
```bash
meteor add pfafman:filesaver
```js
// CLIENT SIDE
const bstr = e.target.result;
// SERVER SIDE
const wb = XLSX.read(bstr, { type: 'binary' });
// CLIENT SIDE
const ws = wb.Sheets[wb.SheetNames[0]];
const html = XLSX.utils.sheet_to_html(ws, { editable: true });
document.getElementById('out').innerHTML = html;
```
### Writing Data
The write demo:
- grabs HTML from the client side
- sends HTML string to server
- processes data on server side
- sends workbook object to client
- generates file on client side and triggers a download
The logic from within the `click` event is split as follows:
```js
// CLIENT SIDE
const html = document.getElementById('out').innerHTML;
// SERVER SIDE
const wb = XLSX.read(html, { type: 'binary' });
// CLIENT SIDE
const o = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(o)], {type:'application/octet-stream'}), 'sheetjs.xlsx');
```
This demo uses the FileSaver library for writing files, installed through the
[`pfafman:filesaver` wrapper](https://atmospherejs.com/pfafman/filesaver).
## Setup
This tree does not include the `.meteor` structure. Rebuild the project with:
@ -45,12 +81,14 @@ meteor
```
## Environment-specific features
## Environment-Specific Features
File-related operations (e.g. `XLSX.readFile` and `XLSX.writeFile`) will not be
File-related operations like `XLSX.readFile` and `XLSX.writeFile` will not be
available in client-side code. If you need to read a local file from the client,
use a file input or drag-and-drop.
Browser-specific operations (e.g. `XLSX.utils.table_to_book`) are limited to
Browser-specific operations like `XLSX.utils.table_to_book` are limited to
client side code. You should never have to read from DOM elements on the server
side, but you can use a third-party virtual DOM to provide the required API.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -6,22 +6,13 @@
<pre>
<b><a href="//sheetjs.com">SheetJS Meteor Demo</a></b>
<b>Meteor Read Demo</b>
{{> read}}
<b>Meteor Write Demo</b>
{{> write}}
{{> sheetjs}}
</pre>
</body>
<template name="read">
<template name="sheetjs">
<label for="upload">Parse File: </label><input type="file" id="upload" />
<div id="out"></div>
</template>
<template name="write">
<label for="dnload">Write File: </label><button id="dnload">Generate Worksheet</button>
<button id="dnload" disabled="true">Generate Worksheet</button>
</template>

@ -1,51 +1,49 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import XLSX from 'xlsx';
/* note: saveAs is made available via the smart package */
/* global saveAs */
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
const XLSX = require('xlsx');
Template.read.events({
'change input' (evt, instance) {
/* "Browser file upload form element" from SheetJS README */
const file = evt.currentTarget.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const data = e.target.result;
const name = file.name;
/* Meteor magic */
Meteor.call('upload', data, name, function(err, wb) {
if(err) console.error(err);
else {
/* do something here -- this just dumps an array of arrays to console */
console.log(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1}));
document.getElementById('out').innerHTML = (XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]));
}
});
};
reader.readAsBinaryString(file);
},
});
Template.write.events({
'click button' (evt, instance) {
Meteor.call('download', function(err, wb) {
if(err) console.error(err);
else {
console.log(wb);
/* "Browser download file" from SheetJS README */
var wopts = { bookType:'xlsx', bookSST:false, type:'binary' };
var wbout = XLSX.write(wb, wopts);
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "meteor.xlsx");
}
});
},
Template.sheetjs.events({
'change input' (event) {
/* "Browser file upload form element" from SheetJS README */
const file = event.currentTarget.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const data = e.target.result;
const name = file.name;
/* Meteor magic */
Meteor.call('upload', data, name, function(err, wb) {
if (err) throw err;
/* load the first worksheet */
const ws = wb.Sheets[wb.SheetNames[0]];
/* generate HTML table and enable export */
const html = XLSX.utils.sheet_to_html(ws, { editable: true });
document.getElementById('out').innerHTML = html;
document.getElementById('dnload').disabled = false;
});
};
reader.readAsBinaryString(file);
},
'click button' () {
const html = document.getElementById('out').innerHTML;
Meteor.call('download', html, function(err, wb) {
if (err) throw err;
/* "Browser download file" from SheetJS README */
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), 'sheetjs.xlsx');
});
},
});
/* eslint no-bitwise:0, no-plusplus:0 */
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
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;
}

@ -1,11 +1,27 @@
{
"name": "meteor-xlsx",
"version": "0.0.0",
"private": true,
"scripts": {
"lint": "eslint .",
"start": "meteor run"
},
"eslintConfig": {
"extends": "@meteorjs/eslint-config-meteor"
},
"dependencies": {
"babel-runtime": "^6.20.0",
"meteor-node-stubs": "~0.2.4"
},
"devDependencies": {
"@meteorjs/eslint-config-meteor": "^1.0.5",
"babel-eslint": "^7.2.3",
"eslint": "^3.19.0",
"eslint-config-airbnb": "^13.0.0",
"eslint-import-resolver-meteor": "^0.3.4",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-meteor": "^4.1.4",
"eslint-plugin-react": "^6.10.3"
}
}

@ -1,23 +1,30 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import { Meteor } from 'meteor/meteor';
const XLSX = require('xlsx');
import { check } from 'meteor/check';
import XLSX from 'xlsx';
Meteor.methods({
upload: (bstr, name) => {
/* read the data and return the workbook object to the frontend */
return XLSX.read(bstr, {type:'binary'});
},
download: () => {
/* generate a workbook object and return to the frontend */
const data = [
["a", "b", "c"],
[ 1 , 2 , 3 ]
];
const ws = XLSX.utils.aoa_to_sheet(data);
const wb = {SheetNames: ["Sheet1"], Sheets:{Sheet1:ws }};
return wb;
}
upload: (bstr, name) => {
/* read the data and return the workbook object to the frontend */
check(bstr, String);
check(name, String);
return XLSX.read(bstr, { type: 'binary' });
},
download: (html) => {
check(html, String);
let wb;
if (html.length > 3) {
/* parse workbook if html is available */
wb = XLSX.read(html, { type: 'binary' });
} else {
/* generate a workbook object otherwise */
const data = [['a', 'b', 'c'], [1, 2, 3]];
const ws = XLSX.utils.aoa_to_sheet(data);
wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
}
return wb;
},
});
Meteor.startup(() => { });

@ -3,8 +3,34 @@
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.
## Reading data
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/)
the [SheetJS Data Preview Live Demo](http://oss.sheetjs.com/js-xlsx/).
## Writing data
File input elements with the attribute `nwsaveas` show UI for saving a file. The
standard trick is to generate a hidden file input DOM element and "click" it.
Since NW.js does not present a `writeFileSync` in the `fs` package, a manual
step is required:
```js
/* from within the input change callback, `this.value` is the file name */
var filename = this.value, bookType = (filename.match(/[^\.]*$/)||["xlsx"])[0];
/* convert the TABLE element back to a workbook */
var wb = XLSX.utils.table_to_book(HTMLOUT);
/* write to buffer */
var wbout = XLSX.write(wb, {type:'buffer', bookType:bookType});
/* use the async fs.writeFile to save the data */
fs.writeFile(filename, wbout, function(err) {
if(!err) return alert("Saved to " + filename);
alert("Error: " + (err.message || err));
});
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -29,6 +29,7 @@ a { text-decoration: none }
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
</pre>
<p><input type="submit" value="Export Data!" id="xport" onclick="export_xlsx();" disabled="true"></p>
<div id="htmlout"></div>
<br />
<script src="xlsx.full.min.js"></script>

@ -1,12 +1,14 @@
var X = XLSX;
var fs = require('fs');
var process_wb = (function() {
var HTMLOUT = document.getElementById('htmlout');
var XPORT = document.getElementById('xport');
return function process_wb(wb) {
XPORT.disabled = false;
HTMLOUT.innerHTML = "";
wb.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(wb, {sheet:sheetName, type:'binary', bookType:'html'});
var htmlstr = XLSX.utils.sheet_to_html(wb.Sheets[sheetName],{editable:true});
HTMLOUT.innerHTML += htmlstr;
});
};
@ -29,7 +31,7 @@ var do_file = (function() {
reader.onload = function(e) {
var data = e.target.result;
data = new Uint8Array(data);
process_wb(X.read(data, {type: 'array'}));
process_wb(XLSX.read(data, {type: 'array'}));
};
reader.readAsArrayBuffer(f);
};
@ -60,3 +62,25 @@ var do_file = (function() {
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();
var export_xlsx = (function() {
/* pre-build the nwsaveas input element */
var HTMLOUT = document.getElementById('htmlout');
var input = document.createElement('input');
input.style.display = 'none';
input.setAttribute('nwsaveas', 'sheetjs.xlsx');
input.setAttribute('type', 'file');
document.body.appendChild(input);
input.addEventListener('cancel',function(){ alert("Save was canceled!"); });
input.addEventListener('change',function(e){
var filename=this.value, bookType=(filename.match(/[^\.]*$/)||["xlsx"])[0];
var wb = XLSX.utils.table_to_book(HTMLOUT);
var wbout = XLSX.write(wb, {type:'buffer', bookType:bookType});
fs.writeFile(filename, wbout, function(err) {
if(!err) return alert("Saved to " + filename);
alert("Error: " + (err.message || err));
});
});
return function() { input.click(); };
})();

@ -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

@ -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
demos/react/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 />

@ -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); });
};

@ -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}));

@ -1,4 +1,4 @@
xlsx.full*
r.js
require.js
requirejs-built.js
app-built.js

@ -7,4 +7,4 @@ $(TOOL).js:
if [ ! -e require.js ]; then curl -O http://requirejs.org/docs/release/2.3.3/comments/require.js; fi
if [ ! -e r.js ]; then curl -O http://requirejs.org/docs/release/2.3.3/r.js; fi
rm -f xlsx.full.min.js; ln -s ../../dist/xlsx.full.min.js
node r.js -o build.js
node r.js -o build.js paths.requireLib=./require include=requireLib

@ -2,10 +2,75 @@
The minified dist files trip up the RequireJS mechanism. To bypass, the scripts
automatically expose an `XLSX` variable that can be used if the require callback
argument is `_XLSX` rather than `XLSX`:
argument is `_XLSX` rather than `XLSX`. This trick is employed in the included
`xlsx-shim.js` script:
```js
require(["xlsx.full.min"], function(_XLSX) { /* ... */ });
/* xlsx-shim.js */
define(['xlsx'], function (_XLSX) {
return XLSX;
});
```
This demo uses the `r.js` optimizer to build a source file.
The require config should set `xlsx` path to the appropriate dist file:
```js
paths: {
xlsx: "xlsx.full.min"
},
```
Once that is set, app code can freely require `"xlsx-shim"`:
```js
require(["xlsx-shim"], function(XLSX) {
/* use XLSX here */
});
```
## Deployments
`browser.html` demonstrates a dynamic deployment, using the in-browser config:
```html
<script src="require.js"></script>
<script>
require.config({
baseUrl: ".",
name: "app",
paths: {
xlsx: "xlsx.full.min"
}
});
</script>
<script src="app.js"></script>
```
`optimizer.html` demonstrates an optimized deployment using `build.js` config:
```js
/* build config */
({
baseUrl: ".",
name: "app",
paths: {
xlsx: "xlsx.full.min"
},
out: "app-built.js"
})
```
The optimizer is invoked with:
```bash
node r.js -o build.js paths.requireLib=./require include=requireLib
```
That step creates a file `app-built.js` that can be included in a page:
```html
<!-- final bundle includes require.js, xlsx-shim, library and app code -->
<script src="app-built.js"></script>
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,5 +1,6 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
require(["xlsx.full.min"], function(_XLSX) {
require(["xlsx-shim"], function(XLSX) {
console.log(XLSX);
var X = XLSX;
var global_wb;

@ -0,0 +1,69 @@
<!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 Live 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
}
#b64data{
width:100%;
}
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
(Base64 text works back to IE6; drag and drop works back to IE10)
<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>
Output Format: <select name="format" onchange="setfmt()">
<option value="csv" selected> CSV</option>
<option value="json"> JSON</option>
<option value="form"> FORMULAE</option>
<option value="html"> HTML</option>
</select><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
<textarea id="b64data">... or paste a base64-encoding here</textarea>
<input type="button" id="dotext" value="Click here to process the base64 text" onclick="b64it();"/><br />
<b>Advanced Demo Options:</b>
Use Web Workers: (when available) <input type="checkbox" name="useworker" checked>
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked>
</pre>
<pre id="out"></pre>
<div id="htmlout"></div>
<br />
<script>
var XW = {
/* worker message */
msg: 'xlsx',
/* worker scripts */
worker: './xlsxworker.js'
};
</script>
<script src="require.js"></script>
<script>
require.config({
baseUrl: ".",
name: "app",
paths: {
xlsx: "xlsx.full.min"
}
});
</script>
<script src="app.js"></script>
</body>
</html>

@ -1,6 +1,9 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
({
baseUrl: ".",
name: "requirejs",
out: "requirejs-built.js"
name: "app",
paths: {
xlsx: "xlsx.full.min"
},
out: "app-built.js"
})

@ -46,7 +46,6 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<pre id="out"></pre>
<div id="htmlout"></div>
<br />
<script src="require.js"></script>
<script>
var XW = {
/* worker message */
@ -55,6 +54,6 @@ var XW = {
worker: './xlsxworker.js'
};
</script>
<script src="requirejs-built.js"></script>
<script src="app-built.js"></script>
</body>
</html>

@ -0,0 +1,5 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
define(['xlsx'], function (_XLSX) {
/* work around require.js */
return XLSX;
});

@ -1,3 +1,5 @@
rollup.js
rollup.min.js
rollup.node.js
worker.js
worker.min.js

@ -1,6 +1,6 @@
TOOL=rollup
.PHONY: all
all: $(TOOL).min.js
all: $(TOOL).min.js worker.min.js
$(TOOL).min.js: $(TOOL).js
uglifyjs $< > $@
@ -12,6 +12,10 @@ $(TOOL).js:
node -e 'require("./rollup.node")'
# browser
rollup -c
rollup -c rollup.config.worker.js
worker.min.js: worker.js
uglifyjs $< > $@
.PHONY: init
init:

@ -2,7 +2,11 @@
This library presents itself as a CommonJS library, so some configuration is
required. The examples at <https://rollupjs.org> can be followed pretty much in
verbatim. This sample demonstrates a rollup for browser as well as for node.
verbatim. This sample demonstrates a bundle for browser as well as for node.
This demo uses the `import` form to expose the whole library, enabling client
code to access the library with `import XLSX from 'xlsx'`. The JS code from
the root demo was moved to a separate `app.js` script.
## Required Plugins
@ -24,3 +28,17 @@ export default {
};
```
For the browser deployments, the output format is `'iife'`. For node, the
output format is `'cjs'`.
### Worker Scripts
Rollup can also bundle worker scripts! Instead of using `importScripts`, the
worker script should import the module:
```diff
-importScripts('dist/xlsx.full.min.js');
+import XLSX from 'xlsx';
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +1,7 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint browser:true */
/*global XLSX */
import XLSX from 'xlsx';
var X = XLSX;
var global_wb;

@ -2,7 +2,7 @@
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
export default {
entry: 'main.js',
entry: 'app.js',
dest: 'rollup.js',
plugins: [
resolve({
@ -11,6 +11,5 @@ export default {
}),
commonjs()
],
moduleName: 'XLSX',
format: 'iife'
};

@ -0,0 +1,15 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
export default {
entry: 'xlsxworker.js',
dest: 'worker.js',
plugins: [
resolve({
module: false,
browser: true,
}),
commonjs()
],
format: 'iife'
};

@ -46,15 +46,14 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<pre id="out"></pre>
<div id="htmlout"></div>
<br />
<script src="rollup.min.js"></script>
<script>
var XW = {
/* worker message */
msg: 'xlsx',
/* worker scripts */
worker: './xlsxworker.js'
worker: './worker.js'
};
</script>
<script src="app.js"></script>
<script src="rollup.min.js"></script>
</body>
</html>

@ -1,11 +1,11 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
importScripts('rollup.min.js');
import XLSX from 'xlsx';
postMessage({t:"ready"});
onmessage = function (oEvent) {
onmessage = function (evt) {
var v;
try {
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b});
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

1
demos/server/.gitignore vendored Normal file

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

@ -19,3 +19,8 @@ micro: init ## micro demo
.PHONY: koa
koa: init ## koa demo
node koa.js
.PHONY: hapi
hapi: init ## hapi demo
cp ../../dist/xlsx.full.min.js .
node hapi.js

@ -25,6 +25,15 @@ request(url, {encoding: null}, function(err, res, data) {
});
```
The `readFile` / `writeFile` functions wrap `fs.{read,write}FileSync`:
```js
/* equivalent to `var wb = XLSX.readFile("sheetjs.xlsx");` */
var buf = fs.readFileSync("sheetjs.xlsx");
var wb = XLSX.read(buf, {type:'buffer'});
```
### Example servers
Each example server is expected to hold an array-of-arrays in memory. They are
@ -82,11 +91,11 @@ 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
## command-line utility 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 npm module ships with the `xlsx` command line tool. For global installs, the
script `bin/xlsx.njs` is added to a directory in `PATH`. For local installs, the
appropriate script or symbolic link 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
@ -94,3 +103,26 @@ array of arrays to a CSV, the server writes the file, and the `xlsx` command is
used to generate files of different formats.
## tiny-worker with hapi
`tiny-worker` provides a Web Worker-like interface. Binary strings and simple
objects are readily passed across the Worker divide.
The main server script is `hapi.js` and the worker script is `worker.js`. State
is maintained in the server script.
Note: due to an issue with hapi payload parsing, the route `POST /file` is used
to handle the case of reading from file, so the cURL test is:
```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/file?f=sheetjs.xlsx
# write sheetjs.xlsb in the XLSB format
curl -X GET http://localhost:7262/?f=sheetjs.xlsb
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,36 +1,61 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var Hapi = require('hapi'), server = new Hapi.Server();
var logit = require('./_logit');
var Worker = require('webworker-threads').Worker;
var Worker = require('tiny-worker');
var fs = require('fs');
var data = "a,b,c\n1,2,3".split("\n").map(x => x.split(","));
function get_data(req, res, type) {
var work = new Worker(function(){
var XLSX = require('xlsx');
this.onmessage = function(e) {
console.log("get data " + e.data);
var ws = XLSX.utils.aoa_to_sheet(e.data[1]);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
console.log("prepared wb");
postMessage(XLSX.write(wb, {type:'binary', bookType:type}));
console.log("sent data");
};
});
work.onmessage = function(e) { console.log(e); res(e); };
work.postMessage([type, data]);
var work = new Worker('worker.js');
work.onmessage = function(e) {
if(e.data.err) console.log(e.data.err);
return res(e.data.data);
};
work.postMessage({action:"write", type:type, data:data});
}
function get_file(req, res, file) {
var work = new Worker('worker.js');
work.onmessage = function(e) {
fs.writeFileSync(file, e.data.data, 'binary');
return res("wrote to " + file + "\n");
};
work.postMessage({action:"write", file:file, data:data});
}
function post_file(req, res, file) {
var work = new Worker('worker.js');
work.onmessage = function(e) {
data = e.data.data;
return res("read from " + file + "\n");
};
work.postMessage({action:"read", file:file});
}
function post_data(req, res, type) {
var keys = Object.keys(req.payload), k = keys[0];
post_file(req, res, req.payload[k].path);
}
var port = 7262;
server.connection({ host:'localhost', port: port});
server.route({ method: 'GET', path: '/', handler: function(req, res) {
server.route({ method: 'GET', path: '/',
handler: function(req, res) {
logit(req.raw.req, req.raw.res);
if(req.query.t) return get_data(req, res, req.query.t);
else if(req.query.f) return get_file(req, res, req.query.f);
return res('Forbidden').code(403);
if(req.query.t) get_data(req, res, req.query.t);
else if(req.query.f) get_file(req, res, req.query.f);
else res('Forbidden').code(403);
}});
server.route({ method: 'POST', path: '/', handler: function(req, res) {
server.route({ method: 'POST', path: '/',
config:{payload:{ output: 'file', parse: true, allow: 'multipart/form-data'}},
handler: function(req, res) {
logit(req.raw.req, req.raw.res);
if(req.query.f) return post_file(req, res, req.query.f);
return post_data(req, res);
}});
server.route({ method: 'POST', path: '/file',
handler: function(req, res) {
logit(req.raw.req, req.raw.res);
if(req.query.f) return post_file(req, res, req.query.f);
return post_data(req, res);

22
demos/server/worker.js Normal file

@ -0,0 +1,22 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('xlsx');
var fs = require('fs');
onmessage = function(e) {
try { switch(e.data.action) {
case 'write':
var ws = XLSX.utils.aoa_to_sheet(e.data.data);
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "SheetJS");
postMessage({data: XLSX.write(wb, {type:'binary', bookType:e.data.type || e.data.file.match(/\.([^\.]*)$/)[1]})});
break;
case 'read':
var wb;
if(e.data.file) wb = XLSX.readFile(e.data.file);
else wb = XLSX.read(e.data.data);
var ws = wb.Sheets[wb.SheetNames[0]];
postMessage({data: XLSX.utils.sheet_to_json(ws, {header:1})});
break;
default: throw "unknown action";
}} catch(e) { postMessage({err:e.message || e}); }
};

@ -1,4 +1,4 @@
.PHONY: test
test:
cp ../../dist/xlsx.full.min.js .
node systemjsnode.js
node test.node.js

@ -35,7 +35,29 @@ var j = XLSX.utils.sheet_to_json(w.Sheets[w.SheetNames[0]], {header:1});
console.log(j);
```
The file functions `readFile` and `writeFile` are not available in the browser.
Note: The `readFile` and `writeFile` functions are not available in the browser.
## Web Workers
Web Workers can load the SystemJS library with `importScripts`, but the imported
code cannot assign the original worker's `onmessage` callback. This demo works
around the limitation by exposing the desired function as a global:
```js
/* main worker script */
importScripts('system.js');
SystemJS.config({ /* ... browser config ... */ });
onmessage = function(evt) {
SystemJS.import('xlsxworker.js').then(function() { _cb(evt); });
};
/* xlsxworker.js */
var XLSX = require('xlsx');
_cb = function (evt) { /* ... do work here ... */ };
```
## Node
@ -64,3 +86,4 @@ SystemJS.import('xlsx').then(function(XLSX) {
});
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +1,154 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint browser:true */
/*global XLSX */
var XLSX = require('xlsx');
console.log(XLSX);
var w = XLSX.read('abc,def\nghi,jkl', {type:'binary'});
var j = XLSX.utils.sheet_to_json(w.Sheets[w.SheetNames[0]], {header:1});
console.log(j);
var X = XLSX;
var global_wb;
var process_wb = (function() {
var OUT = document.getElementById('out');
var HTMLOUT = document.getElementById('htmlout');
var get_format = (function() {
var radios = document.getElementsByName( "format" );
return function() {
for(var i = 0; i < radios.length; ++i) if(radios[i].checked || radios.length === 1) return radios[i].value;
};
})();
var to_json = function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length) result[sheetName] = roa;
});
return JSON.stringify(result, 2, 2);
};
var to_csv = function to_csv(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var csv = X.utils.sheet_to_csv(workbook.Sheets[sheetName]);
if(csv.length){
result.push("SHEET: " + sheetName);
result.push("");
result.push(csv);
}
});
return result.join("\n");
};
var to_fmla = function to_fmla(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var formulae = X.utils.get_formulae(workbook.Sheets[sheetName]);
if(formulae.length){
result.push("SHEET: " + sheetName);
result.push("");
result.push(formulae.join("\n"));
}
});
return result.join("\n");
};
var to_html = function to_html(workbook) {
HTMLOUT.innerHTML = "";
workbook.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(workbook, {sheet:sheetName, type:'binary', bookType:'html'});
HTMLOUT.innerHTML += htmlstr;
});
return "";
};
return function process_wb(wb) {
global_wb = wb;
var output = "";
switch(get_format()) {
case "form": output = to_fmla(wb); break;
case "html": output = to_html(wb); break;
case "json": output = to_json(wb); break;
default: output = to_csv(wb);
}
if(OUT.innerText === undefined) OUT.textContent = output;
else OUT.innerText = output;
if(typeof console !== 'undefined') console.log("output", new Date());
};
})();
var setfmt = window.setfmt = function setfmt() { if(global_wb) process_wb(global_wb); };
var b64it = window.b64it = (function() {
var tarea = document.getElementById('b64data');
return function b64it() {
if(typeof console !== 'undefined') console.log("onload", new Date());
var wb = X.read(tarea.value, {type:'base64', WTF:false});
process_wb(wb);
};
})();
var do_file = (function() {
var rABS = typeof FileReader !== "undefined" && (FileReader.prototype||{}).readAsBinaryString;
var domrabs = document.getElementsByName("userabs")[0];
if(!rABS) domrabs.disabled = !(domrabs.checked = false);
var use_worker = typeof Worker !== 'undefined';
var domwork = document.getElementsByName("useworker")[0];
if(!use_worker) domwork.disabled = !(domwork.checked = false);
var xw = function xw(data, cb) {
var worker = new Worker(XW.worker);
worker.onmessage = function(e) {
switch(e.data.t) {
case 'ready': break;
case 'e': console.error(e.data.d); break;
case XW.msg: cb(JSON.parse(e.data.d)); break;
}
};
worker.postMessage({d:data,b:rABS?'binary':'array'});
};
return function do_file(files) {
rABS = domrabs.checked;
use_worker = domwork.checked;
var f = files[0];
var reader = new FileReader();
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS, use_worker);
var data = e.target.result;
if(!rABS) data = new Uint8Array(data);
if(use_worker) xw(data, process_wb);
else process_wb(X.read(data, {type: rABS ? 'binary' : 'array'}));
};
if(rABS) reader.readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
};
})();
(function() {
var drop = document.getElementById('drop');
if(!drop.addEventListener) return;
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');
if(!xlf.addEventListener) return;
function handleFile(e) { do_file(e.target.files); }
xlf.addEventListener('change', handleFile, false);
})();

@ -0,0 +1,6 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('xlsx');
console.log(XLSX);
var w = XLSX.read('abc,def\nghi,jkl', {type:'binary'});
var j = XLSX.utils.sheet_to_json(w.Sheets[w.SheetNames[0]], {header:1});
console.log(j);

@ -0,0 +1,18 @@
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.16/system.js"></script>
<script>
SystemJS.config({
meta: {
'xlsx': {
exports: 'XLSX' // <-- tell SystemJS to expose the XLSX variable
}
},
map: {
'xlsx': 'xlsx.full.min.js', // <-- make sure xlsx.full.min.js is in same dir
'fs': '', // <--|
'crypto': '', // <--| suppress native node modules
'stream': '' // <--|
}
});
SystemJS.import('main.simple.js');
</script>

@ -1,18 +0,0 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.16/system.js"></script>
<script>
SystemJS.config({
meta: {
'xlsx': {
exports: 'XLSX'
}
},
map: {
'xlsx': 'xlsx.full.min.js',
'fs': '',
'crypto': '',
'stream': ''
}
});
SystemJS.import('main.js');
</script>

21
demos/systemjs/worker.js Normal file

@ -0,0 +1,21 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
importScripts('https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.19/system.js');
SystemJS.config({
meta: {
'xlsx': {
exports: 'XLSX' // <-- tell SystemJS to expose the XLSX variable
}
},
map: {
'xlsx': 'xlsx.full.min.js', // <-- make sure xlsx.full.min.js is in same dir
'fs': '', // <--|
'crypto': '', // <--| suppress native node modules
'stream': '' // <--|
}
});
onmessage = function(evt) {
/* the real action is in the _cb function from xlsxworker.js */
SystemJS.import('xlsxworker.js').then(function() { _cb(evt); });
};

@ -0,0 +1,12 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('xlsx');
postMessage({t:"ready"});
/* expose a global that can be accessed from the worker script */
_cb = function (evt) {
var v;
try {
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

@ -1,36 +1,85 @@
# VueJS 2
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>
```
Strictly speaking, there should be no need for a Vue.JS demo! You can proceed
as you would with any other browser-friendly library.
The library can also be imported directly from single-file components with:
```js
import XLSX from 'xlsx';
```
This demo directly generates HTML using `sheet_to_html` and adds an element to
a pregenerated template. It also has a button for exporting as XLSX.
a pre-generated template. It also has a button for exporting as XLSX.
Other scripts in this demo show:
- server-rendered VueJS component (with `nuxt.js`)
- `weex` deployment for iOS
## Single File Components
## Internal State
For Single File Components, a simple `import XLSX from 'xlsx'` should suffice.
The webpack demo includes a sample `webpack.config.js`.
The plain JS demo embeds state in the DOM. Other demos use proper 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 ]
]
}
```
`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;
}
```
## WeeX
<img src="screen.png" width="400px"/>
Reproducing the full project is a little bit tricky. The included `weex.sh`
script performs the necessary installation steps.
WeeX is a framework for building real mobile apps, akin to React Native. The
ecosystem is not quite as mature as React Native, missing basic features like
document access. As a result, this demo uses the `stream.fetch` API to upload
Base64-encoded documents to <https://hastebin.com> and download a precomputed
[Base64-encoded workbook](http://sheetjs.com/sheetjs.xlsx.b64).
Using NodeJS it is straightforward to convert to/from base64:
Using NodeJS it is straightforward to convert to/from Base64:
```js
/* convert sheetjs.xlsx -> sheetjs.xlsx.b64 */
@ -42,24 +91,9 @@ var str = fs.readFileSync("sheetjs.xls.b64").toString();
fs.writeFileSync("sheetjs.xls", new Buffer(str, "base64"));
```
## Nuxt and State
## Other Demos
The `nuxt.js` demo uses the same state approach as the React next.js demo:
```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 ]
]
}
```
#### Server-Rendered VueJS Components with Nuxt.js
Due to webpack configuration issues on client/server bundles, the library should
be explicitly included in the layout HTML (as script tag) and in the component:
@ -69,3 +103,5 @@ const _XLSX = require('xlsx');
const X = typeof XLSX !== 'undefined' ? XLSX : _XLSX;
/* use the variable X rather than XLSX in the component */
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -29,8 +29,6 @@ function s2ab(s) {
Vue.component('html-preview', {
template: SJSTemplate,
methods: {
// as per: https://github.com/SheetJS/js-xlsx/wiki/Reading-XLSX-from-FileReader.readAsArrayBuffer()
// changing the readAsBinaryString (deprecated) to readAsArrayBuffer()
onchange: function(evt) {
var file;
var files = evt.target.files;
@ -38,7 +36,7 @@ Vue.component('html-preview', {
if (!files || files.length == 0) return;
file = files[0];
var reader = new FileReader();
reader.onload = function (e) {
// pre-process data
@ -48,7 +46,7 @@ Vue.component('html-preview', {
for (var i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
/* read workbook */
var wb = XLSX.read(binary, {type: 'binary'});
@ -57,7 +55,7 @@ Vue.component('html-preview', {
var ws = wb.Sheets[wsname];
/* generate HTML */
var HTML = XLSX.utils.sheet_to_html(ws);
var HTML = XLSX.utils.sheet_to_html(ws);
/* update table */
document.getElementById('out-table').innerHTML = HTML;

@ -9,9 +9,9 @@
<text :style="{ color: data.length ? '#841584' : '#CDCDCD', disabled: !data.length }" @click="exportFile">Upload XLSX</text>
<text style="instructions">Current Data</text>
<scroller class="scroller">
<div class="row" v-for="(row, ridx) in data">
<div class="row" v-for="(row, ridx) in data" :key="ridx">
<text>ROW {{ridx + 1}}</text>
<text v-for="(cell, cidx) in row">CELL {{get_label(ridx, cidx)}}:{{cell}}</text>
<text v-for="(cell, cidx) in row" :key="cidx">CELL {{get_label(ridx, cidx)}}:{{cell}}</text>
</div>
</scroller>
</div>

@ -1,4 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
<!-- xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com -->
<template>
<div @drop="_drop" @dragenter="_suppress" @dragover="_suppress">
<div class="row"><div class="col-xs-12">
@ -16,11 +16,13 @@
<div class="table-responsive">
<table class="table table-striped">
<thead><tr>
<th v-for="c in cols">{{c.name}}</th>
<th v-for="c in cols" :key="c.key">{{c.name}}</th>
</tr></thead>
<tbody><tr v-for="r in data">
<td v-for="c in cols"> {{ r[c.key] }}</td>
</tr></tbody>
<tbody>
<tr v-for="(r, key) in data" :key="key">
<td v-for="c in cols" :key="c.key"> {{ r[c.key] }}</td>
</tr>
</tbody>
</table>
</div>
</div></div>

BIN
demos/vue/screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

@ -5,9 +5,9 @@ if [ ! -e SheetJS ]; then
cd SheetJS
npm install
weexpack platform add ios
sed -i 's/ATSDK-Weex/ATSDK/g' platforms/ios/Podfile
# see https://github.com/weexteam/weex-pack/issues/133#issuecomment-295806132
sed -i.bak 's/ATSDK-Weex/ATSDK/g' platforms/ios/Podfile
cd -
# weexpack run ios
fi
cp native.vue SheetJS/src/index.vue
if [ ! -e SheetJS/web/bootstrap.min.css ]; then

@ -1,3 +1,3 @@
webpack.js
webpack.min.js
main.js
main.min.js
*.out.js

@ -1,15 +1,15 @@
TOOL=webpack
WPOPTS=--display-modules --display-reasons --profile
.PHONY: all
all: $(TOOL).min.js core.out.js full.out.js
all: main.min.js core.out.js full.out.js app.out.js
$(TOOL).min.js: $(TOOL).js
main.min.js: main.out.js
uglifyjs $< > $@
.PHONY: $(TOOL).js
$(TOOL).js:
webpack main.js --output-filename $@ $(WPOPTS)
.PHONY: core.out.js full.out.js
core.out.js full.out.js: %.out.js: %.js
.PHONY: main.out.js core.out.js full.out.js
main.out.js core.out.js full.out.js: %.out.js: %.js
webpack $< --output-filename $@ $(WPOPTS)
.PHONY: app.out.js
app.out.js: webpack.app.js app.js appworker.js
webpack --config $< $(WPOPTS)

@ -4,6 +4,30 @@ This library is built with some dynamic logic to determine if it is invoked in a
script tag or in nodejs. Webpack does not understand those feature tests, so by
default it will do some strange things.
## Basic Usage
`webpack.app.js` demonstrates bundling an entire app script in a bundle. For
basic projects requiring the module from the npm package, it is sufficient to
suppress the node shims:
```js
/* webpack config for app.out.js */
{
/* entry point app.js */
entry: './app.js',
/* write to app.out.js */
output: { path:__dirname, filename: './app.out.js' },
/* suppress node shims */
node: {
fs: false,
process: false,
Buffer: false
}
}
```
## Suppressing the Node shims
The library properly guards against accidental leakage of node features in the
@ -17,18 +41,6 @@ browser but webpack disregards those. The config should explicitly suppress:
}
```
## Exporting the XLSX variable
This library will not assign to module.exports if it is run in the browser. To
convince webpack, set `output` in the webpack config:
```js
output: {
libraryTarget: 'var',
library: 'XLSX'
}
```
## Omitting optional dependencies
The `codepage` is needed in certain special cases, including files generated by
@ -41,6 +53,8 @@ the module can be omitted by aliasing the dependency:
},
```
Alternatively, bundling the `xlsx.core.min.js` script always omits dependencies.
## Bower and minified versions
Webpack may show a message like "This seems to be a pre-built javascript file"
@ -55,3 +69,44 @@ harmless. To suppress the message, set `module.noParse` in the webpack config:
]
}
```
## Other Demos
This demo also attempts to demonstrate bundling of the library as well as the
core and full distribution versions. `app.js` is the common app code (it will
not be bundled). The individual bundles merely wrap and reflect `XLSX`. The
app code uses the bundles with script tag inclusion in the main HTML files. The
worker scripts use the bundles with `importScripts` references.
| required script | HTML page | entry | worker script |
|----------------:|------------:|----------:|----------------:|
| main `xlsx` lib | `main.html` | `main.js` | `mainworker.js` |
| `xlsx.core.min` | `core.html` | `core.js` | `coreworker.js` |
| `xlsx.full.min` | `full.html` | `full.js` | `fullworker.js` |
The entry points in the demo merely require and re-export the library:
```js
/* main.js */
var XLSX = require('../../');
console.log("it works!");
module.exports = XLSX;
```
The main advantage of reflecting the library is deduplication: the library code
is only downloaded once. The basic example builds a separate worker script and
eventually ships the library twice.
### Reflecting the XLSX variable
This library will not assign to `module.exports` if it is run in the browser. To
convince webpack, the demo webpack config sets `output`:
```js
output: {
libraryTarget: 'var',
library: 'XLSX'
}
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +1,7 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint browser:true */
/*global XLSX */
var X = XLSX;
var X = typeof require !== "undefined" && require('../../') || XLSX;
var global_wb;

@ -1,11 +1,11 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
importScripts('webpack.min.js');
var XLSX = require('../../');
postMessage({t:"ready"});
onmessage = function (oEvent) {
onmessage = function (evt) {
var v;
try {
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b});
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

@ -2,10 +2,10 @@
importScripts('core.out.js');
postMessage({t:"ready"});
onmessage = function (oEvent) {
onmessage = function (evt) {
var v;
try {
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b});
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

@ -2,10 +2,10 @@
importScripts('full.out.js');
postMessage({t:"ready"});
onmessage = function (oEvent) {
onmessage = function (evt) {
var v;
try {
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b});
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

@ -46,13 +46,13 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<pre id="out"></pre>
<div id="htmlout"></div>
<br />
<script src="webpack.min.js"></script>
<script src="main.min.js"></script>
<script>
var XW = {
/* worker message */
msg: 'xlsx',
/* worker scripts */
worker: './xlsxworker.js'
worker: './mainworker.js'
};
</script>
<script src="app.js"></script>

@ -0,0 +1,11 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
importScripts('main.min.js');
postMessage({t:"ready"});
onmessage = function (evt) {
var v;
try {
v = XLSX.read(evt.data.d, {type: evt.data.b});
postMessage({t:"xlsx", d:JSON.stringify(v)});
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
};

@ -0,0 +1,26 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var commonops = {
/* suppress node shims */
node: {
fs: false,
process: false,
Buffer: false
}
}
/* app.out.js */
var app_config = Object.assign({
entry: './app.js',
output: { path:__dirname, filename: './app.out.js' }
}, commonops);
/* appworker.out.js */
var appworker_config = Object.assign({
entry: './appworker.js',
output: { path:__dirname, filename: './appworker.out.js' }
}, commonops);
module.exports = [
app_config,
appworker_config
]

@ -1,5 +1,6 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
module.exports = {
/* ensure that the XLSX variable is exported */
output: {
libraryTarget: 'var',
library: 'XLSX'
@ -17,6 +18,7 @@ module.exports = {
alias: { "./dist/cpexcel.js": "" }
},
*/
/* suppress node shims */
node: {
fs: false,
process: false,

@ -5,7 +5,20 @@ web browser clients and web servers. Since this library works in web browsers,
server conversion work can be offloaded to the client! This demo shows a few
common scenarios involving browser APIs and popular wrapper libraries.
## Sample Server
## Demos
The included demos focus on an editable table. There are two separate flows:
- When the page is accessed, the browser will attempt to download `sheetjs.xlsx`
and read the workbook. The old table will be replaced with an editable table
whose contents match the first worksheet. The table is generated using the
`sheet_to_html` utility with `editable:true` option
- When the upload button is clicked, the browser will generate a new worksheet
using `table_to_book` and build up a new workbook. It will then attempt to
generate a Base64-encoded XLSX string and upload it to the server.
### Demo Server
The `server.js` nodejs server serves static files on `GET` request. On a `POST`
request to `/upload`, the server processes the body and looks for the `file` and
@ -14,6 +27,7 @@ name specified in `file`.
To start the demo, run `npm start` and navigate to <http://localhost:7262/>
## XMLHttpRequest
For downloading data, the `arraybuffer` response type generates an `ArrayBuffer`
@ -26,10 +40,10 @@ req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
/* parse the data when it is received */
var data = new Uint8Array(oReq.response);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
/* parse the data when it is received */
var data = new Uint8Array(req.response);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
};
req.send();
```
@ -48,31 +62,57 @@ fd.append('data', b64);
/* send data */
var req = new XMLHttpRequest();
req.open("POST", "/upload", true);
req.send(formdata);
req.send(fd);
```
axios and superagent patterns are similar to the XMLHttpRequest pattern but
involve much less boilerplate:
### superagent Wrapper Library
The `superagent` library usage mirrors XHR:
```js
/* set up an async GET request with superagent */
superagent.get(url).responseType('arraybuffer').end(function(err, res) {
/* parse the data when it is received */
var data = new Uint8Array(res.body);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
});
```
The upload portion only differs in the actual request command:
```js
/* send data (fd is the FormData object) */
superagent.post("/upload").send(fd);
```
### superagent Wrapper Library
The `axios` library presents a Promise interface. The axios demo uses a single
promise, but for production deployments it may make sense to separate parsing:
```js
/* set up an async GET request with axios */
axios(url, {responseType:'arraybuffer'}).then(function(res) {
/* parse the data when it is received */
var data = new Uint8Array(res.data);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
axios(url, {responseType:'arraybuffer'}).catch(function(err) {
/* error in getting data */
}).then(function(res) {
/* parse the data when it is received */
var data = new Uint8Array(res.data);
var workbook = XLSX.read(data, {type:"array"});
return workbook;
}).catch(function(err) {
/* error in parsing */
}).then(function(workbook) {
/* DO SOMETHING WITH workbook HERE */
});
```
/* set up an async GET request with superagent */
superagent.get(url).responseType('arraybuffer').end(function(err, res) {
/* parse the data when it is received */
var data = new Uint8Array(res.body);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
});
The upload portion only differs in the actual request command:
```js
/* send data (fd is the FormData object) */
axios("/upload", {method: "POST", data: fd});
```
## fetch
@ -82,20 +122,29 @@ converted to `ArrayBuffer` using a `FileReader`:
```js
fetch(url).then(function(res) {
/* get the data as a Blob */
if(!res.ok) throw new Error("fetch failed");
return res.blob();
/* get the data as a Blob */
if(!res.ok) throw new Error("fetch failed");
return res.blob();
}).catch(function(err) {
/* error in getting data */
}).then(function(blob) {
/* configure a FileReader to process the blob */
var reader = new FileReader();
reader.addEventListener("loadend", function() {
/* parse the data when it is received */
var data = new Uint8Array(this.result);
var workbook = XLSX.read(data, {type:"array"});
/* configure a FileReader to process the blob */
var reader = new FileReader();
reader.addEventListener("loadend", function() {
/* parse the data when it is received */
var data = new Uint8Array(this.result);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
});
reader.readAsArrayBuffer(blob);
/* DO SOMETHING WITH workbook HERE */
});
reader.readAsArrayBuffer(blob);
});
```
The upload code is identical to `axios`, except for the variable name:
```js
fetch("/upload", {method: "POST", body: fd});
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -46,10 +46,10 @@ axios(url, {responseType:'arraybuffer'}).then(function(res) {
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var formdata = new FormData();
formdata.append('file', demo + '.' + book);
formdata.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
axios("/upload", {method: "POST", data: formdata});
var fd = new FormData();
fd.append('file', demo + '.' + book);
fd.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
axios("/upload", {method: "POST", data: fd});
};
</script>
<script type="text/javascript">

@ -55,10 +55,10 @@ fetch(url).then(function(res) {
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var formdata = new FormData();
formdata.append('file', demo + '.' + book);
formdata.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
fetch("/upload", {method: "POST", body: formdata}).then(function(r) { return r.text(); }).then(function(t) { console.log(t); });
var fd = new FormData();
fd.append('file', demo + '.' + book);
fd.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
fetch("/upload", {method: "POST", body: fd}).then(function(r) { return r.text(); }).then(function(t) { console.log(t); });
};
</script>
<script type="text/javascript">

@ -28,7 +28,6 @@ a { text-decoration: none }
<script>
var demo = 'superagent', book = 'xlsx';
var request = window.superagent;
function process_wb(wb) {
console.log(wb);
htmlout.innerHTML = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]], {editable:true}).replace("<table", '<table id="table" border="1"');
@ -38,7 +37,7 @@ var url = "sheetjs.xlsx";
document.getElementById('fileurl').innerHTML = '<a href="' + url + '">Download original file</a>';
document.getElementById('outfile').innerHTML = '<a href="' + demo + '.' + book + '">Download new file</a>';
request.get(url)
superagent.get(url)
.responseType('arraybuffer')
.end(function(err, res) {
var data = new Uint8Array(res.body);
@ -49,10 +48,10 @@ request.get(url)
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var formdata = new FormData();
formdata.append('file', demo + '.' + book);
formdata.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
request.post("/upload").send(formdata).end(function(e,r) { console.log(r.text); });
var fd = new FormData();
fd.append('file', demo + '.' + book);
fd.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
superagent.post("/upload").send(fd).end(function(e,r) { console.log(r.text); });
};
</script>
<script type="text/javascript">

@ -40,26 +40,26 @@ document.getElementById('fileurl').innerHTML = '<a href="' + url + '">Download o
document.getElementById('outfile').innerHTML = '<a href="' + demo + '.' + book + '">Download new file</a>';
{
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var data = new Uint8Array(oReq.response);
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
var data = new Uint8Array(req.response);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
};
oReq.send();
req.send();
}
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var formdata = new FormData();
formdata.append('file', demo + '.' + book);
formdata.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
var oReq = new XMLHttpRequest();
oReq.open("POST", "/upload", true);
oReq.send(formdata);
var fd = new FormData();
fd.append('file', demo + '.' + book);
fd.append('data', XLSX.write(wb, {bookType:book, type:'base64'}));
var req = new XMLHttpRequest();
req.open("POST", "/upload", true);
req.send(fd);
};
</script>
<script type="text/javascript">

@ -26,7 +26,7 @@ enhancements, additional features by request, and dedicated support.
[**File format support for known spreadsheet data formats:**](#file-formats)
<details>
<summary><b>Graph of supported formats</b> (click to show)</summary>
<summary><b>Graph of supported formats</b> (click to show)</summary>
![circo graph of format support](formats.png)
@ -42,7 +42,7 @@ enhancements, additional features by request, and dedicated support.
[![Build Status](https://semaphoreci.com/api/v1/sheetjs/js-xlsx/branches/master/shields_badge.svg)](https://semaphoreci.com/sheetjs/js-xlsx)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-xlsx/master.svg)](https://coveralls.io/r/SheetJS/js-xlsx?branch=master)
[![Dependencies Status](https://david-dm.org/sheetjs/js-xlsx/status.svg)](https://david-dm.org/sheetjs/js-xlsx)
[![NPM Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
[![npm Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

Some files were not shown because too many files have changed in this diff Show More