precise time parse (h/t @ragearino @MyAddonsDev )

This commit is contained in:
SheetJS 2022-08-06 22:50:58 -04:00
parent c02eb14255
commit fdbbf2d6bf
51 changed files with 414 additions and 1479 deletions

@ -159,22 +159,22 @@ function fuzzynum(s/*:string*/)/*:number*/ {
}
/* NOTE: Chrome rejects bare times like 1:23 PM */
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))([ap])m?/;
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))\s+([ap])m?$/;
function fuzzytime1(M) /*:Date*/ {
/* TODO: 1904 adjustment */
if(!M[2]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
/* TODO: 1904 adjustment, keep in sync with base date */
if(!M[2]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
if(M[3]) {
if(M[4]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1900,0,0,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
if(M[4]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1899,11,30,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
}
else if(M[5]) return new Date(1900, 0, 0, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
else if(M[5]) return new Date(1899,11,30, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
}
var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
function fuzzydate(s/*:string*/)/*:Date*/ {
var lower = s.toLowerCase();
var lnos = lower.replace(/\s+/g, "");
var lnos = lower.replace(/\s+/g, " ").trim();
var M = lnos.match(FDRE1);
if(M) return fuzzytime1(M);

@ -960,12 +960,12 @@ var PRN = /*#__PURE__*/(function() {
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
else if(!isNaN((v = fuzzydate(s)).getDate()) || _re && s.match(_re)) {
cell.z = o.dateNF || table_fmt[14];
var k = 0;
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; v = parseDate(s, k); }
if(o.cellDates) { cell.t = 'd'; cell.v = v; }
else { cell.t = 'n'; cell.v = datenum(v); }
if(o.cellText !== false) cell.w = SSF_format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
if(!o.cellNF) delete cell.z;
} else {

@ -18,7 +18,7 @@ can be installed with Bash on Windows or with `cygwin`.
### Included Demos
**JavaScript APIs**
- [`XMLHttpRequest and fetch`](xhr/)
- [`XMLHttpRequest and fetch`](https://docs.sheetjs.com/docs/getting-started/demos/network)
- [`Clipboard Data`](https://docs.sheetjs.com/docs/getting-started/demos/clipboard)
- [`Typed Arrays for Machine Learning`](https://docs.sheetjs.com/docs/getting-started/demos/ml)
- [`LocalStorage and SessionStorage`](https://docs.sheetjs.com/docs/getting-started/demos/database#localstorage-and-sessionstorage)
@ -29,7 +29,6 @@ can be installed with Bash on Windows or with `cygwin`.
- [`Angular.JS`](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
- [`Angular 2+ and Ionic`](angular2/)
- [`Knockout`](https://docs.sheetjs.com/docs/getting-started/demos/legacy#knockoutjs)
- [`Meteor`](meteor/)
- [`React, React Native and NextJS`](react/)
- [`VueJS, WeeX and NuxtJS`](vue/)
@ -43,8 +42,7 @@ can be installed with Bash on Windows or with `cygwin`.
**Platforms and Integrations**
- [`Command-Line Tools`](https://docs.sheetjs.com/docs/getting-started/demos/cli)
- [`NodeJS Server-Side Processing`](server/)
- [`Deno`](deno/)
- [`Electron`](electron/)
- [`Electron`](https://docs.sheetjs.com/docs/getting-started/demos/desktop#electron)
- [`NW.js`](https://docs.sheetjs.com/docs/getting-started/demos/desktop#nwjs)
- [`Chrome / Chromium Extension`](https://docs.sheetjs.com/docs/getting-started/demos/chromium)
- [`Google Sheets API`](https://docs.sheetjs.com/docs/getting-started/demos/gsheet)
@ -68,7 +66,7 @@ can be installed with Bash on Windows or with `cygwin`.
- [`rollup`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#rollup)
- [`snowpack`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#snowpack)
- [`swc`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#swc)
- [`systemjs`](systemjs/)
- [`systemjs`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#systemjs)
- [`vite`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#vite)
- [`webpack 2.x`](webpack/)
- [`wmr`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#wmr)

@ -1,15 +0,0 @@
.PHONY: init
init:
mkdir -p node_modules
cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx ; fi; cd -
.PHONY: lint
lint:
eslint *.js
.PHONY: run
run:
npm i
npx electron .
.PHONY: build
build:
npm run make

@ -1,56 +1,6 @@
# Electron
This library is compatible with Electron and should just work out of the box.
The demonstration uses Electron 18.2.0. The library is added via `require` from
the renderer process.
The library can also be required from the main process, as shown in this demo
to render a version string in the About dialog on OSX.
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/sheetjs/)
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`.
The demo project is structured for `electron-forge`:
- `npm start` will start the app.
- `npm run make` will build a standalone app.
The standalone app was tested on an Intel Mac (`darwin-x64`).
## Reading and Writing Files
Since electron provides an `fs` implementation, `readFile` and `writeFile` can
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;
/* show a file-open dialog and read the first selected file */
var o = dialog.showOpenDialog({ properties: ['openFile'] });
var workbook = XLSX.readFile(o[0]);
/* show a file-save dialog and write the workbook */
var o = dialog.showSaveDialog();
XLSX.writeFile(workbook, o);
```
## Breaking Changes in Electron
The first version of this demo used Electron 1.7.5.
Electron 9.0.0 and later require the preference `nodeIntegration: true` in order
to `require('XLSX')` in the renderer process.
Electron 12.0.0 and later also require `worldSafeExecuteJavascript: true` and
`contextIsolation: true`.
Electron 14+ must use `@electron/remote` instead of `remote`.
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/desktop#electron)
includes an improved example and detailed explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,39 +0,0 @@
<!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" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' https:">
<title>SheetJS Electron 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
}
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS Electron 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 />
<button id="readBtn">Click here to select a file from your computer</button><br />
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
<input type="file" name="xlfile" id="readIn" /> ... or click here to select a file
</pre>
<p><input type="submit" value="Export Data!" id="exportBtn" disabled="true"></p>
<div id="htmlout"></div>
<br />
<script src="index.js"></script>
</body>
</html>

@ -1,79 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- https://sheetjs.com */
const XLSX = require('xlsx');
const electron = require('@electron/remote');
const EXTENSIONS = "xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html".split("|");
const processWb = function(wb) {
const HTMLOUT = document.getElementById('htmlout');
const XPORT = document.getElementById('exportBtn');
XPORT.disabled = false;
HTMLOUT.innerHTML = "";
wb.SheetNames.forEach(function(sheetName) {
const htmlstr = XLSX.utils.sheet_to_html(wb.Sheets[sheetName],{editable:true});
HTMLOUT.innerHTML += htmlstr;
});
};
const readFile = function(files) {
const f = files[0];
const reader = new FileReader();
reader.onload = function(e) {
let data = e.target.result;
data = new Uint8Array(data);
processWb(XLSX.read(data, {type: 'array'}));
};
reader.readAsArrayBuffer(f);
};
const handleReadBtn = async function() {
const o = await electron.dialog.showOpenDialog({
title: 'Select a file',
filters: [{
name: "Spreadsheets",
extensions: EXTENSIONS
}],
properties: ['openFile']
});
if(o.filePaths.length > 0) processWb(XLSX.readFile(o.filePaths[0]));
};
const exportXlsx = async function() {
const HTMLOUT = document.getElementById('htmlout');
const wb = XLSX.utils.table_to_book(HTMLOUT.getElementsByTagName("TABLE")[0]);
const o = await electron.dialog.showSaveDialog({
title: 'Save file as',
filters: [{
name: "Spreadsheets",
extensions: EXTENSIONS
}]
});
console.log(o.filePath);
XLSX.writeFile(wb, o.filePath);
electron.dialog.showMessageBox({ message: "Exported data to " + o.filePath, buttons: ["OK"] });
};
// add event listeners
const readBtn = document.getElementById('readBtn');
const readIn = document.getElementById('readIn');
const exportBtn = document.getElementById('exportBtn');
const drop = document.getElementById('drop');
readBtn.addEventListener('click', handleReadBtn, false);
readIn.addEventListener('change', (e) => { readFile(e.target.files); }, false);
exportBtn.addEventListener('click', exportXlsx, false);
drop.addEventListener('dragenter', (e) => {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}, false);
drop.addEventListener('dragover', (e) => {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}, false);
drop.addEventListener('drop', (e) => {
e.stopPropagation();
e.preventDefault();
readFile(e.dataTransfer.files);
}, false);

@ -1,30 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* from the electron quick-start */
var electron = require('electron');
var XLSX = require('xlsx');
var app = electron.app;
require('@electron/remote/main').initialize();
var win = null;
function createWindow() {
if (win) return;
win = new electron.BrowserWindow({
width: 800, height: 600,
webPreferences: {
worldSafeExecuteJavaScript: true, // required for Electron 12+
contextIsolation: false, // required for Electron 12+
nodeIntegration: true,
enableRemoteModule: true
}
});
win.loadURL("file://" + __dirname + "/index.html");
require('@electron/remote/main').enable(win.webContents);
win.webContents.openDevTools();
win.on('closed', function () { win = null; });
}
if (app.setAboutPanelOptions) app.setAboutPanelOptions({ applicationName: 'sheetjs-electron', applicationVersion: "XLSX " + XLSX.version, copyright: "(C) 2017-present SheetJS LLC" });
app.on('open-file', function () { console.log(arguments); });
app.on('ready', createWindow);
app.on('activate', createWindow);
app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });

@ -1,51 +0,0 @@
{
"name": "sheetjs-electron",
"author": "sheetjs",
"version": "0.0.0",
"main": "main.js",
"dependencies": {
"@electron/remote": "2.0.8",
"electron-squirrel-startup": "^1.0.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
},
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
},
"devDependencies": {
"@electron-forge/cli": "^6.0.0-beta.64",
"@electron-forge/maker-deb": "^6.0.0-beta.64",
"@electron-forge/maker-rpm": "^6.0.0-beta.64",
"@electron-forge/maker-squirrel": "^6.0.0-beta.64",
"@electron-forge/maker-zip": "^6.0.0-beta.64",
"electron": "19.0.5"
},
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"name": "sheetjs_electron"
}
},
{
"name": "@electron-forge/maker-zip",
"platforms": [
"darwin"
]
},
{
"name": "@electron-forge/maker-deb",
"config": {}
},
{
"name": "@electron-forge/maker-rpm",
"config": {}
}
]
}
}
}

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

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

@ -1,89 +1,8 @@
# Meteor
This library is universal: outside of environment-specific features (parsing DOM
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 * as 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
Note: this demo intentionally mixes logic between client and server code.
Pure-client and pure-server examples are covered in other demos.
### 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 logic from within the `FileReader` is split as follows:
```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
XLSX.writeFile(wb, 'sheetjs.xlsx');
```
## Setup
This tree does not include the `.meteor` structure. Rebuild the project with:
```bash
meteor create .
npm install babel-runtime meteor-node-stubs https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
meteor
```
## Environment-Specific Features
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 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.
This demo originally covered Meteor's package manager and other nuances. At the
time the demo was written, Meteor had its own ecosystem that clashed with the
burgeoning NodeJS package ecosystem. Eventually, Meteor added proper support
for NodeJS modules. New projects should follow the instructions for packages.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,2 +0,0 @@
/* CSS declarations go here */
a { text-decoration: none }

@ -1,18 +0,0 @@
<head>
<title>meteor-xlsx</title>
</head>
<body>
<pre>
<b><a href="//sheetjs.com">SheetJS Meteor Demo</a></b>
{{> sheetjs}}
</pre>
</body>
<template name="sheetjs">
<label for="upload">Parse File: </label><input type="file" id="upload" />
<div id="out"></div>
<button id="dnload" disabled="true">Generate Worksheet</button>
</template>

@ -1,39 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import XLSX from 'xlsx';
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import './main.html';
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('uploadU', new Uint8Array(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.readAsArrayBuffer(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 */
XLSX.writeFile(wb, 'sheetjs.xlsx');
});
},
});

@ -1,27 +0,0 @@
{
"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,30 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import XLSX from 'xlsx';
Meteor.methods({
/* read the data and return the workbook object to the frontend */
uploadU: (ab, name) => {
check(ab, Uint8Array);
check(name, String);
return XLSX.read(ab, { type: 'array' });
},
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(() => { });

@ -1,7 +0,0 @@
.PHONY: test ctest
test:
cp ../../dist/xlsx.full.min.js .
node test.node.js
ctest:
python -mSimpleHTTPServer

@ -1,89 +1,6 @@
# SystemJS Demos
SystemJS supports both browser and nodejs deployments. It does not recognize
browser environments and automatically suppress node core modules, but with some
configuration magic SystemJS can load the library.
## Browser
SystemJS fails by default because the library does not export anything in the
web browser. The `meta` configuration option can be used to expose `XLSX`:
```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': '' // <--|
}
});
SystemJS.import('main.js')
```
With the new configuration, `require('xlsx')` will load the library:
```js
var XLSX = require('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);
```
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
The node core modules should be mapped to their `@node` equivalents:
```js
var SystemJS = require('systemjs');
SystemJS.config({
map: {
'xlsx': 'node_modules/xlsx/xlsx.js',
'fs': '@node/fs',
'crypto': '@node/crypto',
'stream': '@node/stream'
}
});
```
And use is pretty straightforward:
```js
SystemJS.import('xlsx').then(function(XLSX) {
/* XLSX is available here */
var w = XLSX.readFile('test.xlsx');
var j = XLSX.utils.sheet_to_json(w.Sheets[w.SheetNames[0]], {header:1});
console.log(j);
});
```
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/bundler#systemjs)
includes a live example and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,5 +0,0 @@
/* 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');
var XLSX_N = require('xlsx');

@ -1,129 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint browser:true */
/*global XLSX */
var XLSX = require('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 = XLSX.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 = XLSX.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 = XLSX.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 = XLSX.write(workbook, {sheet:sheetName, type:'string', 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 = XLSX.read(tarea.value, {type:'base64', WTF:false});
process_wb(wb);
};
})();
var do_file = (function() {
return function do_file(files) {
var f = files[0];
var reader = new FileReader();
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date());
var data = e.target.result;
data = new Uint8Array(data);
process_wb(XLSX.read(data, {type: 'array'}));
};
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);
})();

@ -1,6 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var XLSX = require('xlsx');
console.log(XLSX.version);
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);

@ -1,52 +0,0 @@
<!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 SystemJS Test</title>
<style>
a { text-decoration: none }
</style>
</head>
<body>
<pre>
<b><a href="http://sheetjs.com">SheetJS SystemJS 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>
Original script: <a href="main.simple.js">main.simple.js</a>
<b>Console Output:</b>
</pre>
<pre id="console"></pre>
<b>
<script>
if(typeof console !== "undefined") console = {};
console.__log = console.log || function(){};
console.log = function(x) {
console.__log.apply(console, arguments);
document.getElementById('console').innerText += x + "\n";
};
console.error = console.debug = console.info = console.log
</script>
<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>
</body>
</html>

@ -1,77 +0,0 @@
<!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>
</pre>
<pre id="out"></pre>
<div id="htmlout"></div>
<br />
<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>
<script type="text/javascript">
/* eslint no-use-before-define:0 */
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,19 +0,0 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
var SystemJS = require('systemjs');
SystemJS.config({
meta: {
'../../xlsx.js': { format: 'global' },
'../../dist/xlsx.core.min.js': { format: 'global' },
'../../dist/xlsx.full.min.js': { format: 'global' },
},
paths: {
'npm:': '/usr/local/lib/node_modules/'
},
map: {
'xlsx': 'npm:xlsx/xlsx.js',
'fs': '@node/fs',
'crypto': '@node/crypto',
'stream': '@node/stream'
}
});
SystemJS.import('./app.node.js');

@ -1,21 +0,0 @@
/* 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); });
};

@ -1,12 +0,0 @@
/* 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}); }
};

@ -2,7 +2,7 @@
This demo originally covered direct use of the `tsc` TypeScript compiler. At
the time when the demo was first written, TypeScript 2.2 had a module system
that was incompatibile with the pure JS ecosystem. Since then, various
that was incompatible with the pure JS ecosystem. Since then, various
language improvements and compiler changes have obviated this demo. Uses of
TypeScript are scattered throughout other demos.

@ -1 +0,0 @@
files/

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

@ -1,142 +1,7 @@
# XMLHttpRequest and fetch
`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.
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/network)
includes interactive demos and improved explanations.
## 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 file 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 uploaded file.
It will write the data for the first file to the indicated file name.
To start the demo, run `npm start` and navigate to <http://localhost:7262/>
## XMLHttpRequest
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:
```js
/* set up an async GET request */
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
/* 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();
```
For uploading data, this demo populates a `FormData` object with an ArrayBuffer
generated with the `array` output type:
```js
/* generate XLSX as array buffer */
var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'});
/* build FormData with the generated file */
var fd = new FormData();
fd.append('data', new File([data], 'sheetjs.xlsx'));
/* send data */
var req = new XMLHttpRequest();
req.open("POST", "/upload", true);
req.send(fd);
```
### 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);
```
### axios 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'}).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 */
});
```
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
For downloading data, `response.arrayBuffer()` resolves to an `ArrayBuffer` that
can be converted to `Uint8Array` and passed to `XLSX.read`:
```js
fetch(url).then(function(res) {
/* get the data as a Blob */
if(!res.ok) throw new Error("fetch failed");
return res.arrayBuffer();
}).then(function(ab) {
/* parse the data when it is received */
var data = new Uint8Array(ab);
var workbook = XLSX.read(data, {type:"array"});
/* DO SOMETHING WITH workbook HERE */
});
```
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)

@ -1,80 +0,0 @@
<!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', orig = 'sheetjs.xlsx';
if(!window.axios) 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 path = 'files/' + demo + '.' + book;
document.getElementById('fileurl').innerHTML = '<a href="' + orig + '">Download original file</a>';
document.getElementById('outfile').innerHTML = '<a href="' + path + '">Download new file: ' + path + '</a>';
axios(orig, {responseType:'arraybuffer'}).then(function(res) {
var data = new Uint8Array(res.data);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
}).catch(function(e) {
if(/404/.test(e.message) || e.response.status) {
var ws = XLSX.utils.aoa_to_sheet([
["Fetch for " + orig + " failed :("],
["Error Code", e.response.status],
["Error Text", e.message],
]);
ws["!merges"] = [XLSX.utils.decode_range("A1:B1")];
process_wb({ "Sheets": { "Sheet1": ws }, "SheetNames": [ "Sheet1" ] });
}
});
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var fd = new FormData();
var data = XLSX.write(wb, {bookType:book, type:'array'});
console.log(data);
fd.append('data', new File([data], demo + '.' + book));
axios("/upload", {method: "POST", data: fd});
};
</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,82 +0,0 @@
<!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', orig = 'sheetjs.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 path = 'files/' + demo + '.' + book;
document.getElementById('fileurl').innerHTML = '<a href="' + orig + '">Download original file</a>';
document.getElementById('outfile').innerHTML = '<a href="' + path + '">Download new file: ' + path + '</a>';
fetch(orig).then(function(res) {
if(!res.ok) { var e = new Error(res.statusText); e.response = res; return Promise.reject(e);}
return res.arrayBuffer();
}).then(function(ab) {
var data = new Uint8Array(ab);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
}).catch(function(e) {
if(/404/.test(e.message) || e.response.status) {
var ws = XLSX.utils.aoa_to_sheet([
["Fetch for " + orig + " failed :("],
["Error Code", e.response.status],
["Error Text", e.message],
]);
ws["!merges"] = [XLSX.utils.decode_range("A1:B1")];
process_wb({ "Sheets": { "Sheet1": ws }, "SheetNames": [ "Sheet1" ] });
}
});
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var fd = new FormData();
var data = XLSX.write(wb, {bookType:book, type:'array'});
console.log(data);
fd.append('data', new File([data], demo + '.' + book));
fetch("/upload", {method: "POST", body: fd}).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>

@ -1,14 +0,0 @@
{
"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"
}
}

@ -1,38 +0,0 @@
#!/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;
function logit(req, res, next) {
console.log(sprintf("%s %s %d", req.method, req.url, res.statusCode));
next();
}
function cors(req, res, next) {
if(!res.headersSent) res.header('Access-Control-Allow-Origin', '*');
next();
}
var port = +process.argv[2] || +process.env.PORT || 7262;
var basepath = process.cwd();
var dir = path.join(__dirname, "files");
try { fs.mkdirSync(dir); } catch(e) {}
app.use(logit);
app.use(cors);
app.use(require('express-formidable')({uploadDir: dir}));
app.post('/upload', function(req, res) {
console.log(req.files);
var f = req.files[Object.keys(req.files)[0]];
var newpath = path.join(dir, f.name);
fs.renameSync(f.path, newpath);
console.log("moved " + f.path + " to " + newpath);
res.end("wrote to " + f.name);
});
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); });

@ -1,82 +0,0 @@
<!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@7.1.1/dist/superagent.min.js"></script>
<script>
var demo = 'superagent', book = 'xlsx', orig = 'sheetjs.xlsx';
if(!window.superagent) 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 path = 'files/' + demo + '.' + book;
document.getElementById('fileurl').innerHTML = '<a href="' + orig + '">Download original file</a>';
document.getElementById('outfile').innerHTML = '<a href="' + path + '">Download new file: ' + path + '</a>';
superagent.get(orig).responseType('arraybuffer').end(function(e, res) {
if(!e) {
var data = new Uint8Array(res.body);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
return;
}
if(/404/.test(e.message) || e.response.status) {
var ws = XLSX.utils.aoa_to_sheet([
["Fetch for " + orig + " failed :("],
["Error Code", e.response.status],
["Error Text", e.message],
]);
ws["!merges"] = [XLSX.utils.decode_range("A1:B1")];
process_wb({ "Sheets": { "Sheet1": ws }, "SheetNames": [ "Sheet1" ] });
}
});
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var fd = new FormData();
var data = XLSX.write(wb, {bookType:book, type:'array'});
console.log(data);
fd.append('data', new File([data], demo + '.' + book));
superagent.post("/upload").send(fd).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>

@ -1,87 +0,0 @@
<!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', orig = 'sheetjs.xlsx2';
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 path = 'files/' + demo + '.' + book;
document.getElementById('fileurl').innerHTML = '<a href="' + orig + '">Download original file</a>';
document.getElementById('outfile').innerHTML = '<a href="' + path + '">Download new file: ' + path + '</a>';
{
var req = new XMLHttpRequest();
req.open("GET", orig, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
if(req.status == 200) {
var data = new Uint8Array(req.response);
var wb = XLSX.read(data, {type:"array"});
process_wb(wb);
return;
}
var ws = XLSX.utils.aoa_to_sheet([
["Fetch for " + orig + " failed :("],
["Error Code", req.status],
["Error Text", req.statusText],
]);
ws["!merges"] = [XLSX.utils.decode_range("A1:B1")];
process_wb({ "Sheets": { "Sheet1": ws }, "SheetNames": [ "Sheet1" ] });
};
req.send();
}
document.getElementById('ulbutton').onclick = function() {
var wb = XLSX.utils.table_to_book(document.getElementById('htmlout'));
console.log(wb);
var fd = new FormData();
var data = XLSX.write(wb, {bookType:book, type:'array'});
console.log(data);
fd.append('data', new File([data], demo + '.' + book));
var req = new XMLHttpRequest();
req.open("POST", "/upload", true);
req.send(fd);
};
</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 +0,0 @@
../../dist/xlsx.full.min.js

11
packages/s2c/README.md Normal file

@ -0,0 +1,11 @@
# s2c
`mod.ts` exports the following methods:
- `parse_book_from_request` reads a field from a request, parses the field with
the Drash body parser, and returns a SheetJS workbook object. This does not
use the filesystem, so it supports Deno Deploy and other restricted services.
`s2c.ts` is the script that powers <https://s2c.sheetjs.com>
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

21
packages/s2c/mod.ts Normal file

@ -0,0 +1,21 @@
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import { read, set_cptable } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
import * as cptable from 'https://cdn.sheetjs.com/xlsx-latest/package/dist/cpexcel.full.mjs';
set_cptable(cptable);
import type { Request } from "https://deno.land/x/drash@v2.5.4/mod.ts";
import { Types } from "https://deno.land/x/drash@v2.5.4/mod.ts";
/**
* Parse a workbook from an uploaded file
*
* This works with Deno Deploy (Drash body parser does not use temp files)
*
* request is a Drash.Request object
* field is the name of the field to read
*/
export function parse_book_from_request(request: Request, field: string) {
const file = request.bodyParam<Types.BodyFile>(field);
if(!file) throw new Error(`Field ${field} is missing!`);
return read(file.content, { type: "buffer" });
}

78
packages/s2c/s2c.ts Normal file

@ -0,0 +1,78 @@
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import { read, utils, set_cptable, version } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
import * as cptable from 'https://cdn.sheetjs.com/xlsx-latest/package/dist/cpexcel.full.mjs';
set_cptable(cptable);
import * as Drash from "https://deno.land/x/drash@v2.5.4/mod.ts";
class S2CResource extends Drash.Resource {
public paths = ["/"];
// see https://github.com/drashland/drash/issues/194
public OPTIONS(request: Drash.Request, response: Drash.Response) {
const allHttpMethods: string[] = [ "GET", "POST", "PUT", "DELETE" ];
response.headers.set("Allow", allHttpMethods.join()); // Use this
response.headers.set("Access-Control-Allow-Methods", allHttpMethods.join()); // or this
response.headers.set("access-control-allow-origin", "*");
response.status_code = 204;
return response;
}
public POST(request: Drash.Request, response: Drash.Response) {
const file = request.bodyParam<Drash.Types.BodyFile>("file");
try { response.headers.set("access-control-allow-origin", "*"); } catch(e) {}
if (!file) throw new Error("File is required!");
var wb = read(file.content, {type: "buffer"});
return response.html( utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]));
}
public GET(request: Drash.Request, response: Drash.Response): void {
try { response.headers.set("access-control-allow-origin", "*"); } catch(e) {}
return response.html(`\
<!DOCTYPE html>
<html>
<head>
<title>SheetJS Spreadsheet to HTML Conversion Service</title>
<meta charset="utf-8" />
</head>
<body>
<pre><h3><a href="//sheetjs.com/">SheetJS</a> Spreadsheet Conversion Service</h3>
<b>API</b>
Send a POST request to https://s2c.deno.dev/ with the file in the "file" body parameter:
$ curl -X POST -F"file=@test.xlsx" https://s2c.deno.dev/
The response will be an HTML TABLE generated from the first worksheet.
<b>Try it out!</b><form action="/" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
Use the file input element to select a file, then click "Submit"
<button type="submit">Submit</button>
</form>
Library Version: ${version}
</pre>
</body>
</html>`,
);
}
}
// Create and run your server
const server = new Drash.Server({
hostname: "",
port: 3000,
protocol: "http",
resources: [
S2CResource,
],
});
server.run();
console.log(`Server running at ${server.address}.`);

74
packages/s2c/test.ts Normal file

@ -0,0 +1,74 @@
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import { utils, set_cptable, version } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
import { parse_book_from_request } from "./mod.ts";
import * as Drash from "https://deno.land/x/drash@v2.5.4/mod.ts";
class S2CResource extends Drash.Resource {
public paths = ["/"];
// see https://github.com/drashland/drash/issues/194
public OPTIONS(request: Drash.Request, response: Drash.Response) {
const allHttpMethods: string[] = [ "GET", "POST", "PUT", "DELETE" ];
response.headers.set("Allow", allHttpMethods.join()); // Use this
response.headers.set("Access-Control-Allow-Methods", allHttpMethods.join()); // or this
response.headers.set("access-control-allow-origin", "*");
response.status_code = 204;
return response;
}
public POST(request: Drash.Request, response: Drash.Response) {
try { response.headers.set("access-control-allow-origin", "*"); } catch(e) {}
var wb = parse_book_from_request(request, "file");
return response.html( utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]));
}
public GET(request: Drash.Request, response: Drash.Response): void {
try { response.headers.set("access-control-allow-origin", "*"); } catch(e) {}
return response.html(`\
<!DOCTYPE html>
<html>
<head>
<title>SheetJS Spreadsheet to HTML Conversion Service</title>
<meta charset="utf-8" />
</head>
<body>
<pre><h3><a href="//sheetjs.com/">SheetJS</a> Spreadsheet Conversion Service</h3>
<b>API</b>
Send a POST request to https://s2c.deno.dev/ with the file in the "file" body parameter:
$ curl -X POST -F"file=@test.xlsx" https://s2c.deno.dev/
The response will be an HTML TABLE generated from the first worksheet.
<b>Try it out!</b><form action="/" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
Use the file input element to select a file, then click "Submit"
<button type="submit">Submit</button>
</form>
Library Version: ${version}
</pre>
</body>
</html>`,
);
}
}
// Create and run your server
const server = new Drash.Server({
hostname: "",
port: 3000,
protocol: "http",
resources: [
S2CResource,
],
});
server.run();
console.log(`Server running at ${server.address}.`);

24
test.js

@ -2197,6 +2197,30 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
it('should parse date-less meridien time values', function() {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
describe('output', function(){
var data, ws;

24
test.mjs generated

@ -2183,6 +2183,30 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
it('should parse date-less meridien time values', function() {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
describe('output', function(){
var data, ws;

@ -2139,6 +2139,30 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
it('should parse date-less meridien time values', function() {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
describe('output', function(){
var data = [

24
test.ts

@ -2139,6 +2139,30 @@ Deno.test('CSV', async function(t) {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
await t.step('should parse date-less meridien time values', async function(t) {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
await t.step('output', async function(t){
var data = [

@ -2138,6 +2138,30 @@ Deno.test('CSV', async function(t) {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
await t.step('should parse date-less meridien time values', async function(t) {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
await t.step('output', async function(t){
var data = [

24
tests/core.js generated

@ -2196,6 +2196,30 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
it('should parse date-less meridien time values', function() {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
describe('output', function(){
var data, ws;

@ -3447,22 +3447,22 @@ function fuzzynum(s/*:string*/)/*:number*/ {
}
/* NOTE: Chrome rejects bare times like 1:23 PM */
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))([ap])m?/;
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))\s+([ap])m?$/;
function fuzzytime1(M) /*:Date*/ {
/* TODO: 1904 adjustment */
if(!M[2]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
/* TODO: 1904 adjustment, keep in sync with base date */
if(!M[2]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
if(M[3]) {
if(M[4]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1900,0,0,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
if(M[4]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1899,11,30,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
}
else if(M[5]) return new Date(1900, 0, 0, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
else if(M[5]) return new Date(1899,11,30, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
}
var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
function fuzzydate(s/*:string*/)/*:Date*/ {
var lower = s.toLowerCase();
var lnos = lower.replace(/\s+/g, "");
var lnos = lower.replace(/\s+/g, " ").trim();
var M = lnos.match(FDRE1);
if(M) return fuzzytime1(M);
@ -8064,6 +8064,8 @@ var SYLK = /*#__PURE__*/(function() {
}
wb.Workbook.Names.push(nn);
} break;
// case 'NE': // ??
// case 'NU': // ??
case 'C': /* cell */
var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1, formula = "", cell_t = "z";
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
@ -8097,6 +8099,8 @@ var SYLK = /*#__PURE__*/(function() {
case 'G': break; // unknown
case 'R': _R = parseInt(record[rj].slice(1), 10)-1; break;
case 'C': _C = parseInt(record[rj].slice(1), 10)-1; break;
// case 'P': // ??
// case 'D': // ??
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
if(C_seen_K) {
@ -8150,6 +8154,8 @@ var SYLK = /*#__PURE__*/(function() {
if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
else if(Mval === 0) rowinfo[R].hidden = true;
break;
// case 'K': // ??
// case 'E': // ??
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
if(F_seen < 1) next_cell_format = null; break;
@ -8575,12 +8581,12 @@ var PRN = /*#__PURE__*/(function() {
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
else if(!isNaN((v = fuzzydate(s)).getDate()) || _re && s.match(_re)) {
cell.z = o.dateNF || table_fmt[14];
var k = 0;
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; v = parseDate(s, k); }
if(o.cellDates) { cell.t = 'd'; cell.v = v; }
else { cell.t = 'n'; cell.v = datenum(v); }
if(o.cellText !== false) cell.w = SSF_format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
if(!o.cellNF) delete cell.z;
} else {
@ -23896,6 +23902,8 @@ function parse_numbers_iwa(cfb, opts) {
cfb.FileIndex.forEach(function(s) {
if (!s.name.match(/\.iwa$/))
return;
if (s.content[0] == 98)
return;
var o;
try {
o = decompress_iwa_file(s.content);

32
xlsx.js generated

@ -3373,22 +3373,22 @@ function fuzzynum(s) {
}
/* NOTE: Chrome rejects bare times like 1:23 PM */
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))([ap])m?/;
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))\s+([ap])m?$/;
function fuzzytime1(M) {
/* TODO: 1904 adjustment */
if(!M[2]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
/* TODO: 1904 adjustment, keep in sync with base date */
if(!M[2]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
if(M[3]) {
if(M[4]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1900,0,0,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
if(M[4]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1899,11,30,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
}
else if(M[5]) return new Date(1900, 0, 0, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
else if(M[5]) return new Date(1899,11,30, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
}
var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
function fuzzydate(s) {
var lower = s.toLowerCase();
var lnos = lower.replace(/\s+/g, "");
var lnos = lower.replace(/\s+/g, " ").trim();
var M = lnos.match(FDRE1);
if(M) return fuzzytime1(M);
@ -7974,6 +7974,8 @@ var SYLK = (function() {
}
wb.Workbook.Names.push(nn);
} break;
// case 'NE': // ??
// case 'NU': // ??
case 'C': /* cell */
var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1, formula = "", cell_t = "z";
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
@ -8007,6 +8009,8 @@ var SYLK = (function() {
case 'G': break; // unknown
case 'R': _R = parseInt(record[rj].slice(1), 10)-1; break;
case 'C': _C = parseInt(record[rj].slice(1), 10)-1; break;
// case 'P': // ??
// case 'D': // ??
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
if(C_seen_K) {
@ -8060,6 +8064,8 @@ var SYLK = (function() {
if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
else if(Mval === 0) rowinfo[R].hidden = true;
break;
// case 'K': // ??
// case 'E': // ??
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
if(F_seen < 1) next_cell_format = null; break;
@ -8485,12 +8491,12 @@ var PRN = (function() {
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
else if(!isNaN((v = fuzzydate(s)).getDate()) || _re && s.match(_re)) {
cell.z = o.dateNF || table_fmt[14];
var k = 0;
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; v = parseDate(s, k); }
if(o.cellDates) { cell.t = 'd'; cell.v = v; }
else { cell.t = 'n'; cell.v = datenum(v); }
if(o.cellText !== false) cell.w = SSF_format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
if(!o.cellNF) delete cell.z;
} else {
@ -23786,6 +23792,8 @@ function parse_numbers_iwa(cfb, opts) {
cfb.FileIndex.forEach(function(s) {
if (!s.name.match(/\.iwa$/))
return;
if (s.content[0] == 98)
return;
var o;
try {
o = decompress_iwa_file(s.content);

32
xlsx.mjs generated

@ -3446,22 +3446,22 @@ function fuzzynum(s/*:string*/)/*:number*/ {
}
/* NOTE: Chrome rejects bare times like 1:23 PM */
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))([ap])m?/;
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))\s+([ap])m?$/;
function fuzzytime1(M) /*:Date*/ {
/* TODO: 1904 adjustment */
if(!M[2]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
/* TODO: 1904 adjustment, keep in sync with base date */
if(!M[2]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
if(M[3]) {
if(M[4]) return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1900,0,0,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
if(M[4]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1899,11,30,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
}
else if(M[5]) return new Date(1900, 0, 0, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1900,0,0,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
else if(M[5]) return new Date(1899,11,30, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
}
var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
function fuzzydate(s/*:string*/)/*:Date*/ {
var lower = s.toLowerCase();
var lnos = lower.replace(/\s+/g, "");
var lnos = lower.replace(/\s+/g, " ").trim();
var M = lnos.match(FDRE1);
if(M) return fuzzytime1(M);
@ -8059,6 +8059,8 @@ var SYLK = /*#__PURE__*/(function() {
}
wb.Workbook.Names.push(nn);
} break;
// case 'NE': // ??
// case 'NU': // ??
case 'C': /* cell */
var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1, formula = "", cell_t = "z";
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
@ -8092,6 +8094,8 @@ var SYLK = /*#__PURE__*/(function() {
case 'G': break; // unknown
case 'R': _R = parseInt(record[rj].slice(1), 10)-1; break;
case 'C': _C = parseInt(record[rj].slice(1), 10)-1; break;
// case 'P': // ??
// case 'D': // ??
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
if(C_seen_K) {
@ -8145,6 +8149,8 @@ var SYLK = /*#__PURE__*/(function() {
if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
else if(Mval === 0) rowinfo[R].hidden = true;
break;
// case 'K': // ??
// case 'E': // ??
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
if(F_seen < 1) next_cell_format = null; break;
@ -8570,12 +8576,12 @@ var PRN = /*#__PURE__*/(function() {
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
else if(!isNaN((v = fuzzydate(s)).getDate()) || _re && s.match(_re)) {
cell.z = o.dateNF || table_fmt[14];
var k = 0;
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; v = parseDate(s, k); }
if(o.cellDates) { cell.t = 'd'; cell.v = v; }
else { cell.t = 'n'; cell.v = datenum(v); }
if(o.cellText !== false) cell.w = SSF_format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
if(!o.cellNF) delete cell.z;
} else {
@ -23891,6 +23897,8 @@ function parse_numbers_iwa(cfb, opts) {
cfb.FileIndex.forEach(function(s) {
if (!s.name.match(/\.iwa$/))
return;
if (s.content[0] == 98)
return;
var o;
try {
o = decompress_iwa_file(s.content);