diff --git a/bits/20_jsutils.js b/bits/20_jsutils.js index 8c58bc8..786e38b 100644 --- a/bits/20_jsutils.js +++ b/bits/20_jsutils.js @@ -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); diff --git a/bits/40_harb.js b/bits/40_harb.js index 6b85b7e..4d12c5c 100644 --- a/bits/40_harb.js +++ b/bits/40_harb.js @@ -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 { diff --git a/demos/README.md b/demos/README.md index 7539740..c700643 100644 --- a/demos/README.md +++ b/demos/README.md @@ -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) diff --git a/demos/electron/Makefile b/demos/electron/Makefile deleted file mode 100644 index ea5d241..0000000 --- a/demos/electron/Makefile +++ /dev/null @@ -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 diff --git a/demos/electron/README.md b/demos/electron/README.md index 0947ecd..95ad5dc 100644 --- a/demos/electron/README.md +++ b/demos/electron/README.md @@ -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) diff --git a/demos/electron/index.html b/demos/electron/index.html deleted file mode 100644 index c8ef088..0000000 --- a/demos/electron/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - -SheetJS Electron Demo - - - -
-SheetJS Electron Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
-
Drop a spreadsheet file here to see sheet data
- ... or click here to select a file - -
-

-
-
- - - diff --git a/demos/electron/index.js b/demos/electron/index.js deleted file mode 100644 index fcd9a5d..0000000 --- a/demos/electron/index.js +++ /dev/null @@ -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); diff --git a/demos/electron/main.js b/demos/electron/main.js deleted file mode 100644 index cc015ea..0000000 --- a/demos/electron/main.js +++ /dev/null @@ -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(); }); diff --git a/demos/electron/package.json b/demos/electron/package.json deleted file mode 100644 index b25da2e..0000000 --- a/demos/electron/package.json +++ /dev/null @@ -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": {} - } - ] - } - } -} diff --git a/demos/meteor/.gitignore b/demos/meteor/.gitignore deleted file mode 100644 index 6636f38..0000000 --- a/demos/meteor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.meteor -node_modules/ diff --git a/demos/meteor/Makefile b/demos/meteor/Makefile deleted file mode 100644 index 77af10d..0000000 --- a/demos/meteor/Makefile +++ /dev/null @@ -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 diff --git a/demos/meteor/README.md b/demos/meteor/README.md index 2bfbfa7..e3974d8 100644 --- a/demos/meteor/README.md +++ b/demos/meteor/README.md @@ -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) diff --git a/demos/meteor/client/main.css b/demos/meteor/client/main.css deleted file mode 100644 index d001463..0000000 --- a/demos/meteor/client/main.css +++ /dev/null @@ -1,2 +0,0 @@ -/* CSS declarations go here */ -a { text-decoration: none } diff --git a/demos/meteor/client/main.html b/demos/meteor/client/main.html deleted file mode 100644 index d1065b4..0000000 --- a/demos/meteor/client/main.html +++ /dev/null @@ -1,18 +0,0 @@ - - meteor-xlsx - - - -
-SheetJS Meteor Demo
-
-{{> sheetjs}}
-
-
- - - diff --git a/demos/meteor/client/main.js b/demos/meteor/client/main.js deleted file mode 100644 index ac5adfc..0000000 --- a/demos/meteor/client/main.js +++ /dev/null @@ -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'); - }); - }, -}); - diff --git a/demos/meteor/package.json b/demos/meteor/package.json deleted file mode 100644 index 0cc1a39..0000000 --- a/demos/meteor/package.json +++ /dev/null @@ -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" - } -} diff --git a/demos/meteor/server/main.js b/demos/meteor/server/main.js deleted file mode 100644 index da4ab43..0000000 --- a/demos/meteor/server/main.js +++ /dev/null @@ -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(() => { }); diff --git a/demos/systemjs/Makefile b/demos/systemjs/Makefile deleted file mode 100644 index 5ca2648..0000000 --- a/demos/systemjs/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -.PHONY: test ctest -test: - cp ../../dist/xlsx.full.min.js . - node test.node.js - -ctest: - python -mSimpleHTTPServer diff --git a/demos/systemjs/README.md b/demos/systemjs/README.md index 12c69fc..eceb198 100644 --- a/demos/systemjs/README.md +++ b/demos/systemjs/README.md @@ -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) diff --git a/demos/systemjs/app.node.js b/demos/systemjs/app.node.js deleted file mode 100644 index db2a0ef..0000000 --- a/demos/systemjs/app.node.js +++ /dev/null @@ -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'); diff --git a/demos/systemjs/main.js b/demos/systemjs/main.js deleted file mode 100644 index c29c394..0000000 --- a/demos/systemjs/main.js +++ /dev/null @@ -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); -})(); diff --git a/demos/systemjs/main.simple.js b/demos/systemjs/main.simple.js deleted file mode 100644 index a21d1a4..0000000 --- a/demos/systemjs/main.simple.js +++ /dev/null @@ -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); diff --git a/demos/systemjs/simple.html b/demos/systemjs/simple.html deleted file mode 100644 index 2a034de..0000000 --- a/demos/systemjs/simple.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - -SheetJS SystemJS Test - - - -
-SheetJS SystemJS Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-Original script: main.simple.js
-
-Console Output:
-
-

-
-
-
-
-
-
diff --git a/demos/systemjs/systemjs.html b/demos/systemjs/systemjs.html
deleted file mode 100644
index 131032b..0000000
--- a/demos/systemjs/systemjs.html
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
-
-
-
-SheetJS Live Demo
-
-
-
-
-SheetJS Data Preview Live Demo
-(Base64 text works back to IE6; drag and drop works back to IE10)
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-Output Format: 
-
Drop a spreadsheet file here to see sheet data
- ... or click here to select a file - - -
-Advanced Demo Options: -
-

-
-
- - - - - diff --git a/demos/systemjs/test.node.js b/demos/systemjs/test.node.js deleted file mode 100644 index 1dc0f2d..0000000 --- a/demos/systemjs/test.node.js +++ /dev/null @@ -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'); diff --git a/demos/systemjs/worker.js b/demos/systemjs/worker.js deleted file mode 100644 index 434e06b..0000000 --- a/demos/systemjs/worker.js +++ /dev/null @@ -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); }); -}; diff --git a/demos/systemjs/xlsxworker.js b/demos/systemjs/xlsxworker.js deleted file mode 100644 index 80c3872..0000000 --- a/demos/systemjs/xlsxworker.js +++ /dev/null @@ -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}); } -}; diff --git a/demos/typescript/README.md b/demos/typescript/README.md index c345d86..090d51d 100644 --- a/demos/typescript/README.md +++ b/demos/typescript/README.md @@ -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. diff --git a/demos/xhr/.gitignore b/demos/xhr/.gitignore deleted file mode 100644 index a37273b..0000000 --- a/demos/xhr/.gitignore +++ /dev/null @@ -1 +0,0 @@ -files/ diff --git a/demos/xhr/Makefile b/demos/xhr/Makefile deleted file mode 100644 index 06c7beb..0000000 --- a/demos/xhr/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -.PHONY: serve -serve: - npm start - -.PHONY: init -init: - if [ ! -e sheetjs.xlsx ]; then ln -s ../../sheetjs.xlsx; fi diff --git a/demos/xhr/README.md b/demos/xhr/README.md index 8056833..ecbbc34 100644 --- a/demos/xhr/README.md +++ b/demos/xhr/README.md @@ -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 - - -## 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) diff --git a/demos/xhr/axios.html b/demos/xhr/axios.html deleted file mode 100644 index 7a492be..0000000 --- a/demos/xhr/axios.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - -SheetJS Live Demo - - - -
-SheetJS Data Preview Live Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
-
-
- -
-
-
- - - - - - diff --git a/demos/xhr/fetch.html b/demos/xhr/fetch.html deleted file mode 100644 index d7da261..0000000 --- a/demos/xhr/fetch.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - -SheetJS Live Demo - - - -
-SheetJS Data Preview Live Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
-
-
- -
-
-
- - - - - diff --git a/demos/xhr/package.json b/demos/xhr/package.json deleted file mode 100644 index 749e533..0000000 --- a/demos/xhr/package.json +++ /dev/null @@ -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" - } -} diff --git a/demos/xhr/server.js b/demos/xhr/server.js deleted file mode 100644 index 464bb3c..0000000 --- a/demos/xhr/server.js +++ /dev/null @@ -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); }); - diff --git a/demos/xhr/superagent.html b/demos/xhr/superagent.html deleted file mode 100644 index 10893e8..0000000 --- a/demos/xhr/superagent.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - -SheetJS Live Demo - - - -
-SheetJS Data Preview Live Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
-
-
- -
-
-
- - - - - - diff --git a/demos/xhr/xhr.html b/demos/xhr/xhr.html deleted file mode 100644 index 48e5bfc..0000000 --- a/demos/xhr/xhr.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - -SheetJS Live Demo - - - -
-SheetJS Data Preview Live Demo
-
-Source Code Repo
-Issues?  Something look weird?  Click here and report an issue
-
-
-
-
- -
-
-
- - - - - diff --git a/demos/xhr/xlsx.full.min.js b/demos/xhr/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/xhr/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/packages/s2c/README.md b/packages/s2c/README.md new file mode 100644 index 0000000..70acdf4 --- /dev/null +++ b/packages/s2c/README.md @@ -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 + +[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/packages/s2c/mod.ts b/packages/s2c/mod.ts new file mode 100644 index 0000000..84d04bd --- /dev/null +++ b/packages/s2c/mod.ts @@ -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(field); + if(!file) throw new Error(`Field ${field} is missing!`); + return read(file.content, { type: "buffer" }); +} diff --git a/packages/s2c/s2c.ts b/packages/s2c/s2c.ts new file mode 100644 index 0000000..bf01f70 --- /dev/null +++ b/packages/s2c/s2c.ts @@ -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("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(`\ + + + + SheetJS Spreadsheet to HTML Conversion Service + + + +

SheetJS Spreadsheet Conversion Service

+API + +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. + +Try it out!
+ + + +Use the file input element to select a file, then click "Submit" + + +
+ +Library Version: ${version} +
+ +`, + ); + } +} + +// 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}.`); diff --git a/packages/s2c/test.ts b/packages/s2c/test.ts new file mode 100644 index 0000000..a4c78e6 --- /dev/null +++ b/packages/s2c/test.ts @@ -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(`\ + + + + SheetJS Spreadsheet to HTML Conversion Service + + + +

SheetJS Spreadsheet Conversion Service

+API + +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. + +Try it out!
+ + + +Use the file input element to select a file, then click "Submit" + + +
+ +Library Version: ${version} +
+ +`, + ); + } +} + +// 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}.`); + diff --git a/test.js b/test.js index a76eccf..1c25e3e 100644 --- a/test.js +++ b/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; diff --git a/test.mjs b/test.mjs index b85edd5..1e7e914 100644 --- a/test.mjs +++ b/test.mjs @@ -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; diff --git a/test.mts b/test.mts index ee6731e..1f25456 100644 --- a/test.mts +++ b/test.mts @@ -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 = [ diff --git a/test.ts b/test.ts index ea02f33..0d8de53 100644 --- a/test.ts +++ b/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 = [ diff --git a/testnocp.ts b/testnocp.ts index 5d207cc..f8b155d 100644 --- a/testnocp.ts +++ b/testnocp.ts @@ -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 = [ diff --git a/tests/core.js b/tests/core.js index 4fefe5e..c697cc8 100644 --- a/tests/core.js +++ b/tests/core.js @@ -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; diff --git a/xlsx.flow.js b/xlsx.flow.js index 5f70776..9f9aef5 100644 --- a/xlsx.flow.js +++ b/xlsx.flow.js @@ -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 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); diff --git a/xlsx.js b/xlsx.js index ed2e042..d277b1f 100644 --- a/xlsx.js +++ b/xlsx.js @@ -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 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); diff --git a/xlsx.mjs b/xlsx.mjs index 9e3a819..80894bd 100644 --- a/xlsx.mjs +++ b/xlsx.mjs @@ -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 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);