From 045adba80d8d367d1b6e676e6500aea10c3db624 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 21 Aug 2022 20:51:51 -0400 Subject: [PATCH] parse ZIP64 length (fixes #2766 h/t @silvialeung) --- bits/18_cfb.js | 24 +- demos/README.md | 19 +- demos/angular2/.angular-cli.json | 23 -- demos/angular2/.eslintrc | 6 - demos/angular2/.gitattributes | 1 - demos/angular2/.gitignore | 8 - demos/angular2/Makefile | 34 --- demos/angular2/README.md | 147 +---------- demos/angular2/ionic-app.module.ts | 22 -- demos/angular2/ionic.sh | 16 -- demos/angular2/ionic.ts | 126 --------- demos/angular2/package.json | 39 --- demos/angular2/screen.png | Bin 95983 -> 0 bytes demos/angular2/src/app/app.module.ts | 28 -- demos/angular2/src/app/sheetjs.component.ts | 64 ----- .../src/environments/environment.prod.ts | 3 - .../angular2/src/environments/environment.ts | 3 - demos/angular2/src/index.html | 30 --- demos/angular2/src/main.ts | 3 - demos/angular2/src/styles.css | 1 - demos/angular2/src/tsconfig.app.json | 9 - demos/angular2/tsconfig.json | 20 -- demos/angular2/versions/angular.json-ng10 | 125 --------- demos/angular2/versions/angular.json-ng11 | 124 --------- demos/angular2/versions/angular.json-ng12 | 106 -------- demos/angular2/versions/angular.json-ng13 | 106 -------- demos/angular2/versions/angular.json-ng6 | 127 --------- demos/angular2/versions/angular.json-ng7 | 136 ---------- demos/angular2/versions/angular.json-ng8 | 126 --------- demos/angular2/versions/angular.json-ng9 | 125 --------- demos/angular2/versions/package.json-ng10 | 39 --- demos/angular2/versions/package.json-ng11 | 39 --- demos/angular2/versions/package.json-ng12 | 39 --- demos/angular2/versions/package.json-ng13 | 39 --- demos/angular2/versions/package.json-ng2 | 37 --- demos/angular2/versions/package.json-ng4 | 38 --- demos/angular2/versions/package.json-ng5 | 38 --- demos/angular2/versions/package.json-ng6 | 39 --- demos/angular2/versions/package.json-ng7 | 39 --- demos/angular2/versions/package.json-ng8 | 39 --- demos/angular2/versions/package.json-ng9 | 39 --- demos/angular2/versions/polyfills.ts-ng10 | 1 - demos/angular2/versions/polyfills.ts-ng11 | 1 - demos/angular2/versions/polyfills.ts-ng12 | 1 - demos/angular2/versions/polyfills.ts-ng13 | 1 - demos/angular2/versions/polyfills.ts-ng2 | 3 - demos/angular2/versions/polyfills.ts-ng4 | 3 - demos/angular2/versions/polyfills.ts-ng5 | 3 - demos/angular2/versions/polyfills.ts-ng6 | 3 - demos/angular2/versions/polyfills.ts-ng7 | 3 - demos/angular2/versions/polyfills.ts-ng8 | 1 - demos/angular2/versions/polyfills.ts-ng9 | 1 - .../angular2/versions/tsconfig.app.json-ng10 | 14 - .../angular2/versions/tsconfig.app.json-ng11 | 14 - .../angular2/versions/tsconfig.app.json-ng12 | 14 - .../angular2/versions/tsconfig.app.json-ng13 | 14 - demos/angular2/versions/tsconfig.app.json-ng8 | 18 -- demos/angular2/versions/tsconfig.app.json-ng9 | 14 - demos/function/.eslintrc | 7 - demos/function/AzureHTTPTrigger/function.json | 17 -- demos/function/AzureHTTPTrigger/index.js | 44 ---- demos/function/Firebase/.gitignore | 65 ----- demos/function/Firebase/firebase.json | 1 - demos/function/Firebase/functions/.gitignore | 1 - demos/function/Firebase/functions/index.js | 39 --- .../function/Firebase/functions/package.json | 24 -- demos/function/LambdaProxy/index.js | 40 --- demos/function/LambdaProxy/template.yaml | 18 -- demos/function/Makefile | 28 -- demos/function/README.md | 112 +------- demos/function/host.json | 3 - demos/function/local.settings.json | 11 - demos/react/.gitignore | 4 - demos/react/Makefile | 24 -- demos/react/NOTES.md | 22 -- demos/react/README.md | 154 +---------- demos/react/index.html | 29 --- demos/react/modify/.gitignore | 23 -- demos/react/modify/README.md | 10 - demos/react/modify/package.json | 36 --- demos/react/modify/public/index.html | 43 ---- demos/react/modify/src/components/App.tsx | 107 -------- demos/react/modify/src/index.tsx | 12 - demos/react/modify/src/react-app-env.d.ts | 1 - demos/react/modify/src/styles/App.css | 14 - demos/react/modify/src/styles/index.css | 8 - demos/react/modify/tsconfig.json | 26 -- demos/react/nexthdr.js | 3 - demos/react/pages/getServerSideProps.js | 32 --- demos/react/pages/getStaticPaths.js | 38 --- demos/react/pages/getStaticProps.js | 32 --- demos/react/pages/index.js | 24 -- demos/react/pages/sheets/[id].js | 51 ---- demos/react/public/sheetjs.xlsx | Bin 10328 -> 0 bytes demos/react/sheetjs.js | 144 ----------- demos/server/.gitignore | 2 - demos/server/Makefile | 29 --- demos/server/README.md | 207 +-------------- demos/server/_cors.js | 4 - demos/server/_logit.js | 7 - demos/server/_request.js | 9 - demos/server/drash.ts | 68 ----- demos/server/express.js | 65 ----- demos/server/hapi.js | 67 ----- demos/server/koa.js | 79 ------ demos/server/koasub.js | 39 --- demos/server/nest.sh | 24 -- demos/server/nodejs.js | 84 ------ demos/server/sheetjs.controller.ts | 19 -- demos/server/sheetjs.csv | 19 -- demos/server/sheetjs.module.ts | 13 - demos/server/worker.js | 22 -- demos/vue/Makefile | 3 - demos/vue/README.md | 83 +----- demos/vue/SheetJS-vue.js | 68 ----- demos/vue/index2.html | 63 ----- demos/vue/index3.html | 63 ----- demos/vue/modify/.gitignore | 24 -- demos/vue/modify/README.md | 10 - demos/vue/modify/index.html | 13 - demos/vue/modify/package.json | 21 -- demos/vue/modify/src/App.vue | 241 ------------------ demos/vue/modify/src/env.d.ts | 8 - demos/vue/modify/src/main.ts | 4 - demos/vue/modify/tsconfig.json | 16 -- demos/vue/modify/tsconfig.node.json | 8 - demos/vue/modify/vite.config.ts | 7 - demos/vue/shim.js | 1 - demos/vue/xlsx.full.min.js | 1 - demos/xspreadsheet/README.md | 60 +---- demos/xspreadsheet/index.html | 135 ---------- demos/xspreadsheet/shim.js | 1 - demos/xspreadsheet/xlsx.full.min.js | 1 - demos/xspreadsheet/xlsxspread.js | 2 + 134 files changed, 65 insertions(+), 4907 deletions(-) delete mode 100644 demos/angular2/.angular-cli.json delete mode 100644 demos/angular2/.eslintrc delete mode 100644 demos/angular2/.gitattributes delete mode 100644 demos/angular2/.gitignore delete mode 100644 demos/angular2/Makefile delete mode 100644 demos/angular2/ionic-app.module.ts delete mode 100755 demos/angular2/ionic.sh delete mode 100644 demos/angular2/ionic.ts delete mode 100644 demos/angular2/package.json delete mode 100644 demos/angular2/screen.png delete mode 100644 demos/angular2/src/app/app.module.ts delete mode 100644 demos/angular2/src/app/sheetjs.component.ts delete mode 100644 demos/angular2/src/environments/environment.prod.ts delete mode 100644 demos/angular2/src/environments/environment.ts delete mode 100644 demos/angular2/src/index.html delete mode 100644 demos/angular2/src/main.ts delete mode 100644 demos/angular2/src/styles.css delete mode 100644 demos/angular2/src/tsconfig.app.json delete mode 100644 demos/angular2/tsconfig.json delete mode 100644 demos/angular2/versions/angular.json-ng10 delete mode 100644 demos/angular2/versions/angular.json-ng11 delete mode 100644 demos/angular2/versions/angular.json-ng12 delete mode 100644 demos/angular2/versions/angular.json-ng13 delete mode 100644 demos/angular2/versions/angular.json-ng6 delete mode 100644 demos/angular2/versions/angular.json-ng7 delete mode 100644 demos/angular2/versions/angular.json-ng8 delete mode 100644 demos/angular2/versions/angular.json-ng9 delete mode 100644 demos/angular2/versions/package.json-ng10 delete mode 100644 demos/angular2/versions/package.json-ng11 delete mode 100644 demos/angular2/versions/package.json-ng12 delete mode 100644 demos/angular2/versions/package.json-ng13 delete mode 100644 demos/angular2/versions/package.json-ng2 delete mode 100644 demos/angular2/versions/package.json-ng4 delete mode 100644 demos/angular2/versions/package.json-ng5 delete mode 100644 demos/angular2/versions/package.json-ng6 delete mode 100644 demos/angular2/versions/package.json-ng7 delete mode 100644 demos/angular2/versions/package.json-ng8 delete mode 100644 demos/angular2/versions/package.json-ng9 delete mode 100644 demos/angular2/versions/polyfills.ts-ng10 delete mode 100644 demos/angular2/versions/polyfills.ts-ng11 delete mode 100644 demos/angular2/versions/polyfills.ts-ng12 delete mode 100644 demos/angular2/versions/polyfills.ts-ng13 delete mode 100644 demos/angular2/versions/polyfills.ts-ng2 delete mode 100644 demos/angular2/versions/polyfills.ts-ng4 delete mode 100644 demos/angular2/versions/polyfills.ts-ng5 delete mode 100644 demos/angular2/versions/polyfills.ts-ng6 delete mode 100644 demos/angular2/versions/polyfills.ts-ng7 delete mode 100644 demos/angular2/versions/polyfills.ts-ng8 delete mode 100644 demos/angular2/versions/polyfills.ts-ng9 delete mode 100644 demos/angular2/versions/tsconfig.app.json-ng10 delete mode 100644 demos/angular2/versions/tsconfig.app.json-ng11 delete mode 100644 demos/angular2/versions/tsconfig.app.json-ng12 delete mode 100644 demos/angular2/versions/tsconfig.app.json-ng13 delete mode 100644 demos/angular2/versions/tsconfig.app.json-ng8 delete mode 100644 demos/angular2/versions/tsconfig.app.json-ng9 delete mode 100644 demos/function/.eslintrc delete mode 100644 demos/function/AzureHTTPTrigger/function.json delete mode 100644 demos/function/AzureHTTPTrigger/index.js delete mode 100644 demos/function/Firebase/.gitignore delete mode 100644 demos/function/Firebase/firebase.json delete mode 100644 demos/function/Firebase/functions/.gitignore delete mode 100644 demos/function/Firebase/functions/index.js delete mode 100644 demos/function/Firebase/functions/package.json delete mode 100644 demos/function/LambdaProxy/index.js delete mode 100644 demos/function/LambdaProxy/template.yaml delete mode 100644 demos/function/Makefile delete mode 100644 demos/function/host.json delete mode 100644 demos/function/local.settings.json delete mode 100644 demos/react/.gitignore delete mode 100644 demos/react/Makefile delete mode 100644 demos/react/NOTES.md delete mode 100644 demos/react/index.html delete mode 100644 demos/react/modify/.gitignore delete mode 100644 demos/react/modify/README.md delete mode 100644 demos/react/modify/package.json delete mode 100644 demos/react/modify/public/index.html delete mode 100644 demos/react/modify/src/components/App.tsx delete mode 100644 demos/react/modify/src/index.tsx delete mode 100644 demos/react/modify/src/react-app-env.d.ts delete mode 100644 demos/react/modify/src/styles/App.css delete mode 100644 demos/react/modify/src/styles/index.css delete mode 100644 demos/react/modify/tsconfig.json delete mode 100644 demos/react/nexthdr.js delete mode 100644 demos/react/pages/getServerSideProps.js delete mode 100644 demos/react/pages/getStaticPaths.js delete mode 100644 demos/react/pages/getStaticProps.js delete mode 100644 demos/react/pages/index.js delete mode 100644 demos/react/pages/sheets/[id].js delete mode 100644 demos/react/public/sheetjs.xlsx delete mode 100644 demos/react/sheetjs.js delete mode 100644 demos/server/.gitignore delete mode 100644 demos/server/Makefile delete mode 100644 demos/server/_cors.js delete mode 100644 demos/server/_logit.js delete mode 100644 demos/server/_request.js delete mode 100644 demos/server/drash.ts delete mode 100644 demos/server/express.js delete mode 100644 demos/server/hapi.js delete mode 100644 demos/server/koa.js delete mode 100644 demos/server/koasub.js delete mode 100755 demos/server/nest.sh delete mode 100644 demos/server/nodejs.js delete mode 100644 demos/server/sheetjs.controller.ts delete mode 100644 demos/server/sheetjs.csv delete mode 100644 demos/server/sheetjs.module.ts delete mode 100644 demos/server/worker.js delete mode 100644 demos/vue/Makefile delete mode 100644 demos/vue/SheetJS-vue.js delete mode 100644 demos/vue/index2.html delete mode 100644 demos/vue/index3.html delete mode 100644 demos/vue/modify/.gitignore delete mode 100644 demos/vue/modify/README.md delete mode 100644 demos/vue/modify/index.html delete mode 100644 demos/vue/modify/package.json delete mode 100644 demos/vue/modify/src/App.vue delete mode 100644 demos/vue/modify/src/env.d.ts delete mode 100644 demos/vue/modify/src/main.ts delete mode 100644 demos/vue/modify/tsconfig.json delete mode 100644 demos/vue/modify/tsconfig.node.json delete mode 100644 demos/vue/modify/vite.config.ts delete mode 120000 demos/vue/shim.js delete mode 120000 demos/vue/xlsx.full.min.js delete mode 100644 demos/xspreadsheet/index.html delete mode 120000 demos/xspreadsheet/shim.js delete mode 120000 demos/xspreadsheet/xlsx.full.min.js diff --git a/bits/18_cfb.js b/bits/18_cfb.js index 58dbe25..8ac3c6e 100644 --- a/bits/18_cfb.js +++ b/bits/18_cfb.js @@ -211,8 +211,15 @@ function parse_extra_field(blob/*:CFBlob*/)/*:any*/ { if(flags & 4) p.ctime = blob.read_shift(4); } if(p.mtime) p.mt = new Date(p.mtime*1000); - } - break; + } break; + /* ZIP64 Extended Information Field */ + case 0x0001: { + var sz1 = blob.read_shift(4), sz2 = blob.read_shift(4); + p.usz = (sz2 * Math.pow(2,32) + sz1); + sz1 = blob.read_shift(4); sz2 = blob.read_shift(4); + p.csz = (sz2 * Math.pow(2,32) + sz1); + // NOTE: volume fields are skipped + } break; } blob.l = tgt; o[type] = p; @@ -1401,6 +1408,11 @@ function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ var L = blob.l; blob.l = offset + 4; + /* ZIP64 lengths */ + if(EF && EF[0x0001]) { + if((EF[0x0001]||{}).usz) usz = EF[0x0001].usz; + if((EF[0x0001]||{}).csz) csz = EF[0x0001].csz; + } parse_local_file(blob, csz, usz, o, EF); blob.l = L; } @@ -1430,7 +1442,13 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C if(efsz) { var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/); if((ef[0x5455]||{}).mt) date = ef[0x5455].mt; - if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt; + if((ef[0x0001]||{}).usz) _usz = ef[0x0001].usz; + if((ef[0x0001]||{}).csz) _csz = ef[0x0001].csz; + if(EF) { + if((EF[0x5455]||{}).mt) date = EF[0x5455].mt; + if((EF[0x0001]||{}).usz) _usz = ef[0x0001].usz; + if((EF[0x0001]||{}).csz) _csz = ef[0x0001].csz; + } } blob.l += efsz; diff --git a/demos/README.md b/demos/README.md index 98db244..e7df176 100644 --- a/demos/README.md +++ b/demos/README.md @@ -26,23 +26,23 @@ can be installed with Bash on Windows or with `cygwin`. - [`IndexedDB`](https://docs.sheetjs.com/docs/demos/database#indexeddb) **Frameworks** +- [`Angular 2+ and Ionic`](https://docs.sheetjs.com/docs/demos/angular) +- [`React`](https://docs.sheetjs.com/docs/demos/react) +- [`VueJS`](https://docs.sheetjs.com/docs/demos/vue) - [`Angular.JS`](https://docs.sheetjs.com/docs/demos/legacy#angularjs) -- [`Angular 2+ and Ionic`](angular2/) - [`Knockout`](https://docs.sheetjs.com/docs/demos/legacy#knockoutjs) -- [`React and NextJS`](react/) -- [`VueJS`](vue/) **Front-End UI Components** - [`canvas-datagrid`](https://docs.sheetjs.com/docs/demos/grid#canvas-datagrid) -- [`x-spreadsheet`](xspreadsheet/) -- [`react-data-grid`](react/modify/) -- [`vue3-table-light`](vue/modify/) +- [`x-spreadsheet`](https://docs.sheetjs.com/docs/demos/grid#x-spreadsheet) +- [`react-data-grid`](https://docs.sheetjs.com/docs/demos/grid#react-data-grid) +- [`vue3-table-lite`](https://docs.sheetjs.com/docs/demos/grid#vue3-table-lite) - [`angular-ui-grid`](https://docs.sheetjs.com/docs/demos/grid#angular-ui-grid) **Platforms and Integrations** - [`Command-Line Tools`](https://docs.sheetjs.com/docs/demos/cli) - [`iOS and Android Mobile Applications`](https://docs.sheetjs.com/docs/demos/mobile) -- [`NodeJS Server-Side Processing`](server/) +- [`NodeJS Server-Side Processing`](https://docs.sheetjs.com/docs/demos/server#nodejs) - [`Content Management and Static Sites`](https://docs.sheetjs.com/docs/demos/content) - [`Electron`](https://docs.sheetjs.com/docs/demos/desktop#electron) - [`NW.js`](https://docs.sheetjs.com/docs/demos/desktop#nwjs) @@ -54,8 +54,9 @@ can be installed with Bash on Windows or with `cygwin`. - [`SalesForce Lightning Web Components`](https://docs.sheetjs.com/docs/demos/salesforce) - [`Excel JavaScript API`](https://docs.sheetjs.com/docs/demos/excel) - [`Headless Automation`](https://docs.sheetjs.com/docs/demos/headless) -- [`Swift JSC and Other JavaScript Engines`](https://docs.sheetjs.com/docs/demos/engines) -- [`"serverless" functions`](function/) +- [`Other JavaScript Engines`](https://docs.sheetjs.com/docs/demos/engines) +- [`Azure Functions and Storage`](https://docs.sheetjs.com/docs/demos/azure) +- [`Amazon Web Services`](https://docs.sheetjs.com/docs/demos/aws) - [`Databases and Structured Data Stores`](https://docs.sheetjs.com/docs/demos/database) - [`NoSQL and Unstructured Data Stores`](https://docs.sheetjs.com/docs/demos/nosql) - [`Legacy Internet Explorer`](https://docs.sheetjs.com/docs/demos/legacy#internet-explorer) diff --git a/demos/angular2/.angular-cli.json b/demos/angular2/.angular-cli.json deleted file mode 100644 index 35d76d7..0000000 --- a/demos/angular2/.angular-cli.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "project": { - "name": "angular2" - }, - "apps": [ - { - "root": "src", - "outDir": "dist", - "index": "index.html", - "main": "main.ts", - "polyfills": "polyfills.ts", - "test": "test.ts", - "tsconfig": "tsconfig.app.json", - "prefix": "app", - "scripts": [] - } - ], - "defaults": { - "styleExt": "css", - "component": {} - } -} diff --git a/demos/angular2/.eslintrc b/demos/angular2/.eslintrc deleted file mode 100644 index 31ada8c..0000000 --- a/demos/angular2/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended" - ] -} diff --git a/demos/angular2/.gitattributes b/demos/angular2/.gitattributes deleted file mode 100644 index 80fa1f4..0000000 --- a/demos/angular2/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.*-ng* linguist-generated=true binary diff --git a/demos/angular2/.gitignore b/demos/angular2/.gitignore deleted file mode 100644 index f1fd2db..0000000 --- a/demos/angular2/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -dist -hooks -SheetJSIonic -SheetJSNS -angular.json -tsconfig.app.json -src/polyfills.ts -.angular diff --git a/demos/angular2/Makefile b/demos/angular2/Makefile deleted file mode 100644 index b37e495..0000000 --- a/demos/angular2/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -.PHONY: ng2 ng4 ng5 ng6 ng7 ng8 ng9 ng10 ng11 ng12 ng13 -ng2 ng4 ng5 ng6 ng7 ng8 ng9 ng10 ng11 ng12 ng13: - rm -f angular.json tsconfig.app.json src/polyfills.ts - cp versions/package.json-$@ package.json - if [ -e versions/angular.json-$@ ]; then cp versions/angular.json-$@ angular.json; fi - if [ -e versions/tsconfig.app.json-$@ ]; then cp versions/tsconfig.app.json-$@ tsconfig.app.json; fi - if [ -e versions/polyfills.ts-$@ ]; then cp versions/polyfills.ts-$@ src/polyfills.ts; fi - rm -rf node_modules - if [ ! -e node_modules ]; then mkdir node_modules; fi - npm install - if [ ! -e node_modules/xlsx ]; then cd node_modules; ln -s ../../../ xlsx; cd -; fi - npm run build - -.PHONY: refresh -refresh: ## refresh the `xlsx` symlink to force angular to rebuild - rm -rf .angular/ - rm -f node_modules/xlsx - cd node_modules; ln -s ../../../ xlsx; cd - - touch node_modules/xlsx - -.PHONY: all -all: - for i in 2 4 5 6 7 8 9 10 11 12 13; do make ng$$i; done - -.PHONY: ionic -ionic: - bash ./ionic.sh - -.PHONY: ios android browser -ios browser: ionic - cd SheetJSIonic; ionic cordova emulate $@ >`) as the core state. -The component template includes a file input element, a table that updates with -the data, and a button to export the data. - -Other scripts in this demo show: -- `ionic` deployment for iOS, android, and browser -- `nativescript` deployment for iOS and android - -## Array of Arrays - -`Array>` neatly maps to a table with `ngFor`: - -```html - - - - -
- {{val}} -
-``` - -The `aoa_to_sheet` utility function returns a worksheet. Exporting is simple: - -```typescript -/* generate worksheet */ -const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data); - -/* generate workbook and add the worksheet */ -const wb: XLSX.WorkBook = XLSX.utils.book_new(); -XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); - -/* save to file */ -XLSX.writeFile(wb, 'SheetJS.xlsx'); -``` - -`sheet_to_json` with the option `header:1` makes importing simple: - -```typescript -/* */ -/* ... (within the component class definition) ... */ - onFileChange(evt: any) { - /* wire up file reader */ - const target: DataTransfer = (evt.target); - if (target.files.length !== 1) throw new Error('Cannot use multiple files'); - const reader: FileReader = new FileReader(); - reader.onload = (e: any) => { - /* read workbook */ - const ab: ArrayBuffer = e.target.result; - const wb: XLSX.WorkBook = XLSX.read(ab); - - /* grab first sheet */ - const wsname: string = wb.SheetNames[0]; - const ws: XLSX.WorkSheet = wb.Sheets[wsname]; - - /* save data */ - this.data = (XLSX.utils.sheet_to_json(ws, {header: 1})); - }; - reader.readAsArrayBuffer(target.files[0]); - } -``` - -## Switching between Angular versions - -Modules that work with Angular 2 largely work as-is with Angular 4+. Switching -between versions is mostly a matter of installing the correct version of the -core and associated modules. This demo includes `package.json-angular#` files -for every major version of Angular up to 12. - -To test a particular Angular version, overwrite `package.json`: - -```bash -# switch to Angular 2 -$ cp package.json-ng2 package.json -$ npm install -$ ng serve -``` - -Note: when running the demos, Angular 2 requires Node <= 14. This is due to a -tooling issue with `ng` and does not affect browser use. - -## XLSX Symbolic Link - -In this tree, `node_modules/xlsx` is a link pointing back to the root. This -enables testing the development version of the library. In order to use this -demo in other applications, add the `xlsx` dependency: - -```bash -$ npm install --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz -``` - -## SystemJS Configuration - -The default angular-cli configuration requires no additional configuration. - -Some deployments use the SystemJS loader, which does require configuration. -[SystemJS](https://docs.sheetjs.com/docs/demos/bundler#systemjs) -demo in the SheetJS CE docs describe the required settings. - -## Ionic - - - -Reproducing the full project is a little bit tricky. The included `ionic.sh` -script performs the necessary installation steps. - -`Array>` neatly maps to a table with `ngFor`: - -```html - - - - {{val}} - - - -``` - - -`@ionic-native/file` reads and writes files on devices. `readAsArrayBuffer` -returns `ArrayBuffer` objects suitable for `array` type, and `array` type can -be converted to blobs that can be exported with `writeFile`: - -```typescript -/* read a workbook */ -const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, filename); -const wb: XLSX.WorkBook = XLSX.read(bstr, {type: 'array'}); - -/* write a workbook */ -const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); -let blob = new Blob([wbout], {type: 'application/octet-stream'}); -this.file.writeFile(url, filename, blob, {replace: true}); -``` - -## NativeScript - -[The new demo](https://docs.sheetjs.com/docs/demos/mobile#nativescript) -is updated for NativeScript 8 and uses more idiomatic data patterns. +- [NativeScript](https://docs.sheetjs.com/docs/demos/mobile#nativescript) is now part of "iOS and Android Apps" +- [Ionic](https://docs.sheetjs.com/docs/demos/mobile#ionic) is now part of "iOS and Android Apps" [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/angular2/ionic-app.module.ts b/demos/angular2/ionic-app.module.ts deleted file mode 100644 index 5d92df0..0000000 --- a/demos/angular2/ionic-app.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -/* vim: set ts=2: */ -/* NOTE: this file exists because `File` must be added as a provider */ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { RouteReuseStrategy } from '@angular/router'; - -import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; - -import { AppComponent } from './app.component'; -import { AppRoutingModule } from './app-routing.module'; - -import { File } from '@ionic-native/file/ngx'; - -@NgModule({ - declarations: [AppComponent], - entryComponents: [], - imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule], - providers: [File, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/demos/angular2/ionic.sh b/demos/angular2/ionic.sh deleted file mode 100755 index c12a32e..0000000 --- a/demos/angular2/ionic.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -if [ ! -e SheetJSIonic ]; then - ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm - - SheetJS Ionic Demo - - - - - - - SheetJS Demo - - - - - - - {{val}} - - - - - - - - - - -` -}) - -export class HomePage { - data: any[][] = [[1,2,3],[4,5,6]]; - constructor(public file: File) {} - - read(ab: ArrayBuffer) { - /* read workbook */ - const wb: XLSX.WorkBook = XLSX.read(new Uint8Array(ab), {type: 'array'}); - - /* grab first sheet */ - const wsname: string = wb.SheetNames[0]; - const ws: XLSX.WorkSheet = wb.Sheets[wsname]; - - /* save data */ - this.data = (XLSX.utils.sheet_to_json(ws, {header: 1}) as AOA); - }; - - write(): XLSX.WorkBook { - /* generate worksheet */ - const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data); - - /* generate workbook and add the worksheet */ - const wb: XLSX.WorkBook = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(wb, ws, 'SheetJS'); - - return wb; - }; - - /* File Input element for browser */ - onFileChange(evt: any) { - /* wire up file reader */ - const target: DataTransfer = (evt.target as DataTransfer); - if (target.files.length !== 1) { throw new Error('Cannot use multiple files'); } - const reader: FileReader = new FileReader(); - reader.onload = (e: any) => { - const ab: ArrayBuffer = e.target.result; - this.read(ab); - }; - reader.readAsArrayBuffer(target.files[0]); - }; - - /* Import button for mobile */ - async import() { - try { - const target: string = this.file.documentsDirectory || this.file.externalDataDirectory || this.file.dataDirectory || ''; - const dentry = await this.file.resolveDirectoryUrl(target); - const url: string = dentry.nativeURL || ''; - alert(`Attempting to read SheetJSIonic.xlsx from ${url}`); - const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, 'SheetJSIonic.xlsx'); - this.read(ab); - } catch(e) { - const m: string = e.message; - alert(m.match(/It was determined/) ? 'Use File Input control' : `Error: ${m}`); - } - }; - - /* Export button */ - async export() { - const wb: XLSX.WorkBook = this.write(); - const filename = 'SheetJSIonic.xlsx'; - try { - /* generate Blob */ - const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); - - /* find appropriate path for mobile */ - const target: string = this.file.documentsDirectory || this.file.externalDataDirectory || this.file.dataDirectory || ''; - const dentry = await this.file.resolveDirectoryUrl(target); - const url: string = dentry.nativeURL || ''; - - /* attempt to save blob to file */ - await this.file.writeFile(url, filename, wbout, {replace: true}); - alert(`Wrote to SheetJSIonic.xlsx in ${url}`); - } catch(e) { - if(e.message.match(/It was determined/)) { - /* in the browser, use writeFile */ - XLSX.writeFile(wb, filename); - } else { - alert(`Error: ${e.message}`); - } - } - }; -} - diff --git a/demos/angular2/package.json b/demos/angular2/package.json deleted file mode 100644 index a214cef..0000000 --- a/demos/angular2/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular13", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~13.2.0", - "@angular/common": "~13.2.0", - "@angular/compiler": "~13.2.0", - - "@angular/core": "~13.2.0", - "@angular/forms": "~13.2.0", - - "@angular/platform-browser": "~13.2.0", - "@angular/platform-browser-dynamic": "~13.2.0", - - "@angular/router": "~13.2.0", - - - "rxjs": "~7.5.0", - "tslib": "^2.3.0", - "zone.js": "~0.11.4" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~13.2.1", - "@angular/cli": "~13.2.1", - "@angular/compiler-cli": "~13.2.0", - - "@types/node": "^12.11.1", - - - "typescript": "~4.5.2" - } -} diff --git a/demos/angular2/screen.png b/demos/angular2/screen.png deleted file mode 100644 index 18963733cfc5909e99d89b579f07baf054fe4ef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95983 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 TSJa~a0RAb;L1jxHo4)xE6;A%> diff --git a/demos/angular2/src/app/app.module.ts b/demos/angular2/src/app/app.module.ts deleted file mode 100644 index d7bb39a..0000000 --- a/demos/angular2/src/app/app.module.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; - -import { SheetJSComponent } from './sheetjs.component'; - - -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-root', - template: `` -}) -export class AppComponent { - title = 'test'; -} - -@NgModule({ - declarations: [ - SheetJSComponent, - AppComponent - ], - imports: [ - BrowserModule - ], - providers: [], - bootstrap: [AppComponent] -}) -export class AppModule { } diff --git a/demos/angular2/src/app/sheetjs.component.ts b/demos/angular2/src/app/sheetjs.component.ts deleted file mode 100644 index 0015d61..0000000 --- a/demos/angular2/src/app/sheetjs.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -/* vim: set ts=2: */ -import { Component } from '@angular/core'; - -import { WorkBook, WorkSheet, WritingOptions, read, writeFileXLSX as writeFile, utils, version, set_cptable } from 'xlsx'; -//import * as cpexcel from 'xlsx/dist/cpexcel.full.mjs'; -//set_cptable(cpexcel); - -type AOA = any[][]; - -@Component({ - selector: 'sheetjs', - template: ` -
Version: {{ver}}
- - - - - -
- {{val}} -
- - ` -}) - -export class SheetJSComponent { - data: AOA = [ [1, 2], [3, 4] ]; - wopts: WritingOptions = { bookType: 'xlsx', type: 'array' }; - fileName: string = 'SheetJS.xlsx'; - ver: string = version; - - onFileChange(evt: any) { - /* wire up file reader */ - const target: DataTransfer = (evt.target); - if (target.files.length !== 1) throw new Error('Cannot use multiple files'); - const reader: FileReader = new FileReader(); - reader.onload = (e: any) => { - /* read workbook */ - const ab: ArrayBuffer = e.target.result; - const wb: WorkBook = read(ab); - - /* grab first sheet */ - const wsname: string = wb.SheetNames[0]; - const ws: WorkSheet = wb.Sheets[wsname]; - - /* save data */ - this.data = (utils.sheet_to_json(ws, {header: 1})); - }; - reader.readAsArrayBuffer(target.files[0]); - } - - export(): void { - /* generate worksheet */ - const ws: WorkSheet = utils.aoa_to_sheet(this.data); - - /* generate workbook and add the worksheet */ - const wb: WorkBook = utils.book_new(); - utils.book_append_sheet(wb, ws, 'Sheet1'); - - /* save to file */ - writeFile(wb, this.fileName); - } -} diff --git a/demos/angular2/src/environments/environment.prod.ts b/demos/angular2/src/environments/environment.prod.ts deleted file mode 100644 index 3612073..0000000 --- a/demos/angular2/src/environments/environment.prod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: true -}; diff --git a/demos/angular2/src/environments/environment.ts b/demos/angular2/src/environments/environment.ts deleted file mode 100644 index ffe8aed..0000000 --- a/demos/angular2/src/environments/environment.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: false -}; diff --git a/demos/angular2/src/index.html b/demos/angular2/src/index.html deleted file mode 100644 index bc806fb..0000000 --- a/demos/angular2/src/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - SheetJS + Angular 2+ - - - - - -
-SheetJS + Angular 2+ demo
-
-The core library can be used as-is in angular applications.
-The Community Edition README details some common use cases.
-We also have some more public demos
-
-This demo shows `SheetJSComponent` which provides:
-- File input button with an event handler to parse the workbook
-- `data` property: array of arrays
-- Simple angular table which binds to the `data` property
-- `export` function that exports the `data` property to a new file.
-
-Sample Spreadsheet
-
- - - - diff --git a/demos/angular2/src/main.ts b/demos/angular2/src/main.ts deleted file mode 100644 index d3da1bb..0000000 --- a/demos/angular2/src/main.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { AppModule } from './app/app.module'; -platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/demos/angular2/src/styles.css b/demos/angular2/src/styles.css deleted file mode 100644 index 90d4ee0..0000000 --- a/demos/angular2/src/styles.css +++ /dev/null @@ -1 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ diff --git a/demos/angular2/src/tsconfig.app.json b/demos/angular2/src/tsconfig.app.json deleted file mode 100644 index 321e0d7..0000000 --- a/demos/angular2/src/tsconfig.app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../out-tsc/app", - "module": "es2015", - "baseUrl": "", - "types": [] - } -} diff --git a/demos/angular2/tsconfig.json b/demos/angular2/tsconfig.json deleted file mode 100644 index a35a8ee..0000000 --- a/demos/angular2/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "outDir": "./dist/out-tsc", - "baseUrl": "src", - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "es5", - "typeRoots": [ - "node_modules/@types" - ], - "lib": [ - "es2016", - "dom" - ] - } -} diff --git a/demos/angular2/versions/angular.json-ng10 b/demos/angular2/versions/angular.json-ng10 deleted file mode 100644 index 9e7228c..0000000 --- a/demos/angular2/versions/angular.json-ng10 +++ /dev/null @@ -1,125 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": true, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "sheetjs:build" - }, - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "sheetjs:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sheetjs:serve:production" - } - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng11 b/demos/angular2/versions/angular.json-ng11 deleted file mode 100644 index a1563c1..0000000 --- a/demos/angular2/versions/angular.json-ng11 +++ /dev/null @@ -1,124 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": true, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "sheetjs:build" - }, - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "sheetjs:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sheetjs:serve:production" - } - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng12 b/demos/angular2/versions/angular.json-ng12 deleted file mode 100644 index 69d02ea..0000000 --- a/demos/angular2/versions/angular.json-ng12 +++ /dev/null @@ -1,106 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": { - "@schematics/angular:application": { - "strict": true - } - }, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "2mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - }, - "development": { - "browserTarget": "sheetjs:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng13 b/demos/angular2/versions/angular.json-ng13 deleted file mode 100644 index 69d02ea..0000000 --- a/demos/angular2/versions/angular.json-ng13 +++ /dev/null @@ -1,106 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": { - "@schematics/angular:application": { - "strict": true - } - }, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "2mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - }, - "development": { - "browserTarget": "sheetjs:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng6 b/demos/angular2/versions/angular.json-ng6 deleted file mode 100644 index 30e40df..0000000 --- a/demos/angular2/versions/angular.json-ng6 +++ /dev/null @@ -1,127 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.app.json", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "sheetjs:build" - }, - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "karmaConfig": "src/karma.conf.js", - "styles": [ - "src/styles.css" - ], - "scripts": [], - "assets": [ - "src/favicon.ico", - "src/assets" - ] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "src/tsconfig.app.json", - "src/tsconfig.spec.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - } - } - }, - "sheetjs-e2e": { - "root": "e2e/", - "projectType": "application", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "sheetjs:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sheetjs:serve:production" - } - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": "e2e/tsconfig.e2e.json", - "exclude": [ - "**/node_modules/**" - ] - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng7 b/demos/angular2/versions/angular.json-ng7 deleted file mode 100644 index be12951..0000000 --- a/demos/angular2/versions/angular.json-ng7 +++ /dev/null @@ -1,136 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.app.json", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [], - "es5BrowserSupport": true - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "sheetjs:build" - }, - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "karmaConfig": "src/karma.conf.js", - "styles": [ - "src/styles.css" - ], - "scripts": [], - "assets": [ - "src/favicon.ico", - "src/assets" - ] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "src/tsconfig.app.json", - "src/tsconfig.spec.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - } - } - }, - "sheetjs-e2e": { - "root": "e2e/", - "projectType": "application", - "prefix": "", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "sheetjs:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sheetjs:serve:production" - } - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": "e2e/tsconfig.e2e.json", - "exclude": [ - "**/node_modules/**" - ] - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng8 b/demos/angular2/versions/angular.json-ng8 deleted file mode 100644 index de608c0..0000000 --- a/demos/angular2/versions/angular.json-ng8 +++ /dev/null @@ -1,126 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": false, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "sheetjs:build" - }, - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "sheetjs:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sheetjs:serve:production" - } - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/angular.json-ng9 b/demos/angular2/versions/angular.json-ng9 deleted file mode 100644 index 9e7228c..0000000 --- a/demos/angular2/versions/angular.json-ng9 +++ /dev/null @@ -1,125 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "sheetjs": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "prefix": "app", - "schematics": {}, - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/sheetjs", - "index": "src/index.html", - "main": "src/main.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.app.json", - "aot": true, - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" - } - ] - } - } - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "sheetjs:build" - }, - "configurations": { - "production": { - "browserTarget": "sheetjs:build:production" - } - } - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sheetjs:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" - ] - } - }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "sheetjs:serve" - }, - "configurations": { - "production": { - "devServerTarget": "sheetjs:serve:production" - } - } - } - } - } - }, - "defaultProject": "sheetjs" -} diff --git a/demos/angular2/versions/package.json-ng10 b/demos/angular2/versions/package.json-ng10 deleted file mode 100644 index fff68df..0000000 --- a/demos/angular2/versions/package.json-ng10 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular10", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~10.2.4", - "@angular/common": "~10.2.4", - "@angular/compiler": "~10.2.4", - - "@angular/core": "~10.2.4", - "@angular/forms": "~10.2.4", - - "@angular/platform-browser": "~10.2.4", - "@angular/platform-browser-dynamic": "~10.2.4", - - "@angular/router": "~10.2.4", - - - "rxjs": "~6.6.0", - "tslib": "^2.0.0", - "zone.js": "~0.10.2" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.1002.3", - "@angular/cli": "~10.2.3", - "@angular/compiler-cli": "~10.2.4", - - "@types/node": "^12.11.1", - "ts-node": "~8.3.0", - "tslint": "~6.1.0", - "typescript": "~4.0.2" - } -} diff --git a/demos/angular2/versions/package.json-ng11 b/demos/angular2/versions/package.json-ng11 deleted file mode 100644 index 9bb80a8..0000000 --- a/demos/angular2/versions/package.json-ng11 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular11", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~11.2.14", - "@angular/common": "~11.2.14", - "@angular/compiler": "~11.2.14", - - "@angular/core": "~11.2.14", - "@angular/forms": "~11.2.14", - - "@angular/platform-browser": "~11.2.14", - "@angular/platform-browser-dynamic": "~11.2.14", - - "@angular/router": "~11.2.14", - - - "rxjs": "~6.6.0", - "tslib": "^2.0.0", - "zone.js": "~0.11.3" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.1102.13", - "@angular/cli": "~11.2.14", - "@angular/compiler-cli": "~11.2.14", - - "@types/node": "^12.11.1", - "ts-node": "~8.3.0", - "tslint": "~6.1.0", - "typescript": "~4.1.5" - } -} diff --git a/demos/angular2/versions/package.json-ng12 b/demos/angular2/versions/package.json-ng12 deleted file mode 100644 index 74df6c5..0000000 --- a/demos/angular2/versions/package.json-ng12 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular12", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~12.2.0", - "@angular/common": "~12.2.0", - "@angular/compiler": "~12.2.0", - - "@angular/core": "~12.2.0", - "@angular/forms": "~12.2.0", - - "@angular/platform-browser": "~12.2.0", - "@angular/platform-browser-dynamic": "~12.2.0", - - "@angular/router": "~12.2.0", - - - "rxjs": "~6.6.0", - "tslib": "^2.3.0", - "zone.js": "~0.11.4" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~12.2.7", - "@angular/cli": "~12.2.7", - "@angular/compiler-cli": "~12.2.0", - - "@types/node": "^12.11.1", - - - "typescript": "~4.3.5" - } -} diff --git a/demos/angular2/versions/package.json-ng13 b/demos/angular2/versions/package.json-ng13 deleted file mode 100644 index a214cef..0000000 --- a/demos/angular2/versions/package.json-ng13 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular13", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~13.2.0", - "@angular/common": "~13.2.0", - "@angular/compiler": "~13.2.0", - - "@angular/core": "~13.2.0", - "@angular/forms": "~13.2.0", - - "@angular/platform-browser": "~13.2.0", - "@angular/platform-browser-dynamic": "~13.2.0", - - "@angular/router": "~13.2.0", - - - "rxjs": "~7.5.0", - "tslib": "^2.3.0", - "zone.js": "~0.11.4" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~13.2.1", - "@angular/cli": "~13.2.1", - "@angular/compiler-cli": "~13.2.0", - - "@types/node": "^12.11.1", - - - "typescript": "~4.5.2" - } -} diff --git a/demos/angular2/versions/package.json-ng2 b/demos/angular2/versions/package.json-ng2 deleted file mode 100644 index c6cdfe9..0000000 --- a/demos/angular2/versions/package.json-ng2 +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "angular2", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/common": "~2.4.1", - "@angular/compiler": "~2.4.1", - "@angular/compiler-cli": "^2.4.1", - "@angular/core": "~2.4.1", - "@angular/forms": "~2.4.1", - "@angular/http": "~2.4.1", - "@angular/platform-browser": "~2.4.1", - "@angular/platform-browser-dynamic": "~2.4.1", - "@angular/platform-server": "^2.4.1", - "@angular/router": "~3.4.0", - "core-js": "^2.4.1", - "reflect-metadata": "^0.1.8", - "rxjs": "^5.0.2", - "systemjs": "0.19.40", - "zone.js": "^0.7.4" - }, - "devDependencies": { - "@angular/cli": "1.1.2", - "@angular/compiler-cli": "^2.0.0", - "@angular/language-service": "^2.0.0", - "@types/node": "~6.0.60", - "ts-node": "~3.0.4", - "tslint": "~5.3.2", - "typescript": "~2.3.3" - } -} diff --git a/demos/angular2/versions/package.json-ng4 b/demos/angular2/versions/package.json-ng4 deleted file mode 100644 index 2891383..0000000 --- a/demos/angular2/versions/package.json-ng4 +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "angular4", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "^4.0.0", - "@angular/common": "^4.0.0", - "@angular/compiler": "^4.0.0", - - "@angular/core": "^4.0.0", - "@angular/forms": "^4.0.0", - "@angular/http": "^4.0.0", - "@angular/platform-browser": "^4.0.0", - "@angular/platform-browser-dynamic": "^4.0.0", - - "@angular/router": "^4.0.0", - "core-js": "^2.4.1", - - "rxjs": "^5.1.0", - - "zone.js": "^0.8.4" - }, - "devDependencies": { - "@angular/cli": "1.1.2", - "@angular/compiler-cli": "^4.0.0", - "@angular/language-service": "^4.0.0", - "@types/node": "~6.0.60", - "ts-node": "~3.0.4", - "tslint": "~5.3.2", - "typescript": "~2.3.3" - } -} diff --git a/demos/angular2/versions/package.json-ng5 b/demos/angular2/versions/package.json-ng5 deleted file mode 100644 index 1f62707..0000000 --- a/demos/angular2/versions/package.json-ng5 +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "angular5", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "^5.0.0", - "@angular/common": "^5.0.0", - "@angular/compiler": "^5.0.0", - - "@angular/core": "^5.0.0", - "@angular/forms": "^5.0.0", - "@angular/http": "^5.0.0", - "@angular/platform-browser": "^5.0.0", - "@angular/platform-browser-dynamic": "^5.0.0", - - "@angular/router": "^5.0.0", - "core-js": "^2.4.1", - - "rxjs": "^5.5.2", - - "zone.js": "^0.8.14" - }, - "devDependencies": { - "@angular/cli": "^1.5.3", - "@angular/compiler-cli": "^5.0.0", - "@angular/language-service": "^5.0.0", - "@types/node": "~6.0.60", - "ts-node": "~3.2.0", - "tslint": "~5.7.0", - "typescript": "~2.4.2" - } -} diff --git a/demos/angular2/versions/package.json-ng6 b/demos/angular2/versions/package.json-ng6 deleted file mode 100644 index a6df172..0000000 --- a/demos/angular2/versions/package.json-ng6 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular6", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "^6.1.0", - "@angular/common": "^6.1.0", - "@angular/compiler": "^6.1.0", - - "@angular/core": "^6.1.0", - "@angular/forms": "^6.1.0", - "@angular/http": "^6.1.0", - "@angular/platform-browser": "^6.1.0", - "@angular/platform-browser-dynamic": "^6.1.0", - - "@angular/router": "^6.1.0", - "core-js": "^2.5.4", - - "rxjs": "~6.2.0", - - "zone.js": "~0.8.26" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.8.0", - "@angular/cli": "~6.2.9", - "@angular/compiler-cli": "^6.1.0", - "@angular/language-service": "^6.1.0", - "@types/node": "~8.9.4", - "ts-node": "~7.0.0", - "tslint": "~5.11.0", - "typescript": "~2.9.2" - } -} diff --git a/demos/angular2/versions/package.json-ng7 b/demos/angular2/versions/package.json-ng7 deleted file mode 100644 index 841dab7..0000000 --- a/demos/angular2/versions/package.json-ng7 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular7", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~7.2.0", - "@angular/common": "~7.2.0", - "@angular/compiler": "~7.2.0", - - "@angular/core": "~7.2.0", - "@angular/forms": "~7.2.0", - - "@angular/platform-browser": "~7.2.0", - "@angular/platform-browser-dynamic": "~7.2.0", - - "@angular/router": "~7.2.0", - "core-js": "^2.5.4", - - "rxjs": "~6.3.3", - "tslib": "^1.9.0", - "zone.js": "~0.8.26" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.13.0", - "@angular/cli": "~7.3.10", - "@angular/compiler-cli": "~7.2.0", - "@angular/language-service": "~7.2.0", - "@types/node": "~8.9.4", - "ts-node": "~7.0.0", - "tslint": "~5.11.0", - "typescript": "~3.2.2" - } -} diff --git a/demos/angular2/versions/package.json-ng8 b/demos/angular2/versions/package.json-ng8 deleted file mode 100644 index 5643841..0000000 --- a/demos/angular2/versions/package.json-ng8 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular8", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~8.2.14", - "@angular/common": "~8.2.14", - "@angular/compiler": "~8.2.14", - - "@angular/core": "~8.2.14", - "@angular/forms": "~8.2.14", - - "@angular/platform-browser": "~8.2.14", - "@angular/platform-browser-dynamic": "~8.2.14", - - "@angular/router": "~8.2.14", - - - "rxjs": "~6.4.0", - "tslib": "^1.10.0", - "zone.js": "~0.9.1" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.803.29", - "@angular/cli": "~8.3.29", - "@angular/compiler-cli": "~8.2.14", - "@angular/language-service": "~8.2.14", - "@types/node": "~8.9.4", - "ts-node": "~7.0.0", - "tslint": "~5.15.0", - "typescript": "~3.5.3" - } -} diff --git a/demos/angular2/versions/package.json-ng9 b/demos/angular2/versions/package.json-ng9 deleted file mode 100644 index fe6c382..0000000 --- a/demos/angular2/versions/package.json-ng9 +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "angular9", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build" - }, - "private": true, - "dependencies": { - "@angular/animations": "~9.1.13", - "@angular/common": "~9.1.13", - "@angular/compiler": "~9.1.13", - - "@angular/core": "~9.1.13", - "@angular/forms": "~9.1.13", - - "@angular/platform-browser": "~9.1.13", - "@angular/platform-browser-dynamic": "~9.1.13", - - "@angular/router": "~9.1.13", - - - "rxjs": "~6.5.4", - "tslib": "^1.10.0", - "zone.js": "~0.10.2" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.901.15", - "@angular/cli": "~9.1.15", - "@angular/compiler-cli": "~9.1.13", - - "@types/node": "^12.11.1", - "ts-node": "~8.3.0", - "tslint": "~6.1.0", - "typescript": "~3.8.3" - } -} diff --git a/demos/angular2/versions/polyfills.ts-ng10 b/demos/angular2/versions/polyfills.ts-ng10 deleted file mode 100644 index 741c886..0000000 --- a/demos/angular2/versions/polyfills.ts-ng10 +++ /dev/null @@ -1 +0,0 @@ -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng11 b/demos/angular2/versions/polyfills.ts-ng11 deleted file mode 100644 index 741c886..0000000 --- a/demos/angular2/versions/polyfills.ts-ng11 +++ /dev/null @@ -1 +0,0 @@ -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng12 b/demos/angular2/versions/polyfills.ts-ng12 deleted file mode 100644 index aa09a9f..0000000 --- a/demos/angular2/versions/polyfills.ts-ng12 +++ /dev/null @@ -1 +0,0 @@ -import 'zone.js'; diff --git a/demos/angular2/versions/polyfills.ts-ng13 b/demos/angular2/versions/polyfills.ts-ng13 deleted file mode 100644 index aa09a9f..0000000 --- a/demos/angular2/versions/polyfills.ts-ng13 +++ /dev/null @@ -1 +0,0 @@ -import 'zone.js'; diff --git a/demos/angular2/versions/polyfills.ts-ng2 b/demos/angular2/versions/polyfills.ts-ng2 deleted file mode 100644 index 2143ebf..0000000 --- a/demos/angular2/versions/polyfills.ts-ng2 +++ /dev/null @@ -1,3 +0,0 @@ -import 'core-js/es6/reflect'; -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng4 b/demos/angular2/versions/polyfills.ts-ng4 deleted file mode 100644 index 2143ebf..0000000 --- a/demos/angular2/versions/polyfills.ts-ng4 +++ /dev/null @@ -1,3 +0,0 @@ -import 'core-js/es6/reflect'; -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng5 b/demos/angular2/versions/polyfills.ts-ng5 deleted file mode 100644 index 2143ebf..0000000 --- a/demos/angular2/versions/polyfills.ts-ng5 +++ /dev/null @@ -1,3 +0,0 @@ -import 'core-js/es6/reflect'; -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng6 b/demos/angular2/versions/polyfills.ts-ng6 deleted file mode 100644 index 2143ebf..0000000 --- a/demos/angular2/versions/polyfills.ts-ng6 +++ /dev/null @@ -1,3 +0,0 @@ -import 'core-js/es6/reflect'; -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng7 b/demos/angular2/versions/polyfills.ts-ng7 deleted file mode 100644 index 2143ebf..0000000 --- a/demos/angular2/versions/polyfills.ts-ng7 +++ /dev/null @@ -1,3 +0,0 @@ -import 'core-js/es6/reflect'; -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng8 b/demos/angular2/versions/polyfills.ts-ng8 deleted file mode 100644 index 741c886..0000000 --- a/demos/angular2/versions/polyfills.ts-ng8 +++ /dev/null @@ -1 +0,0 @@ -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/polyfills.ts-ng9 b/demos/angular2/versions/polyfills.ts-ng9 deleted file mode 100644 index 741c886..0000000 --- a/demos/angular2/versions/polyfills.ts-ng9 +++ /dev/null @@ -1 +0,0 @@ -import 'zone.js/dist/zone'; diff --git a/demos/angular2/versions/tsconfig.app.json-ng10 b/demos/angular2/versions/tsconfig.app.json-ng10 deleted file mode 100644 index f758d98..0000000 --- a/demos/angular2/versions/tsconfig.app.json-ng10 +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/demos/angular2/versions/tsconfig.app.json-ng11 b/demos/angular2/versions/tsconfig.app.json-ng11 deleted file mode 100644 index f758d98..0000000 --- a/demos/angular2/versions/tsconfig.app.json-ng11 +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/demos/angular2/versions/tsconfig.app.json-ng12 b/demos/angular2/versions/tsconfig.app.json-ng12 deleted file mode 100644 index f758d98..0000000 --- a/demos/angular2/versions/tsconfig.app.json-ng12 +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/demos/angular2/versions/tsconfig.app.json-ng13 b/demos/angular2/versions/tsconfig.app.json-ng13 deleted file mode 100644 index f758d98..0000000 --- a/demos/angular2/versions/tsconfig.app.json-ng13 +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/demos/angular2/versions/tsconfig.app.json-ng8 b/demos/angular2/versions/tsconfig.app.json-ng8 deleted file mode 100644 index 565a11a..0000000 --- a/demos/angular2/versions/tsconfig.app.json-ng8 +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "src/test.ts", - "src/**/*.spec.ts" - ] -} diff --git a/demos/angular2/versions/tsconfig.app.json-ng9 b/demos/angular2/versions/tsconfig.app.json-ng9 deleted file mode 100644 index f758d98..0000000 --- a/demos/angular2/versions/tsconfig.app.json-ng9 +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ] -} diff --git a/demos/function/.eslintrc b/demos/function/.eslintrc deleted file mode 100644 index dbf6551..0000000 --- a/demos/function/.eslintrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "env": { "shared-node-browser":true }, - "parserOptions": { - "ecmaVersion": 8 - }, - "plugins": [ "html", "json" ] -} diff --git a/demos/function/AzureHTTPTrigger/function.json b/demos/function/AzureHTTPTrigger/function.json deleted file mode 100644 index 7c64ea6..0000000 --- a/demos/function/AzureHTTPTrigger/function.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "disabled": false, - "bindings": [ - { - "authLevel": "function", - "type": "httpTrigger", - "direction": "in", - "dataType": "binary", - "name": "req" - }, - { - "type": "http", - "direction": "out", - "name": "res" - } - ] -} diff --git a/demos/function/AzureHTTPTrigger/index.js b/demos/function/AzureHTTPTrigger/index.js deleted file mode 100644 index c39d77c..0000000 --- a/demos/function/AzureHTTPTrigger/index.js +++ /dev/null @@ -1,44 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -/* eslint-env node */ -// base64 sheetjs.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost:7262/api/AzureHTTPTrigger - -const XLSX = require('xlsx'); -const formidable = require('formidable'); -const Readable = require('stream').Readable; -var fs = require('fs'); - -/* formidable expects the request object to be a stream */ -const streamify = (req) => { - if(typeof req.on !== 'undefined') return req; - const s = new Readable(); - s._read = ()=>{}; - s.push(new Buffer(req.body)); - s.push(null); - Object.assign(s, req); - return s; -}; - -module.exports = (context, req) => { - const form = new formidable.IncomingForm(); - form.parse(streamify(req), (err, fields, files) => { - /* grab the first file */ - var f = Object.values(files)[0]; - if(!f) { - context.res = { status: 400, body: "Must submit a file for processing!" }; - } else { - /* file is stored in a temp directory, so we can point to that and read it */ - const wb = XLSX.read(f.path, {type:"file"}); - - /* convert to specified output type -- default CSV */ - const ext = (fields.bookType || "csv").toLowerCase(); - const out = XLSX.write(wb, {type:"string", bookType:ext}); - - context.res = { - status: 200, - headers: { "Content-Disposition": `attachment; filename="download.${ext}";` }, - body: out - }; - } - context.done(); - }); -}; diff --git a/demos/function/Firebase/.gitignore b/demos/function/Firebase/.gitignore deleted file mode 100644 index f9ed3da..0000000 --- a/demos/function/Firebase/.gitignore +++ /dev/null @@ -1,65 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -firebase-debug.log* - -# Firebase cache -.firebase/ - -# Firebase config - -# Uncomment this if you'd like others to create their own Firebase project. -# For a team working on the same Firebase project(s), it is recommended to leave -# it commented so all members can deploy to the same project(s) in .firebaserc. -.firebaserc - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env diff --git a/demos/function/Firebase/firebase.json b/demos/function/Firebase/firebase.json deleted file mode 100644 index 0967ef4..0000000 --- a/demos/function/Firebase/firebase.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/demos/function/Firebase/functions/.gitignore b/demos/function/Firebase/functions/.gitignore deleted file mode 100644 index 40b878d..0000000 --- a/demos/function/Firebase/functions/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ \ No newline at end of file diff --git a/demos/function/Firebase/functions/index.js b/demos/function/Firebase/functions/index.js deleted file mode 100644 index d14b499..0000000 --- a/demos/function/Firebase/functions/index.js +++ /dev/null @@ -1,39 +0,0 @@ -const functions = require('firebase-functions'); -const Busboy = require('busboy'); -const XLSX = require('xlsx'); - -// // Create and Deploy Your First Cloud Functions -// // https://firebase.google.com/docs/functions/write-firebase-functions -// -exports.helloWorld = functions.https.onRequest((request, response) => { - response.send("Hello from Firebase!"); -}); - -exports.main = functions.https.onRequest((req, res) => { - var bb = new Busboy({ - headers: { - 'content-type': req.headers['content-type'] - } - }); - let fields = {}; - let files = {}; - bb.on('field', (fieldname, val) => { - fields[fieldname] = val; - }); - bb.on('file', (fieldname, file, filename) => { - var buffers = []; - file.on('data', (data) => { - buffers.push(data); - }); - file.on('end', () => { - files[fieldname] = [Buffer.concat(buffers), filename]; - }); - }); - bb.on('finish', () => { - let f = files[Object.keys(files)[0]]; - const wb = XLSX.read(f[0], { type: "buffer" }); - // Convert to CSV - res.send(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); - }); - bb.end(req.body) -}); diff --git a/demos/function/Firebase/functions/package.json b/demos/function/Firebase/functions/package.json deleted file mode 100644 index 53238b4..0000000 --- a/demos/function/Firebase/functions/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "functions", - "description": "Cloud Functions for Firebase", - "scripts": { - "serve": "firebase emulators:start --only functions", - "shell": "firebase functions:shell", - "start": "npm run shell", - "deploy": "firebase deploy --only functions", - "logs": "firebase functions:log" - }, - "engines": { - "node": "8" - }, - "dependencies": { - "busboy": "^0.3.1", - "firebase-admin": "^8.6.0", - "firebase-functions": "^3.3.0", - "xlsx": "^0.16.2" - }, - "devDependencies": { - "firebase-functions-test": "^0.1.6" - }, - "private": true -} diff --git a/demos/function/LambdaProxy/index.js b/demos/function/LambdaProxy/index.js deleted file mode 100644 index 5d82404..0000000 --- a/demos/function/LambdaProxy/index.js +++ /dev/null @@ -1,40 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -/* eslint-env node */ -// base64 sheetjs.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost:3000/LambdaProxy - -'use strict'; -var XLSX = require('xlsx'); -var Busboy = require('busboy'); - -exports.handler = function(event, context, callback) { - /* set up busboy */ - var ctype = event.headers['Content-Type']||event.headers['content-type']; - var bb = new Busboy({headers:{'content-type':ctype}}); - - /* busboy is evented; accumulate the fields and files manually */ - var fields = {}, files = {}; - bb.on('error', function(err) { console.log('err', err); callback(err); }); - bb.on('field', function(fieldname, val) {fields[fieldname] = val }); - bb.on('file', function(fieldname, file, filename) { - /* concatenate the individual data buffers */ - var buffers = []; - file.on('data', function(data) { buffers.push(data); }); - file.on('end', function() { files[fieldname] = [Buffer.concat(buffers), filename]; }); - }); - - /* on the finish event, all of the fields and files are ready */ - bb.on('finish', function() { - /* grab the first file */ - var f = files[Object.keys(files)[0]]; - if(!f) callback(new Error("Must submit a file for processing!")); - - /* f[0] is a buffer, convert to string and interpret as Base64 */ - var wb = XLSX.read(f[0].toString(), {type:"base64"}); - - /* grab first worksheet and convert to CSV */ - var ws = wb.Sheets[wb.SheetNames[0]]; - callback(null, { body: XLSX.utils.sheet_to_csv(ws) }); - }); - - bb.end(event.body); -}; diff --git a/demos/function/LambdaProxy/template.yaml b/demos/function/LambdaProxy/template.yaml deleted file mode 100644 index 43ef45a..0000000 --- a/demos/function/LambdaProxy/template.yaml +++ /dev/null @@ -1,18 +0,0 @@ -AWSTemplateFormatVersion : '2010-09-09' -Transform: AWS::Serverless-2016-10-31 - -Description: Sample Lambda API Gateway Normalizer -Resources: - LambdaProxy: - Type: AWS::Serverless::Function - Properties: - Runtime: nodejs6.10 - Handler: index.handler - BinaryMediaTypes: '*/*' - Events: - Api: - Type: Api - Properties: - Path: /LambdaProxy - Method: any - BinaryMediaTypes: '*/*' diff --git a/demos/function/Makefile b/demos/function/Makefile deleted file mode 100644 index 1588319..0000000 --- a/demos/function/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -.PHONY: aws -aws: lambda-proxy - -.PHONY: lambda-proxy -lambda-proxy: - cd LambdaProxy; mkdir -p node_modules; npm install https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz busboy; sam local start-api; cd - - -.PHONY: init-azure -init-azure: - cd AzureHTTPTrigger; mkdir -p node_modules; npm install https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz formidable fs - -.PHONY: azure -azure: init-azure - func start - -.PHONY: azure-server -azure-server: - mkdir -p /tmp/azurite - azurite -l /tmp/azurite - -FILES=$(filter-out xlsx.full.min.js,$(wildcard *.js)) $(wildcard *.html) -.PHONY: lint -lint: $(FILES) - eslint $(FILES) - -.PHONY: clean -clean: - rm -f *.db *.xlsx *.csv diff --git a/demos/function/README.md b/demos/function/README.md index c5cd76a..238afbc 100644 --- a/demos/function/README.md +++ b/demos/function/README.md @@ -1,113 +1,9 @@ # "Serverless" Functions -Because the library is pure JS, the hard work of reading and writing files can -be performed in the client browser or on the server side. On the server side, -the mechanical process is essentially independent from the data parsing or -generation. As a result, it is sometimes sensible to organize applications so -that the "last mile" conversion between JSON data and spreadsheet files is -independent from the main application. +Cloud services are covered in separate demos: -The straightforward architecture would split off the JSON data conversion as a -separate microservice or application. Since it is only needed when an import or -export is requested, and since the process itself is relatively independent from -the rest of a typical service, a "Serverless" architecture makes a great fit. -Since the "function" is separate from the rest of the application, it can be -integrated into a platform built in Java or Go or Python or another language! +- [AWS](https://docs.sheetjs.com/docs/demos/aws) +- [Azure](https://docs.sheetjs.com/docs/demos/azure) -This demo discusses general architectures and provides examples for popular -commercial systems and self-hosted alternatives. The examples are merely -intended to demonstrate very basic functionality. +[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) - -## Simple Strategies - -#### Data Normalization - -Most programming languages and platforms can process CSV or JSON but can't use -XLS or XLSX or XLSB directly. Form data from an HTTP POST request can be parsed -and contained files can be converted to CSV or JSON. The `XLSX.stream.to_csv` -utility can stream rows to a standard HTTP response. `XLSX.utils.sheet_to_json` -can generate an array of objects that can be fed to another service. - -At the simplest level, a file on the filesystem can be converted using the bin -script that ships with the NodeJS package: - -```bash -$ xlsx /path/to/uploads/file > /tmp/new_csv_file -``` - -From a utility script, workbooks can be converted in two lines: - -```js -var workbook = XLSX.readFile("path/to/file.xlsb"); -XLSX.writeFile(workbook, "output/path/file.csv"); -``` - -#### Report Generation - -For an existing platform that already generates JSON or CSV or HTML output, the -library can process the data and generate a new file with embellishments. The -`XLSX.utils.sheet_add_json` and `XLSX.utils.sheet_add_aoa` functions can add -data rows to an existing worksheet: - -```js -var ws = XLSX.utils.aoa_to_sheet([ - ["Company Report"], - [], - ["Item", "Cost"] -]); -XLSX.utils.sheet_add_json(ws, [ - { item: "Coffee", cost: 5 }, - { item: "Cake", cost: 20 } -], { skipHeader: true, origin: -1, header: ["item", "cost"] }); -``` - - -## Deployment Targets - -The library is supported in Node versions starting from `0.8` as well as a -myriad of ES3 and ES5 compatible JS engines. All major services use Node -versions beyond major release 4, so there should be no problem directly using -the library in those environments. - -Note that most cloud providers proactively convert form data to UTF8 strings. -This is especially problematic when dealing with XLSX and XLSB files, as they -naturally contain codes that are not valid UTF8 characters. As a result, these -demos specifically handle Base64-encoded files only. To test on the command -line, use the `base64` tool to encode data before piping to `curl`: - -``` -base64 test.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost/ -``` - -#### AWS Lambda - -Through the AWS Gateway API, Lambda functions can be triggered on HTTP requests. -The `LambdaProxy` example reads files from form data and converts to CSV. - -When deploying on AWS, be sure to `npm install` locally and include the modules -in the ZIP file. - -When reading form data, be sure to include the necessary binary types on the AWS API Gateway console. -To do this, navigate to the "Binary Media Types" section in the settings tab of the console. -For reading a file, you may need to add `"multipart/form-data"`. -For downloading a file, you may need to add `"application/vnd.ms-excel"`. - -#### Azure Functions - -Azure supports many types of triggers. The `AzureHTTPTrigger` shows an example -HTTP trigger that converts the submitted file to CSV. - -When deploying on Azure, be sure to install the module from the remote console, -as described in the "Azure Functions JavaScript developer guide". - -#### Firebase Functions - -Firebase functions can be triggered via HTTP requests, similar to a REST API. -In the `Firebase` directory, the example function reads files sent through -HTTP and converts it to a CSV and sends the response in the form of a string. - -To run this demo locally, run `npm i -g firebase-tools` to install the -Firebase CLI and `npm i` to install the dependencies, then `firebase use --add` -to connect to an existing Firebase project. Run `firebase emulators:start` to -start the local server. diff --git a/demos/function/host.json b/demos/function/host.json deleted file mode 100644 index 81e35b7..0000000 --- a/demos/function/host.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "2.0" -} \ No newline at end of file diff --git a/demos/function/local.settings.json b/demos/function/local.settings.json deleted file mode 100644 index 755966e..0000000 --- a/demos/function/local.settings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "AzureWebJobsDashboard": "UseDevelopmentStorage=true" - }, - "Host": { - "LocalHttpPort": 7262, - "CORS": "*" - } -} diff --git a/demos/react/.gitignore b/demos/react/.gitignore deleted file mode 100644 index 228ee28..0000000 --- a/demos/react/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -SheetJS -.next -static/shim.js -public/shim.js diff --git a/demos/react/Makefile b/demos/react/Makefile deleted file mode 100644 index da556c3..0000000 --- a/demos/react/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -.PHONY: react -react: init ## Simple server for react and clones - python -mSimpleHTTPServer - -.PHONY: next -next: init ## next.js demo - next - -.PHONY: native -native: ## Build react-native project - bash ./native.sh - -.PHONY: ios -ios: native ## react-native ios sim - cd SheetJS; cd ios; pod install; cd -; react-native run-ios --simulator="iPhone X"; cd - - -.PHONY: android -android: native ## react-native android sim - cd SheetJS; react-native run-android; cd - - -.PHONY: init -init: ## set up node_modules and symlink - mkdir -p node_modules - cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd - diff --git a/demos/react/NOTES.md b/demos/react/NOTES.md deleted file mode 100644 index ca6238e..0000000 --- a/demos/react/NOTES.md +++ /dev/null @@ -1,22 +0,0 @@ -# Additional Notes - -## Java, React Native, Gradle versions - -This demo was tested and runs with React Native 0.62.2, Java 11, and Gradle -3.5.2. Running `make native` will invoke `native.sh`, which uses a fixed version -of React Native 0.62.2 to build and run the demo. - -Make sure you have the correct version of Java (11) installed, since 0.62.2 might -not work with newer versions of Java. - -## Common Issues - -``` -ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -``` - -Add `export JAVA_HOME=`, replacing `` with the location of -your Java install, to your `.bashrc` or any other shell that you are using. - - - diff --git a/demos/react/README.md b/demos/react/README.md index ffee578..428f391 100644 --- a/demos/react/README.md +++ b/demos/react/README.md @@ -1,154 +1,12 @@ # React -The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped -into web pages with script tags: +[The new demo](https://docs.sheetjs.com/docs/demos/react) has an updated +exposition for legacy and modern deployments alike. -```html - -``` +The ecosystem demos were grouped by type in the new demo site: -The library can also be imported directly from JSX code with: - -```js -import { read, utils, writeFileXLSX } from 'xlsx'; -``` - -This demo shows a simple React component transpiled in the browser using Babel -standalone library. Since there is no standard React table model, this demo -settles on the array of arrays approach. - - -Other scripts in this demo show: -- server-rendered React component (with `next.js`) -- `react-native` deployment for iOS and android -- [`react-data-grid` reading, modifying, and writing files](modify/) - -## How to run - -Run `make react` to run the browser demo for React, or run `make next` to run -the server-rendered demo using `next.js`. - -## Internal State - -The simplest state representation is an array of arrays. To avoid having the -table component depend on the library, the column labels are precomputed. The -state in this demo is shaped like the following object: - -```js -{ - cols: [{ name: "A", key: 0 }, { name: "B", key: 1 }, { name: "C", key: 2 }], - data: [ - [ "id", "name", "value" ], - [ 1, "sheetjs", 7262 ], - [ 2, "js-xlsx", 6969 ] - ] -} -``` - -`sheet_to_json` and `aoa_to_sheet` utility functions can convert between arrays -of arrays and worksheets: - -```js -/* convert from workbook to array of arrays */ -var first_worksheet = workbook.Sheets[workbook.SheetNames[0]]; -var data = XLSX.utils.sheet_to_json(first_worksheet, {header:1}); - -/* convert from array of arrays to workbook */ -var worksheet = XLSX.utils.aoa_to_sheet(data); -var new_workbook = XLSX.utils.book_new(); -XLSX.utils.book_append_sheet(new_workbook, worksheet, "SheetJS"); -``` - -The column objects can be generated with the `encode_col` utility function: - -```js -function make_cols(refstr/*:string*/) { - var o = []; - var range = XLSX.utils.decode_range(refstr); - for(var i = 0; i <= range.e.c; ++i) { - o.push({name: XLSX.utils.encode_col(i), key:i}); - } - return o; -} -``` - -## React Native - -[The new demo](https://docs.sheetjs.com/docs/demos/mobile#react-native) uses -up-to-date file I/O and file picker libraries. - -## Server-Rendered React Components with Next.js - -The demo reads from `public/sheetjs.xlsx`. HTML output is generated using -`XLSX.utils.sheet_to_html` and inserted with `dangerouslySetInnerHTML`: - -```jsx -export default function Index({html, type}) { return ( - // ... -
- // ... -); } -``` - -Next currently offers 3 general strategies for server-side data fetching: - -#### "Server-Side Rendering" using `getServerSideProps` - -`/getServerSideProps` reads the file on each request. The first worksheet is -converted to HTML: - -```js -export async function getServerSideProps() { - const wb = XLSX.readFile(path); - return { props: { - html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]) - }}; -} -``` - -#### "Static Site Generation" using `getStaticProps` - -`/getServerSideProps` reads the file at build time. The first worksheet is -converted to HTML: - -```js -export async function getStaticProps() { - const wb = XLSX.readFile(path); - return { props: { - html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]) - }}; -} -``` - -#### "Static Site Generation with Dynamic Routes" using `getStaticPaths` - -`/getStaticPaths` reads the file at build time and generates a list of sheets. - -`/sheets/[id]` uses `getStaticPaths` to generate a path per sheet index: - -```js -export async function getStaticPaths() { - const wb = XLSX.readFile(path); - return { - paths: wb.SheetNames.map((name, idx) => ({ params: { id: idx.toString() } })), - fallback: false - }; -} -``` - -It also uses `getStaticProps` for the actual HTML generation: - -```js -export async function getStaticProps(ctx) { - const wb = XLSX.readFile(path); - return { props: { - html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[ctx.params.id]]), - }}; -} -``` - -## Additional Notes - -Some additional notes can be found in [`NOTES.md`](NOTES.md). +- [server-rendered React components with `next.js`](https://docs.sheetjs.com/docs/demos/content#nextjs) is now part of "Content and Site Generation" +- [`react-native` deployment for iOS and android](https://docs.sheetjs.com/docs/demos/mobile#react-native) is now part of "iOS and Android Apps" +- [`react-data-grid` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demo/grid#react-data-grid) is now part of "Data Grids and UI" [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/react/index.html b/demos/react/index.html deleted file mode 100644 index 8487db4..0000000 --- a/demos/react/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - -SheetJS React Demo - - - - - - - - - - -
- - - - diff --git a/demos/react/modify/.gitignore b/demos/react/modify/.gitignore deleted file mode 100644 index 4d29575..0000000 --- a/demos/react/modify/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/demos/react/modify/README.md b/demos/react/modify/README.md deleted file mode 100644 index 97180e0..0000000 --- a/demos/react/modify/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# react-modify - -This demo shows import and export with the `react-data-grid` table component. - -In the project directory, you can run: - -```bash -$ npm install -$ npm start -``` diff --git a/demos/react/modify/package.json b/demos/react/modify/package.json deleted file mode 100644 index dde42e3..0000000 --- a/demos/react/modify/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "react-modify-demo", - "dependencies": { - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", - "react": "^17.0.2", - "react-data-grid": "^7.0.0-beta.11", - "react-dom": "^17.0.2", - "react-scripts": "4.0.3", - "typescript": "^4.1.2", - "xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/demos/react/modify/public/index.html b/demos/react/modify/public/index.html deleted file mode 100644 index aa069f2..0000000 --- a/demos/react/modify/public/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - React App - - - -
- - - diff --git a/demos/react/modify/src/components/App.tsx b/demos/react/modify/src/components/App.tsx deleted file mode 100644 index 7e979d5..0000000 --- a/demos/react/modify/src/components/App.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import React, { useState, ChangeEvent } from "react"; -import DataGrid, { TextEditor } from "react-data-grid"; -import { read, utils, WorkSheet, writeFile } from "xlsx"; - -import "../styles/App.css"; - -type Row = any[]; /*{ - [index: string]: string | number; -};*/ - -type Column = { - key: string; - name: string; - editor: typeof TextEditor; -}; - -type DataSet = { - [index: string]: WorkSheet; -}; - -function getRowsCols( - data: DataSet, - sheetName: string -): { - rows: Row[]; - columns: Column[]; -} { - const rows: Row[] = utils.sheet_to_json(data[sheetName], {header:1}); - let columns: Column[] = []; - - for (let row of rows) { - const keys: string[] = Object.keys(row); - - if (keys.length > columns.length) { - columns = keys.map((key) => { - return { key, name: utils.encode_col(+key), editor: TextEditor }; - }); - } - } - - return { rows, columns }; -} - -export default function App() { - const [rows, setRows] = useState([]); - const [columns, setColumns] = useState([]); - const [workBook, setWorkBook] = useState({} as DataSet); - const [sheets, setSheets] = useState([]); - const [current, setCurrent] = useState(""); - - const exportTypes = ["xlsx", "xlsb", "csv", "html"]; - - function selectSheet(name: string, reset = true) { - if(reset) workBook[current] = utils.json_to_sheet(rows, { - header: columns.map((col: Column) => col.key), - skipHeader: true - }); - - const { rows: new_rows, columns: new_columns } = getRowsCols(workBook, name); - - setRows(new_rows); - setColumns(new_columns); - setCurrent(name); - } - - async function handleFile(ev: ChangeEvent): Promise { - const file = await ev.target.files?.[0]?.arrayBuffer(); - const data = read(file); - - setWorkBook(data.Sheets); - setSheets(data.SheetNames); - } - - function saveFile(ext: string): void { - const wb = utils.book_new(); - - sheets.forEach((n) => { - utils.book_append_sheet(wb, workBook[n], n); - }); - - writeFile(wb, "sheet." + ext); - } - - return ( - <> - -
- {sheets.map((sheet) => ( - - ))} -
-
- Current Sheet: {current} -
- -
- {exportTypes.map((ext) => ( - - ))} -
- - ); -} diff --git a/demos/react/modify/src/index.tsx b/demos/react/modify/src/index.tsx deleted file mode 100644 index 270ed1a..0000000 --- a/demos/react/modify/src/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './components/App'; - -import './styles/index.css'; - -ReactDOM.render( - - - , - document.getElementById('root') -); diff --git a/demos/react/modify/src/react-app-env.d.ts b/demos/react/modify/src/react-app-env.d.ts deleted file mode 100644 index 6431bc5..0000000 --- a/demos/react/modify/src/react-app-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/demos/react/modify/src/styles/App.css b/demos/react/modify/src/styles/App.css deleted file mode 100644 index 28b9df9..0000000 --- a/demos/react/modify/src/styles/App.css +++ /dev/null @@ -1,14 +0,0 @@ -input { - margin: 0.5rem; -} - -.flex-cont { - display: flex; - margin: 0.5rem; - justify-content: center; -} - -.flex-cont button { - margin: 0.3rem; - padding: 0.2rem; -} diff --git a/demos/react/modify/src/styles/index.css b/demos/react/modify/src/styles/index.css deleted file mode 100644 index 1532074..0000000 --- a/demos/react/modify/src/styles/index.css +++ /dev/null @@ -1,8 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/demos/react/modify/tsconfig.json b/demos/react/modify/tsconfig.json deleted file mode 100644 index 5136b52..0000000 --- a/demos/react/modify/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, - "include": [ - "src" - ] -} diff --git a/demos/react/nexthdr.js b/demos/react/nexthdr.js deleted file mode 100644 index 1ba3dc6..0000000 --- a/demos/react/nexthdr.js +++ /dev/null @@ -1,3 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -import * as XLSX from 'xlsx'; -import React from 'react'; diff --git a/demos/react/pages/getServerSideProps.js b/demos/react/pages/getServerSideProps.js deleted file mode 100644 index 55cd11f..0000000 --- a/demos/react/pages/getServerSideProps.js +++ /dev/null @@ -1,32 +0,0 @@ -import Head from 'next/head'; -import { readFile, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; - -export default function Index({html, type}) { return ( -
- - - SheetJS Next.JS {type} Demo - - - -
-

SheetJS Next.JS {type} Demo

-This demo reads from /public/sheetjs.xlsx and generates HTML from the first sheet. -
-
-
-); } - -export async function getServerSideProps() { - const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")) - return { - props: { - type: "getStaticProps", - html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]), - }, - } -} \ No newline at end of file diff --git a/demos/react/pages/getStaticPaths.js b/demos/react/pages/getStaticPaths.js deleted file mode 100644 index 3852295..0000000 --- a/demos/react/pages/getStaticPaths.js +++ /dev/null @@ -1,38 +0,0 @@ -import Head from 'next/head'; -import Link from "next/link"; -import { readFile, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; - -export default function Index({snames, type}) { return ( -
- - - SheetJS Next.JS {type} Demo - - - -
-

SheetJS Next.JS {type} Demo

-This demo reads from /public/sheetjs.xlsx. Each worksheet maps to a path:

-{snames.map((sname, idx) => (<> - {`Sheet index=${idx} name="${sname}"`} -
-
-))} - -
-
-); } - -export async function getStaticProps() { - const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")) - return { - props: { - type: "getStaticPaths", - snames: wb.SheetNames, - }, - } -} \ No newline at end of file diff --git a/demos/react/pages/getStaticProps.js b/demos/react/pages/getStaticProps.js deleted file mode 100644 index ca2e304..0000000 --- a/demos/react/pages/getStaticProps.js +++ /dev/null @@ -1,32 +0,0 @@ -import Head from 'next/head'; -import { readFile, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; - -export default function Index({html, type}) { return ( -
- - - SheetJS Next.JS {type} Demo - - - -
-

SheetJS Next.JS {type} Demo

-This demo reads from /public/sheetjs.xlsx and generates HTML from the first sheet. -
-
-
-); } - -export async function getStaticProps() { - const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")) - return { - props: { - type: "getStaticProps", - html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]), - }, - } -} \ No newline at end of file diff --git a/demos/react/pages/index.js b/demos/react/pages/index.js deleted file mode 100644 index c93bccd..0000000 --- a/demos/react/pages/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import Head from 'next/head'; - -export default function Index() { return ( -
- - - SheetJS Next.JS Demo - - - -
-

SheetJS Next.JS Demos

-All demos read from /public/sheetjs.xlsx.
-
-- getStaticProps
-
-- getServerSideProps
-
-- getStaticPaths
-
-
-); } \ No newline at end of file diff --git a/demos/react/pages/sheets/[id].js b/demos/react/pages/sheets/[id].js deleted file mode 100644 index 530b675..0000000 --- a/demos/react/pages/sheets/[id].js +++ /dev/null @@ -1,51 +0,0 @@ -import Head from 'next/head'; -import { readFile, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; - -export default function Index({html, type, name}) { return ( -
- - - SheetJS Next.JS {type} Demo - - - -
-

SheetJS Next.JS {type} Demo

-This demo reads from /public/sheetjs.xlsx.
-
-{name} -
-
-
-); } - -let cache = []; - -export async function getStaticProps(ctx) { - if(!cache || !cache.length) { - const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")); - cache = wb.SheetNames.map((name) => ({ name, sheet: wb.Sheets[name] })); - } - const entry = cache[ctx.params.id]; - return { - props: { - type: "getStaticPaths", - name: entry.name, - id: ctx.params.id.toString(), - html: entry.sheet ? utils.sheet_to_html(entry.sheet) : "", - }, - } -} - -export async function getStaticPaths() { - const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")); - cache = wb.SheetNames.map((name) => ({ name, sheet: wb.Sheets[name] })); - return { - paths: wb.SheetNames.map((name, idx) => ({ params: { id: idx.toString() } })), - fallback: false, - }; -} diff --git a/demos/react/public/sheetjs.xlsx b/demos/react/public/sheetjs.xlsx deleted file mode 100644 index 25496b9bf02e58b00d3610e257610798bf251d21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10328 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 UEDV@w007d@ADFD%)Ib0IA7+oOumAu6 diff --git a/demos/react/sheetjs.js b/demos/react/sheetjs.js deleted file mode 100644 index cdb0237..0000000 --- a/demos/react/sheetjs.js +++ /dev/null @@ -1,144 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -/* Notes: - - usage: `ReactDOM.render( , document.getElementById('app') );` - - xlsx.full.min.js is loaded in the head of the HTML page - - this script should be referenced with type="text/babel" - - babel.js in-browser transpiler should be loaded before this script -*/ -function SheetJSApp() { - const [data, setData] = React.useState([]); - const [cols, setCols] = React.useState([]); - - const handleFile = (file) => { - const reader = new FileReader(); - reader.onload = (e) => { - /* Parse data */ - const ab = e.target.result; - const wb = XLSX.read(ab, {type:'array'}); - /* Get first worksheet */ - const wsname = wb.SheetNames[0]; - const ws = wb.Sheets[wsname]; - /* Convert array of arrays */ - const data = XLSX.utils.sheet_to_json(ws, {header:1}); - /* Update state */ - setData(data); - setCols(make_cols(ws['!ref'])) - }; - reader.readAsArrayBuffer(file); - } - - const exportFile = () => { - /* convert state to workbook */ - const ws = XLSX.utils.aoa_to_sheet(data); - const wb = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(wb, ws, "SheetJS"); - /* generate XLSX file and send to client */ - XLSX.writeFile(wb, "sheetjs.xlsx") - }; - - return ( - -
- -
-
- -
-
- -
-
- ); -} - -if(typeof module !== 'undefined') module.exports = SheetJSApp - -/* -------------------------------------------------------------------------- */ - -/* - Simple HTML5 file drag-and-drop wrapper - usage: ... - handleFile(file:File):void; -*/ - -function DragDropFile({ handleFile, children }) { - const suppress = (e) => { e.stopPropagation(); e.preventDefault(); }; - const handleDrop = (e) => { e.stopPropagation(); e.preventDefault(); - const files = e.dataTransfer.files; - if(files && files[0]) handleFile(files[0]); - }; - - return ( -
- {children} -
- ); -} - -/* - Simple HTML5 file input wrapper - usage: - handleFile(file:File):void; -*/ - -function DataInput({ handleFile }) { - const handleChange = (e) => { - const files = e.target.files; - if(files && files[0]) handleFile(files[0]); - }; - - return ( -
-
- -
- -
-
- ) -} - -/* - Simple HTML Table - usage: - data:Array >; - cols:Array<{name:string, key:number|string}>; -*/ -function OutTable({ data, cols }) { - return ( -
- - - {cols.map((c) => )} - - - {data.map((r,i) => - {cols.map(c => )} - )} - -
{c.name}
{ r[c.key] }
-
- ); -} - -/* list of supported file types */ -const SheetJSFT = [ - "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm" -].map(x => `.${x}`).join(","); - -/* generate an array of column objects */ -const make_cols = refstr => { - let o = [], C = XLSX.utils.decode_range(refstr).e.c + 1; - for(var i = 0; i < C; ++i) o[i] = {name:XLSX.utils.encode_col(i), key:i} - return o; -}; diff --git a/demos/server/.gitignore b/demos/server/.gitignore deleted file mode 100644 index 0bb4e01..0000000 --- a/demos/server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -xlsx.full.min.js -xlsx-demo diff --git a/demos/server/Makefile b/demos/server/Makefile deleted file mode 100644 index 9a340b6..0000000 --- a/demos/server/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -.PHONY: init -init: - mkdir -p node_modules - cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd - - -.PHONY: request -request: init ## request demo - node _request.js - -.PHONY: express -express: init ## express demo - node express.js - -.PHONY: koa -koa: init ## koa demo - node koa.js - -.PHONY: hapi -hapi: init ## hapi demo - cp ../../dist/xlsx.full.min.js . - node hapi.js - -.PHONY: nest -nest: init ## nest demo - bash -c ./nest.sh - -.PHONY: drash -drash: ## drash demo - deno run --allow-net drash.ts diff --git a/demos/server/README.md b/demos/server/README.md index 41df3fd..4f03372 100644 --- a/demos/server/README.md +++ b/demos/server/README.md @@ -1,208 +1,11 @@ # NodeJS Server Deployments -This library is 100% pure JS. This is great for compatibility but tends to lock -up long-running processes. In the web browser, Web Workers are used to offload -work from the main browser thread. In NodeJS, there are other strategies. This -demo shows a few different strategies applied to different server frameworks. +[The new demo](https://docs.sheetjs.com/docs/demos/server) has a more focused +discussion with examples for popular JS server-side frameworks. -NOTE: these examples merely demonstrate the core concepts and do not include -appropriate error checking or other production-level features. - - -### Express Setup - -The following commands are required in order to test the [Express](https://github.com/expressjs/express) demo: - -```bash -npm install express printj express-formidable https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz -node express.js -``` - -### Koa Setup - -The following commands are required in order to test the [Koa](https://github.com/koajs/koa) demo: - -```bash -npm install koa printj formidable https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz -node koa.js -``` - -### Hapi Setup - -**Note: Hapi demo as written only works with Hapi version 16 and below.** - -The following commands are required in order to test the [Hapi](https://github.com/hapijs/hapi) demo: - -```bash -npm install hapi@16.x printj tiny-worker https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz -node hapi.js -``` - - - -### Node Buffer - -The `read` and `write` functions can handle `Buffer` data with `type:"buffer"`. -For example, the `request` library returns data in a buffer: - -```js -var XLSX = require('xlsx'), request = require('request'); -request(url, {encoding: null}, function(err, res, data) { - if(err || res.statusCode !== 200) return; - - /* data is a node Buffer that can be passed to XLSX.read */ - var workbook = XLSX.read(data, {type:'buffer'}); - - /* DO SOMETHING WITH workbook HERE */ -}); -``` - -The `readFile` / `writeFile` functions wrap `fs.{read,write}FileSync`: - -```js -/* equivalent to `var wb = XLSX.readFile("sheetjs.xlsx");` */ -var buf = fs.readFileSync("sheetjs.xlsx"); -var wb = XLSX.read(buf, {type:'buffer'}); -``` - -### Responding to Form Uploads - -Using `formidable`, files uploaded to forms are stored to temporary files that -can be read with `readFile`: - -```js -/* within the server callback function(request, response) { */ -var form = new formidable.IncomingForm(); -form.parse(req, function(err, fields, files) { - var f = files[Object.keys(files)[0]]; - var workbook = XLSX.readFile(f.path); - /* DO SOMETHING WITH workbook HERE */ -}); -``` - -The `node.js` demo shows a plain HTTP server that accepts file uploads and -converts data to requested output format. - -### Example servers - -Each example server is expected to hold an array-of-arrays in memory. They are -expected to handle: - -- `POST / ` accepts an encoded `file` and updates the internal storage -- `GET /?t=` returns the internal storage in the specified type -- `POST /?f=` reads the local file and updates the internal storage -- `GET /?f=` writes the file to the specified name - -Testing with cURL is straightforward: - -```bash -# upload sheetjs.csv and update data -curl -X POST -F "data=@sheetjs.csv" http://localhost:7262/ -# download data in SYLK format -curl -X GET http://localhost:7262/?t=slk -# read sheetjs.csv from the server directory -curl -X POST http://localhost:7262/?f=sheetjs.csv -# write sheetjs.xlsb in the XLSB format -curl -X GET http://localhost:7262/?f=sheetjs.xlsb -``` - - -## Main-process logic with express - -The most straightforward approach is to handle the data directly in HTTP event -handlers. The `buffer` type for `XLSX.read` and `XLSX.write` work with `http` -module and with express directly. The following snippet generates a workbook -based on an array of arrays and sends it to the client: - -```js -function send_aoa_to_client(req, res, data, bookType) { - /* generate workbook */ - var ws = XLSX.utils.aoa_to_sheet(data); - var wb = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(wb, ws, "SheetJS"); - - /* generate buffer */ - var buf = XLSX.write(wb, {type:'buffer', bookType:bookType || "xlsx"}); - - /* send to client */ - res.status(200).send(buf); -} -``` - - -## fork with koa - -`child_process.fork` provides a light-weight and customizable way to offload -work from the main server process. This demo passes commands to a custom child -process and the child passes back buffers of data. - -The main server script is `koa.js` and the worker script is `koasub.js`. State -is maintained in the worker script. - - - -## tiny-worker with hapi - -`tiny-worker` provides a Web Worker-like interface. Binary strings and simple -objects are readily passed across the Worker divide. - -The main server script is `hapi.js` and the worker script is `worker.js`. State -is maintained in the server script. - -Note: due to an issue with hapi payload parsing, the route `POST /file` is used -to handle the case of reading from file, so the cURL test is: - -```bash -# upload sheetjs.csv and update data -curl -X POST -F "data=@sheetjs.csv" http://localhost:7262/ -# download data in SYLK format -curl -X GET http://localhost:7262/?t=slk -# read sheetjs.csv from the server directory -curl -X POST http://localhost:7262/file?f=sheetjs.csv -# write sheetjs.xlsb in the XLSB format -curl -X GET http://localhost:7262/?f=sheetjs.xlsb -``` - - - -## NestJS - -[NestJS](https://nestjs.com/) is a Node.js framework for server-side web applications. - -This demo uses SheetJS to parse a spreadsheet via a POST API endpoint. The file -arrives to the endpoint as body `form-data`, accessible using the `file` key. -After parsing the file, CSV contents of the first worksheet will be returned. -[Body parsing uses `multer`](https://docs.nestjs.com/techniques/file-upload). - -Before running the demo, the NestJS CLI tool must be installed. The instruction -is described in the NestJS ["First Steps"](https://docs.nestjs.com/first-steps): - -```bash -npm i -g @nestjs/cli -make nest -``` - -The demo can be tested using the `/sheetjs/upload-xlsx-file` endpoint: - -```bash -curl -X POST -F "file=@test.xlsx" http://localhost:3000/sheetjs/upload-xlsx-file -``` - -The included [`nest.sh`](./nest.sh) script creates and configures the project. - - -This demo creates a module and a controller. The controller handles the actual -requests (creating the endpoint) while the module is used to configure `multer`. - - - -## Deno - -[`Drash`](https://drash.land/drash/) is a Deno framework for Deno's HTTP server. - -The `drash.ts` demo responds to POST requests and responds with HTML previews. - - is a live deployment of the service. +Cloud services are covered in separate demos: +- [AWS](https://docs.sheetjs.com/docs/demos/aws) +- [Azure](https://docs.sheetjs.com/docs/demos/azure) [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/server/_cors.js b/demos/server/_cors.js deleted file mode 100644 index 22b04c2..0000000 --- a/demos/server/_cors.js +++ /dev/null @@ -1,4 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var cors = function(req, res) { res.header('Access-Control-Allow-Origin', '*'); }; -cors.mw = function(req, res, next) { cors(req, res); next(); }; -module.exports = cors; diff --git a/demos/server/_logit.js b/demos/server/_logit.js deleted file mode 100644 index 94f1a44..0000000 --- a/demos/server/_logit.js +++ /dev/null @@ -1,7 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var sprintf = require('printj').sprintf; -var logit = function(req, res) { - console.log(sprintf("%s %s %d", req.method, req.url, res.statusCode)); -}; -logit.mw = function(req, res, next) { logit(req, res); next(); } -module.exports = logit; diff --git a/demos/server/_request.js b/demos/server/_request.js deleted file mode 100644 index 1e3aee0..0000000 --- a/demos/server/_request.js +++ /dev/null @@ -1,9 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var XLSX = require('xlsx'), request = require('request'); -var url = 'http://www.freddiemac.com/pmms/2017/historicalweeklydata.xls' -request(url, {encoding: null}, function(err, res, data) { - if(err || res.statusCode !== 200) return; - var wb = XLSX.read(data, {type:'buffer'}); - var ws = wb.Sheets[wb.SheetNames[0]]; - console.log(XLSX.utils.sheet_to_csv(ws, {blankrows:false})); -}); diff --git a/demos/server/drash.ts b/demos/server/drash.ts deleted file mode 100644 index 5446b66..0000000 --- a/demos/server/drash.ts +++ /dev/null @@ -1,68 +0,0 @@ -/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ -// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts" -import { read, utils, 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 * as Drash from "https://deno.land/x/drash@v2.5.4/mod.ts"; - - -// Create your resource - -class HomeResource extends Drash.Resource { - public paths = ["/"]; - - public POST(request: Drash.Request, response: Drash.Response) { - const file = request.bodyParam("file"); - 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 { - 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" - - -
-
- -`, - ); - } -} - -// Create and run your server -const server = new Drash.Server({ - hostname: "", - port: 3000, - protocol: "http", - resources: [ - HomeResource, - ], -}); - -server.run(); - -console.log(`Server running at ${server.address}.`); - diff --git a/demos/server/express.js b/demos/server/express.js deleted file mode 100644 index 2b50552..0000000 --- a/demos/server/express.js +++ /dev/null @@ -1,65 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ - -var fs = require('fs'), path = require('path'), URL = require('url'); -var express = require('express'), app = express(); -var sprintf = require('printj').sprintf; -var logit = require('./_logit'); -var cors = require('./_cors'); -var data = "a,b,c\n1,2,3".split("\n").map(function(x) { return x.split(","); }); -var XLSX = require('xlsx'); - -/* helper to generate the workbook object */ -function make_book() { - var ws = XLSX.utils.aoa_to_sheet(data); - var wb = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(wb, ws, "SheetJS"); - return wb; -} - -function get_data(req, res, type) { - var wb = make_book(); - /* send buffer back */ - res.status(200).send(XLSX.write(wb, {type:'buffer', bookType:type})); -} - -function get_file(req, res, file) { - var wb = make_book(); - /* write using XLSX.writeFile */ - XLSX.writeFile(wb, file); - res.status(200).send("wrote to " + file + "\n"); -} - -function load_data(file) { - var wb = XLSX.readFile(file); - /* generate array of arrays */ - data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1}); - console.log(data); -} - -function post_data(req, res) { - var keys = Object.keys(req.files), k = keys[0]; - load_data(req.files[k].path); - res.status(200).send("ok\n"); -} - -function post_file(req, res, file) { - load_data(file); - res.status(200).send("ok\n"); -} -app.use(logit.mw); -app.use(cors.mw); -app.use(require('express-formidable')()); -app.get('/', function(req, res, next) { - var url = URL.parse(req.url, true); - if(url.query.t) return get_data(req, res, url.query.t); - else if(url.query.f) return get_file(req, res, url.query.f); - res.status(403).end("Forbidden"); -}); -app.post('/', function(req, res, next) { - var url = URL.parse(req.url, true); - if(url.query.f) return post_file(req, res, url.query.f); - return post_data(req, res); -}); - -var port = +process.argv[2] || +process.env.PORT || 7262; -app.listen(port, function() { console.log('Serving HTTP on port ' + port); }); diff --git a/demos/server/hapi.js b/demos/server/hapi.js deleted file mode 100644 index a9db56b..0000000 --- a/demos/server/hapi.js +++ /dev/null @@ -1,67 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var Hapi = require('hapi'), server = new Hapi.Server(); -var logit = require('./_logit'); -var Worker = require('tiny-worker'); -var fs = require('fs'); -var data = "a,b,c\n1,2,3".split("\n").map(x => x.split(",")); - -function get_data(req, res, type) { - var work = new Worker('worker.js'); - work.onmessage = function(e) { - if(e.data.err) console.log(e.data.err); - var buf = new Buffer(e.data.data, "binary"); - return res(buf); - }; - work.postMessage({action:"write", type:type, data:data}); -} - -function get_file(req, res, file) { - var work = new Worker('worker.js'); - work.onmessage = function(e) { - fs.writeFileSync(file, e.data.data, 'binary'); - return res("wrote to " + file + "\n"); - }; - work.postMessage({action:"write", file:file, data:data}); -} - -function post_file(req, res, file) { - var work = new Worker('worker.js'); - work.onmessage = function(e) { - data = e.data.data; - return res("read from " + file + "\n"); - }; - work.postMessage({action:"read", file:file}); -} - -function post_data(req, res, type) { - var keys = Object.keys(req.payload), k = keys[0]; - post_file(req, res, req.payload[k].path); -} - -var port = 7262; -server.connection({ host:'localhost', port: port}); - -server.route({ method: 'GET', path: '/', -handler: function(req, res) { - logit(req.raw.req, req.raw.res); - if(req.query.t) get_data(req, res, req.query.t); - else if(req.query.f) get_file(req, res, req.query.f); - else res('Forbidden').code(403); -}}); -server.route({ method: 'POST', path: '/', -config:{payload:{ output: 'file', parse: true, allow: 'multipart/form-data'}}, -handler: function(req, res) { - logit(req.raw.req, req.raw.res); - if(req.query.f) return post_file(req, res, req.query.f); - return post_data(req, res); -}}); -server.route({ method: 'POST', path: '/file', -handler: function(req, res) { - logit(req.raw.req, req.raw.res); - if(req.query.f) return post_file(req, res, req.query.f); - return post_data(req, res); -}}); -server.start(function(err) { - if(err) throw err; - console.log('Serving HTTP on port ' + port); -}); diff --git a/demos/server/koa.js b/demos/server/koa.js deleted file mode 100644 index 1f1176d..0000000 --- a/demos/server/koa.js +++ /dev/null @@ -1,79 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ - -const Koa = require('koa'), app = new Koa(); -const { sprintf } = require('printj'); -const { IncomingForm } = require('formidable'); -const { fork } = require('child_process'); -const logit = require('./_logit'); -const subprocess = fork('koasub.js'); - -const get_data = async (ctx, type) => { - await new Promise((resolve, reject) => { - const cb = (data) => { - ctx.response.body = Buffer(data); - subprocess.removeListener('message', cb); - resolve(); - }; - subprocess.on('message', cb); - subprocess.send(['get data', type]); - }); -}; - -const get_file = async (ctx, file) => { - await new Promise((resolve, reject) => { - const cb = (data) => { - ctx.response.body = Buffer(data); - subprocess.removeListener('message', cb); - resolve(); - }; - subprocess.on('message', cb); - subprocess.send(['get file', file]); - }); -}; - -const load_data = async (ctx, file) => { - await new Promise((resolve, reject) => { - const cb = (data) => { - ctx.response.body = "ok\n"; - subprocess.removeListener('message', cb); - resolve(); - }; - subprocess.on('message', cb); - subprocess.send(['load data', file]); - }); -}; - -const post_data = async (ctx) => { - const keys = Object.keys(ctx.request._files), k = keys[0]; - await load_data(ctx, ctx.request._files[k].path); -}; - -app.use(async (ctx, next) => { logit(ctx.req, ctx.res); await next(); }); -app.use(async (ctx, next) => { - const form = new IncomingForm(); - await new Promise((resolve, reject) => { - form.parse(ctx.req, (err, fields, files) => { - if(err) return reject(err); - ctx.request._fields = fields; - ctx.request._files = files; - resolve(); - }); - }); - await next(); -}); -app.use(async (ctx, next) => { - if(ctx.request.method !== 'GET') await next(); - else if(ctx.request.path !== '/') await next(); - else if(ctx.request.query.t) await get_data(ctx, ctx.request.query.t); - else if(ctx.request.query.f) await get_file(ctx, ctx.request.query.f); - else ctx.throw(403, "Forbidden"); -}); -app.use(async (ctx, next) => { - if(ctx.request.method !== 'POST') await next(); - else if(ctx.request.path !== '/') await next(); - else if(ctx.request.query.f) await load_data(ctx, ctx.request.query.f); - else await post_data(ctx); -}); - -const port = +process.argv[2] || +process.env.PORT || 7262; -app.listen(port, () => { console.log('Serving HTTP on port ' + port); }); diff --git a/demos/server/koasub.js b/demos/server/koasub.js deleted file mode 100644 index 1eeb989..0000000 --- a/demos/server/koasub.js +++ /dev/null @@ -1,39 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -const XLSX = require('xlsx'); -let data = "a,b,c\n1,2,3".split("\n").map(x => x.split(",")); -process.on('message', ([m, data] = _) => { - switch(m) { - case 'load data': load_data(data); break; - case 'get data': get_data(data); break; - case 'get file': get_file(data); break; - } -}); - -function load_data(file) { - var wb = XLSX.readFile(file); - /* generate array of arrays */ - data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {header:1}); - console.log(data); - process.send("done"); -} - -/* helper to generate the workbook object */ -function make_book() { - var ws = XLSX.utils.aoa_to_sheet(data); - var wb = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(wb, ws, "SheetJS"); - return wb; -} - -function get_data(type) { - var wb = make_book(); - /* send buffer back */ - process.send(XLSX.write(wb, {type:'buffer', bookType:type})); -} - -function get_file(file) { - var wb = make_book(); - /* write using XLSX.writeFile */ - XLSX.writeFile(wb, file); - process.send("wrote to " + file + "\n"); -} diff --git a/demos/server/nest.sh b/demos/server/nest.sh deleted file mode 100755 index ce3f07d..0000000 --- a/demos/server/nest.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# it is assumed that @nestjs/cli is installed globally - -if [ ! -e xlsx-demo ]; then - nest new -p npm xlsx-demo -fi - -cd xlsx-demo -npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz -npm i --save-dev @types/multer - -if [ ! -e src/sheetjs/sheetjs.module.ts ]; then - nest generate module sheetjs -fi - -if [ ! -e src/sheetjs/sheetjs.controller.ts ]; then - nest generate controller sheetjs -fi - -cp ../sheetjs.module.ts src/sheetjs/ -cp ../sheetjs.controller.ts src/sheetjs/ -mkdir -p upload -npm run start diff --git a/demos/server/nodejs.js b/demos/server/nodejs.js deleted file mode 100644 index 7b54d37..0000000 --- a/demos/server/nodejs.js +++ /dev/null @@ -1,84 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ - -var http = require('http'); -var XLSX = require('xlsx'); -var formidable = require('formidable'); -var html = ""; -var PORT = 3000; - -var extmap = {}; - -var server = http.createServer(function(req, res) { - if(req.method !== 'POST') return res.end(html); - var form = new formidable.IncomingForm(); - form.parse(req, function(err, fields, files) { - var f = files[Object.keys(files)[0]]; - var wb = XLSX.readFile(f.path); - var ext = (fields.bookType || "xlsx").toLowerCase(); - res.setHeader('Content-Disposition', 'attachment; filename="download.' + (extmap[ext] || ext) + '";'); - res.end(XLSX.write(wb, {type:"buffer", bookType:ext})); - }); -}).listen(PORT); - -html = [ -'
',
-'

SheetJS File Converter

', -'Upload a file to convert the contents to another format.', -'', -'Form Fields:', -'- bookType: output format type (defaults to "XLSX")', -'- basename: basename for output file (defaults to "download")', -'', -'
', -'', -'', -'', -'
', -'', -'Form code:', -'<form method="POST" enctype="multipart/form-data" action="/">', -'<input type="file" id="file" name="file"/>', -'<select name="bookType">', -'<!-- options here -->', -'</select>', -'<input type="submit" value="Submit Form">', -'</form>', -'', -'fetch Code:', -'var blob = new Blob("1,2,3\\n4,5,6".split("")); // original file', -'var fd = new FormData();', -'fd.set("data", blob, "foo.bar");', -'fd.set("bookType", "xlsb");', -'var res = await fetch("/", {method:"POST", body:fd});', -'var data = await res.arrayBuffer();', -'
' -].join("\n"); - -extmap = { - "biff2" : "xls", - "biff5" : "xls", - "biff8" : "xls", - "xlml" : "xls" -}; -console.log('listening on port ' + PORT); diff --git a/demos/server/sheetjs.controller.ts b/demos/server/sheetjs.controller.ts deleted file mode 100644 index bad90eb..0000000 --- a/demos/server/sheetjs.controller.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Controller, Logger, Post, UploadedFile, UseInterceptors } from '@nestjs/common'; -import { FileInterceptor } from '@nestjs/platform-express'; -import { readFile, utils } from 'xlsx'; - -@Controller('sheetjs') -export class SheetjsController { - private readonly logger = new Logger(SheetjsController.name); - - @Post('upload-xlsx-file') - @UseInterceptors(FileInterceptor('file')) - async uploadXlsxFile(@UploadedFile() file: Express.Multer.File) { - // Open the uploaded XLSX file and perform SheetJS operations - const workbook = readFile(file.path); - const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; - const output = utils.sheet_to_csv(firstSheet); - this.logger.log(output); - return output; - } -} diff --git a/demos/server/sheetjs.csv b/demos/server/sheetjs.csv deleted file mode 100644 index eddbf8a..0000000 --- a/demos/server/sheetjs.csv +++ /dev/null @@ -1,19 +0,0 @@ -Text,Number,Rich,Span -This is Bold,123,This is Bold,This is Bold -This is Italic,234,This is Italic,This is Italic -This is Underline,345,This is Underline,This is Underline -This is Stricken,456,This is Stricken,This is Stricken -This is 18 px,567,This is 18 px,This is 18 px -This is superscript,678,This is superscript,This is superscript -This is subscript,789,This is subscript,This is subscript -This is red,135,This is red,This is red -This is green,246,This is green,This is green -This is Times,357,This is Times,This is Times -This is BIU,159,This is 01324576 yes,This is BIU -BG Green,255,White on Blue,Green on Black -Standard Newline,W S,"BR -New line","Pre -New line" -Height,100,px (not pt),yeah -Top Left,80,Middle Center,Bottom Right -Top Right,60,Bottom Center,Bottom Left diff --git a/demos/server/sheetjs.module.ts b/demos/server/sheetjs.module.ts deleted file mode 100644 index 4dd9a53..0000000 --- a/demos/server/sheetjs.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Module } from '@nestjs/common'; -import { SheetjsController } from './sheetjs.controller'; -import { MulterModule } from '@nestjs/platform-express'; - -@Module({ - controllers: [SheetjsController], - imports: [ - MulterModule.register({ - dest: './upload', - }), - ], -}) -export class SheetjsModule {} diff --git a/demos/server/worker.js b/demos/server/worker.js deleted file mode 100644 index c8e1a63..0000000 --- a/demos/server/worker.js +++ /dev/null @@ -1,22 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var XLSX = require('xlsx'); -var fs = require('fs'); - -onmessage = function(e) { - try { switch(e.data.action) { - case 'write': - var ws = XLSX.utils.aoa_to_sheet(e.data.data); - var wb = XLSX.utils.book_new(); - XLSX.utils.book_append_sheet(wb, ws, "SheetJS"); - postMessage({data: XLSX.write(wb, {type:'binary', bookType:e.data.type || e.data.file.match(/\.([^\.]*)$/)[1]})}); - break; - case 'read': - var wb; - if(e.data.file) wb = XLSX.readFile(e.data.file); - else wb = XLSX.read(e.data.data); - var ws = wb.Sheets[wb.SheetNames[0]]; - postMessage({data: XLSX.utils.sheet_to_json(ws, {header:1})}); - break; - default: throw "unknown action"; - }} catch(e) { postMessage({err:e.message || e}); } -}; diff --git a/demos/vue/Makefile b/demos/vue/Makefile deleted file mode 100644 index 0adece9..0000000 --- a/demos/vue/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -.PHONY: vue -vue: ## Simple server for vue - python -mSimpleHTTPServer || python3 -mhttp.server diff --git a/demos/vue/README.md b/demos/vue/README.md index c364a8a..6229e41 100644 --- a/demos/vue/README.md +++ b/demos/vue/README.md @@ -1,83 +1,12 @@ # VueJS -The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped -into web pages with script tags: +[The new demo](https://docs.sheetjs.com/docs/demos/vue) has an updated +exposition for legacy and modern deployments alike. -```html - -``` +The ecosystem demos were grouped by type in the new demo site: -The library can also be imported directly from single-file components with: - -```js -// full import -import * as XLSX from 'xlsx'; - -// named imports -import { read, utils, writeFileXLSX } from 'xlsx'; -``` - -This demo directly generates HTML using `sheet_to_html` and adds an element to -a pre-generated template. It also has a button for exporting as XLSX. - -Other scripts in this demo show: -- server-rendered VueJS component (with `nuxt.js`) -- `weex` deployment for iOS - -## Internal State - -The plain JS demo embeds state in the DOM. Other demos use proper state. - -The simplest state representation is an array of arrays. To avoid having the -table component depend on the library, the column labels are precomputed. The -state in this demo is shaped like the following object: - -```js -{ - cols: [{ name: "A", key: 0 }, { name: "B", key: 1 }, { name: "C", key: 2 }], - data: [ - [ "id", "name", "value" ], - [ 1, "sheetjs", 7262 ], - [ 2, "js-xlsx", 6969 ] - ] -} -``` - -`sheet_to_json` and `aoa_to_sheet` utility functions can convert between arrays -of arrays and worksheets: - -```js -/* convert from workbook to array of arrays */ -var first_worksheet = workbook.Sheets[workbook.SheetNames[0]]; -var data = XLSX.utils.sheet_to_json(first_worksheet, {header:1}); - -/* convert from array of arrays to workbook */ -var worksheet = XLSX.utils.aoa_to_sheet(data); -var new_workbook = XLSX.utils.book_new(); -XLSX.utils.book_append_sheet(new_workbook, worksheet, "SheetJS"); -``` - -The column objects can be generated with the `encode_col` utility function: - -```js -function make_cols(refstr/*:string*/) { - var o = []; - var range = XLSX.utils.decode_range(refstr); - for(var i = 0; i <= range.e.c; ++i) { - o.push({name: XLSX.utils.encode_col(i), key:i}); - } - return o; -} -``` - -## Mobile Apps - -[The new demo](https://docs.sheetjs.com/docs/demos/mobile#quasar) uses the -Quasar Framework in a VueJS + Vite project to generate a native iOS app. - -## Nuxt Content - -[The new demo](https://docs.sheetjs.com/docs/demos/content#nuxtjs) includes a -complete example starting from `create-nuxt-app`. +- [Nuxt Content](https://docs.sheetjs.com/docs/demos/content#nuxtjs) is now part of "Content and Site Generation" +- [The new iOS app demo](https://docs.sheetjs.com/docs/demos/mobile#quasar) uses the Quasar Framework in a VueJS + Vite project to generate a native iOS app. +- [`vue3-table-lite` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demo/grid#vue3-table-lite) is now part of "Data Grids and UI" [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/vue/SheetJS-vue.js b/demos/vue/SheetJS-vue.js deleted file mode 100644 index a21d563..0000000 --- a/demos/vue/SheetJS-vue.js +++ /dev/null @@ -1,68 +0,0 @@ -/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var SheetJSFT = [ - "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm", "numbers" -].map(function(x) { return "." + x; }).join(","); - -var SJSTemplate = [ - '
', - '', - '
', - '', - '
', - '
', - '
' -].join(""); -var component_struct = { - template: SJSTemplate, - methods: { - onchange: function(evt) { - var file; - var files = evt.target.files; - - if (!files || files.length == 0) return; - - file = files[0]; - - var reader = new FileReader(); - reader.onload = function (e) { - // pre-process data - var binary = ""; - var bytes = new Uint8Array(e.target.result); - var length = bytes.byteLength; - for (var i = 0; i < length; i++) { - binary += String.fromCharCode(bytes[i]); - } - - /* read workbook */ - var wb = XLSX.read(binary, {type: 'binary'}); - - /* grab first sheet */ - var wsname = wb.SheetNames[0]; - var ws = wb.Sheets[wsname]; - - /* generate HTML */ - var HTML = XLSX.utils.sheet_to_html(ws); - - /* update table */ - document.getElementById('out-table').innerHTML = HTML; - /* show export button */ - document.getElementById('export-table').style.visibility = "visible"; - }; - - reader.readAsArrayBuffer(file); - }, - onexport: function(evt) { - /* generate workbook object from table */ - var wb = XLSX.utils.table_to_book(document.getElementById('out-table')); - /* generate file and force a download*/ - XLSX.writeFile(wb, "sheetjs.xlsx"); - } - } -}; -var app; -if(Vue.component) { - Vue.component('html-preview', component_struct); -} else { - app = Vue.createApp({}); - app.component('html-preview', component_struct); -} diff --git a/demos/vue/index2.html b/demos/vue/index2.html deleted file mode 100644 index 1870671..0000000 --- a/demos/vue/index2.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - SheetJS + VueJS2 - - - - - - - - - - - - - - - -
-SheetJS + VueJS2 demo
-
-The core library can be used as-is in Vue applications.
-The Community Edition README details some common use cases.
-We also have some more public demos
-
-This demo shows a sample Vue component "html-preview" that:
-- displays a file input that accepts a spreadsheet file
-- draws the first worksheet of a submitted file as HTML
-- presents an export button to generate XLSX files
-
-Sample Spreadsheet
-
- - -
- -
- - - - - diff --git a/demos/vue/index3.html b/demos/vue/index3.html deleted file mode 100644 index c095d70..0000000 --- a/demos/vue/index3.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - SheetJS + VueJS3 - - - - - - - - - - - - - - - -
-SheetJS + VueJS3 demo
-
-The core library can be used as-is in Vue applications.
-The Community Edition README details some common use cases.
-We also have some more public demos
-
-This demo shows a sample Vue component "html-preview" that:
-- displays a file input that accepts a spreadsheet file
-- draws the first worksheet of a submitted file as HTML
-- presents an export button to generate XLSX files
-
-Sample Spreadsheet
-
- - -
- -
- - - - - diff --git a/demos/vue/modify/.gitignore b/demos/vue/modify/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/demos/vue/modify/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/demos/vue/modify/README.md b/demos/vue/modify/README.md deleted file mode 100644 index 4d76306..0000000 --- a/demos/vue/modify/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# vue-modify - -This demo shows import an export with `vue3-table-light` table component. - -In this directory, run - -```bash -npm i -npm run dev -``` diff --git a/demos/vue/modify/index.html b/demos/vue/modify/index.html deleted file mode 100644 index 867581c..0000000 --- a/demos/vue/modify/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite App - - -
- - - diff --git a/demos/vue/modify/package.json b/demos/vue/modify/package.json deleted file mode 100644 index e39cc11..0000000 --- a/demos/vue/modify/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "vue-modify", - "private": true, - "version": "0.0.0", - "scripts": { - "dev": "vite --host", - "build": "vue-tsc --noEmit && vite build", - "preview": "vite preview" - }, - "dependencies": { - "vue": "^3.2.25", - "vue3-table-lite": "^1.1.7-1", - "xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^2.2.0", - "typescript": "^4.5.4", - "vite": "^2.8.0", - "vue-tsc": "^0.29.8" - } -} diff --git a/demos/vue/modify/src/App.vue b/demos/vue/modify/src/App.vue deleted file mode 100644 index 2b1f5ec..0000000 --- a/demos/vue/modify/src/App.vue +++ /dev/null @@ -1,241 +0,0 @@ - - - - - diff --git a/demos/vue/modify/src/env.d.ts b/demos/vue/modify/src/env.d.ts deleted file mode 100644 index aafef95..0000000 --- a/demos/vue/modify/src/env.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -declare module '*.vue' { - import type { DefineComponent } from 'vue' - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types - const component: DefineComponent<{}, {}, any> - export default component -} diff --git a/demos/vue/modify/src/main.ts b/demos/vue/modify/src/main.ts deleted file mode 100644 index 684d042..0000000 --- a/demos/vue/modify/src/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { createApp } from 'vue'; -import App from './App.vue'; - -createApp(App).mount('#app'); diff --git a/demos/vue/modify/tsconfig.json b/demos/vue/modify/tsconfig.json deleted file mode 100644 index af31eb8..0000000 --- a/demos/vue/modify/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "useDefineForClassFields": true, - "module": "esnext", - "moduleResolution": "node", - "strict": true, - "jsx": "preserve", - "sourceMap": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "lib": ["esnext", "dom"] - }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/demos/vue/modify/tsconfig.node.json b/demos/vue/modify/tsconfig.node.json deleted file mode 100644 index e993792..0000000 --- a/demos/vue/modify/tsconfig.node.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "esnext", - "moduleResolution": "node" - }, - "include": ["vite.config.ts"] -} diff --git a/demos/vue/modify/vite.config.ts b/demos/vue/modify/vite.config.ts deleted file mode 100644 index 315212d..0000000 --- a/demos/vue/modify/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()] -}) diff --git a/demos/vue/shim.js b/demos/vue/shim.js deleted file mode 120000 index 7ec5819..0000000 --- a/demos/vue/shim.js +++ /dev/null @@ -1 +0,0 @@ -../../shim.js \ No newline at end of file diff --git a/demos/vue/xlsx.full.min.js b/demos/vue/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/vue/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/demos/xspreadsheet/README.md b/demos/xspreadsheet/README.md index 2321769..5d21b9e 100644 --- a/demos/xspreadsheet/README.md +++ b/demos/xspreadsheet/README.md @@ -5,62 +5,14 @@ with other JS libraries such as data grids for previewing data. With a familiar UI, [`x-spreadsheet`](https://myliang.github.io/x-spreadsheet/) is an excellent choice for developers looking for a modern editor. -This demo is available at +[The new docs](https://docs.sheetjs.com/docs/demos/grid/#x-spreadsheet) +include more detail and examples. -## Obtaining the Library +The original demo is available at -The `x-data-spreadsheet` NodeJS packages include a minified script that can be -directly inserted as a script tag. The unpkg CDN also serves this script: +A hosted version of the `xlsxspread.js` script is available on the SheetJS CDN: -```html - -``` - -## Previewing Data - -The HTML document needs a container element: - -```html -
-``` - -Grid initialization is a one-liner: - -```js -/* note that the browser build exposes the variable `x` */ -var grid = x_spreadsheet(document.getElementById("gridctr")); -``` - -The following function converts data from SheetJS to x-spreadsheet: - -```js -/* load data */ -grid.loadData(stox(workbook_object)); -``` - -`stox` is defined in [`xlsxspread.js`](./xlsxspread.js) - -## Editing - -`x-spreadsheet` handles the entire edit cycle. No intervention is necessary. - -## Saving Data - -`grid.getData()` returns an object that can be converted back to a worksheet: - -```js -/* build workbook from the grid data */ -var new_wb = xtos(xspr.getData()); - -/* generate download */ -XLSX.writeFile(new_wb, "SheetJS.xlsx"); -``` - -`stox` is defined in [`xlsxspread.js`](./xlsxspread.js) - -## Additional Features - -This demo barely scratches the surface. The underlying grid component includes -many additional features that work with [SheetJS Pro](https://sheetjs.com/pro). +- original script +- minified [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/xspreadsheet/index.html b/demos/xspreadsheet/index.html deleted file mode 100644 index dd80a43..0000000 --- a/demos/xspreadsheet/index.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - -SheetJS + x-spreadsheet Live Demo - - - - - -
-SheetJS Data Preview Live Demo
-
-x-spreadsheet component library
-
-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/xspreadsheet/shim.js b/demos/xspreadsheet/shim.js deleted file mode 120000 index 7ec5819..0000000 --- a/demos/xspreadsheet/shim.js +++ /dev/null @@ -1 +0,0 @@ -../../shim.js \ No newline at end of file diff --git a/demos/xspreadsheet/xlsx.full.min.js b/demos/xspreadsheet/xlsx.full.min.js deleted file mode 120000 index dbca48d..0000000 --- a/demos/xspreadsheet/xlsx.full.min.js +++ /dev/null @@ -1 +0,0 @@ -../../dist/xlsx.full.min.js \ No newline at end of file diff --git a/demos/xspreadsheet/xlsxspread.js b/demos/xspreadsheet/xlsxspread.js index d4b88f9..cced956 100644 --- a/demos/xspreadsheet/xlsxspread.js +++ b/demos/xspreadsheet/xlsxspread.js @@ -2,6 +2,7 @@ /* eslint-env browser */ /*global XLSX */ /*exported stox, xtos */ +console.log("The latest version of the xlsxspread.js script is at https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js !") /** * Converts data from SheetJS to x-spreadsheet @@ -129,3 +130,4 @@ function xtos(sdata) { return out; } +