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"] });
};
})();