Math.LOG2E precision issue + new demos [ci skip]

- swift + jsc
- java + rhino
- XMLHttpRequest and friends
This commit is contained in:
SheetJS 2017-09-05 01:26:50 -04:00
parent e34b6e78d2
commit ad47cb433c
47 changed files with 822 additions and 26 deletions

@ -4,7 +4,7 @@ This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code.
## Unreleased (2017-08-??)
## 0.11.3 (2017-08-19)
* XLS cell ixfe/XF removed

@ -167,24 +167,25 @@ CDNjs automatically pulls the latest version and makes all versions available at
The `demos` directory includes sample projects for:
**Frameworks**
**JS Frameworks and APIs**
- [`angular 1.x`](demos/angular/)
- [`angular 2.x / 4.x`](demos/angular2/)
- [`meteor`](demos/meteor/)
- [`vue 2`](demos/vue/)
- [`vue 2.x`](demos/vue/)
- [`XMLHttpRequest and fetch`](demos/xhr/)
**JS Bundlers and Tooling**
- [`browserify`](demos/browserify/)
- [`requirejs`](demos/requirejs/)
- [`rollup`](demos/rollup/)
- [`systemjs`](demos/systemjs/)
- [`webpack`](demos/webpack/)
- [`webpack 2.x`](demos/webpack/)
**JS Platforms and Integrations**
- [`Adobe ExtendScript`](demos/extendscript/)
- [`Headless Browsers`](demos/headless/)
- [`canvas-datagrid`](demos/datagrid/)
- [`Other JS engines`](demos/altjs/)
- [`Swift JSC and other engines`](demos/altjs/)
### Optional Modules
@ -616,6 +617,29 @@ saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "test.xlsx");
```
</details>
<details>
<summary><b>Browser upload to server</b> (click to show)</summary>
A complete example using XHR is [included in the xhr demo](demos/xhr/), along
with examples for fetch and wrapper libraries. This example assumes the server
can handle Base64-encoded files (see the demo for a basic nodejs server):
```js
/* in this example, send a base64 string to the server */
var wopts = { bookType:'xlsx', bookSST:false, type:'base64' };
var wbout = XLSX.write(workbook,wopts);
var oReq = new XMLHttpRequest();
oReq.open("POST", "/upload", true);
var formdata = new FormData();
formdata.append('file', 'test.xlsx'); // <-- server expects `file` to hold name
formdata.append('data', wbout); // <-- `data` holds the base64-encoded data
oReq.send(formdata);
```
</details>
### Writing Examples
- <http://sheetjs.com/demos/table.html> exporting an HTML table

@ -14,8 +14,8 @@ function write_double_le(b, v/*:number*/, idx/*:number*/) {
var av = bs ? -v : v;
if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
else {
e = Math.floor(Math.log(av) * Math.LOG2E);
m = v * Math.pow(2, 52 - e);
e = Math.floor(Math.log(av) / Math.LN2);
m = av * Math.pow(2, 52 - e);
if(e <= -1023 && (!isFinite(m) || m < Math.pow(2,52))) { e = -1022; }
else { m -= Math.pow(2,52); e+=1023; }
}

@ -1,2 +1,6 @@
jvm-npm.js
sheetjs.*
*.class
*.jar
rhino
xlsx.swift.js

@ -1,5 +1,5 @@
.PHONY: all
all: duktape nashorn
all: duktape nashorn rhinojs swift
.PHONY: base
base:
@ -13,3 +13,32 @@ duktape: base ## duktape / skookum demo
nashorn: base ## nashorn demo
if [ ! -e jvm-npm.js ]; then curl -O https://rawgit.com/nodyn/jvm-npm/master/src/main/javascript/jvm-npm.js; fi
jjs nashorn.js
.PHONY: swift
swift: base ## swift demo
if [ ! -e xlsx.swift.js ]; then cp ../../dist/xlsx.full.min.js xlsx.swift.js; fi
./SheetJSCore.swift
.PHONY: rhinojs ## rhino demo
rhinojs: base SheetJSRhino.class
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xlsx
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xlsb
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xls
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xml.xls
RHDEPS=$(filter-out SheetJSRhino.class,$(patsubst %.java,%.class,$(wildcard com/sheetjs/*.java)))
$(RHDEPS): %.class: %.java rhino.jar
javac -cp .:SheetJS.jar:rhino.jar $*.java
SheetJSRhino.class: $(RHDEPS)
jar -cf SheetJS.jar $^ ../../dist/xlsx.full.min.js
javac -cp .:SheetJS.jar:rhino.jar SheetJSRhino.java
rhino.jar:
if [ ! -e rhino ]; then git clone https://github.com/mozilla/rhino; fi
if [ ! -e rhino/build/rhino*/js.jar ]; then cd rhino; ant jar; fi
cp rhino/build/rhino*/js.jar rhino.jar
.PHONY: clean
clean:
rm SheetJS.jar *.class com/sheetjs/*.class

@ -6,6 +6,21 @@ optimize for low overhead and others optimize for ease of embedding within other
applications. Since it was designed for ES3 engines, the library can be used in
those settings! This demo tries to demonstrate a few alternative deployments.
Some engines provide no default global object. To create a global reference:
```js
var global = (function(){ return this; }).call(null);
```
## Swift + JavaScriptCore
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.
Binary strings can be passed back and forth using `String.Encoding.ascii`.
## Nashorn
@ -21,6 +36,20 @@ a byte array. To use in `XLSX.read`, the demo copies the bytes into a plain JS
array and calls `XLSX.read` with type `"array"`.
## Rhino
[Rhino](http://www.mozilla.org/rhino) is an ES3+ engine written in Java. The
`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:
```java
Context context = Context.enter();
context.setOptimizationLevel(-1);
```
## duktape and skookum
[Duktape](http://duktape.org/) is an embeddable JS engine written in C. The

62
demos/altjs/SheetJSCore.swift Executable file

@ -0,0 +1,62 @@
#!/usr/bin/env xcrun swift
import JavaScriptCore;
class SheetJS {
var context: JSContext!;
var XLSX: JSValue!;
enum SJSError: Error {
case badJSContext;
};
func init_context() throws -> JSContext {
var context: JSContext!
do {
context = JSContext();
context.exceptionHandler = { ctx, X in if let e = X { print(e.toString()); }; }
var src = "var global = (function(){ return this; }).call(null);";
context.evaluateScript(src);
src = try String(contentsOfFile: "xlsx.swift.js");
context.evaluateScript(src);
if context != nil { return context!; }
} catch { print(error.localizedDescription); }
throw SheetJS.SJSError.badJSContext;
}
func version() throws -> String {
if let version = XLSX.objectForKeyedSubscript("version") { return version.toString(); }
throw SheetJS.SJSError.badJSContext;
}
func readFileToCSV(file: String) throws -> String {
let data:String! = try String(contentsOfFile: file, encoding:String.Encoding.ascii);
self.context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
let src = [
"var wb = XLSX.read(payload, {type:'binary'});",
"var ws = wb.Sheets[wb.SheetNames[0]];",
"var result = XLSX.utils.sheet_to_csv(ws);"
].joined(separator: "\n");
self.context.evaluateScript(src);
return context.objectForKeyedSubscript("result").toString();
}
init() throws {
do {
self.context = try init_context();
self.XLSX = context.objectForKeyedSubscript("XLSX");
if self.XLSX == nil {
throw SheetJS.SJSError.badJSContext;
}
} catch { print(error.localizedDescription); }
}
}
let sheetjs = try SheetJS();
try print(sheetjs.version());
try print(sheetjs.readFileToCSV(file:"sheetjs.xlsx"));
try print(sheetjs.readFileToCSV(file:"sheetjs.xlsb"));
try print(sheetjs.readFileToCSV(file:"sheetjs.xls"));
try print(sheetjs.readFileToCSV(file:"sheetjs.xml.xls"));

@ -0,0 +1,31 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
import com.sheetjs.SheetJS;
import com.sheetjs.SheetJSFile;
import com.sheetjs.SheetJSSheet;
public class SheetJSRhino {
public static void main(String args[]) throws Exception {
try {
SheetJS sjs = new SheetJS();
/* open file */
SheetJSFile xl = sjs.read_file(args[0]);
/* get sheetnames */
String[] sheetnames = xl.get_sheet_names();
System.err.println(sheetnames[0]);
/* convert to CSV */
SheetJSSheet sheet = xl.get_sheet(0);
String csv = sheet.get_csv();
System.out.println(csv);
} catch(Exception e) {
throw e;
} finally {
SheetJS.close();
}
}
}

@ -0,0 +1,51 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
package com.sheetjs;
import java.lang.Integer;
import java.lang.StringBuilder;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
public class JSHelper {
static String read_file(String file) throws IOException {
byte[] b = Files.readAllBytes(Paths.get(file));
System.out.println(b.length);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < b.length; ++i) sb.append(Character.toString((char)b[i]));
return sb.toString();
}
static Object get_object(String path, Object base) throws ObjectNotFoundException {
int idx = path.indexOf(".");
Scriptable b = (Scriptable)base;
if(idx == -1) return b.get(path, b);
Object o = b.get(path.substring(0,idx), b);
if(o == Scriptable.NOT_FOUND) throw new ObjectNotFoundException("not found: |" + path.substring(0,idx) + "|" + Integer.toString(idx));
return get_object(path.substring(idx+1), (NativeObject)o);
}
static Object[] get_array(String path, Object base) throws ObjectNotFoundException {
NativeArray arr = (NativeArray)get_object(path, base);
Object[] out = new Object[(int)arr.getLength()];
int idx;
for(Object o : arr.getIds()) out[idx = (Integer)o] = arr.get(idx, arr);
return out;
}
static String[] get_string_array(String path, Object base) throws ObjectNotFoundException {
NativeArray arr = (NativeArray)get_object(path, base);
String[] out = new String[(int)arr.getLength()];
int idx;
for(Object o : arr.getIds()) out[idx = (Integer)o] = arr.get(idx, arr).toString();
return out;
}
public static void close() { Context.exit(); }
}

@ -0,0 +1,10 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
package com.sheetjs;
import java.lang.Exception;
public class ObjectNotFoundException extends Exception {
public ObjectNotFoundException() {}
public ObjectNotFoundException(String message) { super(message); }
}

@ -0,0 +1,58 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
package com.sheetjs;
import java.lang.Integer;
import java.util.Scanner;
import java.io.IOException;
import java.io.File;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
public class SheetJS {
public Scriptable scope;
public Context cx;
public NativeObject nXLSX;
public SheetJS() throws Exception {
this.cx = Context.enter();
this.scope = this.cx.initStandardObjects();
/* boilerplate */
cx.setOptimizationLevel(-1);
String s = "var global = (function(){ return this; }).call(null);";
cx.evaluateString(scope, s, "<cmd>", 1, null);
/* eval library */
s = new Scanner(SheetJS.class.getResourceAsStream("/dist/xlsx.full.min.js")).useDelimiter("\\Z").next();
//s = new Scanner(new File("xlsx.full.min.js")).useDelimiter("\\Z").next();
cx.evaluateString(scope, s, "<cmd>", 1, null);
/* grab XLSX variable */
Object XLSX = scope.get("XLSX", scope);
if(XLSX == Scriptable.NOT_FOUND) throw new Exception("XLSX not found");
this.nXLSX = (NativeObject)XLSX;
}
public SheetJSFile read_file(String filename) throws IOException, ObjectNotFoundException {
/* open file */
String d = JSHelper.read_file(filename);
/* options argument */
NativeObject q = (NativeObject)this.cx.evaluateString(this.scope, "q = {'type':'binary'};", "<cmd>", 2, null);
/* set up function arguments */
Object functionArgs[] = {d, q};
/* call read -> wb workbook */
Function readfunc = (Function)JSHelper.get_object("XLSX.read",this.scope);
NativeObject wb = (NativeObject)readfunc.call(this.cx, this.scope, this.nXLSX, functionArgs);
return new SheetJSFile(wb, this);
}
public static void close() { JSHelper.close(); }
}

@ -0,0 +1,24 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
package com.sheetjs;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Function;
public class SheetJSFile {
public NativeObject wb;
public SheetJS sheetjs;
public SheetJSFile() {}
public SheetJSFile(NativeObject wb, SheetJS sheetjs) { this.wb = wb; this.sheetjs = sheetjs; }
public String[] get_sheet_names() {
try {
return JSHelper.get_string_array("SheetNames", this.wb);
} catch(ObjectNotFoundException e) {
return null;
}
}
public SheetJSSheet get_sheet(int idx) throws ObjectNotFoundException {
return new SheetJSSheet(this, idx);
}
}

@ -0,0 +1,29 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
package com.sheetjs;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeObject;
public class SheetJSSheet {
public NativeObject ws;
public SheetJSFile wb;
public SheetJSSheet(SheetJSFile wb, int idx) throws ObjectNotFoundException {
this.wb = wb;
this.ws = (NativeObject)JSHelper.get_object("Sheets." + wb.get_sheet_names()[idx],wb.wb);
}
public String get_range() throws ObjectNotFoundException {
return JSHelper.get_object("!ref",this.ws).toString();
}
public String get_string_value(String address) throws ObjectNotFoundException {
return JSHelper.get_object(address + ".v",this.ws).toString();
}
public String get_csv() throws ObjectNotFoundException {
Function csvify = (Function)JSHelper.get_object("XLSX.utils.sheet_to_csv",this.wb.sheetjs.scope);
Object csvArgs[] = {this.ws};
Object csv = csvify.call(this.wb.sheetjs.cx, this.wb.sheetjs.scope, this.wb.sheetjs.scope, csvArgs);
return csv.toString();
}
}

@ -1,4 +1,5 @@
#!/usr/bin/env jjs
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* read file */
var path = java.nio.file.Paths.get('sheetjs.xlsx');
var fileArray = java.nio.file.Files.readAllBytes(path);

@ -1,4 +1,5 @@
#!/usr/bin/env sjs
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('../../xlsx.js');

@ -1,3 +1,4 @@
/* 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,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var fs = require('fs');
var xlsx = require('../../xlsx');
var page = require('webpage').create();

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
const puppeteer = require('puppeteer');
(async () => {

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var fs = require('fs');
var xlsx = require('../../dist/xlsx.full.min');
var page = require('webpage').create();

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import { Meteor } from 'meteor/meteor';
const XLSX = require('xlsx');

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
({
baseUrl: ".",
name: "requirejs",

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

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint browser:true */
/*global XLSX */
var X = XLSX;

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX_1 = require('../../xlsx.js');
var XLSX_2 = require('../../dist/xlsx.core.min.js');
var XLSX_3 = require('../../dist/xlsx.full.min.js');

@ -1,3 +1,4 @@
/* 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'});

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var SystemJS = require('systemjs');
SystemJS.config({
meta: {

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var 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(",");

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint browser:true */
/*global XLSX */
var X = XLSX;

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('./xlsx.core.min');
console.log("it works!");
module.exports = XLSX;

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('./xlsx.full.min');
console.log("it works!");
module.exports = XLSX;

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('../../');
console.log("it works!");
module.exports = XLSX;

@ -1,3 +1,4 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
module.exports = {
output: {
libraryTarget: 'var',

7
demos/xhr/Makefile Normal file

@ -0,0 +1,7 @@
.PHONY: serve
serve:
npm start
.PHONY: init
init:
if [ ! -e sheetjs.xlsx ]; then ln -s ../../sheetjs.xlsx; fi

34
demos/xhr/README.md Normal file

@ -0,0 +1,34 @@
# XMLHttpRequest and Friends
`XMLHttpRequest` and `fetch` browser APIs enable binary data transfer between
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
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
`data` fields. It will write the Base64-decoded data from `data` to the file
name specified in `file`.
To start the demo, run `npm start` and navigate to <http://localhost:7262/>
## XMLHttpRequest (xhr.html)
For downloading data, the `arraybuffer` response type generates an `ArrayBuffer`
that can be viewed as an `Uint8Array` and fed to `XLSX.read` using `array` type.
For uploading data, this demo populates a `FormData` object with string data
generated with the `base64` output type.
## axios (axios.html) and superagent (superagent.html)
The codes are structurally similar to the XMLHttpRequest example. `axios` uses
a Promise-based API while `superagent` opts for a more traditional chain.
## fetch (fetch.html)
For downloading data, `response.blob()` resolves to a `Blob` object that can be
converted to `ArrayBuffer` using a `FileReader`.

67
demos/xhr/axios.html Normal file

@ -0,0 +1,67 @@
<!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>
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
<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>
<br/><div id="fileurl"></div>
</pre>
<div id="htmlout"></div>
<br />
<button id="ulbutton">Click here to upload the modified table</button>
<pre>
<div id="outfile"></div>
</pre>
<script src="xlsx.full.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var demo = 'axios', book = 'xlsx';
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"');
}
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>';
axios(url, {responseType:'arraybuffer'}).then(function(res) {
var data = new Uint8Array(res.data);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
});
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});
};
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

76
demos/xhr/fetch.html Normal file

@ -0,0 +1,76 @@
<!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>
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
<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>
<br/><div id="fileurl"></div>
</pre>
<div id="htmlout"></div>
<br />
<button id="ulbutton">Click here to upload the modified table</button>
<pre>
<div id="outfile"></div>
</pre>
<script src="xlsx.full.min.js"></script>
<script>
var demo = 'fetch', book = 'xlsx';
if(!window.fetch)
throw new Error("This demo is not supported in your browser");
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"');
}
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>';
fetch(url).then(function(res) {
if(!res.ok) throw new Error("fetch failed");
return res.blob();
}).then(function(blob) {
var reader = new FileReader();
reader.addEventListener("loadend", function() {
var data = new Uint8Array(this.result);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
});
reader.readAsArrayBuffer(blob);
});
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); });
};
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

14
demos/xhr/package.json Normal file

@ -0,0 +1,14 @@
{
"name": "sheetjs-xhr-demo",
"author": "sheetjs",
"version": "0.72.62",
"dependencies": {
"printj": "1.1.0",
"express": "4.15.4",
"express-formidable": "1.0.0",
"serve-index": "1.9.0"
},
"scripts": {
"start": "node server.js 7262"
}
}

34
demos/xhr/server.js Normal file

@ -0,0 +1,34 @@
#!/usr/bin/env node
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var fs = require('fs'), path = require('path');
var express = require('express'), app = express();
var sprintf = require('printj').sprintf;
var port = +process.argv[2] || +process.env.PORT || 7262;
var basepath = process.cwd();
function doit(cb) {
return function(req, res, next) {
cb(req, res);
next();
};
}
app.use(doit(function(req, res) {
console.log(sprintf("%s %s %d", req.method, req.url, res.statusCode));
}));
app.use(doit(function(req, res) {
res.header('Access-Control-Allow-Origin', '*');
}));
app.use(require('express-formidable')());
app.post('/upload', function(req, res) {
fs.writeFile(req.fields.file, req.fields.data, 'base64', function(err, r) {
res.end("wrote to " + req.fields.file);
});
});
app.use(express.static(path.resolve(basepath)));
app.use(require('serve-index')(basepath, {'icons':true}));
app.listen(port, function() { console.log('Serving HTTP on port ' + port); });

70
demos/xhr/superagent.html Normal file

@ -0,0 +1,70 @@
<!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>
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
<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>
<br/><div id="fileurl"></div>
</pre>
<div id="htmlout"></div>
<br />
<button id="ulbutton">Click here to upload the modified table</button>
<pre>
<div id="outfile"></div>
</pre>
<script src="xlsx.full.min.js"></script>
<script src="https://unpkg.com/superagent/superagent.js"></script>
<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"');
}
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)
.responseType('arraybuffer')
.end(function(err, res) {
var data = new Uint8Array(res.body);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
});
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); });
};
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

77
demos/xhr/xhr.html Normal file

@ -0,0 +1,77 @@
<!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>
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
<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>
<br/><div id="fileurl"></div>
</pre>
<div id="htmlout"></div>
<br />
<button id="ulbutton">Click here to upload the modified table</button>
<pre>
<div id="outfile"></div>
</pre>
<script src="xlsx.full.min.js"></script>
<script>
var demo = 'xhr', book = 'xlsx';
if(!window.XMLHttpRequest || typeof Uint8Array === 'undefined')
throw new Error("This demo is not supported in your browser");
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"');
}
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>';
{
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var data = new Uint8Array(oReq.response);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
};
oReq.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);
};
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

1
demos/xhr/xlsx.full.min.js vendored Symbolic link

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

@ -25,24 +25,25 @@ CDNjs automatically pulls the latest version and makes all versions available at
The `demos` directory includes sample projects for:
**Frameworks**
**JS Frameworks and APIs**
- [`angular 1.x`](demos/angular/)
- [`angular 2.x / 4.x`](demos/angular2/)
- [`meteor`](demos/meteor/)
- [`vue 2`](demos/vue/)
- [`vue 2.x`](demos/vue/)
- [`XMLHttpRequest and fetch`](demos/xhr/)
**JS Bundlers and Tooling**
- [`browserify`](demos/browserify/)
- [`requirejs`](demos/requirejs/)
- [`rollup`](demos/rollup/)
- [`systemjs`](demos/systemjs/)
- [`webpack`](demos/webpack/)
- [`webpack 2.x`](demos/webpack/)
**JS Platforms and Integrations**
- [`Adobe ExtendScript`](demos/extendscript/)
- [`Headless Browsers`](demos/headless/)
- [`canvas-datagrid`](demos/datagrid/)
- [`Other JS engines`](demos/altjs/)
- [`Swift JSC and other engines`](demos/altjs/)
### Optional Modules

@ -40,6 +40,29 @@ saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "test.xlsx");
```
</details>
<details>
<summary><b>Browser upload to server</b> (click to show)</summary>
A complete example using XHR is [included in the xhr demo](demos/xhr/), along
with examples for fetch and wrapper libraries. This example assumes the server
can handle Base64-encoded files (see the demo for a basic nodejs server):
```js
/* in this example, send a base64 string to the server */
var wopts = { bookType:'xlsx', bookSST:false, type:'base64' };
var wbout = XLSX.write(workbook,wopts);
var oReq = new XMLHttpRequest();
oReq.open("POST", "/upload", true);
var formdata = new FormData();
formdata.append('file', 'test.xlsx'); // <-- server expects `file` to hold name
formdata.append('data', wbout); // <-- `data` holds the base64-encoded data
oReq.send(formdata);
```
</details>
### Writing Examples
- <http://sheetjs.com/demos/table.html> exporting an HTML table

@ -161,24 +161,25 @@ CDNjs automatically pulls the latest version and makes all versions available at
The `demos` directory includes sample projects for:
**Frameworks**
**JS Frameworks and APIs**
- [`angular 1.x`](demos/angular/)
- [`angular 2.x / 4.x`](demos/angular2/)
- [`meteor`](demos/meteor/)
- [`vue 2`](demos/vue/)
- [`vue 2.x`](demos/vue/)
- [`XMLHttpRequest and fetch`](demos/xhr/)
**JS Bundlers and Tooling**
- [`browserify`](demos/browserify/)
- [`requirejs`](demos/requirejs/)
- [`rollup`](demos/rollup/)
- [`systemjs`](demos/systemjs/)
- [`webpack`](demos/webpack/)
- [`webpack 2.x`](demos/webpack/)
**JS Platforms and Integrations**
- [`Adobe ExtendScript`](demos/extendscript/)
- [`Headless Browsers`](demos/headless/)
- [`canvas-datagrid`](demos/datagrid/)
- [`Other JS engines`](demos/altjs/)
- [`Swift JSC and other engines`](demos/altjs/)
### Optional Modules
@ -565,6 +566,26 @@ function s2ab(s) {
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "test.xlsx");
```
A complete example using XHR is [included in the xhr demo](demos/xhr/), along
with examples for fetch and wrapper libraries. This example assumes the server
can handle Base64-encoded files (see the demo for a basic nodejs server):
```js
/* in this example, send a base64 string to the server */
var wopts = { bookType:'xlsx', bookSST:false, type:'base64' };
var wbout = XLSX.write(workbook,wopts);
var oReq = new XMLHttpRequest();
oReq.open("POST", "/upload", true);
var formdata = new FormData();
formdata.append('file', 'test.xlsx'); // <-- server expects `file` to hold name
formdata.append('data', wbout); // <-- `data` holds the base64-encoded data
oReq.send(formdata);
```
### Writing Examples
- <http://sheetjs.com/demos/table.html> exporting an HTML table

@ -1434,7 +1434,7 @@ var ENDOFCHAIN = -2;
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
var HEADER_CLSID = '00000000000000000000000000000000';
var consts = {
/* 2.1 Compund File Sector Numbers and Types */
/* 2.1 Compound File Sector Numbers and Types */
MAXREGSECT: -6,
DIFSECT: -4,
FATSECT: -3,
@ -1907,8 +1907,8 @@ function write_double_le(b, v/*:number*/, idx/*:number*/) {
var av = bs ? -v : v;
if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
else {
e = Math.floor(Math.log(av) * Math.LOG2E);
m = v * Math.pow(2, 52 - e);
e = Math.floor(Math.log(av) / Math.LN2);
m = av * Math.pow(2, 52 - e);
if(e <= -1023 && (!isFinite(m) || m < Math.pow(2,52))) { e = -1022; }
else { m -= Math.pow(2,52); e+=1023; }
}
@ -5423,7 +5423,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
case 'L': switch(s.toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case ' ': case '?': out[R][C] = false; break; /* NOTE: technically unitialized */
case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -6658,7 +6658,7 @@ function parse_EncryptionInfo(blob, length/*:?number*/) {
case 0x03: return parse_EncInfoExt(blob, vers);
case 0x04: return parse_EncInfoAgl(blob, vers);
}
throw new Error("ECMA-376 Encryped file unrecognized Version: " + vers.Minor);
throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
}
/* [MS-OFFCRYPTO] 2.3.4.5 EncryptionInfo Stream (Standard Encryption) */

10
xlsx.js

@ -1372,7 +1372,7 @@ var ENDOFCHAIN = -2;
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
var HEADER_CLSID = '00000000000000000000000000000000';
var consts = {
/* 2.1 Compund File Sector Numbers and Types */
/* 2.1 Compound File Sector Numbers and Types */
MAXREGSECT: -6,
DIFSECT: -4,
FATSECT: -3,
@ -1843,8 +1843,8 @@ function write_double_le(b, v, idx) {
var av = bs ? -v : v;
if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
else {
e = Math.floor(Math.log(av) * Math.LOG2E);
m = v * Math.pow(2, 52 - e);
e = Math.floor(Math.log(av) / Math.LN2);
m = av * Math.pow(2, 52 - e);
if(e <= -1023 && (!isFinite(m) || m < Math.pow(2,52))) { e = -1022; }
else { m -= Math.pow(2,52); e+=1023; }
}
@ -5349,7 +5349,7 @@ function dbf_to_aoa(buf, opts) {
case 'L': switch(s.toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case ' ': case '?': out[R][C] = false; break; /* NOTE: technically unitialized */
case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -6583,7 +6583,7 @@ function parse_EncryptionInfo(blob, length) {
case 0x03: return parse_EncInfoExt(blob, vers);
case 0x04: return parse_EncInfoAgl(blob, vers);
}
throw new Error("ECMA-376 Encryped file unrecognized Version: " + vers.Minor);
throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
}
/* [MS-OFFCRYPTO] 2.3.4.5 EncryptionInfo Stream (Standard Encryption) */