forked from sheetjs/sheetjs
		
	stox skip blank worksheets [ci skip]
This commit is contained in:
		
							parent
							
								
									d55b7a3063
								
							
						
					
					
						commit
						c02eb14255
					
				@ -26,7 +26,7 @@ can be installed with Bash on Windows or with `cygwin`.
 | 
			
		||||
- [`IndexedDB`](https://docs.sheetjs.com/docs/getting-started/demos/database#indexeddb)
 | 
			
		||||
 | 
			
		||||
**Frameworks**
 | 
			
		||||
- [`Angular.JS`](angular/)
 | 
			
		||||
- [`Angular.JS`](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
 | 
			
		||||
- [`Angular 2+ and Ionic`](angular2/)
 | 
			
		||||
- [`Knockout`](https://docs.sheetjs.com/docs/getting-started/demos/legacy#knockoutjs)
 | 
			
		||||
- [`Meteor`](meteor/)
 | 
			
		||||
@ -34,17 +34,19 @@ can be installed with Bash on Windows or with `cygwin`.
 | 
			
		||||
- [`VueJS, WeeX and NuxtJS`](vue/)
 | 
			
		||||
 | 
			
		||||
**Front-End UI Components**
 | 
			
		||||
- [`canvas-datagrid`](datagrid/)
 | 
			
		||||
- [`canvas-datagrid`](https://docs.sheetjs.com/docs/getting-started/demos/grid#canvas-datagrid)
 | 
			
		||||
- [`x-spreadsheet`](xspreadsheet/)
 | 
			
		||||
- [`react-data-grid`](react/modify/)
 | 
			
		||||
- [`vue3-table-light`](vue/modify/)
 | 
			
		||||
- [`angular-ui-grid`](https://docs.sheetjs.com/docs/getting-started/demos/grid#angular-ui-grid)
 | 
			
		||||
 | 
			
		||||
**Platforms and Integrations**
 | 
			
		||||
- [`Command-Line Tools`](https://docs.sheetjs.com/docs/getting-started/demos/cli)
 | 
			
		||||
- [`NodeJS Server-Side Processing`](server/)
 | 
			
		||||
- [`Deno`](deno/)
 | 
			
		||||
- [`Electron`](electron/)
 | 
			
		||||
- [`NW.js`](nwjs/)
 | 
			
		||||
- [`Chrome / Chromium Extension`](chrome/)
 | 
			
		||||
- [`NW.js`](https://docs.sheetjs.com/docs/getting-started/demos/desktop#nwjs)
 | 
			
		||||
- [`Chrome / Chromium Extension`](https://docs.sheetjs.com/docs/getting-started/demos/chromium)
 | 
			
		||||
- [`Google Sheets API`](https://docs.sheetjs.com/docs/getting-started/demos/gsheet)
 | 
			
		||||
- [`ExtendScript for Adobe Apps`](https://docs.sheetjs.com/docs/getting-started/demos/extendscript)
 | 
			
		||||
- [`NetSuite SuiteScript`](https://docs.sheetjs.com/docs/getting-started/demos/netsuite)
 | 
			
		||||
@ -53,10 +55,9 @@ can be installed with Bash on Windows or with `cygwin`.
 | 
			
		||||
- [`Headless Automation`](https://docs.sheetjs.com/docs/getting-started/demos/headless)
 | 
			
		||||
- [`Swift JSC and Other JavaScript Engines`](altjs/)
 | 
			
		||||
- [`"serverless" functions`](function/)
 | 
			
		||||
- [`databases and key/value stores`](database/)
 | 
			
		||||
- [`Databases and Structured Data Stores`](https://docs.sheetjs.com/docs/getting-started/demos/database)
 | 
			
		||||
- [`NoSQL, K/V, and Unstructured Data Stores`](https://docs.sheetjs.com/docs/getting-started/demos/nosql)
 | 
			
		||||
- [`internet explorer`](oldie/)
 | 
			
		||||
- [`Legacy Internet Explorer`](oldie/)
 | 
			
		||||
 | 
			
		||||
**Bundlers and Tooling**
 | 
			
		||||
- [`browserify`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#browserify)
 | 
			
		||||
@ -68,7 +69,6 @@ can be installed with Bash on Windows or with `cygwin`.
 | 
			
		||||
- [`snowpack`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#snowpack)
 | 
			
		||||
- [`swc`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#swc)
 | 
			
		||||
- [`systemjs`](systemjs/)
 | 
			
		||||
- [`typescript`](typescript/)
 | 
			
		||||
- [`vite`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#vite)
 | 
			
		||||
- [`webpack 2.x`](webpack/)
 | 
			
		||||
- [`wmr`](https://docs.sheetjs.com/docs/getting-started/demos/bundler#wmr)
 | 
			
		||||
 | 
			
		||||
@ -1,148 +1,10 @@
 | 
			
		||||
# AngularJS
 | 
			
		||||
 | 
			
		||||
The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped
 | 
			
		||||
into web pages with script tags:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<script src="xlsx.full.min.js"></script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Strictly speaking, there should be no need for an Angular demo!  You can proceed
 | 
			
		||||
as you would with any other browser-friendly library.
 | 
			
		||||
 | 
			
		||||
This demo uses AngularJS 1.5.0.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Array of Objects
 | 
			
		||||
 | 
			
		||||
A common data table is often stored as an array of objects:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
$scope.data = [
 | 
			
		||||
  { Name: "Bill Clinton", Index: 42 },
 | 
			
		||||
  { Name: "GeorgeW Bush", Index: 43 },
 | 
			
		||||
  { Name: "Barack Obama", Index: 44 },
 | 
			
		||||
  { Name: "Donald Trump", Index: 45 }
 | 
			
		||||
];
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This neatly maps to a table with `ng-repeat`:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<table id="sjs-table">
 | 
			
		||||
  <tr><th>Name</th><th>Index</th></tr>
 | 
			
		||||
  <tr ng-repeat="row in data">
 | 
			
		||||
    <td>{{row.Name}}</td>
 | 
			
		||||
    <td>{{row.Index}}</td>
 | 
			
		||||
  </tr>
 | 
			
		||||
</table>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `$http` service can request binary data using the `"arraybuffer"` response
 | 
			
		||||
type coupled with `XLSX.read` with type `"array"`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
  $http({
 | 
			
		||||
    method:'GET',
 | 
			
		||||
    url:'https://sheetjs.com/pres.xlsx',
 | 
			
		||||
    responseType:'arraybuffer'
 | 
			
		||||
  }).then(function(data) {
 | 
			
		||||
    var wb = XLSX.read(data.data, {type:"array"});
 | 
			
		||||
    var d = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
 | 
			
		||||
    $scope.data = d;
 | 
			
		||||
  }, function(err) { console.log(err); });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The HTML table can be directly exported with `XLSX.utils.table_to_book`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var wb = XLSX.utils.table_to_book(document.getElementById('sjs-table'));
 | 
			
		||||
XLSX.writeFile(wb, "export.xlsx");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Import Directive
 | 
			
		||||
 | 
			
		||||
A general import directive is fairly straightforward:
 | 
			
		||||
 | 
			
		||||
- Define the `importSheetJs` directive in the app:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
app.directive("importSheetJs", [SheetJSImportDirective]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Add the attribute `import-sheet-js=""` to the file input element:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<input type="file" import-sheet-js="" multiple="false"  />
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- Define the directive:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
function SheetJSImportDirective() {
 | 
			
		||||
  return {
 | 
			
		||||
    scope: { opts: '=' },
 | 
			
		||||
    link: function ($scope, $elm) {
 | 
			
		||||
      $elm.on('change', function (changeEvent) {
 | 
			
		||||
        var reader = new FileReader();
 | 
			
		||||
 | 
			
		||||
        reader.onload = function (e) {
 | 
			
		||||
          /* read workbook */
 | 
			
		||||
          var ab = e.target.result;
 | 
			
		||||
          var workbook = XLSX.read(ab);
 | 
			
		||||
 | 
			
		||||
          /* DO SOMETHING WITH workbook HERE */
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        reader.readAsArrayBuffer(changeEvent.target.files[0]);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Export Service
 | 
			
		||||
 | 
			
		||||
An export can be triggered at any point!  Depending on how data is represented,
 | 
			
		||||
a workbook object can be built using the utility functions.  For example, using
 | 
			
		||||
an array of objects:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* starting from this data */
 | 
			
		||||
var data = [
 | 
			
		||||
  { name: "Barack Obama", pres: 44 },
 | 
			
		||||
  { name: "Donald Trump", pres: 45 }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/* generate a worksheet */
 | 
			
		||||
var ws = XLSX.utils.json_to_sheet(data);
 | 
			
		||||
 | 
			
		||||
/* add to workbook */
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
 | 
			
		||||
 | 
			
		||||
/* write workbook and force a download */
 | 
			
		||||
XLSX.writeFile(wb, "sheetjs.xlsx");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Demo
 | 
			
		||||
 | 
			
		||||
`grid.html` uses `angular-ui-grid` to display a table.  The library does not
 | 
			
		||||
provide any way to modify the import button, so the demo includes a simple
 | 
			
		||||
directive for a HTML File Input control.  It also includes a sample service for
 | 
			
		||||
export which adds an item to the export menu.
 | 
			
		||||
 | 
			
		||||
The demo `SheetJSImportDirective` follows the prescription from the README for
 | 
			
		||||
File input controls using `readAsArrayBuffer`, converting to a suitable
 | 
			
		||||
representation and updating the scope.
 | 
			
		||||
 | 
			
		||||
`SheetJSExportService` exposes export functions for `XLSB` and `XLSX`.  Other
 | 
			
		||||
file formats can be exported by changing the `bookType` variable.  It grabs
 | 
			
		||||
values from the grid, builds an array of arrays, generates a workbook and forces
 | 
			
		||||
a download.  By setting the `filename` and `sheetname` options in the `ui-grid`
 | 
			
		||||
options, the output can be controlled.
 | 
			
		||||
The content has been reorganized;
 | 
			
		||||
 | 
			
		||||
- [The "Legacy Frameworks" section](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
 | 
			
		||||
  covers the AngularJS basics.
 | 
			
		||||
- [The "Angular UI Grid" section](https://docs.sheetjs.com/docs/getting-started/demos/legacy#angularjs)
 | 
			
		||||
  covers the integration with Angular UI Grid.
 | 
			
		||||
 | 
			
		||||
[](https://github.com/SheetJS/js-xlsx)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										96
									
								
								demos/angular/SheetJS-angular.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										96
									
								
								demos/angular/SheetJS-angular.js
									
									
									
									
										vendored
									
									
								
							@ -1,96 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* global XLSX */
 | 
			
		||||
/* exported SheetJSExportService, SheetJSImportDirective */
 | 
			
		||||
function SheetJSExportService(uiGridExporterService) {
 | 
			
		||||
 | 
			
		||||
  function exportSheetJS(gridApi, wopts) {
 | 
			
		||||
    var columns = uiGridExporterService.getColumnHeaders(gridApi.grid, 'all');
 | 
			
		||||
    var data = uiGridExporterService.getData(gridApi.grid, 'all', 'all');
 | 
			
		||||
 | 
			
		||||
    var fileName = gridApi.grid.options.filename || 'SheetJS';
 | 
			
		||||
    fileName += wopts.bookType ? "." + wopts.bookType : '.xlsx';
 | 
			
		||||
 | 
			
		||||
    var sheetName = gridApi.grid.options.sheetname || 'Sheet1';
 | 
			
		||||
 | 
			
		||||
    var wb = XLSX.utils.book_new(), ws = uigrid_to_sheet(data, columns);
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, ws, sheetName);
 | 
			
		||||
    XLSX.writeFile(wb, fileName);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var service = {};
 | 
			
		||||
  service.exportXLSB = function exportXLSB(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsb', bookSST: true, type: 'array' }); };
 | 
			
		||||
  service.exportXLSX = function exportXLSX(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsx', bookSST: true, type: 'array' }); }
 | 
			
		||||
 | 
			
		||||
  return service;
 | 
			
		||||
 | 
			
		||||
  /* utilities */
 | 
			
		||||
  function uigrid_to_sheet(data, columns) {
 | 
			
		||||
    var o = [], oo = [], i = 0, j = 0;
 | 
			
		||||
 | 
			
		||||
    /* column headers */
 | 
			
		||||
    for(j = 0; j < columns.length; ++j) oo.push(get_value(columns[j]));
 | 
			
		||||
    o.push(oo);
 | 
			
		||||
 | 
			
		||||
    /* table data */
 | 
			
		||||
    for(i = 0; i < data.length; ++i) {
 | 
			
		||||
      oo = [];
 | 
			
		||||
      for(j = 0; j < data[i].length; ++j) oo.push(get_value(data[i][j]));
 | 
			
		||||
      o.push(oo);
 | 
			
		||||
    }
 | 
			
		||||
    /* aoa_to_sheet converts an array of arrays into a worksheet object */
 | 
			
		||||
    return XLSX.utils.aoa_to_sheet(o);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get_value(col) {
 | 
			
		||||
    if(!col) return col;
 | 
			
		||||
    if(col.value) return col.value;
 | 
			
		||||
    if(col.displayName) return col.displayName;
 | 
			
		||||
    if(col.name) return col.name;
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function SheetJSImportDirective() {
 | 
			
		||||
  return {
 | 
			
		||||
    scope: { opts: '=' },
 | 
			
		||||
    link: function($scope, $elm) {
 | 
			
		||||
      $elm.on('change', function(changeEvent) {
 | 
			
		||||
        var reader = new FileReader();
 | 
			
		||||
 | 
			
		||||
        reader.onload = function(e) {
 | 
			
		||||
          /* read workbook */
 | 
			
		||||
          var ab = e.target.result;
 | 
			
		||||
          var wb = XLSX.read(ab);
 | 
			
		||||
 | 
			
		||||
          /* grab first sheet */
 | 
			
		||||
          var wsname = wb.SheetNames[0];
 | 
			
		||||
          var ws = wb.Sheets[wsname];
 | 
			
		||||
 | 
			
		||||
          /* grab first row and generate column headers */
 | 
			
		||||
          var aoa = XLSX.utils.sheet_to_json(ws, {header:1, raw:false});
 | 
			
		||||
          var cols = [];
 | 
			
		||||
          for(var i = 0; i < aoa[0].length; ++i) cols[i] = { field: aoa[0][i] };
 | 
			
		||||
 | 
			
		||||
          /* generate rest of the data */
 | 
			
		||||
          var data = [];
 | 
			
		||||
          for(var r = 1; r < aoa.length; ++r) {
 | 
			
		||||
            data[r-1] = {};
 | 
			
		||||
            for(i = 0; i < aoa[r].length; ++i) {
 | 
			
		||||
              if(aoa[r][i] == null) continue;
 | 
			
		||||
              data[r-1][aoa[0][i]] = aoa[r][i];
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          /* update scope */
 | 
			
		||||
          $scope.$apply(function() {
 | 
			
		||||
            $scope.opts.columnDefs = cols;
 | 
			
		||||
            $scope.opts.data = data;
 | 
			
		||||
          });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        reader.readAsArrayBuffer(changeEvent.target.files[0]);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								demos/angular/app.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										45
									
								
								demos/angular/app.js
									
									
									
									
										vendored
									
									
								
							@ -1,45 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* global angular, SheetJSExportService, SheetJSImportDirective */
 | 
			
		||||
var app = angular.module('app', ['ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.selection', 'ui.grid.exporter']);
 | 
			
		||||
 | 
			
		||||
/* Inject SheetJSExportService */
 | 
			
		||||
app.factory('SheetJSExportService', SheetJSExportService);
 | 
			
		||||
SheetJSExportService.inject = ['uiGridExporterService'];
 | 
			
		||||
 | 
			
		||||
app.controller('MainCtrl', ['$scope', '$http','SheetJSExportService', function($scope, $http, SheetJSExportService) {
 | 
			
		||||
  $scope.gridOptions = {
 | 
			
		||||
    columnDefs: [
 | 
			
		||||
      { field: 'name' },
 | 
			
		||||
      { field: 'gender', visible: false},
 | 
			
		||||
      { field: 'company' }
 | 
			
		||||
    ],
 | 
			
		||||
    enableGridMenu: true,
 | 
			
		||||
    enableSelectAll: true,
 | 
			
		||||
    exporterMenuPdf: false,
 | 
			
		||||
    exporterMenuCsv: false,
 | 
			
		||||
    showHeader: true,
 | 
			
		||||
    onRegisterApi: function(gridApi){
 | 
			
		||||
      $scope.gridApi = gridApi;
 | 
			
		||||
    },
 | 
			
		||||
    /* SheetJS Service setup */
 | 
			
		||||
    filename: "SheetJSAngular",
 | 
			
		||||
    sheetname: "ng-SheetJS",
 | 
			
		||||
    gridMenuCustomItems: [
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Export all data as XLSX',
 | 
			
		||||
        action: function() { SheetJSExportService.exportXLSX($scope.gridApi); },
 | 
			
		||||
        order: 200
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: 'Export all data as XLSB',
 | 
			
		||||
        action: function() { SheetJSExportService.exportXLSB($scope.gridApi); },
 | 
			
		||||
        order: 201
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  $http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json').success(function(data) { $scope.gridOptions.data = data; });
 | 
			
		||||
 | 
			
		||||
}]);
 | 
			
		||||
app.directive("importSheetJs", [SheetJSImportDirective]);
 | 
			
		||||
@ -1,64 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html ng-app="app">
 | 
			
		||||
<head>
 | 
			
		||||
  <title>SheetJS + AngularJS + ui-grid</title>
 | 
			
		||||
  <!-- Angular -->
 | 
			
		||||
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
 | 
			
		||||
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-touch.js"></script>
 | 
			
		||||
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-animate.js"></script>
 | 
			
		||||
 | 
			
		||||
  <!-- ui-grid -->
 | 
			
		||||
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.11.0/ui-grid.js"></script>
 | 
			
		||||
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.11.0/ui-grid.css"/>
 | 
			
		||||
 | 
			
		||||
  <!-- SheetJS js-xlsx library -->
 | 
			
		||||
  <script src="shim.js"></script>
 | 
			
		||||
  <script src="xlsx.full.min.js"></script>
 | 
			
		||||
 | 
			
		||||
  <!-- SheetJS Service -->
 | 
			
		||||
  <script src="SheetJS-angular.js"></script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
.grid1 {
 | 
			
		||||
  width: 500px;
 | 
			
		||||
  height: 400px;
 | 
			
		||||
};
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<b><a href="http://sheetjs.com">SheetJS + AngularJS demo</a></b>
 | 
			
		||||
 | 
			
		||||
The core library can be used as-is in AngularJS 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:
 | 
			
		||||
- SheetJSExportService: a service for exporting data from a ui-grid
 | 
			
		||||
- SheetJSImportDirective: a directive providing a file input button for import
 | 
			
		||||
 | 
			
		||||
<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
<div ng-controller="MainCtrl">
 | 
			
		||||
  <input type="file" import-sheet-js="" opts="gridOptions" multiple="false"  />
 | 
			
		||||
  <div id="grid1" ui-grid="gridOptions" ui-grid-selection ui-grid-exporter class="grid"></div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<script src="app.js"></script>
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
/* eslint no-use-before-define:0 */
 | 
			
		||||
  var _gaq = _gaq || [];
 | 
			
		||||
  _gaq.push(['_setAccount', 'UA-36810333-1']);
 | 
			
		||||
  _gaq.push(['_trackPageview']);
 | 
			
		||||
 | 
			
		||||
  (function() {
 | 
			
		||||
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 | 
			
		||||
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 | 
			
		||||
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 | 
			
		||||
  })();
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -1,75 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html ng-app="sjs">
 | 
			
		||||
<head>
 | 
			
		||||
  <title>SheetJS + AngularJS</title>
 | 
			
		||||
  <!-- Angular -->
 | 
			
		||||
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
 | 
			
		||||
 | 
			
		||||
  <!-- SheetJS js-xlsx library -->
 | 
			
		||||
  <script src="shim.js"></script>
 | 
			
		||||
  <script src="xlsx.full.min.js"></script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<b><a href="http://sheetjs.com">SheetJS + AngularJS demo</a></b>
 | 
			
		||||
 | 
			
		||||
The core library can be used as-is in AngularJS 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:
 | 
			
		||||
- $http request for XLSX file and scope update with data
 | 
			
		||||
- HTML table using ng-repeat
 | 
			
		||||
- XLSX table export using `XLSX.utils.table_to_book`
 | 
			
		||||
 | 
			
		||||
<a href="https://sheetjs.com/pres.xlsx">Sample Spreadsheet</a>
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
<div ng-controller="sheetjs">
 | 
			
		||||
 | 
			
		||||
<table id="sjs-table">
 | 
			
		||||
  <tr><th>Name</th><th>Index</th></tr>
 | 
			
		||||
  <tr ng-repeat="row in data">
 | 
			
		||||
    <td>{{row.Name}}</td>
 | 
			
		||||
    <td>{{row.Index}}</td>
 | 
			
		||||
  </tr>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<button id="exportbtn">Export Table</button>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
var app = angular.module('sjs', []);
 | 
			
		||||
app.controller('sheetjs', function($scope, $http) {
 | 
			
		||||
  $http({
 | 
			
		||||
    method:'GET',
 | 
			
		||||
    url:'https://sheetjs.com/pres.xlsx',
 | 
			
		||||
    responseType:'arraybuffer'
 | 
			
		||||
  }).then(function(data) {
 | 
			
		||||
    var wb = XLSX.read(data.data, {type:"array"});
 | 
			
		||||
    var d = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
 | 
			
		||||
    $scope.data = d;
 | 
			
		||||
  }, function(err) { console.log(err); });
 | 
			
		||||
});
 | 
			
		||||
exportbtn.addEventListener('click', function() {
 | 
			
		||||
  var wb = XLSX.utils.table_to_book(document.getElementById('sjs-table'));
 | 
			
		||||
  XLSX.writeFile(wb, "export.xlsx");
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
/* eslint no-use-before-define:0 */
 | 
			
		||||
  var _gaq = _gaq || [];
 | 
			
		||||
  _gaq.push(['_setAccount', 'UA-36810333-1']);
 | 
			
		||||
  _gaq.push(['_trackPageview']);
 | 
			
		||||
 | 
			
		||||
  (function() {
 | 
			
		||||
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 | 
			
		||||
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 | 
			
		||||
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 | 
			
		||||
  })();
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/angular/shim.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/angular/shim.js
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
../../shim.js
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/angular/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/angular/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
../../dist/xlsx.core.min.js
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/angular/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/angular/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
../../dist/xlsx.full.min.js
 | 
			
		||||
							
								
								
									
										4
									
								
								demos/browserify/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										4
									
								
								demos/browserify/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,4 +0,0 @@
 | 
			
		||||
browserify.js
 | 
			
		||||
browserify.min.js
 | 
			
		||||
worker.js
 | 
			
		||||
worker.min.js
 | 
			
		||||
							
								
								
									
										2
									
								
								demos/chrome/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								demos/chrome/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +0,0 @@
 | 
			
		||||
xlsx.*.js
 | 
			
		||||
logo.png
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
.PHONY: init
 | 
			
		||||
init:
 | 
			
		||||
	cp ../../dist/xlsx.full.min.js .
 | 
			
		||||
	if [ ! -e logo.png ]; then curl -O https://sheetjs.com/logo.png; fi
 | 
			
		||||
 | 
			
		||||
.PHONY: lint
 | 
			
		||||
lint:
 | 
			
		||||
	eslint content.js popup.js table.js
 | 
			
		||||
@ -1,89 +1,6 @@
 | 
			
		||||
# Chrome and Chromium
 | 
			
		||||
 | 
			
		||||
This library is compatible with Chrome and Chromium extensions and should just
 | 
			
		||||
work out of the box.  Specific API support is listed in the Chrome extensions
 | 
			
		||||
API documentation.
 | 
			
		||||
 | 
			
		||||
## Generating Downloads
 | 
			
		||||
 | 
			
		||||
The `writeFile` function works in a Chrome or Chromium extension:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.writeFile(wb, "export.xlsx");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Under the hood, it uses the `chrome.downloads` API.  `"downloads"` permission
 | 
			
		||||
should be set in `manifest.json`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
"permissions": [
 | 
			
		||||
  "downloads"
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Content Script Table Scraping
 | 
			
		||||
 | 
			
		||||
`table_to_book` and `table_to_sheet` can help build workbooks from DOM tables:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var tables = document.getElementsByTagName("table");
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
for(var i = 0; i < tables.length; ++i) {
 | 
			
		||||
  var ws = XLSX.utils.table_to_sheet(tables[i]);
 | 
			
		||||
  XLSX.utils.book_append_sheet(wb, ws, "Table" + i);
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Demo
 | 
			
		||||
 | 
			
		||||
The demo extension includes multiple features to demonstrate sample usage.
 | 
			
		||||
Production extensions should include proper error handling.
 | 
			
		||||
 | 
			
		||||
#### Table Exporter
 | 
			
		||||
 | 
			
		||||
The `content.js` content script converts a table in the DOM to workbook object
 | 
			
		||||
using the `table_to_book` utility function:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// event page script trigger
 | 
			
		||||
chrome.tabs.sendMessage(tab.id);
 | 
			
		||||
// content script convert
 | 
			
		||||
var wb = XLSX.utils.table_to_book(elt);
 | 
			
		||||
// event page script callback
 | 
			
		||||
XLSX.writeFile(wb, "export.xlsx");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Since the workbook object is a plain JS object, the object is sent back to an
 | 
			
		||||
event page script which generates the file and attempts a download.
 | 
			
		||||
 | 
			
		||||
#### Bookmark Exporter
 | 
			
		||||
 | 
			
		||||
`chrome.bookmarks` API enables bookmark tree traversal.  The "Export Bookmarks"
 | 
			
		||||
button in the extension pop-up recursively walks the bookmark tree, pushes the
 | 
			
		||||
bookmark URLs into a data array, and exports into a simple spreadsheet:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* walk the bookmark tree */
 | 
			
		||||
function recurse_bookmarks(data, tree) {
 | 
			
		||||
  if(tree.url) data.push({Name: tree.title, Location: tree.url});
 | 
			
		||||
  (tree.children||[]).forEach(function(child) { recurse_bookmarks(data, child); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* get bookmark data */
 | 
			
		||||
chrome.bookmarks.getTree(function(res) {
 | 
			
		||||
  /* load into an array */
 | 
			
		||||
  var data = [];
 | 
			
		||||
  res.forEach(function(t) { recurse_bookmarks(data, t); });
 | 
			
		||||
 | 
			
		||||
  /* create worksheet */
 | 
			
		||||
  var ws = XLSX.utils.json_to_sheet(data, { header: ['Name', 'Location'] });
 | 
			
		||||
 | 
			
		||||
  /* create workbook and export */
 | 
			
		||||
  var wb = XLSX.utils.book_new();
 | 
			
		||||
  XLSX.utils.book_append_sheet(wb, ws, 'Bookmarks');
 | 
			
		||||
  XLSX.writeFile(wb, "bookmarks.xlsx");
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/chromium)
 | 
			
		||||
includes more up-to-date details.
 | 
			
		||||
 | 
			
		||||
[](https://github.com/SheetJS/js-xlsx)
 | 
			
		||||
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* global XLSX, chrome */
 | 
			
		||||
var coords = [0,0];
 | 
			
		||||
document.addEventListener('mousedown', function(mouse) {
 | 
			
		||||
	if(mouse && mouse.button == 2) coords = [mouse.clientX, mouse.clientY];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
chrome.runtime.onMessage.addListener(function(msg, sender, cb) {
 | 
			
		||||
	if(!msg || !msg['Sheet']) return;
 | 
			
		||||
	if(msg.Sheet == "JS") {
 | 
			
		||||
		var elt = document.elementFromPoint(coords[0], coords[1]);
 | 
			
		||||
		while(elt != null) {
 | 
			
		||||
			if(elt.tagName.toLowerCase() == "table") return cb(XLSX.utils.table_to_book(elt));
 | 
			
		||||
			elt = elt.parentElement;
 | 
			
		||||
		}
 | 
			
		||||
	} else if(msg.Sheet == "J5") {
 | 
			
		||||
		var tables = document.getElementsByTagName("table");
 | 
			
		||||
		var wb = XLSX.utils.book_new();
 | 
			
		||||
		for(var i = 0; i < tables.length; ++i) {
 | 
			
		||||
			var ws = XLSX.utils.table_to_sheet(tables[i]);
 | 
			
		||||
			XLSX.utils.book_append_sheet(wb, ws, "Table" + i);
 | 
			
		||||
		}
 | 
			
		||||
		return cb(wb);
 | 
			
		||||
	}
 | 
			
		||||
	cb(coords);
 | 
			
		||||
});
 | 
			
		||||
@ -1,30 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "manifest_version": 2,
 | 
			
		||||
  "name": "SheetJS Demo",
 | 
			
		||||
  "description": "Sample Extension using SheetJS to interact with Chrome",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "browser_action": {
 | 
			
		||||
    "default_popup": "popup.html",
 | 
			
		||||
    "default_icon": "logo.png"
 | 
			
		||||
  },
 | 
			
		||||
  "background": {
 | 
			
		||||
    "scripts": ["xlsx.full.min.js", "table.js"],
 | 
			
		||||
    "persistent": false
 | 
			
		||||
  },
 | 
			
		||||
  "content_scripts": [{
 | 
			
		||||
    "matches": ["<all_urls>"],
 | 
			
		||||
    "js": ["content.js", "xlsx.full.min.js"],
 | 
			
		||||
    "run_at": "document_end"
 | 
			
		||||
  }],
 | 
			
		||||
  "icons": {
 | 
			
		||||
    "16": "logo.png"
 | 
			
		||||
  },
 | 
			
		||||
  "permissions": [
 | 
			
		||||
    "activeTab",
 | 
			
		||||
    "<all_urls>",
 | 
			
		||||
    "bookmarks",
 | 
			
		||||
    "contextMenus",
 | 
			
		||||
    "downloads",
 | 
			
		||||
    "tabs"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<title>SheetJS Chrome Extension Export Test</title>
 | 
			
		||||
<meta charset="utf-8" />
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<!-- SheetJS js-xlsx library -->
 | 
			
		||||
<script type="text/javascript" src="xlsx.full.min.js"></script>
 | 
			
		||||
 | 
			
		||||
<button type="button" id="sjsdownload">Export Bookmarks</button>
 | 
			
		||||
<a><div id="sjsversion">Version</div></a>
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript" src="popup.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -1,31 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* global XLSX, chrome */
 | 
			
		||||
document.getElementById('sjsversion').innerText = "SheetJS " + XLSX.version;
 | 
			
		||||
 | 
			
		||||
document.getElementById('sjsversion').addEventListener('click', function() {
 | 
			
		||||
  chrome.tabs.create({url: "https://sheetjs.com/"}); return false;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* recursively walk the bookmark tree */
 | 
			
		||||
function recurse_bookmarks(data, tree, path) {
 | 
			
		||||
  if(tree.url) data.push({Name: tree.title, Location: tree.url, Path:path});
 | 
			
		||||
  var T = path ? (path + "::" + tree.title) : tree.title;
 | 
			
		||||
  (tree.children||[]).forEach(function(C) { recurse_bookmarks(data, C, T); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* export bookmark data */
 | 
			
		||||
document.getElementById('sjsdownload').addEventListener('click', function() {
 | 
			
		||||
  chrome.bookmarks.getTree(function(res) {
 | 
			
		||||
    var data = [];
 | 
			
		||||
    res.forEach(function(t) { recurse_bookmarks(data, t, ""); });
 | 
			
		||||
 | 
			
		||||
    /* create worksheet */
 | 
			
		||||
    var ws = XLSX.utils.json_to_sheet(data, { header: ['Name', 'Location', 'Path'] });
 | 
			
		||||
 | 
			
		||||
    /* create workbook and export */
 | 
			
		||||
    var wb = XLSX.utils.book_new();
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, ws, 'Bookmarks');
 | 
			
		||||
    XLSX.writeFile(wb, "bookmarks.xlsx");
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -1,43 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* global XLSX, chrome */
 | 
			
		||||
chrome.runtime.onInstalled.addListener(function() {
 | 
			
		||||
	chrome.contextMenus.create({
 | 
			
		||||
		type: "normal",
 | 
			
		||||
		id: "sjsexport",
 | 
			
		||||
		title: "Export Table to XLSX",
 | 
			
		||||
		contexts: ["page", "selection"]
 | 
			
		||||
	});
 | 
			
		||||
	chrome.contextMenus.create({
 | 
			
		||||
		type: "normal",
 | 
			
		||||
		id: "sj5export",
 | 
			
		||||
		title: "Export All Tables in Page",
 | 
			
		||||
		contexts: ["page", "selection"]
 | 
			
		||||
	});
 | 
			
		||||
	chrome.contextMenus.onClicked.addListener(function(info/*, tab*/) {
 | 
			
		||||
		var mode = "";
 | 
			
		||||
		switch(info.menuItemId) {
 | 
			
		||||
			case 'sjsexport': mode = "JS"; break;
 | 
			
		||||
			case 'sj5export': mode = "J5"; break;
 | 
			
		||||
			default: return;
 | 
			
		||||
		}
 | 
			
		||||
		chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
 | 
			
		||||
			chrome.tabs.sendMessage(tabs[0].id, {Sheet:mode}, sjsexport_cb);
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	chrome.contextMenus.create({
 | 
			
		||||
		id: "sjsabout",
 | 
			
		||||
		title: "About",
 | 
			
		||||
		contexts: ["browser_action"]
 | 
			
		||||
	});
 | 
			
		||||
	chrome.contextMenus.onClicked.addListener(function(info/*, tab*/) {
 | 
			
		||||
		if(info.menuItemId !== "sjsabout") return;
 | 
			
		||||
		chrome.tabs.create({url: "https://sheetjs.com/"});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function sjsexport_cb(wb) {
 | 
			
		||||
	if(!wb || !wb.SheetNames || !wb.Sheets) { return alert("Error in exporting table"); }
 | 
			
		||||
	XLSX.writeFile(wb, "export.xlsx");
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
	"env": { "shared-node-browser":true },
 | 
			
		||||
	"parserOptions": {
 | 
			
		||||
		"ecmaVersion": 8
 | 
			
		||||
	},
 | 
			
		||||
	"plugins": [ "html", "json" ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/database/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/database/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
*.db
 | 
			
		||||
@ -1,89 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
			
		||||
<title>SheetJS Firebase Dump Demo</title>
 | 
			
		||||
<style>
 | 
			
		||||
a { text-decoration: none }
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<h3><a href="//sheetjs.com/">SheetJS</a> Firebase Dump Demo</h3>
 | 
			
		||||
<b>Example Code</b>
 | 
			
		||||
 | 
			
		||||
  /* ... connect to firebase */
 | 
			
		||||
  const database = firebase.database();
 | 
			
		||||
 | 
			
		||||
  /* import workbook */
 | 
			
		||||
  await database.ref('foo').set(workbook);
 | 
			
		||||
 | 
			
		||||
  /* change cells */
 | 
			
		||||
  database.ref('foo').update({
 | 
			
		||||
    "Sheets/Sheet1/A1": {"t": "s", "v": "J"},
 | 
			
		||||
    "Sheets/Sheet1/A2": {"t": "n", "v": 5},
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /* export snapshot */
 | 
			
		||||
  const val = await database.ref('foo').once('value').val();
 | 
			
		||||
  XLSX.writeFile(wb, "firebase.xlsx");
 | 
			
		||||
 | 
			
		||||
</pre>
 | 
			
		||||
<script src="xlsx.full.min.js"></script>
 | 
			
		||||
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase.js"></script>
 | 
			
		||||
<script>
 | 
			
		||||
const Firebase = firebase;
 | 
			
		||||
const config = {
 | 
			
		||||
  credential: {
 | 
			
		||||
    getAccessToken: () => ({
 | 
			
		||||
      expires_in: 0,
 | 
			
		||||
      access_token: '',
 | 
			
		||||
    }),
 | 
			
		||||
  },
 | 
			
		||||
  databaseURL: 'ws://localhost:5555'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* make new workbook object from CSV */
 | 
			
		||||
const wb = XLSX.read('a,b,c\n1,2,3', {type:"binary"});
 | 
			
		||||
 | 
			
		||||
let P = Promise.resolve("sheetjs");
 | 
			
		||||
 | 
			
		||||
/* Connect to Firebase server and initialize collection */
 | 
			
		||||
P = P.then(async () => {
 | 
			
		||||
  Firebase.initializeApp(config);
 | 
			
		||||
  const database = Firebase.database();
 | 
			
		||||
  await database.ref('foo').set(null);
 | 
			
		||||
  return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Insert entire workbook object into `foo` ref */
 | 
			
		||||
P = P.then(async ([database]) => {
 | 
			
		||||
  await database.ref('foo').set(wb);
 | 
			
		||||
  return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Change cell A1 of Sheet1 to "J" and change A2 to 5 */
 | 
			
		||||
P = P.then(async ([database]) => {
 | 
			
		||||
  database.ref('foo').update({
 | 
			
		||||
    "Sheets/Sheet1/A1": {"t": "s", "v": "J"},
 | 
			
		||||
    "Sheets/Sheet1/A2": {"t": "n", "v": 5},
 | 
			
		||||
  });
 | 
			
		||||
  return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Write to file */
 | 
			
		||||
P = P.then(async ([database]) => {
 | 
			
		||||
  const val = await database.ref('foo').once('value');
 | 
			
		||||
  const wb = await val.val();
 | 
			
		||||
  XLSX.writeFile(wb, "firebase.xlsx");
 | 
			
		||||
  console.log(csv);
 | 
			
		||||
  return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Close connection */
 | 
			
		||||
P = P.then(async ([database]) => { database.app.delete(); });
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
const XLSX = require('xlsx');
 | 
			
		||||
const assert = require('assert');
 | 
			
		||||
const Firebase = require('firebase-admin');
 | 
			
		||||
 | 
			
		||||
const config = {
 | 
			
		||||
	credential: {
 | 
			
		||||
		getAccessToken: () => ({
 | 
			
		||||
			expires_in: 0,
 | 
			
		||||
			access_token: '',
 | 
			
		||||
		}),
 | 
			
		||||
	},
 | 
			
		||||
	databaseURL: 'ws://localhost:5555'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* make new workbook object from CSV */
 | 
			
		||||
const wb = XLSX.read('a,b,c\n1,2,3', {type:"binary", raw:true});
 | 
			
		||||
 | 
			
		||||
let P = Promise.resolve("sheetjs");
 | 
			
		||||
 | 
			
		||||
/* Connect to Firebase server and initialize collection */
 | 
			
		||||
P = P.then(async () => {
 | 
			
		||||
	Firebase.initializeApp(config);
 | 
			
		||||
	const database = Firebase.database();
 | 
			
		||||
	await database.ref('foo').set(null);
 | 
			
		||||
	return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Insert entire workbook object into `foo` ref */
 | 
			
		||||
P = P.then(async ([database]) => {
 | 
			
		||||
	await database.ref('foo').set(wb);
 | 
			
		||||
	return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Change cell A1 of Sheet1 to "J" and change A2 to 5 */
 | 
			
		||||
P = P.then(async ([database]) => {
 | 
			
		||||
	database.ref('foo').update({
 | 
			
		||||
		"Sheets/Sheet1/A1": {"t": "s", "v": "J"},
 | 
			
		||||
		"Sheets/Sheet1/A2": {"t": "n", "v": 5},
 | 
			
		||||
	});
 | 
			
		||||
	return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Write to file */
 | 
			
		||||
P = P.then(async ([database]) => {
 | 
			
		||||
	const val = await database.ref('foo').once('value');
 | 
			
		||||
	const wb = await val.val();
 | 
			
		||||
	XLSX.writeFile(wb, "firebase.xlsx");
 | 
			
		||||
	const ws = XLSX.readFile("firebase.xlsx").Sheets.Sheet1;
 | 
			
		||||
	const csv = XLSX.utils.sheet_to_csv(ws);
 | 
			
		||||
	assert.equal(csv, "J,b,c\n5,2,3\n");
 | 
			
		||||
	console.log(csv);
 | 
			
		||||
	return [database];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Close connection */
 | 
			
		||||
P = P.then(async ([database]) => { database.app.delete(); });
 | 
			
		||||
@ -1,73 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
/* global Promise */
 | 
			
		||||
const XLSX = require('xlsx');
 | 
			
		||||
const assert = require('assert');
 | 
			
		||||
const SheetJSKnex = require("./SheetJSKnex");
 | 
			
		||||
const Knex = require('knex');
 | 
			
		||||
 | 
			
		||||
/* Connection to both databases are passed around */
 | 
			
		||||
let P = Promise.resolve([
 | 
			
		||||
	Knex({ client: 'sqlite3', connection: { filename: './knex1.db' } }),
 | 
			
		||||
	Knex({ client: 'sqlite3', connection: { filename: './knex2.db' } })
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/* Sample data table */
 | 
			
		||||
P = P.then(async (_) => {
 | 
			
		||||
	const [knex] = _;
 | 
			
		||||
	await knex.schema.dropTableIfExists('pres');
 | 
			
		||||
	await knex.schema.createTable('pres', (table) => {
 | 
			
		||||
		table.string('name');
 | 
			
		||||
		table.integer('idx');
 | 
			
		||||
	});
 | 
			
		||||
	await knex.insert([
 | 
			
		||||
		{ name: "Barack Obama", idx: 44 },
 | 
			
		||||
		{ name: "Donald Trump", idx: 45 }
 | 
			
		||||
	]).into('pres');
 | 
			
		||||
 | 
			
		||||
	await knex.schema.dropTableIfExists('fmts');
 | 
			
		||||
	await knex.schema.createTable('fmts', (table) => {
 | 
			
		||||
		table.string('ext');
 | 
			
		||||
		table.string('ctr');
 | 
			
		||||
		table.integer('multi');
 | 
			
		||||
	});
 | 
			
		||||
	await knex.insert([
 | 
			
		||||
		{ ext: 'XLSB', ctr: 'ZIP', multi: 1 },
 | 
			
		||||
		{ ext: 'XLS',  ctr: 'CFB', multi: 1 },
 | 
			
		||||
		{ ext: 'XLML', ctr: '',    multi: 1 },
 | 
			
		||||
		{ ext: 'CSV',  ctr: 'ZIP', multi: 0 },
 | 
			
		||||
	]).into('fmts');
 | 
			
		||||
 | 
			
		||||
	return _;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Export database to XLSX */
 | 
			
		||||
P = P.then(async (_) => {
 | 
			
		||||
	const [knex] = _;
 | 
			
		||||
	const wb = XLSX.utils.book_new();
 | 
			
		||||
	await SheetJSKnex.book_append_knex(wb, knex, "pres");
 | 
			
		||||
	await SheetJSKnex.book_append_knex(wb, knex, "fmts");
 | 
			
		||||
	XLSX.writeFile(wb, "knex.xlsx");
 | 
			
		||||
	return _;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Import XLSX to database */
 | 
			
		||||
P = P.then(async (_) => {
 | 
			
		||||
	const [, knex] = _;
 | 
			
		||||
	const wb = XLSX.readFile("knex.xlsx");
 | 
			
		||||
	await SheetJSKnex.wb_to_knex(wb, knex);
 | 
			
		||||
	return _;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Compare databases */
 | 
			
		||||
P = P.then(async (_) => {
 | 
			
		||||
	const [k1, k2] = _;
 | 
			
		||||
	const P1 = await k1.select("*").from('pres');
 | 
			
		||||
	const P2 = await k2.select("*").from('pres');
 | 
			
		||||
	const F1 = await k1.select("*").from('fmts');
 | 
			
		||||
	const F2 = await k2.select("*").from('fmts');
 | 
			
		||||
	assert.deepEqual(P1, P2);
 | 
			
		||||
	assert.deepEqual(F1, F2);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
P.then(async () => { process.exit(); });
 | 
			
		||||
@ -1,59 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
			
		||||
<title>SheetJS Live Demo</title>
 | 
			
		||||
<style>
 | 
			
		||||
a { text-decoration: none }
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<b><a href="http://sheetjs.com">SheetJS LocalStorage Demo</a></b>
 | 
			
		||||
<pre id="data_">
 | 
			
		||||
Original Data:
 | 
			
		||||
</pre>
 | 
			
		||||
<pre id="out">
 | 
			
		||||
Output:
 | 
			
		||||
 | 
			
		||||
</pre>
 | 
			
		||||
<script src="xlsx.full.min.js"></script>
 | 
			
		||||
<script src="ObjUtils.js"></script>
 | 
			
		||||
<script src="https://unpkg.com/localforage/dist/localforage.min.js"></script>
 | 
			
		||||
<script src="SheetJSForage.js"></script>
 | 
			
		||||
<script>
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/*global XLSX, localforage */
 | 
			
		||||
var data = {
 | 
			
		||||
  "title": "SheetDB",
 | 
			
		||||
  "metadata": {
 | 
			
		||||
    "author": "SheetJS",
 | 
			
		||||
    "code": 7262
 | 
			
		||||
  },
 | 
			
		||||
  "data": [
 | 
			
		||||
    { "Name": "Barack Obama", "Index": 44 },
 | 
			
		||||
    { "Name": "Donald Trump", "Index": 45 },
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
document.getElementById("data_").innerText += JSON.stringify(data, 2, 2);
 | 
			
		||||
 | 
			
		||||
localforage.setDriver(localforage.INDEXEDDB);
 | 
			
		||||
(async function() {
 | 
			
		||||
  await localforage.clear();
 | 
			
		||||
 | 
			
		||||
  await localforage.load(data);
 | 
			
		||||
  var wb = await localforage.dump();
 | 
			
		||||
  console.log(wb);
 | 
			
		||||
 | 
			
		||||
  var OUT = document.getElementById("out");
 | 
			
		||||
  wb.SheetNames.forEach(function(n, i) {
 | 
			
		||||
    OUT.innerText += "Sheet " + i + " (" + n + ")\n";
 | 
			
		||||
    OUT.innerText += XLSX.utils.sheet_to_csv(wb.Sheets[n]);
 | 
			
		||||
    OUT.innerText += "\n";
 | 
			
		||||
  });
 | 
			
		||||
})();
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -1,57 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
			
		||||
<title>SheetJS Live Demo</title>
 | 
			
		||||
<style>
 | 
			
		||||
a { text-decoration: none }
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<b><a href="http://sheetjs.com">SheetJS LocalStorage Demo</a></b>
 | 
			
		||||
<pre id="data_">
 | 
			
		||||
Original Data:
 | 
			
		||||
</pre>
 | 
			
		||||
<pre id="out">
 | 
			
		||||
Output:
 | 
			
		||||
 | 
			
		||||
</pre>
 | 
			
		||||
<script src="xlsx.full.min.js"></script>
 | 
			
		||||
<script src="ObjUtils.js"></script>
 | 
			
		||||
<script src="SheetJSStorage.js"></script>
 | 
			
		||||
<script>
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/*global XLSX */
 | 
			
		||||
var data = {
 | 
			
		||||
  "title": "SheetDB",
 | 
			
		||||
  "metadata": {
 | 
			
		||||
    "author": "SheetJS",
 | 
			
		||||
    "code": 7262
 | 
			
		||||
  },
 | 
			
		||||
  "data": [
 | 
			
		||||
    { "Name": "Barack Obama", "Index": 44 },
 | 
			
		||||
    { "Name": "Donald Trump", "Index": 45 },
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
document.getElementById("data_").innerText += JSON.stringify(data, 2, 2);
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
  localStorage.clear();
 | 
			
		||||
 | 
			
		||||
  localStorage.load(data);
 | 
			
		||||
  var wb = localStorage.dump();
 | 
			
		||||
  console.log(wb);
 | 
			
		||||
 | 
			
		||||
  var OUT = document.getElementById("out");
 | 
			
		||||
  wb.SheetNames.forEach(function(n, i) {
 | 
			
		||||
    OUT.innerText += "Sheet " + i + " (" + n + ")\n";
 | 
			
		||||
    OUT.innerText += XLSX.utils.sheet_to_csv(wb.Sheets[n]);
 | 
			
		||||
    OUT.innerText += "\n";
 | 
			
		||||
  });
 | 
			
		||||
})();
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var low = require('lowdb');
 | 
			
		||||
var SheetJSAdapter = require('./SheetJSLowDB');
 | 
			
		||||
var adapter = new SheetJSAdapter();
 | 
			
		||||
var db = low(adapter);
 | 
			
		||||
 | 
			
		||||
db.defaults({ posts: [], user: {}, count: 0 }).write();
 | 
			
		||||
db.get('posts').push({ id: 1, title: 'lowdb is awesome'}).write();
 | 
			
		||||
db.set('user.name', 'typicode').write();
 | 
			
		||||
db.update('count', function(n) { return n + 1; }).write();
 | 
			
		||||
 | 
			
		||||
adapter.dumpFile('ldb1.xlsx');
 | 
			
		||||
 | 
			
		||||
var adapter2 = new SheetJSAdapter();
 | 
			
		||||
adapter2.loadFile('ldb1.xlsx');
 | 
			
		||||
var db2 = low(adapter2);
 | 
			
		||||
 | 
			
		||||
db2.get('posts').push({ id: 2, title: 'mongodb is not'}).write();
 | 
			
		||||
db2.set('user.name', 'sheetjs').write();
 | 
			
		||||
db2.update('count', function(n) { return n + 1; }).write();
 | 
			
		||||
 | 
			
		||||
adapter2.dumpFile('ldb2.xlsx');
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
.PHONY: init
 | 
			
		||||
init:
 | 
			
		||||
	rm -f node_modules/xlsx
 | 
			
		||||
	mkdir -p node_modules
 | 
			
		||||
	cd node_modules; ln -s ../../../ xlsx; cd -
 | 
			
		||||
	rm -f xlsx.full.min.js
 | 
			
		||||
	ln -s ../../dist/xlsx.full.min.js
 | 
			
		||||
 | 
			
		||||
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,63 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
/* global Promise */
 | 
			
		||||
const XLSX = require('xlsx');
 | 
			
		||||
const SheetJSMongo = require("./SheetJSMongo");
 | 
			
		||||
const MongoClient = require('mongodb').MongoClient;
 | 
			
		||||
 | 
			
		||||
const url = 'mongodb://localhost:27017/sheetjs';
 | 
			
		||||
const db_name = 'sheetjs';
 | 
			
		||||
 | 
			
		||||
let P = Promise.resolve("sheetjs");
 | 
			
		||||
 | 
			
		||||
/* Connect to mongodb server */
 | 
			
		||||
P = P.then(async () => {
 | 
			
		||||
	const client = await MongoClient.connect(url,{ useUnifiedTopology: true });
 | 
			
		||||
	return [client];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Sample data table */
 | 
			
		||||
P = P.then(async ([client]) => {
 | 
			
		||||
	const db = client.db(db_name);
 | 
			
		||||
 | 
			
		||||
	try { await db.collection('pres').drop(); } catch(e) {}
 | 
			
		||||
	const pres = db.collection('pres');
 | 
			
		||||
	await pres.insertMany([
 | 
			
		||||
		{ name: "Barack Obama", idx: 44 },
 | 
			
		||||
		{ name: "Donald Trump", idx: 45 }
 | 
			
		||||
	], {ordered: true});
 | 
			
		||||
 | 
			
		||||
	try { await db.collection('fmts').drop(); } catch(e) {}
 | 
			
		||||
	const fmts = db.collection('fmts');
 | 
			
		||||
	await fmts.insertMany([
 | 
			
		||||
		{ ext: 'XLSB', ctr: 'ZIP', multi: 1 },
 | 
			
		||||
		{ ext: 'XLS',  ctr: 'CFB', multi: 1 },
 | 
			
		||||
		{ ext: 'XLML',             multi: 1 },
 | 
			
		||||
		{ ext: 'CSV',  ctr: 'ZIP', multi: 0 },
 | 
			
		||||
	], {ordered: true});
 | 
			
		||||
 | 
			
		||||
	return [client, pres, fmts];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Export database to XLSX */
 | 
			
		||||
P = P.then(async ([client, pres, fmts]) => {
 | 
			
		||||
	const wb = XLSX.utils.book_new();
 | 
			
		||||
	await SheetJSMongo.book_append_mongo(wb, pres, "pres");
 | 
			
		||||
	await SheetJSMongo.book_append_mongo(wb, fmts, "fmts");
 | 
			
		||||
	XLSX.writeFile(wb, "mongocrud.xlsx");
 | 
			
		||||
	return [client, pres, fmts];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Read the new file and dump all of the data */
 | 
			
		||||
P = P.then(([client]) => {
 | 
			
		||||
	const wb = XLSX.readFile('mongocrud.xlsx');
 | 
			
		||||
	wb.SheetNames.forEach((n,i) => {
 | 
			
		||||
		console.log(`Sheet #${i+1}: ${n}`);
 | 
			
		||||
		const ws = wb.Sheets[n];
 | 
			
		||||
		console.log(XLSX.utils.sheet_to_csv(ws));
 | 
			
		||||
	});
 | 
			
		||||
    return [client];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Close connection */
 | 
			
		||||
P.then(async ([client]) => { client.close(); });
 | 
			
		||||
@ -1,54 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
/* global Promise */
 | 
			
		||||
const XLSX = require('xlsx');
 | 
			
		||||
const assert = require('assert');
 | 
			
		||||
const MongoClient = require('mongodb').MongoClient;
 | 
			
		||||
 | 
			
		||||
const url = 'mongodb://localhost:27017/sheetjs';
 | 
			
		||||
const db_name = 'sheetjs';
 | 
			
		||||
 | 
			
		||||
/* make new workbook object from CSV */
 | 
			
		||||
const wb = XLSX.read('a,b,c\n1,2,3', {type:"binary", raw:true});
 | 
			
		||||
 | 
			
		||||
let P = Promise.resolve("sheetjs");
 | 
			
		||||
 | 
			
		||||
/* Connect to mongodb server and initialize collection */
 | 
			
		||||
P = P.then(async () => {
 | 
			
		||||
	const client = await MongoClient.connect(url,{ useUnifiedTopology: true });
 | 
			
		||||
	const db = client.db(db_name);
 | 
			
		||||
	try { await db.collection('wb').drop(); } catch(e) {}
 | 
			
		||||
	const coll = db.collection('wb');
 | 
			
		||||
	return [client, coll];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Insert entire workbook object as a document */
 | 
			
		||||
P = P.then(async ([client, coll]) => {
 | 
			
		||||
	const res = await coll.insertOne(wb);
 | 
			
		||||
	assert.equal(res.insertedCount, 1);
 | 
			
		||||
	return [client, coll];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Change cell A1 of Sheet1 to "J" and change A2 to 5 */
 | 
			
		||||
P = P.then(async ([client, coll]) => {
 | 
			
		||||
	const res = await coll.updateOne({}, { $set: {
 | 
			
		||||
		"Sheets.Sheet1.A1": {"t": "s", "v": "J"},
 | 
			
		||||
		"Sheets.Sheet1.A2": {"t": "n", "v": 5},
 | 
			
		||||
	}});
 | 
			
		||||
	assert.equal(res.matchedCount, 1);
 | 
			
		||||
	assert.equal(res.modifiedCount, 1);
 | 
			
		||||
	return [client, coll];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Write to file */
 | 
			
		||||
P = P.then(async ([client, coll]) => {
 | 
			
		||||
	const res = await coll.find({}).toArray();
 | 
			
		||||
	const wb = res[0];
 | 
			
		||||
	XLSX.writeFile(wb, "mongo.xlsx");
 | 
			
		||||
	const ws = XLSX.readFile("mongo.xlsx").Sheets.Sheet1;
 | 
			
		||||
	console.log(XLSX.utils.sheet_to_csv(ws));
 | 
			
		||||
	return [client, coll];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* Close connection */
 | 
			
		||||
P.then(async ([client]) => { client.close(); });
 | 
			
		||||
@ -1,70 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require('xlsx');
 | 
			
		||||
var assert = require('assert');
 | 
			
		||||
var SheetJSSQL = require('./SheetJSSQL');
 | 
			
		||||
var mysql = require('mysql2/promise');
 | 
			
		||||
 | 
			
		||||
/* Connection options (requires two databases sheetjs and sheetj5) */
 | 
			
		||||
var opts = {
 | 
			
		||||
  host     : 'localhost',
 | 
			
		||||
  user     : 'SheetJS',
 | 
			
		||||
  password : 'SheetJS',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Sample data table */
 | 
			
		||||
var init = [
 | 
			
		||||
  "DROP TABLE IF EXISTS pres",
 | 
			
		||||
  "CREATE TABLE pres (name TEXT, idx TINYINT)",
 | 
			
		||||
  "INSERT INTO pres VALUES ('Barack Obama', 44)",
 | 
			
		||||
  "INSERT INTO pres VALUES ('Donald Trump', 45)",
 | 
			
		||||
  "DROP TABLE IF EXISTS fmts",
 | 
			
		||||
  "CREATE TABLE fmts (ext TEXT, ctr TEXT, multi TINYINT)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLSB', 'ZIP', 1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLS',  'CFB', 1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLML', '',    1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('CSV',  '',    0)",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
(async () => {
 | 
			
		||||
  const conn1 = await mysql.createConnection(Object.assign({}, opts, {database: "sheetjs"}));
 | 
			
		||||
  for(var i = 0; i < init.length; ++i) await conn1.query(init[i]);
 | 
			
		||||
 | 
			
		||||
  /* Export table to XLSX */
 | 
			
		||||
  var wb = XLSX.utils.book_new();
 | 
			
		||||
 | 
			
		||||
  async function book_append_table(wb, name) {
 | 
			
		||||
    var r_f = await conn1.query('SELECT * FROM ' + name);
 | 
			
		||||
    var r = r_f[0];
 | 
			
		||||
    var ws = XLSX.utils.json_to_sheet(r);
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, ws, name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  await book_append_table(wb, "pres");
 | 
			
		||||
  await book_append_table(wb, "fmts");
 | 
			
		||||
  XLSX.writeFile(wb, "mysql.xlsx");
 | 
			
		||||
 | 
			
		||||
  /* Capture first database info and close */
 | 
			
		||||
  var P1 = (await conn1.query("SELECT * FROM pres"))[0];
 | 
			
		||||
  var F1 = (await conn1.query("SELECT * FROM fmts"))[0];
 | 
			
		||||
  await conn1.close();
 | 
			
		||||
 | 
			
		||||
  /* Import XLSX to table */
 | 
			
		||||
  const conn2 = await mysql.createConnection(Object.assign({}, opts, {database: "sheetj5"}));
 | 
			
		||||
  var wb2 = XLSX.readFile("mysql.xlsx");
 | 
			
		||||
  var queries = SheetJSSQL.book_to_sql(wb2, "MYSQL");
 | 
			
		||||
  for(i = 0; i < queries.length; ++i) await conn2.query(queries[i]);
 | 
			
		||||
 | 
			
		||||
  /* Capture first database info and close */
 | 
			
		||||
  var P2 = (await conn2.query("SELECT * FROM pres"))[0];
 | 
			
		||||
  var F2 = (await conn2.query("SELECT * FROM fmts"))[0];
 | 
			
		||||
  await conn2.close();
 | 
			
		||||
 | 
			
		||||
  /* Compare results */
 | 
			
		||||
  assert.deepEqual(P1, P2);
 | 
			
		||||
  assert.deepEqual(F1, F2);
 | 
			
		||||
 | 
			
		||||
  /* Display results */
 | 
			
		||||
  console.log(P2);
 | 
			
		||||
  console.log(F2);
 | 
			
		||||
})();
 | 
			
		||||
@ -1,59 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/*global XLSX, module, require */
 | 
			
		||||
var ObjUtils = (function() {
 | 
			
		||||
 | 
			
		||||
var X;
 | 
			
		||||
if(typeof XLSX !== "undefined") X = XLSX;
 | 
			
		||||
else if(typeof require !== 'undefined') X = require('xlsx');
 | 
			
		||||
else throw new Error("Could not find XLSX");
 | 
			
		||||
 | 
			
		||||
function walk(obj, key, arr) {
 | 
			
		||||
  if(Array.isArray(obj)) return;
 | 
			
		||||
  if(typeof obj != "object" || obj instanceof Date) { arr.push({path:key, value:obj}); return; }
 | 
			
		||||
  Object.keys(obj).forEach(function(k) {
 | 
			
		||||
    walk(obj[k], key ? key + "." + k : k, arr);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function object_to_workbook(obj) {
 | 
			
		||||
  var wb = X.utils.book_new();
 | 
			
		||||
 | 
			
		||||
  var base = []; walk(obj, "", base);
 | 
			
		||||
  var ws = X.utils.json_to_sheet(base, {header:["path", "value"]});
 | 
			
		||||
  X.utils.book_append_sheet(wb, ws, "_keys");
 | 
			
		||||
 | 
			
		||||
  Object.keys(obj).forEach(function(k) {
 | 
			
		||||
    if(!Array.isArray(obj[k])) return;
 | 
			
		||||
    X.utils.book_append_sheet(wb, X.utils.json_to_sheet(obj[k]), k);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return wb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deepset(obj, path, value) {
 | 
			
		||||
  if(path.indexOf(".") == -1) return obj[path] = value;
 | 
			
		||||
  var parts = path.split(".");
 | 
			
		||||
  if(!obj[parts[0]]) obj[parts[0]] = {};
 | 
			
		||||
  return deepset(obj[parts[0]], parts.slice(1).join("."), value);
 | 
			
		||||
}
 | 
			
		||||
function workbook_set_object(obj, wb) {
 | 
			
		||||
  var ws = wb.Sheets["_keys"]; if(ws) {
 | 
			
		||||
    var data = X.utils.sheet_to_json(ws, {raw:true});
 | 
			
		||||
    data.forEach(function(r) { deepset(obj, r.path, r.value); });
 | 
			
		||||
  }
 | 
			
		||||
  wb.SheetNames.forEach(function(n) {
 | 
			
		||||
    if(n == "_keys") return;
 | 
			
		||||
    obj[n] = X.utils.sheet_to_json(wb.Sheets[n], {raw:true});
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function workbook_to_object(wb) { var obj = {}; workbook_set_object(obj, wb); return obj; }
 | 
			
		||||
 | 
			
		||||
return {
 | 
			
		||||
  workbook_to_object: workbook_to_object,
 | 
			
		||||
  object_to_workbook: object_to_workbook,
 | 
			
		||||
  workbook_set_object: workbook_set_object
 | 
			
		||||
};
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
if(typeof module !== 'undefined') module.exports = ObjUtils;
 | 
			
		||||
@ -1,72 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require('xlsx');
 | 
			
		||||
var assert = require('assert');
 | 
			
		||||
var SheetJSSQL = require('./SheetJSSQL');
 | 
			
		||||
var Client = require('pg').Client;
 | 
			
		||||
 | 
			
		||||
/* Connection options (requires two databases sheetjs and sheetj5) */
 | 
			
		||||
var opts = {
 | 
			
		||||
  host     : 'localhost',
 | 
			
		||||
  user     : 'SheetJS',
 | 
			
		||||
  password : 'SheetJS',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Sample data table */
 | 
			
		||||
var init = [
 | 
			
		||||
  "DROP TABLE IF EXISTS pres",
 | 
			
		||||
  "CREATE TABLE pres (name text, idx smallint)",
 | 
			
		||||
  "INSERT INTO pres VALUES ('Barack Obama', 44)",
 | 
			
		||||
  "INSERT INTO pres VALUES ('Donald Trump', 45)",
 | 
			
		||||
  "DROP TABLE IF EXISTS fmts",
 | 
			
		||||
  "CREATE TABLE fmts (ext text, ctr text, multi smallint)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLSB', 'ZIP', 1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLS',  'CFB', 1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLML', '',    1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('CSV',  '',    0)",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
var conn1 = new Client(Object.assign({}, opts, {database: "sheetjs"}));
 | 
			
		||||
var conn2 = new Client(Object.assign({}, opts, {database: "sheetj5"}));
 | 
			
		||||
(async () => {
 | 
			
		||||
  await conn1.connect();
 | 
			
		||||
  for(var i = 0; i < init.length; ++i) await conn1.query(init[i]);
 | 
			
		||||
 | 
			
		||||
  /* Export table to XLSX */
 | 
			
		||||
  var wb = XLSX.utils.book_new();
 | 
			
		||||
 | 
			
		||||
  async function book_append_table(wb, name) {
 | 
			
		||||
    var r_f = await conn1.query('SELECT * FROM ' + name);
 | 
			
		||||
    var r = r_f.rows;
 | 
			
		||||
    var ws = XLSX.utils.json_to_sheet(r);
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, ws, name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  await book_append_table(wb, "pres");
 | 
			
		||||
  await book_append_table(wb, "fmts");
 | 
			
		||||
  XLSX.writeFile(wb, "pgsql.xlsx");
 | 
			
		||||
 | 
			
		||||
  /* Capture first database info and close */
 | 
			
		||||
  var P1 = (await conn1.query("SELECT * FROM pres")).rows;
 | 
			
		||||
  var F1 = (await conn1.query("SELECT * FROM fmts")).rows;
 | 
			
		||||
  await conn1.end();
 | 
			
		||||
 | 
			
		||||
  /* Import XLSX to table */
 | 
			
		||||
  await conn2.connect();
 | 
			
		||||
  var wb2 = XLSX.readFile("pgsql.xlsx");
 | 
			
		||||
  var queries = SheetJSSQL.book_to_sql(wb2, "PGSQL");
 | 
			
		||||
  for(i = 0; i < queries.length; ++i) { console.log(queries[i]); await conn2.query(queries[i]); }
 | 
			
		||||
 | 
			
		||||
  /* Capture first database info and close */
 | 
			
		||||
  var P2 = (await conn2.query("SELECT * FROM pres")).rows;
 | 
			
		||||
  var F2 = (await conn2.query("SELECT * FROM fmts")).rows;
 | 
			
		||||
  await conn2.end();
 | 
			
		||||
 | 
			
		||||
  /* Compare results */
 | 
			
		||||
  assert.deepEqual(P1, P2);
 | 
			
		||||
  assert.deepEqual(F1, F2);
 | 
			
		||||
 | 
			
		||||
  /* Display results */
 | 
			
		||||
  console.log(P2);
 | 
			
		||||
  console.log(F2);
 | 
			
		||||
})();
 | 
			
		||||
@ -1,340 +1,11 @@
 | 
			
		||||
# Databases
 | 
			
		||||
 | 
			
		||||
"Database" is a catch-all term referring to traditional RDBMS as well as K/V
 | 
			
		||||
stores, document databases, and other "NoSQL" storages. There are many external
 | 
			
		||||
database systems as well as browser APIs like WebSQL and `localStorage`
 | 
			
		||||
This demo has been split up for clarity:
 | 
			
		||||
 | 
			
		||||
This demo discusses general strategies and provides examples for a variety of
 | 
			
		||||
database systems.  The examples are merely intended to demonstrate very basic
 | 
			
		||||
functionality.
 | 
			
		||||
- <https://docs.sheetjs.com/docs/getting-started/demos/database> covers SQL and
 | 
			
		||||
  structured data (including CRUD operations)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Structured Tables
 | 
			
		||||
 | 
			
		||||
Database tables are a common import and export target for spreadsheets.  One
 | 
			
		||||
common representation of a database table is an array of JS objects whose keys
 | 
			
		||||
are column headers and whose values are the underlying data values. For example,
 | 
			
		||||
 | 
			
		||||
| Name         | Index |
 | 
			
		||||
| :----------- | ----: |
 | 
			
		||||
| Barack Obama |    44 |
 | 
			
		||||
| Donald Trump |    45 |
 | 
			
		||||
 | 
			
		||||
is naturally represented as an array of objects
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
[
 | 
			
		||||
  { Name: "Barack Obama", Index: 44 },
 | 
			
		||||
  { Name: "Donald Trump", Index: 45 }
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `sheet_to_json` and `json_to_sheet` helper functions work with objects of
 | 
			
		||||
similar shape, converting to and from worksheet objects.  The corresponding
 | 
			
		||||
worksheet would include a header row for the labels:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
XXX|      A       |   B   |
 | 
			
		||||
---+--------------+-------+
 | 
			
		||||
 1 | Name         | Index |
 | 
			
		||||
 2 | Barack Obama |    44 |
 | 
			
		||||
 3 | Donald Trump |    45 |
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Building Schemas from Worksheets
 | 
			
		||||
 | 
			
		||||
The `sheet_to_json` helper function generates arrays of JS objects that can be
 | 
			
		||||
scanned to determine the column "types", and there are third-party connectors
 | 
			
		||||
that can push arrays of JS objects to database tables.
 | 
			
		||||
 | 
			
		||||
The [`sql`](http://sheetjs.com/sql) browser demo uses WebSQL, which is
 | 
			
		||||
limited to the SQLite fundamental types.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
	<summary><b>Implementation details</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
The `sql` schema builder scans the first row to find headers:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
  if(!ws || !ws['!ref']) return;
 | 
			
		||||
  var range = XLSX.utils.decode_range(ws['!ref']);
 | 
			
		||||
  if(!range || !range.s || !range.e || range.s > range.e) return;
 | 
			
		||||
  var R = range.s.r, C = range.s.c;
 | 
			
		||||
 | 
			
		||||
  var names = new Array(range.e.c-range.s.c+1);
 | 
			
		||||
  for(C = range.s.c; C<= range.e.c; ++C){
 | 
			
		||||
    var addr = XLSX.utils.encode_cell({c:C,r:R});
 | 
			
		||||
    names[C-range.s.c] = ws[addr] ? ws[addr].v : XLSX.utils.encode_col(C);
 | 
			
		||||
  }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After finding the headers, a deduplication step ensures that data is not lost.
 | 
			
		||||
Duplicate headers will be suffixed with `_1`, `_2`, etc.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
  for(var i = 0; i < names.length; ++i) if(names.indexOf(names[i]) < i)
 | 
			
		||||
    for(var j = 0; j < names.length; ++j) {
 | 
			
		||||
      var _name = names[i] + "_" + (j+1);
 | 
			
		||||
      if(names.indexOf(_name) > -1) continue;
 | 
			
		||||
      names[i] = _name;
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A column-major walk helps determine the data type.  For SQLite the only relevant
 | 
			
		||||
data types are `REAL` and `TEXT`.  If a string or date or error is seen in any
 | 
			
		||||
value of a column, the column is marked as `TEXT`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
  var types = new Array(range.e.c-range.s.c+1);
 | 
			
		||||
  for(C = range.s.c; C<= range.e.c; ++C) {
 | 
			
		||||
    var seen = {}, _type = "";
 | 
			
		||||
    for(R = range.s.r+1; R<= range.e.r; ++R)
 | 
			
		||||
      seen[(ws[XLSX.utils.encode_cell({c:C,r:R})]||{t:"z"}).t] = true;
 | 
			
		||||
    if(seen.s || seen.str) _type = "TEXT";
 | 
			
		||||
    else if(seen.n + seen.b + seen.d + seen.e > 1) _type = "TEXT";
 | 
			
		||||
    else switch(true) {
 | 
			
		||||
      case seen.b:
 | 
			
		||||
      case seen.n: _type = "REAL"; break;
 | 
			
		||||
      case seen.e: _type = "TEXT"; break;
 | 
			
		||||
      case seen.d: _type = "TEXT"; break;
 | 
			
		||||
    }
 | 
			
		||||
    types[C-range.s.c] = _type || "TEXT";
 | 
			
		||||
  }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
The included `SheetJSSQL.js` script demonstrates SQL statement generation.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Objects, K/V and "Schema-less" Databases
 | 
			
		||||
 | 
			
		||||
So-called "Schema-less" databases allow for arbitrary keys and values within the
 | 
			
		||||
entries in the database.  K/V stores and Objects add additional restrictions.
 | 
			
		||||
 | 
			
		||||
There is no natural way to translate arbitrarily shaped schemas to worksheets
 | 
			
		||||
in a workbook.  One common trick is to dedicate one worksheet to holding named
 | 
			
		||||
keys.  For example, considering the JS object:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "title": "SheetDB",
 | 
			
		||||
  "metadata": {
 | 
			
		||||
    "author": "SheetJS",
 | 
			
		||||
    "code": 7262
 | 
			
		||||
  },
 | 
			
		||||
  "data": [
 | 
			
		||||
    { "Name": "Barack Obama", "Index": 44 },
 | 
			
		||||
    { "Name": "Donald Trump", "Index": 45 },
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A dedicated worksheet should store the one-off named values:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
XXX|        A        |    B    |
 | 
			
		||||
---+-----------------+---------+
 | 
			
		||||
 1 | Path            | Value   |
 | 
			
		||||
 2 | title           | SheetDB |
 | 
			
		||||
 3 | metadata.author | SheetJS |
 | 
			
		||||
 4 | metadata.code   |    7262 |
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The included `ObjUtils.js` script demonstrates object-workbook conversion:
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
	<summary><b>Implementation details</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
function deepset(obj, path, value) {
 | 
			
		||||
  if(path.indexOf(".") == -1) return obj[path] = value;
 | 
			
		||||
  var parts = path.split(".");
 | 
			
		||||
  if(!obj[parts[0]]) obj[parts[0]] = {};
 | 
			
		||||
  return deepset(obj[parts[0]], parts.slice(1).join("."), value);
 | 
			
		||||
}
 | 
			
		||||
function workbook_to_object(wb) {
 | 
			
		||||
  var out = {};
 | 
			
		||||
 | 
			
		||||
  /* assign one-off keys */
 | 
			
		||||
  var ws = wb.Sheets["_keys"]; if(ws) {
 | 
			
		||||
    var data = XLSX.utils.sheet_to_json(ws, {raw:true});
 | 
			
		||||
    data.forEach(function(r) { deepset(out, r.path, r.value); });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* assign arrays from worksheet tables */
 | 
			
		||||
  wb.SheetNames.forEach(function(n) {
 | 
			
		||||
    if(n == "_keys") return;
 | 
			
		||||
    out[n] = XLSX.utils.sheet_to_json(wb.Sheets[n], {raw:true});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function walk(obj, key, arr) {
 | 
			
		||||
  if(Array.isArray(obj)) return;
 | 
			
		||||
  if(typeof obj != "object") { arr.push({path:key, value:obj}); return; }
 | 
			
		||||
  Object.keys(obj).forEach(function(k) { walk(obj[k], key?key+"."+k:k, arr); });
 | 
			
		||||
}
 | 
			
		||||
function object_to_workbook(obj) {
 | 
			
		||||
  var wb = XLSX.utils.book_new();
 | 
			
		||||
 | 
			
		||||
  /* keyed entries */
 | 
			
		||||
  var base = []; walk(obj, "", base);
 | 
			
		||||
  var ws = XLSX.utils.json_to_sheet(base, {header:["path", "value"]});
 | 
			
		||||
  XLSX.utils.book_append_sheet(wb, ws, "_keys");
 | 
			
		||||
 | 
			
		||||
  /* arrays */
 | 
			
		||||
  Object.keys(obj).forEach(function(k) {
 | 
			
		||||
    if(!Array.isArray(obj[k])) return;
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(obj[k]), k);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return wb;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Browser APIs
 | 
			
		||||
 | 
			
		||||
#### WebSQL
 | 
			
		||||
 | 
			
		||||
WebSQL is a popular SQL-based in-browser database available on Chrome.  In
 | 
			
		||||
practice, it is powered by SQLite, and most simple SQLite-compatible queries
 | 
			
		||||
work as-is in WebSQL.
 | 
			
		||||
 | 
			
		||||
The public demo <http://sheetjs.com/sql> generates a database from workbook.
 | 
			
		||||
 | 
			
		||||
#### LocalStorage and SessionStorage
 | 
			
		||||
 | 
			
		||||
The Storage API, encompassing `localStorage` and `sessionStorage`, describes
 | 
			
		||||
simple key-value stores that only support string values and keys. Objects can be
 | 
			
		||||
stored as JSON using `JSON.stringify` and `JSON.parse` to set and get keys.
 | 
			
		||||
 | 
			
		||||
`SheetJSStorage.js` extends the `Storage` prototype with a `load` function to
 | 
			
		||||
populate the db based on an object and a `dump` function to generate a workbook
 | 
			
		||||
from the data in the storage.  `LocalStorage.html` tests `localStorage`.
 | 
			
		||||
 | 
			
		||||
#### IndexedDB
 | 
			
		||||
 | 
			
		||||
IndexedDB is a more complex storage solution, but the `localForage` wrapper
 | 
			
		||||
supplies a Promise-based interface mimicking the `Storage` API.
 | 
			
		||||
 | 
			
		||||
`SheetJSForage.js` extends the `localforage` object with a `load` function to
 | 
			
		||||
populate the db based on an object and a `dump` function to generate a workbook
 | 
			
		||||
from the data in the storage.  `LocalForage.html` forces IndexedDB mode.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## External Database Demos
 | 
			
		||||
 | 
			
		||||
### SQL Databases
 | 
			
		||||
 | 
			
		||||
There are nodejs connector libraries for all of the popular RDBMS systems.  They
 | 
			
		||||
have facilities for connecting to a database, executing queries, and obtaining
 | 
			
		||||
results as arrays of JS objects that can be passed to `json_to_sheet`.  The main
 | 
			
		||||
differences surround API shape and supported data types.
 | 
			
		||||
 | 
			
		||||
#### SQLite
 | 
			
		||||
 | 
			
		||||
[The `better-sqlite3` module](https://www.npmjs.com/package/better-sqlite3)
 | 
			
		||||
provides a very simple API for working with SQLite databases.  `Statement#all`
 | 
			
		||||
runs a prepared statement and returns an array of JS objects.
 | 
			
		||||
 | 
			
		||||
`SQLiteTest.js` generates a simple two-table SQLite database (`SheetJS1.db`),
 | 
			
		||||
exports to XLSX (`sqlite.xlsx`), imports the new XLSX file to a new database
 | 
			
		||||
(`SheetJS2.db`) and verifies the tables are preserved.
 | 
			
		||||
 | 
			
		||||
#### MySQL / MariaDB
 | 
			
		||||
 | 
			
		||||
[The `mysql2` module](https://www.npmjs.com/package/mysql2) supplies a callback
 | 
			
		||||
API as well as a Promise wrapper.  `Connection#query` runs a statement and
 | 
			
		||||
returns an array whose first element is an array of JS objects.
 | 
			
		||||
 | 
			
		||||
`MySQLTest.js` connects to the MySQL instance running on `localhost`, builds two
 | 
			
		||||
tables in the `sheetjs` database, exports to XLSX, imports the new XLSX file to
 | 
			
		||||
the `sheetj5` database and verifies the tables are preserved.
 | 
			
		||||
 | 
			
		||||
#### PostgreSQL
 | 
			
		||||
 | 
			
		||||
[The `pg` module](https://node-postgres.com/) supplies a Promise wrapper.
 | 
			
		||||
`Client#query` runs a statement and returns a result object.  The `rows` key of
 | 
			
		||||
the object is an array of JS objects.
 | 
			
		||||
 | 
			
		||||
`PgSQLTest.js` connects to the PostgreSQL server on `localhost`, builds two
 | 
			
		||||
tables in the `sheetjs` database, exports to XLSX, imports the new XLSX file to
 | 
			
		||||
the `sheetj5` database and verifies the tables are preserved.
 | 
			
		||||
 | 
			
		||||
#### Knex Query Builder
 | 
			
		||||
 | 
			
		||||
[The `knex` module](https://www.npmjs.com/package/knex) builds SQL queries.  The
 | 
			
		||||
same exact code can be used against Oracle Database, MSSQL, and other engines.
 | 
			
		||||
 | 
			
		||||
`KnexTest.js` uses the `sqlite3` connector and follows the same procedure as the
 | 
			
		||||
SQLite test.  The included `SheetJSKnex.js` script converts between the query
 | 
			
		||||
builder and the common spreadsheet format.
 | 
			
		||||
 | 
			
		||||
### Key/Value Stores
 | 
			
		||||
 | 
			
		||||
#### Redis
 | 
			
		||||
 | 
			
		||||
Redis is a powerful data structure server that can store simple strings, sets,
 | 
			
		||||
sorted sets, hashes and lists.  One simple database representation stores the
 | 
			
		||||
strings in a special worksheet (`_strs`), the manifest in another worksheet
 | 
			
		||||
(`_manifest`), and each object in its own worksheet (`obj##`).
 | 
			
		||||
 | 
			
		||||
`RedisTest.js` connects to a local Redis server, populates data based on the
 | 
			
		||||
official Redis tutorial, exports to XLSX, flushes the server, imports the new
 | 
			
		||||
XLSX file and verifies the data round-tripped correctly.  `SheetJSRedis.js`
 | 
			
		||||
includes the implementation details.
 | 
			
		||||
 | 
			
		||||
#### LowDB
 | 
			
		||||
 | 
			
		||||
LowDB is a small schemaless database powered by `lodash`.  `_.get` and `_.set`
 | 
			
		||||
helper functions make storing metadata a breeze.  The included `SheetJSLowDB.js`
 | 
			
		||||
script demonstrates a simple adapter that can load and dump data.
 | 
			
		||||
 | 
			
		||||
### Document Databases
 | 
			
		||||
 | 
			
		||||
Since document databases are capable of holding more complex objects, they can
 | 
			
		||||
actually hold the underlying worksheet objects!  In some cases, where arrays are
 | 
			
		||||
supported, they can even hold the workbook object.
 | 
			
		||||
 | 
			
		||||
#### MongoDB
 | 
			
		||||
 | 
			
		||||
MongoDB is a popular document-oriented database engine.  `MongoDBTest.js` uses
 | 
			
		||||
MongoDB to hold a simple workbook and export to XLSX.
 | 
			
		||||
 | 
			
		||||
`MongoDBCRUD.js` follows the SQL examples using an idiomatic collection
 | 
			
		||||
structure.  Exporting and importing collections are straightforward:
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
	<summary><b>Example code</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* generate a worksheet from a collection */
 | 
			
		||||
const aoa = await db.collection('coll').find({}).toArray();
 | 
			
		||||
aoa.forEach((x) => delete x._id);
 | 
			
		||||
const ws = XLSX.utils.json_to_sheet(aoa);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* import data from a worksheet to a collection */
 | 
			
		||||
const aoa = XLSX.utils.sheet_to_json(ws);
 | 
			
		||||
await db.collection('coll').insertMany(aoa, {ordered: true});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
#### Firebase
 | 
			
		||||
 | 
			
		||||
[`firebase-server`](https://www.npmjs.com/package/firebase-server) is a simple
 | 
			
		||||
mock Firebase server used in the tests, but the same code works in an external
 | 
			
		||||
Firebase deployment when plugging in the database connection info.
 | 
			
		||||
 | 
			
		||||
`FirebaseDemo.html` and `FirebaseTest.js` demonstrate a whole-workbook process.
 | 
			
		||||
The entire workbook object is persisted, a few cells are changed, and the stored
 | 
			
		||||
data is dumped and exported to XLSX.
 | 
			
		||||
- https://docs.sheetjs.com/docs/getting-started/demos/nosql covers unstructured
 | 
			
		||||
  data including "NoSQL" data stores.
 | 
			
		||||
 | 
			
		||||
[](https://github.com/SheetJS/js-xlsx)
 | 
			
		||||
 | 
			
		||||
@ -1,50 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require("xlsx");
 | 
			
		||||
var SheetJSRedis = require("./SheetJSRedis");
 | 
			
		||||
var assert = require('assert');
 | 
			
		||||
var redis = require("redis"), util = require("util");
 | 
			
		||||
var client = redis.createClient();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Sample data */
 | 
			
		||||
var init = [
 | 
			
		||||
  ["FLUSHALL", []],
 | 
			
		||||
  ["SADD",  ["birdpowers", "flight", "pecking"]],
 | 
			
		||||
  ["SET",   ["foo", "bar"]],
 | 
			
		||||
  ["SET",   ["baz", 0]],
 | 
			
		||||
  ["RPUSH", ["friends", "sam", "alice", "bob"]],
 | 
			
		||||
  ["ZADD",  ["hackers", 1906, 'Grace Hopper', 1912, 'Alan Turing', 1916, 'Claude Shannon', 1940, 'Alan Kay', 1953, 'Richard Stallman', 1957, 'Sophie Wilson', 1965, 'Yukihiro Matsumoto', 1969, 'Linus Torvalds']],
 | 
			
		||||
  ["SADD",  ["superpowers", "flight", 'x-ray vision']],
 | 
			
		||||
  ["HMSET", ["user:1000", "name", 'John Smith', "email", 'john.smith@example.com', "password", "s3cret", "visits", 1]],
 | 
			
		||||
  ["HMSET", ["user:1001", "name", 'Mary Jones', "email", 'mjones@example.com', "password", "hidden"]]
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const R = (()=>{
 | 
			
		||||
  const Rcache = {};
 | 
			
		||||
  const R_ = (n) => Rcache[n] || (Rcache[n] = util.promisify(client[n]).bind(client));
 | 
			
		||||
  return (n) => R_(n.toLowerCase());
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
(async () => {
 | 
			
		||||
  for(var i = 0; i < init.length; ++i) await R(init[i][0])(init[i][1]);
 | 
			
		||||
 | 
			
		||||
  /* Export database to XLSX */
 | 
			
		||||
  var wb = await SheetJSRedis.redis_to_wb(R);
 | 
			
		||||
  XLSX.writeFile(wb, "redis.xlsx");
 | 
			
		||||
 | 
			
		||||
  /* Import XLSX to database */
 | 
			
		||||
  await R("flushall")();
 | 
			
		||||
  var wb2 = XLSX.readFile("redis.xlsx");
 | 
			
		||||
  await SheetJSRedis.wb_to_redis(wb2, R);
 | 
			
		||||
 | 
			
		||||
  /* Verify */
 | 
			
		||||
  assert.equal(await R("get")("foo"), "bar");
 | 
			
		||||
  assert.equal(await R("lindex")("friends", 1), "alice");
 | 
			
		||||
  assert.equal(await R("zscore")("hackers", "Claude Shannon"), 1916);
 | 
			
		||||
  assert.equal(await R("hget")("user:1000", "name"), "John Smith");
 | 
			
		||||
  assert.equal(await R("sismember")("superpowers", "flight"), "1");
 | 
			
		||||
  assert.equal(await R("sismember")("birdpowers", "pecking"), "1");
 | 
			
		||||
 | 
			
		||||
  client.quit();
 | 
			
		||||
})();
 | 
			
		||||
@ -1,51 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require('xlsx');
 | 
			
		||||
var assert = require('assert');
 | 
			
		||||
var SheetJSSQL = require('./SheetJSSQL');
 | 
			
		||||
var Database = require('better-sqlite3');
 | 
			
		||||
var db1 = new Database('SheetJS1.db');
 | 
			
		||||
 | 
			
		||||
/* Sample data table */
 | 
			
		||||
var init = [
 | 
			
		||||
  "DROP TABLE IF EXISTS pres",
 | 
			
		||||
  "CREATE TABLE pres (name TEXT, idx INTEGER)",
 | 
			
		||||
  "INSERT INTO pres VALUES ('Barack Obama', 44)",
 | 
			
		||||
  "INSERT INTO pres VALUES ('Donald Trump', 45)",
 | 
			
		||||
  "DROP TABLE IF EXISTS fmts",
 | 
			
		||||
  "CREATE TABLE fmts (ext TEXT, ctr TEXT, multi INTEGER)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLSB', 'ZIP', 1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLS',  'CFB', 1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('XLML', '',    1)",
 | 
			
		||||
  "INSERT INTO fmts VALUES ('CSV',  '',    0)",
 | 
			
		||||
];
 | 
			
		||||
db1.exec(init.join(";"));
 | 
			
		||||
 | 
			
		||||
/* Export database to XLSX */
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
function book_append_table(wb, db, name) {
 | 
			
		||||
  var r = db.prepare('SELECT * FROM ' + name).all();
 | 
			
		||||
  var ws = XLSX.utils.json_to_sheet(r);
 | 
			
		||||
  XLSX.utils.book_append_sheet(wb, ws, name);
 | 
			
		||||
}
 | 
			
		||||
book_append_table(wb, db1, "pres");
 | 
			
		||||
book_append_table(wb, db1, "fmts");
 | 
			
		||||
XLSX.writeFile(wb, "sqlite.xlsx");
 | 
			
		||||
 | 
			
		||||
/* Import XLSX to database */
 | 
			
		||||
var db2 = new Database('SheetJS2.db');
 | 
			
		||||
var wb2 = XLSX.readFile("sqlite.xlsx");
 | 
			
		||||
var queries = SheetJSSQL.book_to_sql(wb2, "SQLITE");
 | 
			
		||||
queries.forEach(function(q) { db2.exec(q); });
 | 
			
		||||
 | 
			
		||||
/* Compare databases */
 | 
			
		||||
var P1 = db1.prepare("SELECT * FROM pres").all();
 | 
			
		||||
var P2 = db2.prepare("SELECT * FROM pres").all();
 | 
			
		||||
var F1 = db1.prepare("SELECT * FROM fmts").all();
 | 
			
		||||
var F2 = db2.prepare("SELECT * FROM fmts").all();
 | 
			
		||||
assert.deepEqual(P1, P2);
 | 
			
		||||
assert.deepEqual(F1, F2);
 | 
			
		||||
 | 
			
		||||
console.log(P2);
 | 
			
		||||
console.log(F2);
 | 
			
		||||
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/*global ObjUtils, localforage */
 | 
			
		||||
localforage.load = async function foo(data) {
 | 
			
		||||
  var keys = Object.keys(data);
 | 
			
		||||
  for(var i = 0; i < keys.length; ++i) {
 | 
			
		||||
    var key = keys[i], val = JSON.stringify(data[keys[i]])
 | 
			
		||||
    await localforage.setItem(key, val);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
localforage.dump = async function() {
 | 
			
		||||
  var obj = {};
 | 
			
		||||
  var length = await localforage.length();
 | 
			
		||||
  for(var i = 0; i < length; ++i) {
 | 
			
		||||
    var key = await this.key(i);
 | 
			
		||||
    var val = await this.getItem(key);
 | 
			
		||||
    obj[key] = JSON.parse(val);
 | 
			
		||||
  }
 | 
			
		||||
  return ObjUtils.object_to_workbook(obj);
 | 
			
		||||
};
 | 
			
		||||
@ -1,78 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require("xlsx");
 | 
			
		||||
 | 
			
		||||
async function book_append_knex(wb, knex, tbl) {
 | 
			
		||||
	const aoo = await knex.select("*").from(tbl);
 | 
			
		||||
	XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(aoo), tbl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TYPES = {
 | 
			
		||||
  b: "boolean",
 | 
			
		||||
  n: "float",
 | 
			
		||||
  t: "string",
 | 
			
		||||
  d: "dateTime"
 | 
			
		||||
};
 | 
			
		||||
async function ws_to_knex(ws, knex, n) {
 | 
			
		||||
  if(!ws || !ws['!ref']) return;
 | 
			
		||||
  var range = XLSX.utils.decode_range(ws['!ref']);
 | 
			
		||||
  if(!range || !range.s || !range.e || range.s > range.e) return;
 | 
			
		||||
  var R = range.s.r, C = range.s.c;
 | 
			
		||||
 | 
			
		||||
  var names = new Array(range.e.c-range.s.c+1);
 | 
			
		||||
  for(C = range.s.c; C<= range.e.c; ++C){
 | 
			
		||||
    var addr = XLSX.utils.encode_cell({c:C,r:R});
 | 
			
		||||
    names[C-range.s.c] = ws[addr] ? ws[addr].v : XLSX.utils.encode_col(C);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for(var i = 0; i < names.length; ++i) if(names.indexOf(names[i]) < i)
 | 
			
		||||
    for(var j = 0; j < names.length; ++j) {
 | 
			
		||||
      var _name = names[i] + "_" + (j+1);
 | 
			
		||||
      if(names.indexOf(_name) > -1) continue;
 | 
			
		||||
      names[i] = _name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  var types = new Array(range.e.c-range.s.c+1);
 | 
			
		||||
  for(C = range.s.c; C<= range.e.c; ++C) {
 | 
			
		||||
    var seen = {}, _type = "";
 | 
			
		||||
    for(R = range.s.r+1; R<= range.e.r; ++R)
 | 
			
		||||
      seen[(ws[XLSX.utils.encode_cell({c:C,r:R})]||{t:"z"}).t] = true;
 | 
			
		||||
    if(seen.s || seen.str) _type = TYPES.t;
 | 
			
		||||
    else if(seen.n + seen.b + seen.d + seen.e > 1) _type = TYPES.t;
 | 
			
		||||
    else switch(true) {
 | 
			
		||||
      case seen.b: _type = TYPES.b; break;
 | 
			
		||||
      case seen.n: _type = TYPES.n; break;
 | 
			
		||||
      case seen.e: _type = TYPES.t; break;
 | 
			
		||||
      case seen.d: _type = TYPES.d; break;
 | 
			
		||||
    }
 | 
			
		||||
    types[C-range.s.c] = _type || TYPES.t;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  await knex.schema.dropTableIfExists(n);
 | 
			
		||||
	await knex.schema.createTable(n, (table) => { names.forEach((n, i) => { table[types[i] || "text"](n); }); });
 | 
			
		||||
 | 
			
		||||
  for(R = range.s.r+1; R<= range.e.r; ++R) {
 | 
			
		||||
    var row = {};
 | 
			
		||||
    for(C = range.s.c; C<= range.e.c; ++C) {
 | 
			
		||||
      var cell = ws[XLSX.utils.encode_cell({c:C,r:R})];
 | 
			
		||||
      if(!cell) continue;
 | 
			
		||||
      var key = names[C-range.s.c], val = cell.v;
 | 
			
		||||
      if(types[C-range.s.c] == TYPES.n) if(cell.t == 'b' || typeof val == 'boolean' ) val = +val;
 | 
			
		||||
      row[key] = val;
 | 
			
		||||
    }
 | 
			
		||||
    await knex.insert(row).into(n);;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function wb_to_knex(wb, knex) {
 | 
			
		||||
	for(var i = 0; i < wb.SheetNames.length; ++i) {
 | 
			
		||||
		var n = wb.SheetNames[i];
 | 
			
		||||
		var ws = wb.Sheets[n];
 | 
			
		||||
		await ws_to_knex(ws, knex, n);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
	book_append_knex,
 | 
			
		||||
	wb_to_knex
 | 
			
		||||
};
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
 | 
			
		||||
var XLSX = require('xlsx');
 | 
			
		||||
var ObjUtils = require('./ObjUtils');
 | 
			
		||||
 | 
			
		||||
function SheetJSAdapter() { this.defaultValue = {}; };
 | 
			
		||||
 | 
			
		||||
SheetJSAdapter.prototype.read = function() { return this.defaultValue; };
 | 
			
		||||
SheetJSAdapter.prototype.write = function(/*data*/) {};
 | 
			
		||||
 | 
			
		||||
SheetJSAdapter.prototype.dumpRaw = function() { return ObjUtils.object_to_workbook(this.defaultValue); };
 | 
			
		||||
SheetJSAdapter.prototype.dump = function(options) { XLSX.write(this.dumpRaw(), options); };
 | 
			
		||||
SheetJSAdapter.prototype.dumpFile = function(path, options) { XLSX.writeFile(this.dumpRaw(), path, options); };
 | 
			
		||||
 | 
			
		||||
SheetJSAdapter.prototype.loadRaw = function(wb) { ObjUtils.workbook_set_object(this.defaultValue, wb); };
 | 
			
		||||
SheetJSAdapter.prototype.load = function(data, options) { this.loadRaw(XLSX.read(data, options)); };
 | 
			
		||||
SheetJSAdapter.prototype.loadFile = function(path, options) { this.loadRaw(XLSX.readFile(path, options)); };
 | 
			
		||||
 | 
			
		||||
if(typeof module !== 'undefined') module.exports = SheetJSAdapter;
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require("xlsx");
 | 
			
		||||
 | 
			
		||||
async function book_append_mongo(wb, coll, name) {
 | 
			
		||||
	const aoo = await coll.find({}, {projection:{_id:0}}).toArray();
 | 
			
		||||
	const ws = XLSX.utils.json_to_sheet(aoo);
 | 
			
		||||
	XLSX.utils.book_append_sheet(wb, ws, name);
 | 
			
		||||
	return ws;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
	book_append_mongo
 | 
			
		||||
};
 | 
			
		||||
@ -1,74 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var XLSX = require("xlsx");
 | 
			
		||||
 | 
			
		||||
const pair = (arr) => arr.map((x,i)=>!(i%2)&&[x,+arr[i+1]]).filter(x=>x);
 | 
			
		||||
const keyify = (obj) => Object.keys(obj).map(x => [x, obj[x]]);
 | 
			
		||||
 | 
			
		||||
async function redis_to_wb(R) {
 | 
			
		||||
  var wb = XLSX.utils.book_new();
 | 
			
		||||
  var manifest = [], strs = [];
 | 
			
		||||
 | 
			
		||||
  /* store strings in strs and keep note of other objects in manifest */
 | 
			
		||||
  var keys = await R("keys")("*"), type = "";
 | 
			
		||||
  for(var i = 0; i < keys.length; ++i) {
 | 
			
		||||
    type = await R("type")(keys[i]);
 | 
			
		||||
    switch(type) {
 | 
			
		||||
      case "string": strs.push({key:keys[i], value: await R("get")(keys[i])}); break;
 | 
			
		||||
      case "list": case "zset": case "set": case "hash": manifest.push({key:keys[i], type:type}); break;
 | 
			
		||||
      default: throw new Error("bad type " + type);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* add worksheets if relevant */
 | 
			
		||||
  if(strs.length > 0) {
 | 
			
		||||
    var wss = XLSX.utils.json_to_sheet(strs, {header: ["key", "value"], skipHeader:1});
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, wss, "_strs");
 | 
			
		||||
  }
 | 
			
		||||
  if(manifest.length > 0) {
 | 
			
		||||
    var wsm = XLSX.utils.json_to_sheet(manifest, {header: ["key", "type"]});
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, wsm, "_manifest");
 | 
			
		||||
  }
 | 
			
		||||
  for(i = 0; i < manifest.length; ++i) {
 | 
			
		||||
    var sn = "obj" + i;
 | 
			
		||||
    var aoa, key = manifest[i].key;
 | 
			
		||||
    switch((type=manifest[i].type)) {
 | 
			
		||||
      case "list":
 | 
			
		||||
        aoa = (await R("lrange")(key, 0, -1)).map(x => [x]); break;
 | 
			
		||||
      case "set":
 | 
			
		||||
        aoa = (await R("smembers")(key)).map(x => [x]); break;
 | 
			
		||||
      case "zset":
 | 
			
		||||
        aoa = pair(await R("zrange")(key, 0, -1, "withscores")); break;
 | 
			
		||||
      case "hash":
 | 
			
		||||
        aoa = keyify(await R("hgetall")(key)); break;
 | 
			
		||||
      default: throw new Error("bad type " + type);
 | 
			
		||||
    }
 | 
			
		||||
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(aoa), sn);
 | 
			
		||||
  }
 | 
			
		||||
  return wb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* convert worksheet aoa to specific redis type */
 | 
			
		||||
const aoa_to_redis = {
 | 
			
		||||
  list: async (aoa, R, key) => await R("RPUSH")([key].concat(aoa.map(x=>x[0]))),
 | 
			
		||||
  zset: async (aoa, R, key) => await R("ZADD" )([key].concat(aoa.reduce((acc,x)=>acc.concat([+x[1], x[0]]), []))),
 | 
			
		||||
  hash: async (aoa, R, key) => await R("HMSET")([key].concat(aoa.reduce((acc,x)=>acc.concat(x), []))),
 | 
			
		||||
  set:  async (aoa, R, key) => await R("SADD" )([key].concat(aoa.map(x=>x[0])))
 | 
			
		||||
};
 | 
			
		||||
async function wb_to_redis(wb, R) {
 | 
			
		||||
  if(wb.Sheets._strs) {
 | 
			
		||||
    var strs = XLSX.utils.sheet_to_json(wb.Sheets._strs, {header:1});
 | 
			
		||||
    for(var i = 0; i < strs.length; ++i) await R("SET")(strs[i]);
 | 
			
		||||
  }
 | 
			
		||||
  if(!wb.Sheets._manifest) return;
 | 
			
		||||
  var M = XLSX.utils.sheet_to_json(wb.Sheets._manifest);
 | 
			
		||||
  for(i = 0; i < M.length; ++i) {
 | 
			
		||||
    var aoa = XLSX.utils.sheet_to_json(wb.Sheets["obj" + i], {header:1});
 | 
			
		||||
    await aoa_to_redis[M[i].type](aoa, R, M[i].key);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  redis_to_wb,
 | 
			
		||||
  wb_to_redis
 | 
			
		||||
};
 | 
			
		||||
@ -1,89 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* global XLSX, require, module */
 | 
			
		||||
var SheetJSSQL = (function() {
 | 
			
		||||
 | 
			
		||||
var X;
 | 
			
		||||
if(typeof XLSX !== "undefined") X = XLSX;
 | 
			
		||||
else if(typeof require !== 'undefined') X = require('xlsx');
 | 
			
		||||
else throw new Error("Could not find XLSX");
 | 
			
		||||
 | 
			
		||||
var _TYPES = {
 | 
			
		||||
  "PGSQL":  { t:"text", n:"float8", d:"timestamp", b:"boolean" },
 | 
			
		||||
  "MYSQL":  { t:"TEXT", n:"REAL",   d:"DATETIME",  b:"TINYINT" },
 | 
			
		||||
  "SQLITE": { t:"TEXT", n:"REAL",   d:"TEXT",      b:"REAL"    }
 | 
			
		||||
}
 | 
			
		||||
function sheet_to_sql(ws, sname, mode) {
 | 
			
		||||
  var TYPES = _TYPES[mode || "SQLITE"]
 | 
			
		||||
  if(!ws || !ws['!ref']) return;
 | 
			
		||||
  var range = X.utils.decode_range(ws['!ref']);
 | 
			
		||||
  if(!range || !range.s || !range.e || range.s > range.e) return;
 | 
			
		||||
  var R = range.s.r, C = range.s.c;
 | 
			
		||||
 | 
			
		||||
  var names = new Array(range.e.c-range.s.c+1);
 | 
			
		||||
  for(C = range.s.c; C<= range.e.c; ++C){
 | 
			
		||||
    var addr = X.utils.encode_cell({c:C,r:R});
 | 
			
		||||
    names[C-range.s.c] = ws[addr] ? ws[addr].v : X.utils.encode_col(C);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for(var i = 0; i < names.length; ++i) if(names.indexOf(names[i]) < i)
 | 
			
		||||
    for(var j = 0; j < names.length; ++j) {
 | 
			
		||||
      var _name = names[i] + "_" + (j+1);
 | 
			
		||||
      if(names.indexOf(_name) > -1) continue;
 | 
			
		||||
      names[i] = _name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  var types = new Array(range.e.c-range.s.c+1);
 | 
			
		||||
  for(C = range.s.c; C<= range.e.c; ++C) {
 | 
			
		||||
    var seen = {}, _type = "";
 | 
			
		||||
    for(R = range.s.r+1; R<= range.e.r; ++R)
 | 
			
		||||
      seen[(ws[X.utils.encode_cell({c:C,r:R})]||{t:"z"}).t] = true;
 | 
			
		||||
    if(seen.s || seen.str) _type = TYPES.t;
 | 
			
		||||
    else if(seen.n + seen.b + seen.d + seen.e > 1) _type = TYPES.t;
 | 
			
		||||
    else switch(true) {
 | 
			
		||||
      case seen.b: _type = TYPES.b; break;
 | 
			
		||||
      case seen.n: _type = TYPES.n; break;
 | 
			
		||||
      case seen.e: _type = TYPES.t; break;
 | 
			
		||||
      case seen.d: _type = TYPES.d; break;
 | 
			
		||||
    }
 | 
			
		||||
    types[C-range.s.c] = _type || TYPES.t;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var out = [];
 | 
			
		||||
 | 
			
		||||
  var BT = mode == "PGSQL" ? "" : "`";
 | 
			
		||||
  var Q  = mode == "PGSQL" ? "'" : '"';
 | 
			
		||||
  var J  = mode == "PGSQL" ? /'/g : /"/g;
 | 
			
		||||
  out.push("DROP TABLE IF EXISTS " + BT + sname + BT );
 | 
			
		||||
  out.push("CREATE TABLE " + BT + sname + BT + " (" + names.map(function(n, i) { return BT + n + BT + " " + (types[i]||"TEXT"); }).join(", ") + ");" );
 | 
			
		||||
 | 
			
		||||
  for(R = range.s.r+1; R<= range.e.r; ++R) {
 | 
			
		||||
    var fields = [], values = [];
 | 
			
		||||
    for(C = range.s.c; C<= range.e.c; ++C) {
 | 
			
		||||
      var cell = ws[X.utils.encode_cell({c:C,r:R})];
 | 
			
		||||
      if(!cell) continue;
 | 
			
		||||
      fields.push(BT + names[C-range.s.c] + BT);
 | 
			
		||||
      var val = cell.v;
 | 
			
		||||
      switch(types[C-range.s.c]) {
 | 
			
		||||
        case TYPES.n: if(cell.t == 'b' || typeof val == 'boolean' ) val = +val; break;
 | 
			
		||||
        default: val = Q + val.toString().replace(J, Q + Q) + Q;
 | 
			
		||||
      }
 | 
			
		||||
      values.push(val);
 | 
			
		||||
    }
 | 
			
		||||
    out.push("INSERT INTO " + BT +sname+ BT + " (" + fields.join(", ") + ") VALUES (" + values.join(",") + ");");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function book_to_sql(wb, mode) {
 | 
			
		||||
  return wb.SheetNames.reduce(function(acc, n) {
 | 
			
		||||
    return acc.concat(sheet_to_sql(wb.Sheets[n], n, mode));
 | 
			
		||||
  }, []);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
return {
 | 
			
		||||
  book_to_sql: book_to_sql,
 | 
			
		||||
  sheet_to_sql: sheet_to_sql
 | 
			
		||||
};
 | 
			
		||||
})();
 | 
			
		||||
if(typeof module !== 'undefined') module.exports = SheetJSSQL;
 | 
			
		||||
@ -1,18 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/*global ObjUtils */
 | 
			
		||||
Storage.prototype.load = function(data) {
 | 
			
		||||
  var self = this;
 | 
			
		||||
  Object.keys(data).forEach(function(k) {
 | 
			
		||||
    self.setItem(k, JSON.stringify(data[k]));
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Storage.prototype.dump = function() {
 | 
			
		||||
  var obj = {};
 | 
			
		||||
  for(var i = 0; i < this.length; ++i) {
 | 
			
		||||
    var key = this.key(i);
 | 
			
		||||
    obj[key] = JSON.parse(this.getItem(key));
 | 
			
		||||
  }
 | 
			
		||||
  return ObjUtils.object_to_workbook(obj);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/database/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/database/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
../../dist/xlsx.full.min.js
 | 
			
		||||
@ -1,92 +1,7 @@
 | 
			
		||||
# canvas-datagrid
 | 
			
		||||
 | 
			
		||||
The `sheet_to_json` utility function generates output arrays suitable for use
 | 
			
		||||
with other JS libraries such as data grids for previewing data.  After extensive
 | 
			
		||||
testing, [`canvas-datagrid`](https://canvas-datagrid.js.org/demo.html) stood
 | 
			
		||||
out as a very high-performance grid with an incredibly simple API.
 | 
			
		||||
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/grid#canvas-datagrid)
 | 
			
		||||
includes a live example and improved explanations.
 | 
			
		||||
 | 
			
		||||
This demo is available at <https://oss.sheetjs.com/sheetjs/datagrid.html>
 | 
			
		||||
 | 
			
		||||
## Obtaining the Library
 | 
			
		||||
 | 
			
		||||
The `canvas-datagrid` NodeJS packages include a minified script that can be
 | 
			
		||||
directly inserted as a script tag.  The unpkg CDN also serves this script:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<script src="https://unpkg.com/canvas-datagrid/dist/canvas-datagrid.js"></script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Previewing Data
 | 
			
		||||
 | 
			
		||||
The HTML document needs a container element:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<div id="gridctr"></div>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Grid initialization is a one-liner:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var grid = canvasDatagrid({
 | 
			
		||||
  parentNode: document.getElementById('gridctr'),
 | 
			
		||||
  data: []
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For large data sets, it's necessary to constrain the size of the grid.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
grid.style.height = '100%';
 | 
			
		||||
grid.style.width = '100%';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Once the workbook is read and the worksheet is selected, assigning the data
 | 
			
		||||
variable automatically updates the view:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
grid.data = XLSX.utils.sheet_to_json(ws, {header:1});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This demo previews the first worksheet.
 | 
			
		||||
 | 
			
		||||
## Editing
 | 
			
		||||
 | 
			
		||||
`canvas-datagrid` handles the entire edit cycle.  No intervention is necessary.
 | 
			
		||||
 | 
			
		||||
## Saving Data
 | 
			
		||||
 | 
			
		||||
`grid.data` is immediately readable and can be converted back to a worksheet.
 | 
			
		||||
Some versions return an array-like object without the length, so a little bit of
 | 
			
		||||
preparation may be needed:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* converts an array of array-like objects into an array of arrays */
 | 
			
		||||
function prep(arr) {
 | 
			
		||||
  var out = [];
 | 
			
		||||
  for(var i = 0; i < arr.length; ++i) {
 | 
			
		||||
    if(!arr[i]) continue;
 | 
			
		||||
    if(Array.isArray(arr[i])) { out[i] = arr[i]; continue };
 | 
			
		||||
    var o = new Array();
 | 
			
		||||
    Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] });
 | 
			
		||||
    out[i] = o;
 | 
			
		||||
  }
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* build worksheet from the grid data */
 | 
			
		||||
var ws = XLSX.utils.aoa_to_sheet(prep(grid.data));
 | 
			
		||||
 | 
			
		||||
/* build up workbook */
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
 | 
			
		||||
 | 
			
		||||
/* generate download */
 | 
			
		||||
XLSX.writeFile(wb, "SheetJS.xlsx");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Additional Features
 | 
			
		||||
 | 
			
		||||
This demo barely scratches the surface.  The underlying grid component includes
 | 
			
		||||
many additional features including massive data streaming, sorting and styling.
 | 
			
		||||
 | 
			
		||||
[](https://github.com/SheetJS/js-xlsx)
 | 
			
		||||
 | 
			
		||||
@ -1,162 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
			
		||||
<title>SheetJS + canvas-datagrid Live Demo</title>
 | 
			
		||||
<style>
 | 
			
		||||
#drop{
 | 
			
		||||
	border:2px dashed #bbb;
 | 
			
		||||
	-moz-border-radius:5px;
 | 
			
		||||
	-webkit-border-radius:5px;
 | 
			
		||||
	border-radius:5px;
 | 
			
		||||
	padding:25px;
 | 
			
		||||
	text-align:center;
 | 
			
		||||
	font:20pt bold,"Vollkorn";color:#bbb
 | 
			
		||||
}
 | 
			
		||||
#b64data{
 | 
			
		||||
	width:100%;
 | 
			
		||||
}
 | 
			
		||||
a { text-decoration: none }
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
 | 
			
		||||
 | 
			
		||||
<a href="https://canvas-datagrid.js.org/">canvas-datagrid component library</a>
 | 
			
		||||
 | 
			
		||||
<a href="https://github.com/SheetJS/sheetjs">Source Code Repo</a>
 | 
			
		||||
<a href="https://github.com/SheetJS/sheetjs/issues">Issues?  Something look weird?  Click here and report an issue</a>
 | 
			
		||||
 | 
			
		||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
 | 
			
		||||
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
 | 
			
		||||
<textarea id="b64data">... or paste a base64-encoding here</textarea>
 | 
			
		||||
<b>Advanced Demo Options:</b>
 | 
			
		||||
</pre>
 | 
			
		||||
<p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();" disabled="true"></p>
 | 
			
		||||
<div id="htmlout"></div>
 | 
			
		||||
<br />
 | 
			
		||||
<script src="https://unpkg.com/canvas-datagrid/dist/canvas-datagrid.js"></script>
 | 
			
		||||
<script src="shim.js"></script>
 | 
			
		||||
<script src="xlsx.full.min.js"></script>
 | 
			
		||||
<script>
 | 
			
		||||
/*jshint browser:true */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* eslint no-use-before-define:0 */
 | 
			
		||||
/*global Uint8Array, Uint16Array, ArrayBuffer */
 | 
			
		||||
/*global XLSX */
 | 
			
		||||
 | 
			
		||||
var cDg;
 | 
			
		||||
 | 
			
		||||
var process_wb = (function() {
 | 
			
		||||
	var XPORT = document.getElementById('xport');
 | 
			
		||||
	var HTMLOUT = document.getElementById('htmlout');
 | 
			
		||||
 | 
			
		||||
	return function process_wb(wb) {
 | 
			
		||||
		/* get data */
 | 
			
		||||
		var ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
		var data = XLSX.utils.sheet_to_json(ws, {header:1});
 | 
			
		||||
 | 
			
		||||
		/* update canvas-datagrid */
 | 
			
		||||
		if(!cDg) cDg = canvasDatagrid({ parentNode:HTMLOUT, data:data });
 | 
			
		||||
		cDg.style.height = '100%';
 | 
			
		||||
		cDg.style.width = '100%';
 | 
			
		||||
		cDg.data = data;
 | 
			
		||||
		XPORT.disabled = false;
 | 
			
		||||
 | 
			
		||||
		/* create schema (for A,B,C column headings) */
 | 
			
		||||
		var range = XLSX.utils.decode_range(ws['!ref']);
 | 
			
		||||
		for(var i = range.s.c; i <= range.e.c; ++i) cDg.schema[i - range.s.c].title = XLSX.utils.encode_col(i);
 | 
			
		||||
 | 
			
		||||
		HTMLOUT.style.height = (window.innerHeight - 400) + "px";
 | 
			
		||||
		HTMLOUT.style.width = (window.innerWidth - 50) + "px";
 | 
			
		||||
 | 
			
		||||
		if(typeof console !== 'undefined') console.log("output", new Date());
 | 
			
		||||
	};
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
var do_file = (function() {
 | 
			
		||||
	return function do_file(files) {
 | 
			
		||||
		var f = files[0];
 | 
			
		||||
		var reader = new FileReader();
 | 
			
		||||
		reader.onload = function(e) {
 | 
			
		||||
			if(typeof console !== 'undefined') console.log("onload", new Date());
 | 
			
		||||
			var data = e.target.result;
 | 
			
		||||
			data = new Uint8Array(data);
 | 
			
		||||
			process_wb(XLSX.read(data, {type: 'array'}));
 | 
			
		||||
		};
 | 
			
		||||
		reader.readAsArrayBuffer(f);
 | 
			
		||||
	};
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
	var drop = document.getElementById('drop');
 | 
			
		||||
	if(!drop.addEventListener) return;
 | 
			
		||||
 | 
			
		||||
	function handleDrop(e) {
 | 
			
		||||
		e.stopPropagation();
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		do_file(e.dataTransfer.files);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function handleDragover(e) {
 | 
			
		||||
		e.stopPropagation();
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		e.dataTransfer.dropEffect = 'copy';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drop.addEventListener('dragenter', handleDragover, false);
 | 
			
		||||
	drop.addEventListener('dragover', handleDragover, false);
 | 
			
		||||
	drop.addEventListener('drop', handleDrop, false);
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
	var xlf = document.getElementById('xlf');
 | 
			
		||||
	if(!xlf.addEventListener) return;
 | 
			
		||||
	function handleFile(e) { do_file(e.target.files); }
 | 
			
		||||
	xlf.addEventListener('change', handleFile, false);
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
var export_xlsx = (function() {
 | 
			
		||||
	function prep(arr) {
 | 
			
		||||
		var out = [];
 | 
			
		||||
		for(var i = 0; i < arr.length; ++i) {
 | 
			
		||||
			if(!arr[i]) continue;
 | 
			
		||||
			if(Array.isArray(arr[i])) { out[i] = arr[i]; continue };
 | 
			
		||||
			var o = new Array();
 | 
			
		||||
			Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] });
 | 
			
		||||
			out[i] = o;
 | 
			
		||||
		}
 | 
			
		||||
		return out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return function export_xlsx() {
 | 
			
		||||
		if(!cDg) return;
 | 
			
		||||
		/* convert canvas-datagrid data to worksheet */
 | 
			
		||||
		var new_ws = XLSX.utils.aoa_to_sheet(prep(cDg.data));
 | 
			
		||||
 | 
			
		||||
		/* build workbook */
 | 
			
		||||
		var new_wb = XLSX.utils.book_new();
 | 
			
		||||
		XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS');
 | 
			
		||||
 | 
			
		||||
		/* write file and trigger a download */
 | 
			
		||||
		XLSX.writeFile(new_wb, 'sheetjs.xlsx', {bookSST:true});
 | 
			
		||||
	};
 | 
			
		||||
})();
 | 
			
		||||
</script>
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
/* eslint no-use-before-define:0 */
 | 
			
		||||
	var _gaq = _gaq || [];
 | 
			
		||||
	_gaq.push(['_setAccount', 'UA-36810333-1']);
 | 
			
		||||
	_gaq.push(['_trackPageview']);
 | 
			
		||||
 | 
			
		||||
	(function() {
 | 
			
		||||
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 | 
			
		||||
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 | 
			
		||||
		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 | 
			
		||||
	})();
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
../../shim.js
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/datagrid/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/datagrid/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
../../dist/xlsx.full.min.js
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
	"env": {
 | 
			
		||||
		"es6": true,
 | 
			
		||||
		"browser": true,
 | 
			
		||||
		"node": true
 | 
			
		||||
	},
 | 
			
		||||
	"parserOptions": {
 | 
			
		||||
		"ecmaVersion": 8
 | 
			
		||||
	},
 | 
			
		||||
	"plugins": [ "html", "json" ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/electron/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/electron/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
out/
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
.PHONY: init
 | 
			
		||||
init:
 | 
			
		||||
	if [ ! -e xlsx.full.min.js ]; then ln -s ../../dist/xlsx.full.min.js . ; fi
 | 
			
		||||
 | 
			
		||||
.PHONY: run
 | 
			
		||||
run:
 | 
			
		||||
	npx nw .
 | 
			
		||||
@ -1,36 +1,6 @@
 | 
			
		||||
# NW.js
 | 
			
		||||
 | 
			
		||||
This library is compatible with NW.js and should just work out of the box.
 | 
			
		||||
The demonstration uses NW.js 0.63.0 with the dist script.
 | 
			
		||||
 | 
			
		||||
## Reading data
 | 
			
		||||
 | 
			
		||||
The standard HTML5 `FileReader` techniques from the browser apply to NW.js!
 | 
			
		||||
This demo includes a drag-and-drop box as well as a file input box, mirroring
 | 
			
		||||
the [SheetJS Data Preview Live Demo](https://oss.sheetjs.com/sheetjs/).
 | 
			
		||||
 | 
			
		||||
## Writing data
 | 
			
		||||
 | 
			
		||||
File input elements with the attribute `nwsaveas` show UI for saving a file. The
 | 
			
		||||
standard trick is to generate a hidden file input DOM element and "click" it.
 | 
			
		||||
Since NW.js does not present a `writeFileSync` in the `fs` package, a manual
 | 
			
		||||
step is required:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* from within the input change callback, `this.value` is the file name */
 | 
			
		||||
var filename = this.value, bookType = (filename.match(/[^\.]*$/)||["xlsx"])[0];
 | 
			
		||||
 | 
			
		||||
/* convert the TABLE element back to a workbook */
 | 
			
		||||
var wb = XLSX.utils.table_to_book(HTMLOUT);
 | 
			
		||||
 | 
			
		||||
/* write to buffer */
 | 
			
		||||
var wbout = XLSX.write(wb, {type:'buffer', bookType:bookType});
 | 
			
		||||
 | 
			
		||||
/* use the async fs.writeFile to save the data */
 | 
			
		||||
fs.writeFile(filename, wbout, function(err) {
 | 
			
		||||
	if(!err) return alert("Saved to " + filename);
 | 
			
		||||
	alert("Error: " + (err.message || err));
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
[The new demo](https://docs.sheetjs.com/docs/getting-started/demos/desktop#nwjs)
 | 
			
		||||
includes an improved example and detailed explanations.
 | 
			
		||||
 | 
			
		||||
[](https://github.com/SheetJS/js-xlsx)
 | 
			
		||||
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!-- xlsx.js (C) 2013-present  SheetJS http://sheetjs.com -->
 | 
			
		||||
<!-- vim: set ts=2: -->
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 | 
			
		||||
<title>SheetJS NW.js Demo</title>
 | 
			
		||||
<style>
 | 
			
		||||
#drop{
 | 
			
		||||
	border:2px dashed #bbb;
 | 
			
		||||
	-moz-border-radius:5px;
 | 
			
		||||
	-webkit-border-radius:5px;
 | 
			
		||||
	border-radius:5px;
 | 
			
		||||
	padding:25px;
 | 
			
		||||
	text-align:center;
 | 
			
		||||
	font:20pt bold,"Vollkorn";color:#bbb
 | 
			
		||||
}
 | 
			
		||||
a { text-decoration: none }
 | 
			
		||||
</style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<pre>
 | 
			
		||||
<b><a href="http://sheetjs.com">SheetJS NW.js Demo</a></b>
 | 
			
		||||
 | 
			
		||||
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a>
 | 
			
		||||
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues?  Something look weird?  Click here and report an issue</a>
 | 
			
		||||
<br />
 | 
			
		||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
 | 
			
		||||
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
 | 
			
		||||
 | 
			
		||||
</pre>
 | 
			
		||||
<p><input type="submit" value="Export Data!" id="xport" onclick="export_xlsx();" disabled="true"></p>
 | 
			
		||||
<div id="htmlout"></div>
 | 
			
		||||
<br />
 | 
			
		||||
<script src="xlsx.full.min.js"></script>
 | 
			
		||||
<script src="index.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -1,86 +0,0 @@
 | 
			
		||||
var fs = require('fs');
 | 
			
		||||
 | 
			
		||||
var process_wb = (function() {
 | 
			
		||||
	var HTMLOUT = document.getElementById('htmlout');
 | 
			
		||||
	var XPORT = document.getElementById('xport');
 | 
			
		||||
 | 
			
		||||
	return function process_wb(wb) {
 | 
			
		||||
		XPORT.disabled = false;
 | 
			
		||||
		HTMLOUT.innerHTML = "";
 | 
			
		||||
		wb.SheetNames.forEach(function(sheetName) {
 | 
			
		||||
			var htmlstr = XLSX.utils.sheet_to_html(wb.Sheets[sheetName],{editable:true});
 | 
			
		||||
			HTMLOUT.innerHTML += htmlstr;
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
var _gaq = _gaq || [];
 | 
			
		||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
 | 
			
		||||
_gaq.push(['_trackPageview']);
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
	var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 | 
			
		||||
	ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 | 
			
		||||
	var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
var do_file = (function() {
 | 
			
		||||
	return function do_file(files) {
 | 
			
		||||
		var f = files[0];
 | 
			
		||||
		var reader = new FileReader();
 | 
			
		||||
		reader.onload = function(e) {
 | 
			
		||||
			var data = e.target.result;
 | 
			
		||||
			data = new Uint8Array(data);
 | 
			
		||||
			process_wb(XLSX.read(data, {type: 'array'}));
 | 
			
		||||
		};
 | 
			
		||||
		reader.readAsArrayBuffer(f);
 | 
			
		||||
	};
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
	var drop = document.getElementById('drop');
 | 
			
		||||
 | 
			
		||||
	function handleDrop(e) {
 | 
			
		||||
		e.stopPropagation();
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		do_file(e.dataTransfer.files);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function handleDragover(e) {
 | 
			
		||||
		e.stopPropagation();
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		e.dataTransfer.dropEffect = 'copy';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drop.addEventListener('dragenter', handleDragover, false);
 | 
			
		||||
	drop.addEventListener('dragover', handleDragover, false);
 | 
			
		||||
	drop.addEventListener('drop', handleDrop, false);
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
(function() {
 | 
			
		||||
	var xlf = document.getElementById('xlf');
 | 
			
		||||
	function handleFile(e) { do_file(e.target.files); }
 | 
			
		||||
	xlf.addEventListener('change', handleFile, false);
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
var export_xlsx = (function() {
 | 
			
		||||
	/* pre-build the nwsaveas input element */
 | 
			
		||||
	var HTMLOUT = document.getElementById('htmlout');
 | 
			
		||||
	var input = document.createElement('input');
 | 
			
		||||
	input.style.display = 'none';
 | 
			
		||||
	input.setAttribute('nwsaveas', 'SheetJSNWDemo.xlsx');
 | 
			
		||||
	input.setAttribute('type', 'file');
 | 
			
		||||
	document.body.appendChild(input);
 | 
			
		||||
	input.addEventListener('cancel',function(){ alert("Save was canceled!"); });
 | 
			
		||||
	input.addEventListener('change',function(e){
 | 
			
		||||
		var filename=this.value, bookType=(filename.match(/[^\.]*$/)||["xlsx"])[0];
 | 
			
		||||
		var wb = XLSX.utils.table_to_book(HTMLOUT.getElementsByTagName("TABLE")[0]);
 | 
			
		||||
		var wbout = XLSX.write(wb, {type:'buffer', bookType:bookType});
 | 
			
		||||
		fs.writeFile(filename, wbout, function(err) {
 | 
			
		||||
			if(!err) return alert("Saved to " + filename);
 | 
			
		||||
			alert("Error: " + (err.message || err));
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	return function() { input.click(); };
 | 
			
		||||
})();
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "sheetjs-nwjs",
 | 
			
		||||
	"author": "sheetjs",
 | 
			
		||||
	"version": "0.0.0",
 | 
			
		||||
	"main": "index.html",
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
		"nw": "~0.66.0",
 | 
			
		||||
		"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/nwjs/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/nwjs/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
../../dist/xlsx.full.min.js
 | 
			
		||||
							
								
								
									
										3
									
								
								demos/parcel/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								demos/parcel/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,3 +0,0 @@
 | 
			
		||||
.cache
 | 
			
		||||
.parcel-cache
 | 
			
		||||
dist
 | 
			
		||||
							
								
								
									
										5
									
								
								demos/rollup/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								demos/rollup/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,5 +0,0 @@
 | 
			
		||||
rollup.js
 | 
			
		||||
rollup.min.js
 | 
			
		||||
rollup.node.js
 | 
			
		||||
worker.js
 | 
			
		||||
worker.min.js
 | 
			
		||||
							
								
								
									
										1
									
								
								demos/typescript/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								demos/typescript/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
			
		||||
dist
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
.PHONY: all
 | 
			
		||||
all:
 | 
			
		||||
	@npm run build
 | 
			
		||||
 | 
			
		||||
.PHONY: lint
 | 
			
		||||
lint:
 | 
			
		||||
	@npm run lint
 | 
			
		||||
 | 
			
		||||
.PHONY: init
 | 
			
		||||
init:
 | 
			
		||||
	mkdir -p node_modules
 | 
			
		||||
	npm install typescript
 | 
			
		||||
	cd node_modules; ln -s ../../../ xlsx; cd -
 | 
			
		||||
@ -1,71 +1,9 @@
 | 
			
		||||
# TypeScript
 | 
			
		||||
 | 
			
		||||
The library exports can be imported directly from TS code with:
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import * as XLSX from 'xlsx';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The library type definitions are available in the repo at `types/index.d.ts` and
 | 
			
		||||
in the node module.  The definitions are also available in places that serve the
 | 
			
		||||
node module, like [unpkg](https://unpkg.com/xlsx/types/index.d.ts).
 | 
			
		||||
 | 
			
		||||
This demo shows a small utility function that reads the first worksheet and
 | 
			
		||||
converts to an array of arrays.  The utility function is designed to be used in
 | 
			
		||||
the browser and server.  This project shows a complete deployment as a simple
 | 
			
		||||
browser script and as a node module.
 | 
			
		||||
 | 
			
		||||
This demo is intended to illustrate simple and direct use of the `tsc` command
 | 
			
		||||
line utility.  The Angular 2+ demo shows a more advanced TypeScript deployment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Named Exports
 | 
			
		||||
 | 
			
		||||
Newer TypeScript versions (2.6+) support named exports:
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import { read, write, utils } from 'xlsx'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
However, since this is not supported in all deployments, it is generally easier
 | 
			
		||||
to use the glob import form and destructuring assignment:
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import * as XLSX from 'xlsx';
 | 
			
		||||
const { read, write, utils } = XLSX;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Library Type Definitions
 | 
			
		||||
 | 
			
		||||
Types are exposed in the node module directly in the path `/types/index.d.ts`.
 | 
			
		||||
[unpkg CDN includes the definitions](https://unpkg.com/xlsx/types/index.d.ts).
 | 
			
		||||
The named `@types/xlsx` module should not be installed!
 | 
			
		||||
 | 
			
		||||
Using the glob import, types must be explicitly scoped:
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import * as XLSX from 'xlsx';
 | 
			
		||||
/* the workbook type is accessible as XLSX.WorkBook */
 | 
			
		||||
const wb: XLSX.WorkBook = XLSX.read(data, options);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Using named imports, the explicit type name should be imported:
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import { read, WorkBook } from 'xlsx'
 | 
			
		||||
const wb: WorkBook = read(data, options);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Demo Project Structure
 | 
			
		||||
 | 
			
		||||
`lib/index.ts` is the TS library that will be transpiled to `dist/index.js` and
 | 
			
		||||
`dist/index.d.ts`.
 | 
			
		||||
 | 
			
		||||
`demo.js` is a node script that uses the generated library.
 | 
			
		||||
 | 
			
		||||
`src/index.js` is the browser entry point.  The `browserify` bundle tool is used
 | 
			
		||||
to generate `dist/browser.js`, a browser script loaded by `index.html`.
 | 
			
		||||
This demo originally covered direct use of the `tsc` TypeScript compiler.  At
 | 
			
		||||
the time when the demo was first written, TypeScript 2.2 had a module system
 | 
			
		||||
that was incompatibile with the pure JS ecosystem.  Since then, various
 | 
			
		||||
language improvements and compiler changes have obviated this demo.  Uses of
 | 
			
		||||
TypeScript are scattered throughout other demos.
 | 
			
		||||
 | 
			
		||||
[](https://github.com/SheetJS/js-xlsx)
 | 
			
		||||
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* vim: set ts=2: */
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
var readFirstSheet = require("./").readFirstSheet;
 | 
			
		||||
console.log(readFirstSheet("../../sheetjs.xlsb", {type:"file", cellDates:true}));
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
<script src="dist/browser.js"></script>
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* vim: set ts=2: */
 | 
			
		||||
 | 
			
		||||
import * as XLSX from 'xlsx';
 | 
			
		||||
 | 
			
		||||
const { read, utils: { sheet_to_json } } = XLSX;
 | 
			
		||||
 | 
			
		||||
export function readFirstSheet(data: any, options: XLSX.ParsingOptions): any[][] {
 | 
			
		||||
  const wb: XLSX.WorkBook = read(data, options);
 | 
			
		||||
  const ws: XLSX.WorkSheet = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
  return sheet_to_json(ws, { header: 1, raw: true });
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "xlsx-ts",
 | 
			
		||||
  "main": "dist/index.js",
 | 
			
		||||
  "types": "dist/index.d.ts",
 | 
			
		||||
  "version": "0.0.0",
 | 
			
		||||
  "license": "Apache-2.0",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "build": "tsc && browserify -o dist/browser.js src/index.js",
 | 
			
		||||
    "lint": "tslint lib/*.ts"
 | 
			
		||||
  },
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "typescript": "~2.6.1",
 | 
			
		||||
    "browserify": "~14.5.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
 | 
			
		||||
/* vim: set ts=2: */
 | 
			
		||||
/* eslint-env browser */
 | 
			
		||||
/* global require */
 | 
			
		||||
var readFirstSheet = require("../").readFirstSheet;
 | 
			
		||||
console.log(readFirstSheet("a,b,c\n1,2,3\n4,5,6", {type:"binary"}));
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "target": "es5",
 | 
			
		||||
    "module": "commonjs",
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "outDir": "./dist",
 | 
			
		||||
    "strict": true
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
	"extends": "tslint-config-airbnb",
 | 
			
		||||
	"rules": {
 | 
			
		||||
		"whitespace": false,
 | 
			
		||||
		"no-sparse-arrays": false,
 | 
			
		||||
		"only-arrow-functions": false,
 | 
			
		||||
		"no-consecutive-blank-lines": false,
 | 
			
		||||
		"prefer-conditional-expression": false,
 | 
			
		||||
		"one-variable-per-declaration": false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -15,6 +15,7 @@ function stox(wb) {
 | 
			
		||||
  wb.SheetNames.forEach(function (name) {
 | 
			
		||||
    var o = { name: name, rows: {} };
 | 
			
		||||
    var ws = wb.Sheets[name];
 | 
			
		||||
    if(!ws || !ws["!ref"]) return;
 | 
			
		||||
    var range = XLSX.utils.decode_range(ws['!ref']);
 | 
			
		||||
    // sheet_to_json will lost empty row and col at begin as default
 | 
			
		||||
    range.s = { r: 0, c: 0 };
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user