forked from sheetjs/sheetjs
parse ZIP64 length (fixes #2766 h/t @silvialeung)
This commit is contained in:
parent
199373e918
commit
045adba80d
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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": {}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"eslint:recommended"
|
||||
]
|
||||
}
|
1
demos/angular2/.gitattributes
vendored
1
demos/angular2/.gitattributes
vendored
@ -1 +0,0 @@
|
||||
*.*-ng* linguist-generated=true binary
|
8
demos/angular2/.gitignore
vendored
8
demos/angular2/.gitignore
vendored
@ -1,8 +0,0 @@
|
||||
dist
|
||||
hooks
|
||||
SheetJSIonic
|
||||
SheetJSNS
|
||||
angular.json
|
||||
tsconfig.app.json
|
||||
src/polyfills.ts
|
||||
.angular
|
@ -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 $@ </dev/null; cd -
|
||||
android: ionic
|
||||
cd SheetJSIonic; ionic cordova prepare $@ </dev/null; ionic cordova emulate $@ </dev/null; cd -
|
||||
|
@ -1,148 +1,11 @@
|
||||
# Angular 2+
|
||||
|
||||
The ESM build can be imported directly from TS code with:
|
||||
[The new demo](https://docs.sheetjs.com/docs/demos/angular) has an updated
|
||||
exposition for legacy and modern deployments alike.
|
||||
|
||||
```typescript
|
||||
import { read, utils, writeFileXLSX } from 'xlsx';
|
||||
```
|
||||
The ecosystem demos were grouped by type in the new demo site:
|
||||
|
||||
This demo uses an array of arrays (type `Array<Array<any>>`) as the core state.
|
||||
The component template includes a file input element, a table that updates with
|
||||
the data, and a button to export the data.
|
||||
|
||||
Other scripts in this demo show:
|
||||
- `ionic` deployment for iOS, android, and browser
|
||||
- `nativescript` deployment for iOS and android
|
||||
|
||||
## Array of Arrays
|
||||
|
||||
`Array<Array<any>>` neatly maps to a table with `ngFor`:
|
||||
|
||||
```html
|
||||
<table class="sjs-table">
|
||||
<tr *ngFor="let row of data">
|
||||
<td *ngFor="let val of row">
|
||||
{{val}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
The `aoa_to_sheet` utility function returns a worksheet. Exporting is simple:
|
||||
|
||||
```typescript
|
||||
/* generate worksheet */
|
||||
const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
|
||||
|
||||
/* generate workbook and add the worksheet */
|
||||
const wb: XLSX.WorkBook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
|
||||
|
||||
/* save to file */
|
||||
XLSX.writeFile(wb, 'SheetJS.xlsx');
|
||||
```
|
||||
|
||||
`sheet_to_json` with the option `header:1` makes importing simple:
|
||||
|
||||
```typescript
|
||||
/* <input type="file" (change)="onFileChange($event)" multiple="false" /> */
|
||||
/* ... (within the component class definition) ... */
|
||||
onFileChange(evt: any) {
|
||||
/* wire up file reader */
|
||||
const target: DataTransfer = <DataTransfer>(evt.target);
|
||||
if (target.files.length !== 1) throw new Error('Cannot use multiple files');
|
||||
const reader: FileReader = new FileReader();
|
||||
reader.onload = (e: any) => {
|
||||
/* read workbook */
|
||||
const 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 = <AOA>(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
|
||||
|
||||
<img src="screen.png" width="400px"/>
|
||||
|
||||
Reproducing the full project is a little bit tricky. The included `ionic.sh`
|
||||
script performs the necessary installation steps.
|
||||
|
||||
`Array<Array<any>>` neatly maps to a table with `ngFor`:
|
||||
|
||||
```html
|
||||
<ion-grid>
|
||||
<ion-row *ngFor="let row of data">
|
||||
<ion-col *ngFor="let val of row">
|
||||
{{val}}
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
```
|
||||
|
||||
|
||||
`@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)
|
||||
|
@ -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 {}
|
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
if [ ! -e SheetJSIonic ]; then
|
||||
ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm </dev/null
|
||||
cd SheetJSIonic
|
||||
ionic cordova platform add browser --confirm </dev/null
|
||||
ionic cordova platform add ios --confirm </dev/null
|
||||
ionic cordova platform add android --confirm </dev/null
|
||||
ionic cordova plugin add cordova-plugin-file </dev/null
|
||||
npm install --save @ionic-native/core
|
||||
npm install --save @ionic-native/file
|
||||
npm install --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
|
||||
cp ../ionic-app.module.ts src/app/app.module.ts
|
||||
cd -
|
||||
fi
|
||||
|
||||
cp ionic.ts SheetJSIonic/src/app/home/home.page.ts
|
@ -1,126 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
import { Component } from '@angular/core';
|
||||
import { File } from '@ionic-native/file/ngx';
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
|
||||
type AOA = any[][];
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
//templateUrl: 'home.page.html',
|
||||
styleUrls: ['home.page.scss'],
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>SheetJS Ionic Demo</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content [fullscreen]="true">
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title>SheetJS Demo</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-grid>
|
||||
<ion-row *ngFor="let row of data">
|
||||
<ion-col *ngFor="let val of row">
|
||||
{{val}}
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-content>
|
||||
|
||||
<ion-footer padding>
|
||||
<input type="file" (change)="onFileChange($event)" multiple="false" />
|
||||
<button ion-button color="secondary" (click)="import()">Import Data</button>
|
||||
<button ion-button color="secondary" (click)="export()">Export Data</button>
|
||||
</ion-footer>
|
||||
`
|
||||
})
|
||||
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 94 KiB |
@ -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: `<sheetjs></sheetjs>`
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'test';
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
SheetJSComponent,
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
@ -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: `
|
||||
<pre><b>Version: {{ver}}</b></pre>
|
||||
<input type="file" (change)="onFileChange($event)" multiple="false" />
|
||||
<table class="sjs-table">
|
||||
<tr *ngFor="let row of data">
|
||||
<td *ngFor="let val of row">
|
||||
{{val}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button (click)="export()">Export!</button>
|
||||
`
|
||||
})
|
||||
|
||||
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 = <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 = <AOA>(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);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SheetJS + Angular 2+</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS + Angular 2+ demo</a></b>
|
||||
|
||||
The core library can be used as-is in angular applications.
|
||||
The <a href="https://github.com/sheetjs/js-xlsx">Community Edition README</a> details some common use cases.
|
||||
We also have some <a href="http://sheetjs.com/demos/">more public demos</a>
|
||||
|
||||
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.
|
||||
|
||||
<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
|
||||
</pre>
|
||||
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +0,0 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { AppModule } from './app/app.module';
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1 +0,0 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "es2015",
|
||||
"baseUrl": "",
|
||||
"types": []
|
||||
}
|
||||
}
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
import 'zone.js/dist/zone';
|
@ -1 +0,0 @@
|
||||
import 'zone.js/dist/zone';
|
@ -1 +0,0 @@
|
||||
import 'zone.js';
|
@ -1 +0,0 @@
|
||||
import 'zone.js';
|
@ -1,3 +0,0 @@
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
@ -1,3 +0,0 @@
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
@ -1,3 +0,0 @@
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
@ -1,3 +0,0 @@
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
@ -1,3 +0,0 @@
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
import 'zone.js/dist/zone';
|
@ -1 +0,0 @@
|
||||
import 'zone.js/dist/zone';
|
@ -1 +0,0 @@
|
||||
import 'zone.js/dist/zone';
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
@ -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"
|
||||
]
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"env": { "shared-node-browser":true },
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
},
|
||||
"plugins": [ "html", "json" ]
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"disabled": false,
|
||||
"bindings": [
|
||||
{
|
||||
"authLevel": "function",
|
||||
"type": "httpTrigger",
|
||||
"direction": "in",
|
||||
"dataType": "binary",
|
||||
"name": "req"
|
||||
},
|
||||
{
|
||||
"type": "http",
|
||||
"direction": "out",
|
||||
"name": "res"
|
||||
}
|
||||
]
|
||||
}
|
@ -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();
|
||||
});
|
||||
};
|
65
demos/function/Firebase/.gitignore
vendored
65
demos/function/Firebase/.gitignore
vendored
@ -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
|
@ -1 +0,0 @@
|
||||
{}
|
1
demos/function/Firebase/functions/.gitignore
vendored
1
demos/function/Firebase/functions/.gitignore
vendored
@ -1 +0,0 @@
|
||||
node_modules/
|
@ -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)
|
||||
});
|
@ -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
|
||||
}
|
@ -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);
|
||||
};
|
@ -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: '*/*'
|
@ -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
|
@ -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.
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"version": "2.0"
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
|
||||
"AzureWebJobsDashboard": "UseDevelopmentStorage=true"
|
||||
},
|
||||
"Host": {
|
||||
"LocalHttpPort": 7262,
|
||||
"CORS": "*"
|
||||
}
|
||||
}
|
4
demos/react/.gitignore
vendored
4
demos/react/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
SheetJS
|
||||
.next
|
||||
static/shim.js
|
||||
public/shim.js
|
@ -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 -
|
@ -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=<directory>`, replacing `<directory>` with the location of
|
||||
your Java install, to your `.bashrc` or any other shell that you are using.
|
||||
|
||||
|
||||
|
@ -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
|
||||
<script src="xlsx.full.min.js"></script>
|
||||
```
|
||||
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 (
|
||||
// ...
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
// ...
|
||||
); }
|
||||
```
|
||||
|
||||
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)
|
||||
|
@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html lang="en" style="height: 100%">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS React Demo</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
|
||||
<script src="node_modules/xlsx/dist/shim.min.js"></script>
|
||||
<script src="node_modules/xlsx/dist/xlsx.full.min.js"></script>
|
||||
<style>body, #app { height: 100%; };</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<h1><a href="http://sheetjs.com">SheetJS React Demo</a></h1>
|
||||
<br />
|
||||
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a><br />
|
||||
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a><br /><br />
|
||||
</div>
|
||||
<div id="app" class="container-fluid"></div>
|
||||
<script type="text/babel" src="sheetjs.js"></script>
|
||||
<script type="text/babel">
|
||||
ReactDOM.render( <SheetJSApp />, document.getElementById('app') );
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
23
demos/react/modify/.gitignore
vendored
23
demos/react/modify/.gitignore
vendored
@ -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*
|
@ -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
|
||||
```
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
@ -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<Row[]>([]);
|
||||
const [columns, setColumns] = useState<Column[]>([]);
|
||||
const [workBook, setWorkBook] = useState<DataSet>({} as DataSet);
|
||||
const [sheets, setSheets] = useState<string[]>([]);
|
||||
const [current, setCurrent] = useState<string>("");
|
||||
|
||||
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<HTMLInputElement>): Promise<void> {
|
||||
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 (
|
||||
<>
|
||||
<input type="file" onChange={handleFile} />
|
||||
<div className="flex-cont">
|
||||
{sheets.map((sheet) => (
|
||||
<button key={sheet} onClick={(e) => selectSheet(sheet)}>
|
||||
{sheet}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex-cont">
|
||||
<b>Current Sheet: {current}</b>
|
||||
</div>
|
||||
<DataGrid columns={columns} rows={rows} onRowsChange={setRows} />
|
||||
<div className="flex-cont">
|
||||
{exportTypes.map((ext) => (
|
||||
<button key={ext} onClick={() => saveFile(ext)}>
|
||||
export [.{ext}]
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './components/App';
|
||||
|
||||
import './styles/index.css';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App/>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
1
demos/react/modify/src/react-app-env.d.ts
vendored
1
demos/react/modify/src/react-app-env.d.ts
vendored
@ -1 +0,0 @@
|
||||
/// <reference types="react-scripts" />
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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"
|
||||
]
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
import * as XLSX from 'xlsx';
|
||||
import React from 'react';
|
@ -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 (
|
||||
<div>
|
||||
<Head>
|
||||
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Next.JS {type} Demo</title>
|
||||
<script src="/shim.js"></script>
|
||||
<style jsx>{`
|
||||
body, #app { height: 100%; };
|
||||
`}</style>
|
||||
</Head>
|
||||
<pre>
|
||||
<h3>SheetJS Next.JS {type} Demo</h3>
|
||||
This demo reads from /public/sheetjs.xlsx and generates HTML from the first sheet.
|
||||
</pre>
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
</div>
|
||||
); }
|
||||
|
||||
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]]),
|
||||
},
|
||||
}
|
||||
}
|
@ -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 (
|
||||
<div>
|
||||
<Head>
|
||||
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Next.JS {type} Demo</title>
|
||||
<script src="/shim.js"></script>
|
||||
<style jsx>{`
|
||||
body, #app { height: 100%; };
|
||||
`}</style>
|
||||
</Head>
|
||||
<pre>
|
||||
<h3>SheetJS Next.JS {type} Demo</h3>
|
||||
This demo reads from /public/sheetjs.xlsx. Each worksheet maps to a path:<br/><br/>
|
||||
{snames.map((sname, idx) => (<>
|
||||
<Link key={idx} href="/sheets/[id]" as={`/sheets/${idx}`}><a>{`Sheet index=${idx} name="${sname}"`}</a></Link>
|
||||
<br/>
|
||||
<br/>
|
||||
</>))}
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
); }
|
||||
|
||||
export async function getStaticProps() {
|
||||
const wb = readFile(join(cwd(), "public", "sheetjs.xlsx"))
|
||||
return {
|
||||
props: {
|
||||
type: "getStaticPaths",
|
||||
snames: wb.SheetNames,
|
||||
},
|
||||
}
|
||||
}
|
@ -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 (
|
||||
<div>
|
||||
<Head>
|
||||
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Next.JS {type} Demo</title>
|
||||
<script src="/shim.js"></script>
|
||||
<style jsx>{`
|
||||
body, #app { height: 100%; };
|
||||
`}</style>
|
||||
</Head>
|
||||
<pre>
|
||||
<h3>SheetJS Next.JS {type} Demo</h3>
|
||||
This demo reads from /public/sheetjs.xlsx and generates HTML from the first sheet.
|
||||
</pre>
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
</div>
|
||||
); }
|
||||
|
||||
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]]),
|
||||
},
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import Head from 'next/head';
|
||||
|
||||
export default function Index() { return (
|
||||
<div>
|
||||
<Head>
|
||||
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Next.JS Demo</title>
|
||||
<script src="/shim.js"></script>
|
||||
<style jsx>{`
|
||||
body, #app { height: 100%; };
|
||||
`}</style>
|
||||
</Head>
|
||||
<pre>
|
||||
<h3>SheetJS Next.JS Demos</h3>
|
||||
All demos read from /public/sheetjs.xlsx.<br/>
|
||||
<br/>
|
||||
- <a href="/getStaticProps">getStaticProps</a><br/>
|
||||
<br/>
|
||||
- <a href="/getServerSideProps">getServerSideProps</a><br/>
|
||||
<br/>
|
||||
- <a href="/getStaticPaths">getStaticPaths</a><br/>
|
||||
</pre>
|
||||
</div>
|
||||
); }
|
@ -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 (
|
||||
<div>
|
||||
<Head>
|
||||
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS Next.JS {type} Demo</title>
|
||||
<script src="/shim.js"></script>
|
||||
<style jsx>{`
|
||||
body, #app { height: 100%; };
|
||||
`}</style>
|
||||
</Head>
|
||||
<pre>
|
||||
<h3>SheetJS Next.JS {type} Demo</h3>
|
||||
This demo reads from /public/sheetjs.xlsx.<br/>
|
||||
<br/>
|
||||
<b>{name}</b>
|
||||
</pre>
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
</div>
|
||||
); }
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
Binary file not shown.
@ -1,144 +0,0 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* Notes:
|
||||
- usage: `ReactDOM.render( <SheetJSApp />, 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 (
|
||||
<DragDropFile handleFile={handleFile}>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<DataInput handleFile={handleFile} />
|
||||
</div></div>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<button disabled={!data.length} className="btn btn-success" onClick={exportFile}>Export</button>
|
||||
</div></div>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<OutTable data={data} cols={cols} />
|
||||
</div></div>
|
||||
</DragDropFile>
|
||||
);
|
||||
}
|
||||
|
||||
if(typeof module !== 'undefined') module.exports = SheetJSApp
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
Simple HTML5 file drag-and-drop wrapper
|
||||
usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
|
||||
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 (
|
||||
<div
|
||||
onDrop={handleDrop}
|
||||
onDragEnter={suppress}
|
||||
onDragOver={suppress}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Simple HTML5 file input wrapper
|
||||
usage: <DataInput handleFile={callback} />
|
||||
handleFile(file:File):void;
|
||||
*/
|
||||
|
||||
function DataInput({ handleFile }) {
|
||||
const handleChange = (e) => {
|
||||
const files = e.target.files;
|
||||
if(files && files[0]) handleFile(files[0]);
|
||||
};
|
||||
|
||||
return (
|
||||
<form className="form-inline">
|
||||
<div className="form-group">
|
||||
<label htmlFor="file">Drag or choose a spreadsheet file</label>
|
||||
<br />
|
||||
<input
|
||||
type="file"
|
||||
className="form-control"
|
||||
id="file"
|
||||
accept={SheetJSFT}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
Simple HTML Table
|
||||
usage: <OutTable data={data} cols={cols} />
|
||||
data:Array<Array<any> >;
|
||||
cols:Array<{name:string, key:number|string}>;
|
||||
*/
|
||||
function OutTable({ data, cols }) {
|
||||
return (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((r,i) => <tr key={i}>
|
||||
{cols.map(c => <td key={c.key}>{ r[c.key] }</td>)}
|
||||
</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
};
|
2
demos/server/.gitignore
vendored
2
demos/server/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
xlsx.full.min.js
|
||||
xlsx-demo
|
@ -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
|
@ -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=<type>` returns the internal storage in the specified type
|
||||
- `POST /?f=<name>` reads the local file and updates the internal storage
|
||||
- `GET /?f=<name>` 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.
|
||||
|
||||
<https://s2c.deno.dev> 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)
|
||||
|
@ -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;
|
@ -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;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user