demo refresh
@ -190,7 +190,6 @@ ExecJS
|
||||
ExpressJS
|
||||
ExtendScript
|
||||
FastifyJS
|
||||
Fastmail
|
||||
FerretDB
|
||||
FileReader
|
||||
FileReaderSync
|
||||
|
@ -79,7 +79,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/capacitor"><Data ss:Type="String">CapacitorJS</Data></Cell>
|
||||
@ -90,7 +90,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/ionic"><Data ss:Type="String">Ionic</Data></Cell>
|
||||
|
@ -123,7 +123,7 @@ This demo was last tested in the following deployments:
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `1.1.39` | 2024-12-17 |
|
||||
| `darwin-arm` | `1.1.10` | 2024-09-22 |
|
||||
| `win11-x64` | `1.1.22` | 2024-08-11 |
|
||||
| `win11-x64` | `1.1.42` | 2024-12-22 |
|
||||
| `win11-arm` | `1.1.40` | 2024-12-19 |
|
||||
| `linux-x64` | `1.1.40` | 2024-12-19 |
|
||||
| `linux-arm` | `1.1.40` | 2024-12-19 |
|
||||
@ -146,11 +146,11 @@ The PowerShell file redirect will use the `UTF-16 LE` encoding. Bun does not
|
||||
support the encoding and will fail to install the package:
|
||||
|
||||
```
|
||||
bun add v1.1.22-canary.96 (df33f2b2)
|
||||
1 | <20><>{}
|
||||
|
||||
bun add v1.1.42 (50eec002)
|
||||
1 | <20><>
|
||||
^
|
||||
error: Unexpected <20><>
|
||||
at <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:1:1
|
||||
```
|
||||
|
||||
The file must be resaved in UTF8 (without BOM) or ASCII.
|
||||
|
@ -489,8 +489,9 @@ function SheetJSAoAFilled() {
|
||||
### Select Data Rows
|
||||
|
||||
At this point, each data row will have the year in column `A` and dollar value
|
||||
in column `C`. The year will be between 2007 and 2024 and the value will be
|
||||
positive. The following function tests a data row:
|
||||
in column `C`. The year (first value in the row) will be between 2007 and 2024.
|
||||
The value (third value) will be positive. The following function tests a row
|
||||
against the requirements:
|
||||
|
||||
```js
|
||||
const is_valid_row = r =>
|
||||
|
@ -19,7 +19,12 @@ This demo covers details elided in the official DanfoJS documentation.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This example was last tested on 2024 April 25 against DanfoJS 1.1.2.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Version | Date |
|
||||
|:------------|:--------|:-----------|
|
||||
| Chrome 131 | `1.1.2` | 2025-01-01 |
|
||||
| Safari 18.2 | `1.1.2` | 2025-01-01 |
|
||||
|
||||
:::
|
||||
|
||||
@ -207,15 +212,23 @@ The following example exports a sample dataframe to a XLSX spreadsheet.
|
||||
|
||||
```jsx live
|
||||
function DanfoToExcel() {
|
||||
if(typeof dfd === "undefined") return (<b>RELOAD THIS PAGE</b>);
|
||||
/* sample dataframe */
|
||||
const df = new dfd.DataFrame([{Sheet:1,JS:2},{Sheet:3,JS:4}]);
|
||||
return ( <><button onClick={async() => {
|
||||
/* dfd.toExcel calls the SheetJS `writeFile` method */
|
||||
dfd.toExcel(df, {fileName: "SheetJSDanfoJS.xlsx", writingOptions: {
|
||||
compression: true
|
||||
}});
|
||||
}}>Click to Export</button><pre>{"Data:\n"+df.head()}</pre></> );
|
||||
const [df, setDF] = React.useState({});
|
||||
React.useEffect(() => {
|
||||
/* sample dataframe */
|
||||
setDF(new dfd.DataFrame([{Sheet:1,JS:2},{Sheet:3,JS:4}]));
|
||||
}, []);
|
||||
|
||||
if(!df.head) return ;
|
||||
return !df.head ? ( <b>RELOAD THIS PAGE</b>) : ( <>
|
||||
<button onClick={async() => {
|
||||
/* dfd.toExcel calls the SheetJS `writeFile` method */
|
||||
dfd.toExcel(df, {fileName: "SheetJSDanfoJS.xlsx", writingOptions: {
|
||||
compression: true
|
||||
}});
|
||||
}}>Click to Export</button>
|
||||
<pre>{"Data:\n"+df.head()}</pre>
|
||||
</> );
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -40,11 +40,11 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | JS Engine | Pandas | Python | Date |
|
||||
|:-------------|:----------------|:-------|:-------|:-----------|
|
||||
| `darwin-x64` | Duktape `2.7.0` | 2.2.1 | 3.12.2 | 2024-03-15 |
|
||||
| `darwin-x64` | Duktape `2.7.0` | 2.2.3 | 3.13.1 | 2024-12-31 |
|
||||
| `darwin-arm` | Duktape `2.7.0` | 2.2.2 | 3.12.3 | 2024-06-30 |
|
||||
| `win11-x64` | Duktape `2.7.0` | 2.2.3 | 3.11.8 | 2024-12-21 |
|
||||
| `win11-arm` | Duktape `2.7.0` | 2.2.2 | 3.11.5 | 2024-06-20 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 1.5.3 | 3.11.3 | 2024-03-21 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 1.5.3 | 3.11.7 | 2025-01-01 |
|
||||
| `linux-arm` | Duktape `2.7.0` | 1.5.3 | 3.11.2 | 2024-06-20 |
|
||||
|
||||
:::
|
||||
@ -519,11 +519,11 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | JS Engine | Polars | Python | Date |
|
||||
|:-------------|:----------------|:--------|:-------|:-----------|
|
||||
| `darwin-x64` | Duktape `2.7.0` | 0.20.15 | 3.12.2 | 2024-03-15 |
|
||||
| `darwin-x64` | Duktape `2.7.0` | 1.18.0 | 3.13.1 | 2024-12-31 |
|
||||
| `darwin-arm` | Duktape `2.7.0` | 0.20.31 | 3.12.3 | 2024-06-30 |
|
||||
| `win11-x64` | Duktape `2.7.0` | 1.17.1 | 3.11.8 | 2024-12-21 |
|
||||
| `win11-arm` | Duktape `2.7.0` | 0.20.31 | 3.11.5 | 2024-06-20 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 0.20.16 | 3.11.3 | 2024-03-21 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 1.18.0 | 3.11.7 | 2025-01-01 |
|
||||
| `linux-arm` | Duktape `2.7.0` | 0.20.31 | 3.11.2 | 2024-06-20 |
|
||||
|
||||
:::
|
||||
|
@ -753,7 +753,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| ReactJS | CRA | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `18.2.0` | `5.0.1` | 2024-03-13 |
|
||||
| `18.2.0` | `5.0.1` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -425,8 +425,10 @@ This demo was tested in the following environments:
|
||||
|
||||
| Angular | Date |
|
||||
|:----------|:-----------|
|
||||
| `17.3.0` | 2024-03-13 |
|
||||
| `16.2.12` | 2024-03-13 |
|
||||
| `19.0.5` | 2025-01-03 |
|
||||
| `18.2.13` | 2025-01-03 |
|
||||
| `17.3.12` | 2025-01-03 |
|
||||
| `16.2.12` | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -439,16 +441,16 @@ npx @angular/cli analytics disable -g
|
||||
1) Create a new project:
|
||||
|
||||
```bash
|
||||
npx @angular/cli@17.3.0 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
npx @angular/cli@19 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
The `@angular/cli` version controls the project version of Angular. For example,
|
||||
the following command uses Angular 16.2.12:
|
||||
the following command uses Angular 16:
|
||||
|
||||
```bash
|
||||
npx @angular/cli@16.2.12 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
npx @angular/cli@16 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
```
|
||||
|
||||
:::
|
||||
@ -619,8 +621,10 @@ This demo was tested in the following environments:
|
||||
|
||||
| Angular | Date |
|
||||
|:----------|:-----------|
|
||||
| `17.3.0` | 2024-03-13 |
|
||||
| `16.2.12` | 2024-03-13 |
|
||||
| `19.0.5` | 2025-01-03 |
|
||||
| `18.2.13` | 2025-01-03 |
|
||||
| `17.3.12` | 2025-01-03 |
|
||||
| `16.2.12` | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -633,16 +637,16 @@ npx @angular/cli analytics disable -g
|
||||
1) Create a new project:
|
||||
|
||||
```bash
|
||||
npx @angular/cli@17.3.0 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
npx @angular/cli@19 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
The `@angular/cli` version controls the project version of Angular. For example,
|
||||
the following command uses Angular 16.2.12:
|
||||
the following command uses Angular 16:
|
||||
|
||||
```bash
|
||||
npx @angular/cli@16.2.12 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
npx @angular/cli@16 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
```
|
||||
|
||||
:::
|
||||
|
@ -412,7 +412,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| VueJS | NuxtJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `3.4.21` | `3.11.1` | 2024-03-21 |
|
||||
| `3.5.13` | `3.15.0` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -520,7 +520,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| VueJS | ViteJS | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `3.4.21` | `5.2.2` | 2024-03-21 |
|
||||
| `3.5.13` | `6.0.7` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -573,7 +573,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| VueJS | NuxtJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `3.4.21` | `3.11.1` | 2024-03-21 |
|
||||
| `3.5.13` | `3.15.0` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Sheets in OpenUI5 Sites
|
||||
sidebar_label: OpenUI5
|
||||
title: Sheets in UI5 Sites
|
||||
sidebar_label: OpenUI5 / SAPUI5
|
||||
description: Build enterprise-grade applications with OpenUI5. Seamlessly integrate spreadsheets into your app using SheetJS. Bring Excel-powered workflows and data to the modern web.
|
||||
pagination_prev: demos/index
|
||||
pagination_next: demos/grid/index
|
||||
@ -12,7 +12,8 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[OpenUI5](https://openui5.org/) is a JavaScript framework for building enterprise-ready web applications.
|
||||
[OpenUI5](https://openui5.org/) is a JavaScript framework for building
|
||||
enterprise-ready web applications. It is compatible with the SAPUI5 framework.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
@ -21,19 +22,84 @@ This demo uses OpenUI5 and SheetJS to process and generate a spreadsheets. We'll
|
||||
explore how to load SheetJS in an OpenUI5 app and handle data binding with the
|
||||
Model-View-Controller pattern.
|
||||
|
||||
:::info pass
|
||||
|
||||
[Docs Issue #20](https://git.sheetjs.com/sheetjs/docs.sheetjs.com/issues/20)
|
||||
includes a complete example starting from the OpenUI5 "Worklist App Tutorial".
|
||||
|
||||
:::
|
||||
|
||||
## Installation
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation with Yarn and other package managers.
|
||||
SheetJS libraries conform to the UI5 ECMAScript limitations[^1]. SheetJS
|
||||
libraries can be loaded in a UI5 site at different points in the app lifecycle.
|
||||
|
||||
The library should be loaded via script tag in your HTML:
|
||||
**HTML**
|
||||
|
||||
<CodeBlock language="html" value="html">
|
||||
{`<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
UI5 is typically loaded in a `SCRIPT` tag in `webapp/index.html`. Similarly,
|
||||
[SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
can be loaded in the same HTML page:
|
||||
|
||||
<CodeBlock language="html" value="html">{`\
|
||||
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
||||
`}
|
||||
</CodeBlock>
|
||||
|
||||
This will expose the `XLSX` global object which contains all the necessary methods.
|
||||
This will expose the `XLSX` global object, which includes the functions listed
|
||||
in the ["API Reference"](/docs/api/) section of the documentation.
|
||||
|
||||
:::caution pass
|
||||
|
||||
The SheetJS Standalone script must be loaded before the UI5 bootstrap script:
|
||||
|
||||
<CodeBlock language="html" value="html" title="webapp/index.html">{`\
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>UI5 Walkthrough</title>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
||||
<script
|
||||
id="sap-ui-bootstrap"
|
||||
src="resources/sap-ui-core.js"
|
||||
...(other attributes)...
|
||||
>
|
||||
</script>
|
||||
</head>
|
||||
`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
**UI5 Module**
|
||||
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
comply with AMD `define` semantics. They support `sap.ui.define` out of the box.
|
||||
|
||||
If the SheetJS Standalone script is saved to `webapp/xlsx.full.min.js`, the base
|
||||
script `webapp/index.js` can load the library at `./xlsx.full.min`.
|
||||
|
||||
```js title="webapp/index.js"
|
||||
sap.ui.define([
|
||||
// highlight-next-line
|
||||
"./xlsx.full.min", // relative path to script, without the file extension
|
||||
/* ... other libraries ... */
|
||||
], function(
|
||||
// highlight-next-line
|
||||
_XLSX // !! NOTE: this is not XLSX! A different variable name must be used
|
||||
/* ... variables for the other libraries ... */,
|
||||
) {
|
||||
// highlight-next-line
|
||||
alert(XLSX.version); // use XLSX in the callback
|
||||
});
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
In some deployments, the function argument was `undefined`.
|
||||
|
||||
The standalone scripts add `window.XLSX`, so it is recommended to use `_XLSX`
|
||||
in the function arguments and access the library with `XLSX` in the callback.
|
||||
|
||||
:::
|
||||
|
||||
## Internal State
|
||||
|
||||
@ -70,7 +136,7 @@ object for each row, using the values in the first rows as keys:
|
||||
|
||||
</td></tr></tbody></table>
|
||||
|
||||
The OpenUI5 `JSONModel`[^1] is a client-side model implementation that stores data as JSON.
|
||||
The OpenUI5 `JSONModel`[^2] is a client-side model implementation that stores data as JSON.
|
||||
Here's a basic example of initializing a model, with a more complete implementation shown later:
|
||||
|
||||
<Tabs groupId="lang">
|
||||
@ -132,7 +198,7 @@ _loadExcelFile: async function () {
|
||||
|
||||
#### Rendering Data
|
||||
|
||||
In OpenUI5, the `Model-View-Controller`[^2] pattern is used to organize code and separate concerns.
|
||||
In OpenUI5, the `Model-View-Controller`[^3] pattern is used to organize code and separate concerns.
|
||||
The view defines the UI structure, the controller handles the logic, and the model manages the data.
|
||||
|
||||
```xml title="Example XML for displayin array of objects"
|
||||
@ -360,14 +426,14 @@ will generate a workbook that can be opened in a spreadsheet editor.
|
||||
|
||||
The main disadvantage of the Array of Objects approach is the specific nature
|
||||
of the columns. For more general use, passing around an Array of Arrays works.
|
||||
However, this does not handle merge cells[^3] well!
|
||||
However, this does not handle merge cells[^4] well!
|
||||
|
||||
The [`sheet_to_html`](/docs/api/utilities/html#html-table-output) function generates HTML that is aware of merges and other worksheet
|
||||
features. Using OpenUI5's `core:HTML`[^4] control, we can render this HTML directly. During export, we extract the table element from the
|
||||
features. Using OpenUI5's `core:HTML`[^5] control, we can render this HTML directly. During export, we extract the table element from the
|
||||
rendered HTML and use [`table_to_book`](/docs/api/utilities/html#html-table-input) to create a workbook that maintains all the worksheet
|
||||
features.
|
||||
|
||||
In this example, the component directly renders the HTML table in the model through OpenUI5's `core:HTML`[^4] control. For export, we extract
|
||||
In this example, the component directly renders the HTML table in the model through OpenUI5's `core:HTML`[^5] control. For export, we extract
|
||||
the inner table from the rendered HTML using `getElementsByTagName("table")[1]`, then pass it to [`table_to_book`](/docs/api/utilities/html#html-table-input)
|
||||
to create a workbook that preserves all features.
|
||||
|
||||
@ -513,7 +579,8 @@ will generate a workbook that can be opened in a spreadsheet editor.
|
||||
</details>
|
||||
|
||||
|
||||
[^1]: See [`JSONModel`](https://sdk.openui5.org/1.38.62/docs/api/symbols/sap.ui.model.json.JSONModel.html) in the OpenUI5 documentation.
|
||||
[^2]: See OpenUI5's [MVC Documentation](https://sdk.openui5.org/topic/91f233476f4d1014b6dd926db0e91070) for detailed explanation of the pattern implementation.
|
||||
[^3]: See ["Merged Cells" in "SheetJS Data Model"](/docs/csf/features/merges) for more details.
|
||||
[^4]: See [`core:HTML`](https://sdk.openui5.org/1.38.62/docs/api/symbols/sap.ui.core.HTML.html) in the OpenUI5 documentation.
|
||||
[^1]: See ["ECMAScript Support"](https://sdk.openui5.org/topic/0cb44d7a147640a0890cefa5fd7c7f8e.html#loio0cb44d7a147640a0890cefa5fd7c7f8e/section_UI5Mod) for more details about OpenUI5 compatibility.
|
||||
[^2]: See [`JSONModel`](https://sdk.openui5.org/1.38.62/docs/api/symbols/sap.ui.model.json.JSONModel.html) in the OpenUI5 documentation.
|
||||
[^3]: See OpenUI5's [MVC Documentation](https://sdk.openui5.org/topic/91f233476f4d1014b6dd926db0e91070) for detailed explanation of the pattern implementation.
|
||||
[^4]: See ["Merged Cells" in "SheetJS Data Model"](/docs/csf/features/merges) for more details.
|
||||
[^5]: See [`core:HTML`](https://sdk.openui5.org/1.38.62/docs/api/symbols/sap.ui.core.HTML.html) in the OpenUI5 documentation.
|
@ -41,10 +41,10 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date | Required Workarounds |
|
||||
|:---------|:-----------|:------------------------------------|
|
||||
| `2.7.0` | 2024-03-16 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
| `3.12.0` | 2024-03-16 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
| `4.47.0` | 2024-03-16 | Downgrade NodeJS (tested v16.20.2) |
|
||||
| `5.90.3` | 2024-03-16 | |
|
||||
| `5.97.1` | 2025-01-03 | |
|
||||
| `4.47.0` | 2025-01-03 | |
|
||||
| `3.12.0` | 2025-01-03 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
| `2.7.0` | 2025-01-03 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
|
||||
:::
|
||||
|
||||
@ -269,15 +269,16 @@ version above 4.0 can be pinned by locally installing webpack and the CLI tool.
|
||||
|
||||
**Webpack 4.x**
|
||||
|
||||
:::info pass
|
||||
:::note pass
|
||||
|
||||
Webpack 4 is incompatible with Node 18+. It will elicit the following error:
|
||||
Some Webpack 4 versions are incompatible with Node 18+. They will elicit the
|
||||
following error:
|
||||
|
||||
```
|
||||
Error: error:0308010C:digital envelope routines::unsupported
|
||||
```
|
||||
|
||||
When this demo was last tested, NodeJS was locally downgraded to 16.20.2
|
||||
In some demo tests, NodeJS was locally downgraded to 16.20.2
|
||||
|
||||
:::
|
||||
|
||||
|
@ -46,11 +46,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Platform | Date |
|
||||
|:----------|:---------|:-----------|
|
||||
| `0.19.47` | NodeJS | 2024-03-31 |
|
||||
| `0.20.16` | Browser | 2024-03-31 |
|
||||
| `0.20.19` | NodeJS | 2024-03-31 |
|
||||
| `0.21.6` | NodeJS | 2024-03-31 |
|
||||
| `6.14.3` | NodeJS | 2024-03-31 |
|
||||
| `0.19.47` | NodeJS | 2025-01-03 |
|
||||
| `0.20.16` | Browser | 2025-01-03 |
|
||||
| `0.20.19` | NodeJS | 2025-03-03 |
|
||||
| `0.21.6` | NodeJS | 2025-03-03 |
|
||||
| `6.15.1` | NodeJS | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -203,7 +203,7 @@ npm init -y
|
||||
1) Install the dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz systemjs@6.14.3`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz systemjs@6.15.1`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`SheetJSystem.js`](pathname:///systemjs/SheetJSystem.js) and move
|
||||
|
@ -34,10 +34,10 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `4.13.0` | 2024-03-25 |
|
||||
| `3.29.4` | 2024-03-25 |
|
||||
| `2.79.1` | 2024-03-25 |
|
||||
| `1.32.1` | 2024-03-25 |
|
||||
| `4.29.1` | 2025-01-03 |
|
||||
| `3.29.5` | 2025-01-03 |
|
||||
| `2.79.1` | 2025-01-03 |
|
||||
| `1.32.1` | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -34,8 +34,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `2.12.0` | 2024-06-08 |
|
||||
| `1.12.4` | 2024-06-08 |
|
||||
| `2.13.3` | 2024-12-31 |
|
||||
| `1.12.3` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -22,8 +22,12 @@ The ["Complete Example"](#complete-example) section includes a complete server.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested on 2024 March 11 using `express-formidable@1.2.0` and
|
||||
ExpressJS `4.18.3`
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `4.21.2` | 2025-01-03 |
|
||||
| `5.0.1` | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -136,21 +140,23 @@ app.get('/download', function(req, res) {
|
||||
res.status(200).end(buf);
|
||||
// highlight-end
|
||||
});
|
||||
app.listen(+process.env.PORT||3000);
|
||||
app.listen(+process.env.PORT||3000, function() { console.log("Ready to go"); });
|
||||
```
|
||||
|
||||
2) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz express@4.18.3 express-formidable@1.2.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz express@4.21.2 express-formidable@1.2.0`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Start server (note: it will not print anything to console when running)
|
||||
3) Start server
|
||||
|
||||
```bash
|
||||
node SheetJSExpressCSV.js
|
||||
```
|
||||
|
||||
Once the server starts, the process will print `Ready to go`.
|
||||
|
||||
4) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
|
||||
should be run in a new terminal window:
|
||||
|
||||
|
@ -22,7 +22,13 @@ The ["Complete Example"](#complete-example) section includes a complete server.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested on 2024 March 11 using NestJS `10.3.3`.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| NestJS | Date |
|
||||
|:----------|:-------------|
|
||||
| `10.4.15` | `2024-12-22` |
|
||||
| `9.4.3` | `2024-12-22` |
|
||||
| `8.4.7` | `2024-12-22` |
|
||||
|
||||
:::
|
||||
|
||||
@ -124,10 +130,23 @@ npx @nestjs/cli@latest new -p npm sheetjs-nest
|
||||
cd sheetjs-nest
|
||||
```
|
||||
|
||||
2) Install the `@types/multer` package as a development dependency:
|
||||
:::info pass
|
||||
|
||||
The NestJS CLI generates a project using the latest version of NestJS. To force
|
||||
an older version, install older versions of dependencies in the `@nestjs` scope.
|
||||
|
||||
For example, the following command rolls back to NestJS major version 8:
|
||||
|
||||
```bash
|
||||
npm i --save-dev @types/multer
|
||||
npm install --save @nestjs/cli@8.x @nestjs/common@8.x @nestjs/core@8.x @nestjs/platform-express@8.x @nestjs/schematics@8.x @nestjs/testing@8.x --force
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
2) Install the `@types/multer` package as a dependency:
|
||||
|
||||
```bash
|
||||
npm i --save @types/multer
|
||||
```
|
||||
|
||||
3) Install the SheetJS library:
|
||||
@ -187,7 +206,7 @@ npx @nestjs/cli start
|
||||
|
||||
:::note pass
|
||||
|
||||
In the most recent test, the process failed with a message referencing `Multer`:
|
||||
In some tests, the process failed with a message referencing `Multer`:
|
||||
|
||||
```
|
||||
src/sheetjs/sheetjs.controller.ts:9:54 - error TS2694: Namespace 'global.Express' has no exported member 'Multer'.
|
||||
@ -203,7 +222,7 @@ This error indicates that `@types/multer` is not available.
|
||||
The recommended fix is to install `@types/multer` again:
|
||||
|
||||
```bash
|
||||
npm i --save-dev @types/multer
|
||||
npm i --save @types/multer
|
||||
npx @nestjs/cli start
|
||||
```
|
||||
|
||||
|
@ -21,7 +21,12 @@ The ["Complete Example"](#complete-example) section includes a complete server.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was verified on 2024 March 11 using `fastify@4.26.2`
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `4.29.0` | 2025-01-02 |
|
||||
| `5.2.0` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -157,7 +162,7 @@ fastify.listen({port: process.env.PORT || 3000}, (err, addr) => { if(err) throw
|
||||
1) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify@4.26.2 @fastify/multipart@8.1.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify@4.29.0 @fastify/multipart@8`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Start server
|
||||
|
@ -34,7 +34,13 @@ the file can be downloaded or previewed in the browser.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 March 11 against `pst-extractor` 1.9.0
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Version | Date |
|
||||
|:------------|:---------|:-----------|
|
||||
| Chrome 131 | `1.9.0` | 2024-12-22 |
|
||||
| NodeJS 20 | `1.10.0` | 2024-12-22 |
|
||||
| BunJS 1.1 | `1.10.0` | 2024-12-22 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -32,53 +32,25 @@ before integrating with important inboxes or accounts.
|
||||
:::danger pass
|
||||
|
||||
It is strongly advised to use a test email address before using an important
|
||||
address. One small mistake could erase decades of messages or result in a block
|
||||
address. One small mistake could erase decades of messages or result in a block
|
||||
or ban from Google services.
|
||||
|
||||
:::
|
||||
|
||||
### App Passwords
|
||||
|
||||
Many email providers (including Fastmail, GMail, and Yahoo Mail) require "app
|
||||
passwords" or passwords for "less secure apps". Attempting to connect and send
|
||||
using the account password will throw errors.
|
||||
Many email providers (including GMail and Yahoo Mail) require "app passwords" or
|
||||
passwords for "less secure apps". Attempting to connect and send using the
|
||||
account password will throw errors.
|
||||
|
||||
### Test Account
|
||||
|
||||
It is strongly recommended to first test with an independent service provider.
|
||||
|
||||
#### Fastmail
|
||||
|
||||
This demo will start with a free 30-day trial of Fastmail. At the time the demo
|
||||
was last tested, no payment details were required.
|
||||
|
||||
:::caution pass
|
||||
|
||||
A valid phone number (for SMS verification) was required.
|
||||
|
||||
:::
|
||||
|
||||
0) Create a new Fastmail email account and verify with a mobile number.
|
||||
|
||||
|
||||
_Create App Password_
|
||||
|
||||
1) Open the settings screen (click on the icon in the top-left corner of the
|
||||
screen and select "Settings").
|
||||
|
||||
2) Select "Privacy & Security" in the left pane, then click "Integrations" near
|
||||
the top of the main page. Click "New app password".
|
||||
|
||||
3) Select any name in the top drop-down (the default "iPhone" can be used). In
|
||||
the second drop-down, select "Mail (IMAP/POP/SMTP)". Click "Generate password".
|
||||
|
||||
A new password will be displayed. This is the app password that will be used in
|
||||
the demo script. **Copy the displayed password or write it down.**
|
||||
It is strongly recommended to first test with a separate account.
|
||||
|
||||
#### Gmail
|
||||
|
||||
This demo will start with a free Gmail account. At the time the demo was last
|
||||
tested, no payment details were required.
|
||||
This demo will start with a free Gmail account. When the demo was last tested,
|
||||
no payment details were required.
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -98,7 +70,8 @@ _Create App Password_
|
||||
|
||||
4) Click "2-Step Verification"
|
||||
|
||||
5) Click the right arrow (`>`) next to "App passwords".
|
||||
5) Click the right arrow (`>`) next to "App passwords". If that option is not
|
||||
available, open https://myaccount.google.com/apppasswords
|
||||
|
||||
6) Type a name ("SheetJS Test") and click "Create".
|
||||
|
||||
@ -152,8 +125,7 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Email Provider | Date | Library | Version |
|
||||
|:---------------|:-----------|:-------------|:---------|
|
||||
| `gmail.com` | 2024-03-11 | `nodemailer` | `6.9.12` |
|
||||
| `fastmail.com` | 2024-03-11 | `nodemailer` | `6.9.12` |
|
||||
| `gmail.com` | 2025-01-05 | `nodemailer` | `6.9.16` |
|
||||
|
||||
:::
|
||||
|
||||
@ -175,7 +147,7 @@ const nodemailer = require('nodemailer');
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
// highlight-next-line
|
||||
service: 'fastmail',
|
||||
service: 'gmail',
|
||||
auth: {
|
||||
// highlight-start
|
||||
user: '**',
|
||||
@ -210,7 +182,7 @@ transporter.sendMail(mailOptions, function (err, info) {
|
||||
|
||||
3) Edit `SheetJSend.js` and replace the highlighted lines:
|
||||
|
||||
- `service: 'fastmail',` the value should be one of the supported providers[^1]
|
||||
- `service: 'gmail',` the value should be one of the supported providers[^1]
|
||||
- `user: "**",` the value should be the sender email address
|
||||
- `pass: "**"` the value should be the app password from earlier
|
||||
- `from: "**",` the value should be the sender email address
|
||||
@ -300,8 +272,7 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Email Provider | Date | Library | Version |
|
||||
|:---------------|:-----------|:-----------|:----------|
|
||||
| `gmail.com` | 2024-03-11 | `imapflow` | `1.0.156` |
|
||||
| `fastmail.com` | 2024-03-11 | `imapflow` | `1.0.156` |
|
||||
| `gmail.com` | 2025-01-05 | `imapflow` | `1.0.172` |
|
||||
|
||||
:::
|
||||
|
||||
@ -312,7 +283,7 @@ This demo was tested in the following deployments:
|
||||
<CodeBlock language="bash">{`\
|
||||
mkdir sheetjs-recv
|
||||
cd sheetjs-recv
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz imapflow@1.0.156`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz imapflow@1.0.172`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Save the following script to `SheetJSIMAP.js`:
|
||||
@ -323,7 +294,7 @@ const { ImapFlow } = require('imapflow');
|
||||
|
||||
const client = new ImapFlow({
|
||||
// highlight-next-line
|
||||
host: 'imap.fastmail.com',
|
||||
host: 'imap.gmail.com',
|
||||
port: 993, secure: true, logger: false,
|
||||
auth: {
|
||||
// highlight-start
|
||||
@ -371,18 +342,19 @@ const concat_RS = (stream) => new Promise((res, rej) => {
|
||||
|
||||
- `user: "**",` the value should be the account address
|
||||
- `pass: "**"` the value should be the app password from earlier
|
||||
- `host: 'imap.fastmail.com',` the value should be the host name:
|
||||
- `host: 'imap.gmail.com',` the value should be the host name:
|
||||
|
||||
| Service | `host` value |
|
||||
|:---------------|:--------------------|
|
||||
| `gmail.com` | `imap.gmail.com` |
|
||||
| `fastmail.com` | `imap.fastmail.com` |
|
||||
|
||||
4) Download https://docs.sheetjs.com/pres.numbers . Using a different account,
|
||||
send an email to the test account and attach the file. At the end of this step,
|
||||
the test account should have an email in the inbox that has an attachment.
|
||||
4) Download https://docs.sheetjs.com/pres.numbers .
|
||||
|
||||
5) Run the script:
|
||||
5) Send an email to the test account and attach `pres.numbers` from step 4.
|
||||
|
||||
6) Wait until the test account receives the email.
|
||||
|
||||
7) Run the script:
|
||||
|
||||
```bash
|
||||
node SheetJSIMAP.js
|
||||
|
@ -25,6 +25,17 @@ not generally support passing objects between the browser context and the
|
||||
automation script, so the file data must be generated in the browser context
|
||||
and sent back to the automation script for saving in the file system.
|
||||
|
||||
This demo exports data from https://sheetjs.com/demos/table.
|
||||
|
||||
:::note pass
|
||||
|
||||
It is also possible to parse files from the browser context, but parsing from
|
||||
the automation context is more efficient and strongly recommended.
|
||||
|
||||
:::
|
||||
|
||||
#### Key Steps
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber off
|
||||
@ -50,39 +61,23 @@ sequenceDiagram
|
||||
end
|
||||
```
|
||||
|
||||
<details open>
|
||||
<summary><b>Key Steps</b> (click to hide)</summary>
|
||||
|
||||
1) Launch the headless browser and load the target site.
|
||||
|
||||
2) Add the standalone SheetJS build to the page in a `SCRIPT` tag.
|
||||
|
||||
3) Add a script to the page (in the browser context) that will:
|
||||
|
||||
- Make a workbook object from the first table using `XLSX.utils.table_to_book`
|
||||
- Generate the bytes for an XLSB file using `XLSX.write`
|
||||
- Make a SheetJS workbook object[^1] from the first table using the SheetJS
|
||||
`table_to_book`[^2] method.
|
||||
- Generate the bytes for an XLSB file using the SheetJS `write`[^3] method.
|
||||
- Send the bytes back to the automation script
|
||||
|
||||
4) When the automation context receives data, save to a file
|
||||
|
||||
</details>
|
||||
|
||||
This demo exports data from https://sheetjs.com/demos/table.
|
||||
|
||||
:::note pass
|
||||
|
||||
It is also possible to parse files from the browser context, but parsing from
|
||||
the automation context is more efficient and strongly recommended.
|
||||
|
||||
:::
|
||||
|
||||
## Puppeteer
|
||||
|
||||
[Puppeteer](https://pptr.dev/) enables headless Chromium automation for NodeJS.
|
||||
Releases ship with an installer script that installs a headless browser.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
[Puppeteer](https://pptr.dev/) enables headless Chromium automation for NodeJS
|
||||
and BunJS. Releases ship with a script that installs a headless browser.
|
||||
|
||||
Binary strings are the favored data type. They can be safely passed from the
|
||||
browser context to the automation script. NodeJS provides an API to write
|
||||
@ -131,116 +126,61 @@ const puppeteer = require('puppeteer');
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 June 24 against Puppeteer 22.12.0.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Puppeteer | Date |
|
||||
|:----------|:-----------|
|
||||
| `23.11.1` | 2024-12-31 |
|
||||
| `22.15.0` | 2024-12-31 |
|
||||
| `21.11.0` | 2024-12-31 |
|
||||
| `20.9.0` | 2024-12-31 |
|
||||
| `15.5.0` | 2024-12-31 |
|
||||
| `10.4.0` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
1) Install SheetJS and Puppeteer:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@22.12.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@23.11.1`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bunjs" label="BunJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@23.11.1`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
2) Save the `SheetJSPuppeteer.js` code snippet to `SheetJSPuppeteer.js`.
|
||||
|
||||
3) Run the script:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
```bash
|
||||
node SheetJSPuppeteer.js
|
||||
```
|
||||
|
||||
When the script finishes, the file `SheetJSPuppeteer.xlsb` will be created.
|
||||
This file can be opened with Excel.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="deno" label="Deno">
|
||||
|
||||
:::caution pass
|
||||
|
||||
Deno Puppeteer is a fork. It is not officially supported by the Puppeteer team.
|
||||
|
||||
:::
|
||||
|
||||
Base64 strings are the favored data type. They can be safely passed from the
|
||||
browser context to the automation script. Deno can decode the Base64 strings
|
||||
and write the decoded `Uint8Array` data to file with `Deno.writeFileSync`
|
||||
|
||||
The key steps are commented below:
|
||||
|
||||
<CodeBlock language="ts" title="SheetJSPuppeteer.ts">{`\
|
||||
import puppeteer from "https://deno.land/x/puppeteer@16.2.0/mod.ts";
|
||||
import { decode } from "https://deno.land/std/encoding/base64.ts"
|
||||
\n\
|
||||
/* (1) Load the target page */
|
||||
const browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
page.on("console", msg => console.log("PAGE LOG:", msg.text()));
|
||||
await page.setViewport({width: 1920, height: 1080});
|
||||
await page.goto('https://sheetjs.com/demos/table');
|
||||
\n\
|
||||
/* (2) Load the standalone SheetJS build from the CDN */
|
||||
await page.addScriptTag({ url: 'https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js' });
|
||||
\n\
|
||||
/* (3) Run the snippet in browser and return data */
|
||||
const b64 = await page.evaluate(() => {
|
||||
/* NOTE: this function will be evaluated in the browser context.
|
||||
\`page\`, \`fs\` and \`puppeteer\` are not available.
|
||||
\`XLSX\` will be available thanks to step 2 */
|
||||
\n\
|
||||
/* find first table */
|
||||
var table = document.body.getElementsByTagName('table')[0];
|
||||
\n\
|
||||
/* call table_to_book on first table */
|
||||
var wb = XLSX.utils.table_to_book(table);
|
||||
\n\
|
||||
/* generate XLSB and return binary string */
|
||||
return XLSX.write(wb, {type: "base64", bookType: "xlsb"});
|
||||
});
|
||||
/* (4) write data to file */
|
||||
Deno.writeFileSync("SheetJSPuppeteer.xlsb", decode(b64));
|
||||
\n\
|
||||
await browser.close();`}
|
||||
</CodeBlock>
|
||||
|
||||
**Demo**
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 June 24 against `deno-puppeteer` 16.2.0.
|
||||
|
||||
:::
|
||||
|
||||
1) Install `deno-puppeteer`:
|
||||
<TabItem value="bunjs" label="BunJS">
|
||||
|
||||
```bash
|
||||
env PUPPETEER_PRODUCT=chrome deno run -A --unstable https://deno.land/x/puppeteer@16.2.0/install.ts
|
||||
bun SheetJSPuppeteer.js
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the environment variable should be set separately:
|
||||
|
||||
```powershell
|
||||
[Environment]::SetEnvironmentVariable('PUPPETEER_PRODUCT', 'chrome')
|
||||
deno run -A --unstable https://deno.land/x/puppeteer@16.2.0/install.ts
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
2) Save the `SheetJSPuppeteer.ts` code snippet to `SheetJSPuppeteer.ts`.
|
||||
|
||||
3) Run the script:
|
||||
|
||||
```bash
|
||||
deno run -A --unstable SheetJSPuppeteer.ts
|
||||
```
|
||||
|
||||
When the script finishes, the file `SheetJSPuppeteer.xlsb` will be created.
|
||||
This file can be opened with Excel.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
When the script finishes, the file `SheetJSPuppeteer.xlsb` will be created.
|
||||
This file can be opened with a spreadsheet editor that supports XLSB workbooks.
|
||||
|
||||
## Playwright
|
||||
|
||||
@ -294,26 +234,56 @@ const { webkit } = require('playwright'); // import desired browser
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 June 24 against Playwright 1.45.0.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Playwright | Date |
|
||||
|:-----------|:-----------|
|
||||
| `1.49.1` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
1) Install SheetJS and Playwright:
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz playwright@1.45.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz playwright@1.49.1`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bunjs" label="BunJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz playwright@1.49.1`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
2) Save the `SheetJSPlaywright.js` code snippet to `SheetJSPlaywright.js`.
|
||||
|
||||
3) Run the script
|
||||
|
||||
<Tabs groupId="ssplat">
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
```bash
|
||||
node SheetJSPlaywright.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bunjs" label="BunJS">
|
||||
|
||||
```bash
|
||||
bun SheetJSPlaywright.js
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
When the script finishes, the file `SheetJSPlaywright.xlsb` will be created.
|
||||
This file can be opened with Excel.
|
||||
This file can be opened with a spreadsheet editor that supports XLSB workbooks.
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -456,3 +426,7 @@ env OPENSSL_CONF=/dev/null QT_QPA_PLATFORM=phantom ./phantomjs-2.1.1-linux-x86_6
|
||||
:::
|
||||
|
||||
</details>
|
||||
|
||||
[^1]: See ["Workbook Object"](/docs/csf/book) for more details about the SheetJS workbook object.
|
||||
[^2]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
|
||||
[^3]: See [`write` in "Writing Files"](/docs/api/write-options)
|
@ -16,7 +16,12 @@ With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last verified on 2024 April 25.
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 131 | 2024-12-31 |
|
||||
| Safari 18.2 | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -15,7 +15,12 @@ with a straightforward API.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last verified on 2024 April 25.
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 131 | 2024-12-31 |
|
||||
| Safari 18.2 | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -133,8 +133,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| Lume | Date |
|
||||
|:---------|:-----------|
|
||||
| `1.19.4` | 2024-03-16 |
|
||||
| `2.1.2` | 2024-03-16 |
|
||||
| `1.19.4` | 2025-01-02 |
|
||||
| `2.4.3` | 2025-01-02 |
|
||||
|
||||
This example uses the Nunjucks template format. Lume plugins support additional
|
||||
template formats, including Markdown and JSX.
|
||||
@ -150,15 +150,17 @@ template formats, including Markdown and JSX.
|
||||
```bash
|
||||
mkdir -p sheetjs-lume
|
||||
cd sheetjs-lume
|
||||
deno run -Ar https://deno.land/x/lume@v2.1.2/init.ts
|
||||
deno run -Ar https://deno.land/x/lume@v2.4.3/init.ts
|
||||
```
|
||||
|
||||
When prompted, enter the following options:
|
||||
When prompted, enter the following options. The initialization script has
|
||||
changed over time, so not all questions will be asked.
|
||||
|
||||
- `What kind of setup do you want?`: select `Basic + plugins`
|
||||
- `Choose the configuration file format`: select `_config.ts`
|
||||
- `Do you want to install some plugins now?`: select `Yes`
|
||||
- `Select the plugins to install`: select `sheets` and `nunjucks`
|
||||
- `Do you want to setup a CMS?`: select `Maybe later`
|
||||
- `Do you want to setup a CMS?`: select `No` or `Maybe later`
|
||||
|
||||
The project will be configured and modules will be installed.
|
||||
|
||||
@ -226,7 +228,7 @@ deno task lume
|
||||
|
||||
This will create a static site in the `_site` folder
|
||||
|
||||
7) Test the generated site by starting a web server:
|
||||
8) Test the generated site by starting a web server:
|
||||
|
||||
```bash
|
||||
npx http-server _site
|
||||
|
@ -180,7 +180,7 @@ This demo was tested in the following environments:
|
||||
| GatsbyJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.13.4` | 2024-05-04 |
|
||||
| `4.25.8` | 2024-03-27 |
|
||||
| `4.25.8` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -221,8 +221,8 @@ npx gatsby new sheetjs-gatsby
|
||||
|
||||
For older Gatsby versions, the project must be built from the starter project.
|
||||
|
||||
For GatsbyJS 4, the starter commit is `6bc4466090845f20650117b3d27e68e6e46dc8d5`
|
||||
and the steps are shown below:
|
||||
The starter commit for GatsbyJS 4 is `6bc4466090845f20650117b3d27e68e6e46dc8d5`.
|
||||
This version of the starter can be fetched with `git`:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/gatsbyjs/gatsby-starter-default sheetjs-gatsby
|
||||
@ -234,7 +234,7 @@ cd ..
|
||||
|
||||
:::
|
||||
|
||||
2) Follow the on-screen instructions for starting the local development server:
|
||||
2) Start the local development server:
|
||||
|
||||
```bash
|
||||
cd sheetjs-gatsby
|
||||
@ -257,7 +257,7 @@ Open a web browser to the displayed URL (typically `http://localhost:8000/`)
|
||||
`}
|
||||
</CodeBlock>
|
||||
|
||||
4) Install the library and plugins:
|
||||
4) Install the SheetJS library and GatsbyJS plugins:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
@ -329,14 +329,18 @@ If the `plugins` array exists, the two plugins should be added at the beginning:
|
||||
|
||||
:::
|
||||
|
||||
Stop and restart the development server process (`npm run develop`).
|
||||
7) Stop and restart the development server process:
|
||||
|
||||
```bash
|
||||
npm run develop
|
||||
```
|
||||
|
||||
### GraphiQL test
|
||||
|
||||
7) Open the GraphiQL editor. The output of the previous step displayed the URL
|
||||
(typically `http://localhost:8000/___graphql` )
|
||||
8) Open the GraphiQL editor in a web browser. The output of the previous step
|
||||
displayed the URL (typically `http://localhost:8000/___graphql` ).
|
||||
|
||||
There is an editor in the left pane. Paste the following query into the editor:
|
||||
9) Paste the following query into the code editor:
|
||||
|
||||
```graphql title="GraphQL Query (paste into editor)"
|
||||
{
|
||||
@ -358,7 +362,7 @@ Press the Execute Query button (`▶`) and data should show up in the right pane
|
||||
<details>
|
||||
<summary><b>Sample Output</b> (click to show)</summary>
|
||||
|
||||
In GatsbyJS version `5.13.4`, the raw output was:
|
||||
In GatsbyJS versions `5.13.4` and `4.25.8`, the raw output was:
|
||||
|
||||
```json title="GraphQL query result from GatsbyJS 5.13.4"
|
||||
{
|
||||
@ -406,7 +410,7 @@ In GatsbyJS version `5.13.4`, the raw output was:
|
||||
|
||||
### React page
|
||||
|
||||
8) Create a new file `src/pages/pres.js` that uses the query and displays the result:
|
||||
10) Create a new page `src/pages/pres.js` that displays the raw query result:
|
||||
|
||||
```jsx title="src/pages/pres.js (create new file)"
|
||||
import { graphql } from "gatsby"
|
||||
@ -429,8 +433,8 @@ const PageComponent = ({data}) => {
|
||||
export default PageComponent;
|
||||
```
|
||||
|
||||
After saving the file, access `http://localhost:8000/pres` in the browser. The
|
||||
displayed JSON is the data that the component receives:
|
||||
11) After saving the file, access `http://localhost:8000/pres` in the browser.
|
||||
The displayed JSON is the data that the component receives:
|
||||
|
||||
```js title="Expected contents of /pres"
|
||||
{
|
||||
@ -445,7 +449,7 @@ displayed JSON is the data that the component receives:
|
||||
// ....
|
||||
```
|
||||
|
||||
9) Change `PageComponent` to display a table based on the data:
|
||||
12) Change `PageComponent` to display a table based on the data:
|
||||
|
||||
```jsx title="src/pages/pres.js (replace PageComponent)"
|
||||
import { graphql } from "gatsby"
|
||||
@ -484,7 +488,7 @@ Going back to the browser, `http://localhost:8000/pres` will show a table:
|
||||
|
||||
### Live refresh
|
||||
|
||||
10) Open the file `src/data/pres.xlsx` in Excel or another spreadsheet editor.
|
||||
13) Open the file `src/data/pres.xlsx` in Excel or another spreadsheet editor.
|
||||
Add a new row at the end of the file, setting cell `A7` to "SheetJS Dev" and
|
||||
cell `B7` to `47`. The sheet should look like the following screenshot:
|
||||
|
||||
@ -496,7 +500,7 @@ Save the file and observe that the table has refreshed with the new data:
|
||||
|
||||
### Static site
|
||||
|
||||
11) Stop the development server and build the site:
|
||||
14) Stop the development server and build the site:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
@ -527,7 +531,7 @@ Pages
|
||||
|
||||
The generated page will be placed in `public/pres/index.html`.
|
||||
|
||||
12) Open `public/pres/index.html` with a text editor and search for "SheetJS".
|
||||
15) Open `public/pres/index.html` with a text editor and search for "SheetJS".
|
||||
There will be a HTML row:
|
||||
|
||||
```html title="public/pres/index.html (Expected contents)"
|
||||
|
@ -184,7 +184,11 @@ document.body.appendChild(elt);
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 April 06 against Webpack 5.91.0
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.91.0` | 2024-04-06 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -114,10 +114,10 @@ accessed using the variable `pres` in a template:
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Eleventy | Date |
|
||||
|:----------------|:-----------|
|
||||
| `2.0.1` | 2024-03-15 |
|
||||
| `3.0.0-alpha.5` | 2024-03-15 |
|
||||
| Eleventy | Date |
|
||||
|:---------|:-----------|
|
||||
| `2.0.1` | 2024-12-23 |
|
||||
| `3.0.0` | 2024-12-23 |
|
||||
|
||||
:::
|
||||
|
||||
@ -134,17 +134,17 @@ npm init -y
|
||||
2) Install Eleventy and SheetJS libraries:
|
||||
|
||||
<Tabs groupId="11ty">
|
||||
<TabItem value="2" label="Stable">
|
||||
<TabItem value="2" label="2.x">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @11ty/eleventy@2.0.1`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="3" label="Alpha">
|
||||
<TabItem value="3" label="3.x">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @11ty/eleventy@3.0.0-alpha.5`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @11ty/eleventy@3.0.0`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
|
@ -226,19 +226,19 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS | Device | RN | Date |
|
||||
|:-----------|:------------------|:---------|:-----------|
|
||||
| iOS 15.1 | iPhone 12 Pro Max | `0.73.6` | 2024-03-13 |
|
||||
| Android 29 | NVIDIA Shield | `0.73.6` | 2024-03-13 |
|
||||
| iOS 15.6 | iPhone 13 Pro Max | `0.76.5` | 2025-01-05 |
|
||||
| Android 34 | NVIDIA Shield | `0.76.5` | 2025-01-05 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | RN | Dev Platform | Date |
|
||||
|:-----------|:--------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `darwin-x64` | 2024-03-13 |
|
||||
| iOS 17.4 | iPhone 15 Pro Max | `0.73.6` | `darwin-x64` | 2024-03-13 |
|
||||
| Android 34 | Pixel 3a | `0.74.2` | `darwin-arm` | 2024-06-20 |
|
||||
| iOS 17.5 | iPhone SE (3rd gen) | `0.74.2` | `darwin-arm` | 2024-06-20 |
|
||||
| Android 34 | Pixel 3a | `0.76.5` | `darwin-x64` | 2024-12-31 |
|
||||
| iOS 18.2 | iPhone 16 Pro | `0.76.5` | `darwin-x64` | 2024-12-31 |
|
||||
| Android 34 | Pixel 3a | `0.76.5` | `darwin-arm` | 2025-01-05 |
|
||||
| iOS 18.2 | iPhone 16 Pro | `0.76.5` | `darwin-arm` | 2025-01-05 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `win11-x64` | 2024-12-22 |
|
||||
| Android 34 | Pixel 3a | `0.73.7` | `linux-x64` | 2024-04-29 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `linux-x64` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -280,6 +280,8 @@ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
|
||||
npx -y @react-native-community/cli@15 init SheetJSRNFetch --version="0.76.5"
|
||||
```
|
||||
|
||||
On macOS, if prompted to install `CocoaPods`, press <kbd>Y</kbd>
|
||||
|
||||
:::info pass
|
||||
|
||||
Older versions of this demo used the `react-native` package. The `init` command
|
||||
@ -481,6 +483,12 @@ If the device asks to allow USB debugging, tap "Allow".
|
||||
npx react-native run-android
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
Depending on the device, it may take up to 10 seconds for app to update.
|
||||
|
||||
:::
|
||||
|
||||
**iOS Device Testing**
|
||||
|
||||
13) Connect an iOS device using a USB cable.
|
||||
@ -494,7 +502,7 @@ If the device asks to trust the computer, tap "Trust" and enter the passcode.
|
||||
<details open>
|
||||
<summary><b>Enabling Code Signing</b> (click to show)</summary>
|
||||
|
||||
These instructions were verified against Xcode 15.3.
|
||||
These instructions were verified against Xcode 16.2.
|
||||
|
||||
A) Open the included iOS workspace in Xcode:
|
||||
|
||||
@ -526,6 +534,14 @@ brew install ios-deploy
|
||||
npx react-native run-ios
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
> "SheetJSRNFetch" would like to find and connect to devices on your local network.
|
||||
|
||||
Local network access is not required for the demo. Select "Don't Allow".
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
In some tests, the app failed to run on the device due to "Untrusted Developer":
|
||||
@ -534,7 +550,7 @@ In some tests, the app failed to run on the device due to "Untrusted Developer":
|
||||
Your device management settings do not allow apps from developer ... on this iPhone. You can allow using these apps in Settings.
|
||||
```
|
||||
|
||||
These instructions were verified against iOS 15.1.
|
||||
These instructions were verified against iOS 15.6.
|
||||
|
||||
A) Open the Settings app and select "General" > "VPN & Device Management".
|
||||
|
||||
@ -1027,17 +1043,19 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS | Device | RN | Date |
|
||||
|:-----------|:------------------|:---------|:-----------|
|
||||
| iOS 15.5 | iPhone 13 Pro Max | `0.73.6` | 2024-03-31 |
|
||||
| Android 29 | NVIDIA Shield | `0.73.6` | 2024-03-31 |
|
||||
| iOS 15.6 | iPhone 13 Pro Max | `0.76.5` | 2025-01-05 |
|
||||
| Android 34 | NVIDIA Shield | `0.76.5` | 2025-01-05 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | RN | Dev Platform | Date |
|
||||
|:-----------|:------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `darwin-x64` | 2024-03-31 |
|
||||
| iOS 17.4 | iPhone 15 Pro Max | `0.73.6` | `darwin-x64` | 2024-03-31 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `win11-x64` | 2024-03-31 |
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `linux-x64` | 2024-03-31 |
|
||||
| Android 34 | Pixel 3a | `0.76.5` | `darwin-x64` | 2024-12-31 |
|
||||
| iOS 18.2 | iPhone 16 Pro | `0.76.5` | `darwin-x64` | 2024-12-31 |
|
||||
| Android 34 | Pixel 3a | `0.76.5` | `darwin-arm` | 2025-01-05 |
|
||||
| iOS 18.2 | iPhone 16 Pro | `0.76.5` | `darwin-arm` | 2025-01-05 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `win11-x64` | 2024-12-22 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `linux-x64` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -1060,7 +1078,7 @@ This example tries to separate the library-specific functions.
|
||||
npx -y @react-native-community/cli@15 init SheetJSRN --version="0.76.5"
|
||||
```
|
||||
|
||||
On macOS, if prompted to install `CocoaPods`, press `y`.
|
||||
On macOS, if prompted to install `CocoaPods`, press <kbd>Y</kbd>
|
||||
|
||||
2) Install shared dependencies:
|
||||
|
||||
|
@ -66,6 +66,7 @@ This demo was tested in the following environments:
|
||||
| Android 34 | Pixel 3a | `8.7.2` | `darwin-arm` | 2024-06-09 |
|
||||
| iOS 17.5 | iPhone SE (3rd gen) | `8.7.2` | `darwin-arm` | 2024-06-09 |
|
||||
| Android 35 | Pixel 9 | `8.8.3` | `win11-x64` | 2024-12-21 |
|
||||
| Android 35 | Pixel 9 | `8.8.3` | `linux-x64` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -56,6 +56,7 @@ This demo was tested in the following environments:
|
||||
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
|
||||
| iOS 17.5 | iPhone 15 Pro Max | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
|
||||
| Android 35 | Pixel 9 | `6.2.0` / `6.0.2` | `win11-x64` | 2024-12-21 |
|
||||
| Android 35 | Pixel 9 | `6.2.0` / `6.0.2` | `linux-x64` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -188,11 +188,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Electron | Date |
|
||||
|:---------------|:-------------|:---------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `29.1.4` | 2024-03-15 |
|
||||
| macOS 15.2 | `darwin-x64` | `33.2.1` | 2024-12-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `30.0.8` | 2024-05-28 |
|
||||
| Windows 11 | `win11-x64` | `31.2.0` | 2024-08-18 |
|
||||
| Windows 11 | `win11-arm` | `30.0.8` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `29.1.4` | 2024-03-21 |
|
||||
| Linux (HoloOS) | `linux-x64` | `33.2.1` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `30.0.8` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
@ -321,8 +321,8 @@ and select `pres.numbers`.
|
||||
|
||||
## Electron Breaking Changes
|
||||
|
||||
The first version of this demo used Electron 1.7.5. The current demo includes
|
||||
the required changes for Electron 30.0.8.
|
||||
The first version of this demo used Electron `1.7.5`. The current demo includes
|
||||
the required changes for Electron `33.2.1`.
|
||||
|
||||
There are no Electron-specific workarounds in the library, but Electron broke
|
||||
backwards compatibility multiple times. A summary of changes is noted below.
|
||||
@ -336,6 +336,7 @@ methods have been renamed:
|
||||
|:-----------------|:---------------------|
|
||||
| `showOpenDialog` | `showOpenDialogSync` |
|
||||
| `showSaveDialog` | `showSaveDialogSync` |
|
||||
|
||||
**This change was not properly documented!**
|
||||
|
||||
Electron 9 and later require the preference `nodeIntegration: true` in order to
|
||||
|
@ -113,7 +113,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | NW.js | Date | Notes |
|
||||
|:---------------|:-------------|:---------|:-----------|:---------------------|
|
||||
| macOS 14.3.1 | `darwin-x64` | `0.85.0` | 2024-03-12 | |
|
||||
| macOS 15.2 | `darwin-x64` | `0.94.0` | 2024-12-31 | |
|
||||
| macOS 14.5 | `darwin-arm` | `0.88.0` | 2024-05-28 | |
|
||||
| Windows 11 | `win11-x64` | `0.94.0` | 2024-12-19 | |
|
||||
| Windows 11 | `win11-arm` | `0.88.0` | 2024-05-28 | |
|
||||
@ -198,6 +198,7 @@ testing, version `4.11.6` correctly generated the standalone application.
|
||||
|
||||
| Architecture | Command |
|
||||
|:-------------|:--------------------------------------------------------------|
|
||||
| `darwin-x64` | `open ../out/sheetjs-nwjs.app` |
|
||||
| `linux-x64` | `../out/sheetjs-nwjs` |
|
||||
| `win11-x64` | `..\out\sheetjs-nwjs.exe` |
|
||||
|
||||
|
@ -297,11 +297,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Wails | Date |
|
||||
|:---------------|:-------------|:---------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `v2.8.0` | 2024-03-15 |
|
||||
| macOS 15.2 | `darwin-x64` | `v2.9.2` | 2024-12-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `v2.8.2` | 2024-05-28 |
|
||||
| Windows 11 | `win11-x64` | `v2.9.2` | 2024-12-21 |
|
||||
| Windows 11 | `win11-arm` | `v2.8.2` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.8.0` | 2024-03-21 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.9.2` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `v2.8.2` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
@ -358,7 +358,7 @@ None of the optional packages are required for building and running this demo.
|
||||
On the Steam Deck (HoloOS), some dependencies must be reinstalled:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu base-devel gtk3 glib2 pango harfbuzz cairo gdk-pixbuf2 atk libsoup
|
||||
sudo pacman -Syu base-devel gtk3 glib2 pango harfbuzz cairo gdk-pixbuf2 atk libsoup webkit2gtk
|
||||
```
|
||||
|
||||
:::
|
||||
|
@ -14,6 +14,7 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const c = {style: {color:"cyan"}};
|
||||
export const y = {style: {color:"gold"}};
|
||||
export const g = {style: {color:"green"}};
|
||||
export const B = {style: {fontWeight:"bold"}};
|
||||
@ -352,11 +353,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Tauri | Date |
|
||||
|:---------------|:-------------|:----------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `v1.5.11` | 2024-04-20 |
|
||||
| macOS 15.2 | `darwin-x64` | `v1.6.0` | 2024-12-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `v1.5.14` | 2024-05-26 |
|
||||
| Windows 11 | `win11-x64` | `v1.6.0` | 2024-12-21 |
|
||||
| Windows 11 | `win11-arm` | `v1.5.14` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.5.11` | 2024-03-21 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.6.0` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `v1.5.14` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
@ -383,15 +384,16 @@ If required dependencies are installed, the output will show a checkmark next to
|
||||
|
||||
<pre>
|
||||
<span {...g}>[✔]</span> <span style={{...y.style,...B.style}}>Environment</span>
|
||||
{` `}<span {...g}>-</span> <span {...B}>OS</span>: Mac OS 14.4.1 X64
|
||||
{` `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 15.2.0 x86_64 (X64)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Xcode Command Line Tools</span>: installed
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.77.2 (25ef9e3d8 2024-04-09)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.77.2 (e52e36006 2024-03-26)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.27.0 (bbb9276d2 2024-03-08)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.83.0 (90b35a623 2024-11-26)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.83.0 (5ffbef321 2024-10-29)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.27.1 (54dd3d00f 2024-04-24)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Rust toolchain</span>: stable-x86_64-apple-darwin (default)
|
||||
{` `}<span {...g}>-</span> <span {...B}>node</span>: 20.12.1
|
||||
{` `}<span {...g}>-</span> <span {...B}>npm</span>: 10.5.0
|
||||
{` `}<span {...g}>-</span> <span {...B}>bun</span>: 1.1.4
|
||||
{` `}<span {...c}>-</span> <span {...B}>node</span>: 20.18.0
|
||||
{` `}<span {...c}>-</span> <span {...B}>npm</span>: 10.8.2
|
||||
{` `}<span {...c}>-</span> <span {...B}>bun</span>: 1.1.42
|
||||
{` `}<span {...c}>-</span> <span {...B}>deno</span>: deno 2.1.4
|
||||
</pre>
|
||||
|
||||
:::caution pass
|
||||
|
@ -192,11 +192,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Server | Client | Date |
|
||||
|:---------------|:-------------|:---------|:---------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `5.0.0` | `5.0.1` | 2024-03-15 |
|
||||
| macOS 15.2 | `darwin-x64` | `5.5.0` | `5.5.0` | 2024-12-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `5.1.0` | `5.1.0` | 2024-05-25 |
|
||||
| Windows 11 | `win11-x64` | `5.5.0` | `5.5.0` | 2024-12-20 |
|
||||
| Windows 11 | `win11-arm` | `5.1.0` | `5.1.1` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `5.0.0` | `5.0.1` | 2024-03-21 |
|
||||
| Linux (HoloOS) | `linux-x64` | `5.5.0` | `5.5.0` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `5.1.0` | `5.1.1` | 2024-05-28 |
|
||||
|
||||
NeutralinoJS on Windows on ARM generates X64 binaries that run using the X64
|
||||
@ -211,7 +211,7 @@ the window. Writing files will parse the table into a spreadsheet.
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
NeutralinoJS uses `portable-file-dialogs`[^12] to show open and save dialogs. On
|
||||
Linux, Zenity or KDialog are require.
|
||||
Linux, a dialog box helper (Zenity or KDialog) must be installed.
|
||||
|
||||
The last Debian test was run on a system using LXDE. KDialog is supported but
|
||||
must be explicitly installed:
|
||||
@ -413,10 +413,12 @@ Platform-specific programs will be created in the `dist` folder:
|
||||
|
||||
| Platform | Path to binary |
|
||||
|:-------------|:---------------------------------------------|
|
||||
| `darwin-x64` | `./dist/sheetjs-neu/sheetjs-neu-mac_x64` |
|
||||
| `darwin-arm` | `./dist/sheetjs-neu/sheetjs-neu-mac_arm64` |
|
||||
| `win11-x64` | `.\dist\sheetjs-neu\sheetjs-neu-win_x64.exe` |
|
||||
| `win11-arm` | `.\dist\sheetjs-neu\sheetjs-neu-win_x64.exe` |
|
||||
| `linux-arm` | `.\dist\sheetjs-neu\sheetjs-neu-linux_arm64` |
|
||||
| `linux-x64` | `./dist/sheetjs-neu/sheetjs-neu-linux_x64` |
|
||||
| `linux-arm` | `./dist/sheetjs-neu/sheetjs-neu-linux_arm64` |
|
||||
|
||||
Run the generated app and confirm that Presidential data is displayed.
|
||||
|
||||
|
@ -41,7 +41,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-25 |
|
||||
| `win11-x64` | `4.0.0-rc.6` | `14.15.3` | Pre-built | 2024-12-19 |
|
||||
| `win11-arm` | `4.0.0-rc.6` | `20.10.0` | Compiled | 2024-05-28 |
|
||||
| `linux-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-21 |
|
||||
| `linux-x64` | `4.0.0-rc.6` | `14.15.3` | Pre-built | 2024-12-31 |
|
||||
| `linux-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
@ -41,7 +41,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `5.8.1` | `18.5.0` | 2024-05-25 |
|
||||
| `win11-x64` | `5.8.1` | `18.5.0` | 2024-12-19 |
|
||||
| `win11-arm` | `5.8.1` | `18.5.0` | 2024-10-25 |
|
||||
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-03-21 |
|
||||
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-12-31 |
|
||||
| `linux-arm` | `5.8.1` | `18.5.0` | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
@ -33,7 +33,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-x64` | `2.4.0` | `22.2.0` | 2024-05-28 |
|
||||
| `darwin-arm` | `2.4.3` | `22.2.0` | 2024-05-25 |
|
||||
| `win11-x64` | `2.4.4` | `16.20.2` | 2024-12-19 |
|
||||
| `linux-x64` | `2.4.0` | `21.7.1` | 2024-03-21 |
|
||||
| `linux-x64` | `2.4.4` | `23.5.0` | 2024-12-31 |
|
||||
| `linux-arm` | `2.4.3` | `20.13.1` | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
@ -162,7 +162,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `22.2.0` | 2024-05-29 |
|
||||
| `win11-x64` | `20.13.1` | 2024-05-22 |
|
||||
| `win11-arm` | `20.14.0` | 2024-06-11 |
|
||||
| `linux-x64` | `20.11.1` | 2024-03-18 |
|
||||
| `linux-x64` | `22.12.0` | 2025-01-02 |
|
||||
| `linux-arm` | `20.14.0` | 2024-06-10 |
|
||||
|
||||
:::
|
||||
|
@ -103,7 +103,7 @@ This demo was last tested in the following deployments:
|
||||
| `darwin-arm` | `1.43.6` | 2024-05-23 |
|
||||
| `win11-x64` | `1.43.6` | 2024-05-25 |
|
||||
| `win11-arm` | `2.0.3` | 2024-10-25 |
|
||||
| `linux-x64` | `1.41.3` | 2024-03-18 |
|
||||
| `linux-x64` | `2.1.4` | 2025-01-02 |
|
||||
| `linux-arm` | `1.43.6` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
|
@ -36,9 +36,12 @@ This demo was tested in the following environments:
|
||||
|
||||
| Postgres | Connector Library | Date |
|
||||
|:---------|:------------------|:-----------|
|
||||
| `16.6.1` | `pg` (`8.13.1`) | 2024-12-03 |
|
||||
| `15.6` | `pg` (`8.11.4`) | 2024-03-31 |
|
||||
| `14.11` | `pg` (`8.11.4`) | 2024-03-31 |
|
||||
| `17.2` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `16.6` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `15.10` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `14.15` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `13.18` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `12.22` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -144,125 +147,125 @@ The `sheet_to_pg_table` function:
|
||||
```js
|
||||
/* create table and load data given a worksheet and a PostgreSQL client */
|
||||
async function sheet_to_pg_table(client, worksheet, tableName) {
|
||||
if (!worksheet['!ref']) return;
|
||||
if (!worksheet['!ref']) return;
|
||||
|
||||
const range = XLSX.utils.decode_range(worksheet['!ref']);
|
||||
const range = XLSX.utils.decode_range(worksheet['!ref']);
|
||||
|
||||
/* Extract headers from first row, clean names for PostgreSQL */
|
||||
const headers = [];
|
||||
/* Extract headers from first row, clean names for PostgreSQL */
|
||||
const headers = [];
|
||||
for (let col = range.s.c; col <= range.e.c; col++) {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: range.s.r, c: col });
|
||||
const cell = worksheet[cellAddress];
|
||||
const headerValue = cell ? String(cell.v).replace(/[^a-zA-Z0-9_]/g, '_') : `column_${col + 1}`;
|
||||
headers.push(headerValue.toLowerCase());
|
||||
}
|
||||
|
||||
/* Group cell values by column for type deduction */
|
||||
const columnValues = headers.map(() => []);
|
||||
for (let row = range.s.r + 1; row <= range.e.r; row++) {
|
||||
for (let col = range.s.c; col <= range.e.c; col++) {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: range.s.r, c: col });
|
||||
const cell = worksheet[cellAddress];
|
||||
const headerValue = cell ? String(cell.v).replace(/[^a-zA-Z0-9_]/g, '_') : `column_${col + 1}`;
|
||||
headers.push(headerValue.toLowerCase());
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
const cell = worksheet[cellAddress];
|
||||
columnValues[col].push(cell);
|
||||
}
|
||||
}
|
||||
|
||||
/* Group cell values by column for type deduction */
|
||||
const columnValues = headers.map(() => []);
|
||||
for (let row = range.s.r + 1; row <= range.e.r; row++) {
|
||||
for (let col = range.s.c; col <= range.e.c; col++) {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
const cell = worksheet[cellAddress];
|
||||
columnValues[col].push(cell);
|
||||
}
|
||||
}
|
||||
/* Deduce PostgreSQL type for each column */
|
||||
const types = {};
|
||||
headers.forEach((header, idx) => {
|
||||
types[header] = deduceType(columnValues[idx]);
|
||||
});
|
||||
|
||||
/* Deduce PostgreSQL type for each column */
|
||||
const types = {};
|
||||
headers.forEach((header, idx) => {
|
||||
types[header] = deduceType(columnValues[idx]);
|
||||
/* Delete table if it exists in the DB */
|
||||
await client.query(format('DROP TABLE IF EXISTS %I', tableName));
|
||||
|
||||
/* Create table */
|
||||
const createTableSQL = format(
|
||||
'CREATE TABLE %I (%s)',
|
||||
tableName,
|
||||
headers.map(header => format('%I %s', header, types[header])).join(', ')
|
||||
);
|
||||
await client.query(createTableSQL);
|
||||
|
||||
/* Insert data row by row */
|
||||
for (let row = range.s.r + 1; row <= range.e.r; row++) {
|
||||
const values = headers.map((header, col) => {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
const cell = worksheet[cellAddress];
|
||||
return parseValue(cell, types[header]);
|
||||
});
|
||||
|
||||
/* Delete table if it exists in the DB */
|
||||
await client.query(format('DROP TABLE IF EXISTS %I', tableName));
|
||||
|
||||
/* Create table */
|
||||
const createTableSQL = format(
|
||||
'CREATE TABLE %I (%s)',
|
||||
tableName,
|
||||
headers.map(header => format('%I %s', header, types[header])).join(', ')
|
||||
const insertSQL = format(
|
||||
'INSERT INTO %I (%s) VALUES (%s)',
|
||||
tableName,
|
||||
headers.map(h => format('%I', h)).join(', '),
|
||||
values.map(() => '%L').join(', ')
|
||||
);
|
||||
await client.query(createTableSQL);
|
||||
|
||||
/* Insert data row by row */
|
||||
for (let row = range.s.r + 1; row <= range.e.r; row++) {
|
||||
const values = headers.map((header, col) => {
|
||||
const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
const cell = worksheet[cellAddress];
|
||||
return parseValue(cell, types[header]);
|
||||
});
|
||||
|
||||
const insertSQL = format(
|
||||
'INSERT INTO %I (%s) VALUES (%s)',
|
||||
tableName,
|
||||
headers.map(h => format('%I', h)).join(', '),
|
||||
values.map(() => '%L').join(', ')
|
||||
);
|
||||
await client.query(format(insertSQL, ...values));
|
||||
}
|
||||
await client.query(format(insertSQL, ...values));
|
||||
}
|
||||
}
|
||||
|
||||
function deduceType(cells) {
|
||||
if (!cells || cells.length === 0) return 'text';
|
||||
if (!cells || cells.length === 0) return 'text';
|
||||
|
||||
const nonEmptyCells = cells.filter(cell => cell && cell.v != null);
|
||||
if (nonEmptyCells.length === 0) return 'text';
|
||||
const nonEmptyCells = cells.filter(cell => cell && cell.v != null);
|
||||
if (nonEmptyCells.length === 0) return 'text';
|
||||
|
||||
// Check for dates by looking at both cell type and formatted value
|
||||
const isDateCell = cell => cell?.t === 'd' || (cell?.t === 'n' && cell.w && /\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{4}|\d{2}-[A-Za-z]{3}-\d{4}|[A-Za-z]{3}-\d{2}|\d{1,2}-[A-Za-z]{3}/.test(cell.w));
|
||||
// Check for dates by looking at both cell type and formatted value
|
||||
const isDateCell = cell => cell?.t === 'd' || (cell?.t === 'n' && cell.w && /\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{4}|\d{2}-[A-Za-z]{3}-\d{4}|[A-Za-z]{3}-\d{2}|\d{1,2}-[A-Za-z]{3}/.test(cell.w));
|
||||
|
||||
if (nonEmptyCells.some(isDateCell)) { return 'date'; }
|
||||
if (nonEmptyCells.some(isDateCell)) { return 'date'; }
|
||||
|
||||
const allBooleans = nonEmptyCells.every(cell => cell.t === 'b');
|
||||
if (allBooleans) { return 'boolean'; }
|
||||
const allBooleans = nonEmptyCells.every(cell => cell.t === 'b');
|
||||
if (allBooleans) { return 'boolean'; }
|
||||
|
||||
const allNumbers = nonEmptyCells.every(cell => cell.t === 'n' || (cell.t === 's' && !isNaN(cell.v.replace(/[,$\s%()]/g, ''))));
|
||||
const allNumbers = nonEmptyCells.every(cell => cell.t === 'n' || (cell.t === 's' && !isNaN(cell.v.replace(/[,$\s%()]/g, ''))));
|
||||
|
||||
if (allNumbers) {
|
||||
const numbers = nonEmptyCells.map(cell => {
|
||||
if (cell.t === 'n') return cell.v;
|
||||
return parseFloat(cell.v.replace(/[,$\s%()]/g, ''));
|
||||
});
|
||||
if (allNumbers) {
|
||||
const numbers = nonEmptyCells.map(cell => {
|
||||
if (cell.t === 'n') return cell.v;
|
||||
return parseFloat(cell.v.replace(/[,$\s%()]/g, ''));
|
||||
});
|
||||
|
||||
const needsPrecision = numbers.some(num => {
|
||||
const str = num.toString();
|
||||
return str.includes('e') ||
|
||||
(str.includes('.') && str.split('.')[1].length > 6) ||
|
||||
Math.abs(num) > 1e15;
|
||||
});
|
||||
const needsPrecision = numbers.some(num => {
|
||||
const str = num.toString();
|
||||
return str.includes('e')
|
||||
|| (str.includes('.') && str.split('.')[1].length > 6)
|
||||
|| Math.abs(num) > 1e15;
|
||||
});
|
||||
|
||||
return needsPrecision ? 'numeric' : 'double precision';
|
||||
}
|
||||
return 'text';
|
||||
return needsPrecision ? 'numeric' : 'double precision';
|
||||
}
|
||||
return 'text';
|
||||
}
|
||||
|
||||
function parseValue(cell, type) {
|
||||
if (!cell || cell.v == null) return null;
|
||||
if (!cell || cell.v == null) return null;
|
||||
|
||||
switch (type) {
|
||||
case 'date':
|
||||
if (cell.t === 'd') { return cell.v.toISOString().split('T')[0]; }
|
||||
if (cell.t === 'n') {
|
||||
const date = new Date((cell.v - 25569) * 86400 * 1000);
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
return null;
|
||||
switch (type) {
|
||||
case 'date':
|
||||
if (cell.t === 'd') { return cell.v.toISOString().split('T')[0]; }
|
||||
if (cell.t === 'n') {
|
||||
const date = new Date((cell.v - 25569) * 86400 * 1000);
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
return null;
|
||||
|
||||
case 'numeric':
|
||||
case 'double precision':
|
||||
if (cell.t === 'n') return cell.v;
|
||||
if (cell.t === 's') {
|
||||
const cleaned = cell.v.replace(/[,$\s%()]/g, '');
|
||||
if (!isNaN(cleaned)) return parseFloat(cleaned);
|
||||
}
|
||||
return null;
|
||||
case 'numeric':
|
||||
case 'double precision':
|
||||
if (cell.t === 'n') return cell.v;
|
||||
if (cell.t === 's') {
|
||||
const cleaned = cell.v.replace(/[,$\s%()]/g, '');
|
||||
if (!isNaN(cleaned)) return parseFloat(cleaned);
|
||||
}
|
||||
return null;
|
||||
|
||||
case 'boolean':
|
||||
return cell.t === 'b' ? cell.v : null;
|
||||
case 'boolean':
|
||||
return cell.t === 'b' ? cell.v : null;
|
||||
|
||||
default:
|
||||
return String(cell.v);
|
||||
}
|
||||
default:
|
||||
return String(cell.v);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -271,7 +274,7 @@ function parseValue(cell, type) {
|
||||
|
||||
## Complete Example
|
||||
|
||||
0) Install and start the PostgreSQL server.
|
||||
0) Install and start the PostgreSQL serve r.
|
||||
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Sheets with MongoDB
|
||||
sidebar_label: MongoDB / FerretDB
|
||||
title: Sheets with FerretDB and MongoDB
|
||||
sidebar_label: FerretDB / MongoDB
|
||||
pagination_prev: demos/cli/index
|
||||
pagination_next: demos/local/index
|
||||
sidebar_custom_props:
|
||||
@ -11,7 +11,8 @@ import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[MongoDB](https://mongodb.github.io/node-mongodb-native/) is a document-oriented
|
||||
database engine.
|
||||
database engine. [FerretDB](https://www.ferretdb.com/) is a truly open source
|
||||
implementation of the MongoDB wire protocol
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
@ -24,11 +25,11 @@ to add data from spreadsheets into a collection.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Server | Connector Library | Date |
|
||||
|:--------------------|:--------------------|:-----------|
|
||||
| FerretDB `1.21.0` | `mongodb` (`5.9.2`) | 2024-03-30 |
|
||||
| MongoDB CE `6.0.15` | `mongodb` (`6.5.0`) | 2024-05-01 |
|
||||
| MongoDB CE `7.0.8` | `mongodb` (`6.5.0`) | 2024-05-01 |
|
||||
| Server | Connector Library | Date |
|
||||
|:--------------------|:---------------------|:-----------|
|
||||
| FerretDB `1.24.0` | `mongodb` (`6.12.0`) | 2025-01-03 |
|
||||
| MongoDB CE `6.0.15` | `mongodb` (`6.5.0`) | 2024-05-01 |
|
||||
| MongoDB CE `7.0.8` | `mongodb` (`6.5.0`) | 2024-05-01 |
|
||||
|
||||
:::
|
||||
|
||||
@ -123,13 +124,69 @@ If Homebrew is configured to use `/opt/homebrew`, the command is:
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>FerretDB Setup</b> (click to show)</summary>
|
||||
|
||||
The official documentation recommends Docker, but it is strongly recommended to
|
||||
use [`colima`](https://github.com/abiosoft/colima) on MacOS:
|
||||
|
||||
```bash
|
||||
brew install colima docker docker-compose
|
||||
```
|
||||
|
||||
To properly install `docker-compose`, the `colima` process must be run once:
|
||||
|
||||
```bash
|
||||
/opt/homebrew/opt/colima/bin/colima start -f
|
||||
```
|
||||
|
||||
After stopping the process, delete any containers:
|
||||
|
||||
```bash
|
||||
/opt/homebrew/opt/colima/bin/colima delete
|
||||
```
|
||||
|
||||
`config.json` must be edited:
|
||||
|
||||
- Homebrew docker plugins folder must be added to `cliPluginsExtraDirs`.
|
||||
- All `credsStore` settings must be removed.
|
||||
|
||||
When the demo was last tested, the following `config.json` was used:
|
||||
|
||||
```json title="~/.docker/config.json"
|
||||
{
|
||||
"auths": {},
|
||||
"currentContext": "colima",
|
||||
/* highlight-start */
|
||||
"cliPluginsExtraDirs": [
|
||||
"/opt/homebrew/lib/docker/cli-plugins"
|
||||
]
|
||||
/* highlight-end */
|
||||
}
|
||||
```
|
||||
|
||||
After making the changes, start `colima` again and keep the window open:
|
||||
|
||||
```bash
|
||||
/opt/homebrew/opt/colima/bin/colima start -f
|
||||
```
|
||||
|
||||
Start the FerretDB server in a new terminal window:
|
||||
|
||||
```bash
|
||||
cd /tmp
|
||||
docker run -d --rm --name ferretdb -p 27017:27017 -e FERRETDB_HANDLER=sqlite ghcr.io/ferretdb/all-in-one
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
2) Create base project and install the dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
mkdir sheetjs-mongo
|
||||
cd sheetjs-mongo
|
||||
npm init -y
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz mongodb@6.5.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz mongodb@6.12.0`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Save the following to `SheetJSMongoCRUD.mjs` (the key step is highlighted):
|
||||
|
@ -20,8 +20,8 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 122 | 2024-03-25 |
|
||||
| Safari 17.3 | 2024-03-12 |
|
||||
| Chrome 131 | 2024-12-23 |
|
||||
| Safari 18.2 | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
@ -48,8 +48,8 @@ strings using `JSON.stringify` and store using the row index as a key:
|
||||
|
||||
#### Importing Data
|
||||
|
||||
Starting from a worksheet, `XLSX.utils.sheet_to_json` generates an array of row
|
||||
objects. `localStorage.setItem` will store data in Local Storage:
|
||||
Starting from a worksheet, the SheetJS `sheet_to_json` method[^1] generates an
|
||||
array of row objects. `localStorage.setItem` will store data in Local Storage:
|
||||
|
||||
```js
|
||||
function sheet_to_localStorage(worksheet) {
|
||||
@ -65,9 +65,35 @@ function sheet_to_localStorage(worksheet) {
|
||||
`localStorage.length` returns the total number of entries. A simple `for` loop
|
||||
can cover the keys (integers from `0` to `localStorage.length - 1` inclusive)
|
||||
|
||||
`localStorage.getItem` will load the stringified data from the Local Storage. A
|
||||
new array of objects can be constructed by using `JSON.parse` and pushing to an
|
||||
array. `XLSX.utils.json_to_sheet` can create a new worksheet from that array:
|
||||
`localStorage.getItem` will load the stringified data from the Local Storage.
|
||||
|
||||
The following function collects data from `localStorage` to an array of strings:
|
||||
|
||||
```js
|
||||
function localStorage_to_array_of_strings() {
|
||||
const strings = [];
|
||||
for(let i = 0; i < localStorage.length; ++i) {
|
||||
aoo.push(localStorage.getItem(i));
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
```
|
||||
|
||||
Since each entry is a string created using `JSON.stringify`, an object can be
|
||||
constructed using `JSON.parse`:
|
||||
|
||||
```js
|
||||
function localStorage_to_array_of_objects() {
|
||||
const objects = [];
|
||||
for(let i = 0; i < localStorage.length; ++i) {
|
||||
aoo.push(JSON.parse(localStorage.getItem(i)));
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
```
|
||||
|
||||
The SheetJS `json_to_sheet`[^2] method will create a new worksheet from the
|
||||
array of objects:
|
||||
|
||||
```js
|
||||
function localStorage_to_sheet() {
|
||||
@ -173,7 +199,8 @@ objects approach has an ordering. That does not apply to the general case.
|
||||
:::
|
||||
|
||||
In modern browsers, `Object.entries` will generate an array of key/value pairs.
|
||||
`XLSX.utils.aoa_to_sheet` will interpret that array as a worksheet with 2 cols:
|
||||
The SheetJS `aoa_to_sheet`[^3] method will interpret that array as a worksheet
|
||||
with 2 columns (key and value):
|
||||
|
||||
```js
|
||||
function localStorage_to_ws() {
|
||||
@ -185,8 +212,8 @@ function localStorage_to_ws() {
|
||||
#### Importing Storage
|
||||
|
||||
In the other direction, the worksheet is assumed to store keys in column A and
|
||||
values in column B. `XLSX.utils.sheet_to_json` with the `header: 1` option
|
||||
will generate key/value pairs that can be assigned to a storage:
|
||||
values in column B. The SheetJS `sheet_to_json`[^1] method, with the option
|
||||
`header: 1`, will generate key/value pairs that can be assigned to a storage:
|
||||
|
||||
```js
|
||||
function ws_to_localStorage(ws) {
|
||||
@ -239,4 +266,8 @@ function SheetJSRandomStorage() {
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
</details>
|
||||
|
||||
[^1]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^3]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
|
||||
|
@ -8,7 +8,7 @@ sidebar_custom_props:
|
||||
|
||||
<head>
|
||||
<script type="text/javascript" src="https://unpkg.com/localforage@1.10.0/dist/localforage.min.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/dexie@3.2.4/dist/dexie.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/dexie@4.0.10/dist/dexie.js"></script>
|
||||
</head>
|
||||
|
||||
:::danger pass
|
||||
@ -43,8 +43,8 @@ This demo was last tested in the following environments:
|
||||
|
||||
| Browser | Date | `localForage` |
|
||||
|:------------|:-----------|:--------------|
|
||||
| Chrome 122 | 2024-03-21 | 1.10.0 |
|
||||
| Safari 17.4 | 2024-03-23 | 1.10.0 |
|
||||
| Chrome 131 | 2024-12-31 | `1.10.0` |
|
||||
| Safari 18.2 | 2024-12-31 | `1.10.0` |
|
||||
|
||||
:::
|
||||
|
||||
@ -113,9 +113,10 @@ function SheetJSLocalForage() {
|
||||
|
||||
This demo was last tested in the following environments:
|
||||
|
||||
| Browser | Date | DexieJS |
|
||||
|:------------|:-----------|:--------|
|
||||
| Chrome 122 | 2024-03-21 | 3.2.4 |
|
||||
| Browser | Date | DexieJS |
|
||||
|:------------|:-----------|:---------|
|
||||
| Chrome 131 | 2024-12-31 | `4.0.10` |
|
||||
| Safari 18.2 | 2024-12-31 | `4.0.10` |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -29,7 +29,11 @@ may require some adjustments. The official documentation should be consulted.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 October 06 using Lightning API version `61.0`.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Lightning API | Date |
|
||||
|:--------------|:-----------|
|
||||
| `61.0` | 2024-10-06 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -10,11 +10,12 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
:::note pass
|
||||
:::info pass
|
||||
|
||||
This demo focuses on external data processing. For Google Apps Script custom
|
||||
functions, [the "Google Sheets" extension demo](/docs/demos/extensions/gsheet)
|
||||
covers Apps Script integration.
|
||||
This demo focuses on external data processing.
|
||||
|
||||
[The "Google Sheets" extension demo](/docs/demos/extensions/gsheet) covers Apps
|
||||
Script integration and user-defined functions.
|
||||
|
||||
:::
|
||||
|
||||
|
@ -45,10 +45,10 @@ This demo was verified in the following deployments:
|
||||
|
||||
| App | Platform | Date |
|
||||
|:----------|:-------------|:-----------|
|
||||
| Photoshop | ExtendScript | 2024-03-12 |
|
||||
| InDesign | ExtendScript | 2024-08-12 |
|
||||
| InDesign | CEP | 2024-03-12 |
|
||||
| InDesign | UXP | 2024-03-11 |
|
||||
| Photoshop | ExtendScript | 2025-01-03 |
|
||||
| InDesign | ExtendScript | 2025-01-03 |
|
||||
| InDesign | CEP | 2025-01-03 |
|
||||
| InDesign | UXP | 2025-01-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -112,15 +112,20 @@ author (`activeDocument.info.author`) will be changed accordingly.
|
||||
<li><a href={`https://docs.sheetjs.com/extendscript/parse.jsx`}><code>parse.jsx</code></a></li>
|
||||
</ul>
|
||||
|
||||
2) Restart Photoshop and open a file (or create a new one)
|
||||
2) Restart Photoshop.
|
||||
|
||||
3) File > Scripts > parse and select the test workbook
|
||||
3) Create a new file using the default settings.
|
||||
|
||||
4) An alert will confirm that the file was read and the author will be changed:
|
||||
4) In the menu bar, select File > Scripts > parse and select the test workbook
|
||||
|
||||
!["Changing Author" popup](pathname:///files/psparse.png)
|
||||
An alert will confirm that the file was read and the author will be changed:
|
||||
|
||||
5) Check the Author field of the document in File > File Info...
|
||||
!["Changing Author" popup](pathname:///extendscript/psparse.png)
|
||||
|
||||
5) In the menu bar, select File > File Info… and select "Basic" in the popup.
|
||||
The text box next to "Author:" will show `Sh33tJ5`.
|
||||
|
||||
!["Author" property in Photoshop](pathname:///extendscript/psauthor.png)
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="indesign" label="InDesign">
|
||||
@ -133,17 +138,17 @@ the Layers window is "Title") will be set to the name of the first worksheet.
|
||||
|
||||
- The data from the first sheet will be added to the "Table Frame" TextFrame.
|
||||
|
||||
0) Download the [test workbook](https://docs.sheetjs.com/pres.xlsx) and
|
||||
[InDesign template](pathname:///extendscript/Template.idml)
|
||||
0) Download the [`pres.xlsx` test workbook](https://docs.sheetjs.com/pres.xlsx)
|
||||
and [`Template.idml` InDesign template](pathname:///extendscript/Template.idml)
|
||||
|
||||
1) Download the following scripts and move to the scripts directory[^4]:
|
||||
1) Download the following scripts and move to the scripts directory[^3]:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.extendscript.js`}><code>xlsx.extendscript.js</code></a></li>
|
||||
<li><a href={`https://docs.sheetjs.com/extendscript/esidparse.jsx`}><code>esidparse.jsx</code></a></li>
|
||||
</ul>
|
||||
|
||||
2) Open the template
|
||||
2) Open `Template.idml` in InDesign.
|
||||
|
||||
3) Activate the Scripts panel. Expand the "User" folder and double-click
|
||||
`esidparse` in the list.
|
||||
@ -187,25 +192,31 @@ selected, the library will create a new workbook with one worksheet. Cell `A1`
|
||||
will be "Author" and cell `B1` will be the active Photoshop document Author.
|
||||
The PS author is available as `activeDocument.info.author`.
|
||||
|
||||
1) Download the following scripts and move to the scripts directory[^6]:
|
||||
1) Download the following scripts and move to the scripts directory[^3]:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.extendscript.js`}><code>xlsx.extendscript.js</code></a></li>
|
||||
<li><a href={`https://docs.sheetjs.com/extendscript/write.jsx`}><code>write.jsx</code></a></li>
|
||||
</ul>
|
||||
|
||||
2) Restart Photoshop and open a file (or create a new one)
|
||||
2) Restart Photoshop.
|
||||
|
||||
3) File > File Info ... and confirm there is an Author. If not, set to `SheetJS`
|
||||
3) Create a new file using the default settings.
|
||||
|
||||
4) File > Scripts > write and use the popup to select the Documents folder.
|
||||
Enter `SheetJSPSTest.xlsx` and press "Save"
|
||||
4) In the menu bar, select File > File Info… and add an Author if it is blank.
|
||||
|
||||
5) An alert will confirm that the file was created:
|
||||
5) In the menu bar, select File > Scripts > write.
|
||||
|
||||
!["Created File" popup](pathname:///files/pswrite.png)
|
||||
Select the Documents folder, enter the file name `SheetJSPSTest.xlsx` and
|
||||
press "Save".
|
||||
|
||||
6) Open the generated `SheetJSPSTest.xlsx` file and compare to Photoshop author
|
||||
6) Click "OK" in the "Created File" alert:
|
||||
|
||||
!["Created File" popup](pathname:///extendscript/pswrite.png)
|
||||
|
||||
7) Open the generated `SheetJSPSTest.xlsx` file.
|
||||
|
||||
Cell `A1` will be "Author" and cell `B1` will match the Photoshop file author.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="indesign" label="InDesign">
|
||||
@ -214,16 +225,16 @@ In this example, the script will show a dialog to select an output file. Once
|
||||
selected, the library will scan all text frames for table objects. Each table
|
||||
object will be scanned and a new worksheet will be created.
|
||||
|
||||
0) Download the [InDesign document](pathname:///extendscript/Filled.idml)
|
||||
0) Download the [`Filled.idml` document](pathname:///extendscript/Filled.idml)
|
||||
|
||||
1) Download the following scripts and move to the scripts directory[^7]:
|
||||
1) Download the following scripts and move to the scripts directory[^3]:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.extendscript.js`}><code>xlsx.extendscript.js</code></a></li>
|
||||
<li><a href={`https://docs.sheetjs.com/extendscript/esidwrite.jsx`}><code>esidwrite.jsx</code></a></li>
|
||||
</ul>
|
||||
|
||||
2) Open the document.
|
||||
2) Open `Filled.idml` in InDesign.
|
||||
|
||||
3) Activate the Scripts panel. Expand the "User" folder and double-click
|
||||
`esidwrite` in the list. Use the popup to select the Documents folder. Enter
|
||||
@ -253,6 +264,8 @@ manifest must include the following flags to enable `cep.fs`:
|
||||
</CEFCommandLine>
|
||||
```
|
||||
|
||||
#### Unsigned Extensions
|
||||
|
||||
:::caution pass
|
||||
|
||||
With newer versions of Creative Cloud apps, a special player debug mode must be
|
||||
@ -318,9 +331,16 @@ If prompted, give administrator privileges.
|
||||
|
||||
4) Show the extension (in the menu bar, select Window > Extensions > SheetJS)
|
||||
|
||||
:::caution pass
|
||||
|
||||
If the extension panel is blank, unsigned extensions must be enabled. See the
|
||||
["Unsigned Extensions" note](#unsigned-extensions) for more details.
|
||||
|
||||
:::
|
||||
|
||||
5) In the extension panel, click "Import from file" and select `pres.xlsx`
|
||||
|
||||
After "success" popup, the first worksheet should be written to the file.
|
||||
After "success" popup, the first worksheet should be written to the document.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@ -358,7 +378,7 @@ cep.fs.writeFile(fn.data, b64, cep.encoding.Base64);
|
||||
0) Download [`com.sheetjs.data.zip`](pathname:///extendscript/com.sheetjs.data.zip)
|
||||
and extract to a `com.sheetjs.data` subdirectory.
|
||||
|
||||
1) Move the entire `com.sheetjs.data` folder to the CEP extensions folder[^13]:
|
||||
1) Move the entire `com.sheetjs.data` folder to the CEP extensions folder[^10]:
|
||||
|
||||
If prompted, give administrator privileges.
|
||||
|
||||
@ -366,9 +386,17 @@ If prompted, give administrator privileges.
|
||||
|
||||
3) Show the extension (in the menu bar, select Window > Extensions > SheetJS)
|
||||
|
||||
:::caution pass
|
||||
|
||||
If the extension panel is blank, unsigned extensions must be enabled. See the
|
||||
["Unsigned Extensions" note](#unsigned-extensions) for more details.
|
||||
|
||||
:::
|
||||
|
||||
4) In the extension panel, click "Export to XLSX" and "Save" in the dialog.
|
||||
|
||||
5) A popup will display the path to the generated file. Open the new file.
|
||||
5) A popup will display the path to the generated file (`SheetJSIDCEP.xlsx` in
|
||||
the Documents folder). Open the new file.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@ -398,7 +426,7 @@ const storage = UXP.storage, ufs = storage.localFileSystem;
|
||||
|
||||
The `getFileForOpening` method resolves to a `File` object. Reading the file
|
||||
with the `binary` format returns an `ArrayBuffer` object that can be parsed
|
||||
with the SheetJS `read` method[^14]:
|
||||
with the SheetJS `read` method[^8]:
|
||||
|
||||
```js
|
||||
/* show file picker (single file, no folders) */
|
||||
@ -415,7 +443,7 @@ const wb = XLSX.read(ab);
|
||||
<Tabs groupId="ccapp">
|
||||
<TabItem value="indesign" label="InDesign">
|
||||
|
||||
0) Open the "Scripts Panel" folder[^15].
|
||||
0) Open the "Scripts Panel" folder[^3].
|
||||
|
||||
1) Download the following scripts:
|
||||
|
||||
@ -450,7 +478,7 @@ If the InDesign version does not support UXP, a tooltip shows a message:
|
||||
|
||||
### Writing Files
|
||||
|
||||
The SheetJS `write` method[^16], with the option `type: "buffer"`[^17], returns
|
||||
The SheetJS `write` method[^11], with the option `type: "buffer"`[^12], returns
|
||||
file data stored in a `Uint8Array`.
|
||||
|
||||
The `getFileForSaving` method resolves to a `File` object. The `write` method
|
||||
@ -474,7 +502,7 @@ await file.write(buf, { data: storage.formats.binary });
|
||||
<Tabs groupId="ccapp">
|
||||
<TabItem value="indesign" label="InDesign">
|
||||
|
||||
0) Open the "Scripts Panel" folder[^18].
|
||||
0) Open the "Scripts Panel" folder[^3].
|
||||
|
||||
1) Download the following scripts:
|
||||
|
||||
@ -501,7 +529,9 @@ Move them to the Scripts Panel folder.
|
||||
### Scripts Panel
|
||||
|
||||
The scripts panel folder is used for ExtendScript and UXP scripts. The location
|
||||
can be revealed from the relevant applications. For InDesign:
|
||||
can be revealed from the relevant applications.
|
||||
|
||||
**InDesign**
|
||||
|
||||
1) Activate Scripts panel (Windows > Utilities > Scripts)
|
||||
|
||||
@ -518,6 +548,13 @@ Some versions of InDesign will open the parent "Scripts" folder. If there is a
|
||||
|
||||
:::
|
||||
|
||||
**Photoshop**
|
||||
|
||||
The scripts folder is located in `\Presets\Scripts` within the app folder.
|
||||
|
||||
For example, on Windows, the Photoshop 2025 scripts folder is typically
|
||||
`c:\Program Files\Adobe\Adobe Photoshop 2025\Presets\Scripts`
|
||||
|
||||
### CEP Extensions
|
||||
|
||||
CEP extension scripts are typically stored in a system-wide folder:
|
||||
@ -532,18 +569,9 @@ Administrator privileges are usually required for writing to the folder.
|
||||
[^1]: Historically, Adobe applications were separate entities. Eventually they were bundled in a package called "Creative Suite". It was rebranded to "Creative Cloud" later. As ExtendScript was introduced during the Creative Suite era, this page will use the phrase "Creative Suite".
|
||||
[^2]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See ["Scripts Panel"](#scripts-panel)
|
||||
[^4]: See ["Scripts Panel"](#scripts-panel)
|
||||
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See ["Scripts Panel"](#scripts-panel)
|
||||
[^7]: See ["Scripts Panel"](#scripts-panel)
|
||||
[^8]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^9]: See [the "base64" type in "Reading Files"](/docs/api/parse-options#input-type)
|
||||
[^10]: See ["CEP Extensions"](#cep-extensions)
|
||||
[^11]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^12]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats)
|
||||
[^13]: See ["CEP Extensions"](#cep-extensions)
|
||||
[^14]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^15]: See ["Scripts Panel"](#scripts-panel)
|
||||
[^16]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^17]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats)
|
||||
[^18]: See ["Scripts Panel"](#scripts-panel)
|
@ -21,7 +21,11 @@ tables with a content script and a background script.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 March 30 against Chrome 122.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 131 | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
@ -383,6 +387,14 @@ chrome.bookmarks.getTree(function(res) {
|
||||
|
||||
### Table Exporter
|
||||
|
||||
:::caution pass
|
||||
|
||||
**Due to security restrictions, V2 table export does not work in Chrome 131!**
|
||||
|
||||
The Manifest V3 table exporter does work in Chrome 131.
|
||||
|
||||
:::
|
||||
|
||||
<details open>
|
||||
<summary><b>Testing</b> (click to hide)</summary>
|
||||
|
||||
|
@ -35,7 +35,12 @@ data into the worksheet.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 August 11 against Excel 365 (version 2407).
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| OS and Version | Architecture | Excel | Date |
|
||||
|:---------------|:-------------|:-----------|:-----------|
|
||||
| macOS 14.5 | `darwin-arm` | 16.81 | 2024-12-22 |
|
||||
| Windows 11 | `win11-x64` | 365 (2407) | 2024-08-11 |
|
||||
|
||||
:::
|
||||
|
||||
@ -125,7 +130,7 @@ export async function extern(url) {
|
||||
|
||||
## Complete Demo
|
||||
|
||||
0) Clear the functions cache. For the tested version of Excel:
|
||||
0) Clear the functions cache. For the tested version of Excel for Windows:
|
||||
|
||||
- Open File Explorer
|
||||
- Select the address bar and enter `%LOCALAPPDATA%\Microsoft\Office\16.0\Wef`
|
||||
@ -143,7 +148,7 @@ after testing is finished.
|
||||
|
||||
1) Install [NodeJS LTS](https://nodejs.org/en/download/).
|
||||
|
||||
2) After installing NodeJS, launch a new PowerShell window.
|
||||
2) Launch a new PowerShell (Windows) or Terminal (MacOS) window.
|
||||
|
||||
3) Disable telemetry:
|
||||
|
||||
@ -220,9 +225,10 @@ element with name `bt:String`. Change the `DefaultValue` attribute to `SHEETJS`:
|
||||
|
||||
8) Close the Excel window and the terminal window. Do not save the XLSX file.
|
||||
|
||||
9) In the PowerShell window, start the development process again:
|
||||
9) In the terminal window, start the development process again:
|
||||
|
||||
```bash
|
||||
npm run stop
|
||||
npm start
|
||||
```
|
||||
|
||||
@ -251,9 +257,10 @@ export function version() {
|
||||
|
||||
12) Close the terminal window and the Excel window. Do not save the Excel file.
|
||||
|
||||
13) In the PowerShell window, start the development process again:
|
||||
13) In a new terminal window, start the development process again:
|
||||
|
||||
```bash
|
||||
npm run stop
|
||||
npm start
|
||||
```
|
||||
|
||||
@ -264,6 +271,33 @@ npm start
|
||||
|
||||
This indicates that the SheetJS library has been loaded.
|
||||
|
||||
:::info pass
|
||||
|
||||
In some MacOS tests, the add-in installed `CONTOSO.VERSION`. To force a refresh
|
||||
of the manifest:
|
||||
|
||||
1) Stop the development process:
|
||||
|
||||
```bash
|
||||
npm run stop
|
||||
```
|
||||
|
||||
2) Close the Excel app by right-clicking Excel in the Dock and selecting "Quit".
|
||||
|
||||
3) Restart the development process:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
4) Activate the Task Pane for the addin (click "Show Task Pane" in the ribbon).
|
||||
|
||||
5) Hover near the top-right corner of the addin and click the `i` icon.
|
||||
|
||||
6) Click "Clear Web Cache" and wait a few moments.
|
||||
|
||||
:::
|
||||
|
||||
### Fetching Files from the Internet
|
||||
|
||||
15) Add the following code snippet to `src\functions\functions.js` and save:
|
||||
@ -296,9 +330,10 @@ export async function extern(url) {
|
||||
|
||||
16) Close the terminal window and the Excel window (do not save the Excel file).
|
||||
|
||||
17) In the PowerShell window, start the development process again:
|
||||
17) In a new terminal window, start the development process again:
|
||||
|
||||
```bash
|
||||
npm run stop
|
||||
npm start
|
||||
```
|
||||
|
||||
|
@ -10,17 +10,20 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
:::note pass
|
||||
:::info pass
|
||||
|
||||
This demo focuses on Google Apps Script custom functions. For external data
|
||||
processing, [the "Google Sheets" cloud data demo](/docs/demos/cloud/gsheet)
|
||||
covers the API for NodeJS scripts
|
||||
This demo focuses on Google Apps Script custom functions.
|
||||
|
||||
[The "Google Sheets" cloud data demo](/docs/demos/cloud/gsheet) covers NodeJS
|
||||
APIs for external data processing.
|
||||
|
||||
:::
|
||||
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
can be uploaded into an Apps Script project. Once uploaded, the `XLSX` variable
|
||||
is available to other scripts in the project.
|
||||
[Google Sheets](https://google.com/sheets/about/) is a collaborative spreadsheet
|
||||
service with powerful JavaScript automation and user-defined functions.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
Google Sheets currently does not provide support for working with Apple Numbers
|
||||
files and some legacy file formats. SheetJS fills the gap.
|
||||
@ -32,12 +35,20 @@ remote file, parses the contents, and writes data to the sheet:
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024 March 11.
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Clasp | Date |
|
||||
|:--------|:-----------|
|
||||
| `2.4.2` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
can be uploaded into an Apps Script project. Once uploaded, the `XLSX` variable
|
||||
is available to other scripts in the project.
|
||||
|
||||
### Adding the script
|
||||
|
||||
The `clasp` command line tool can be used to upload the standalone script:
|
||||
@ -66,24 +77,55 @@ const response = UrlFetchApp.fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const content = response.getContent();
|
||||
```
|
||||
|
||||
The `"array"` type for `XLSX.read` expects an array of *unsigned* bytes.
|
||||
Fortunately, the content can be corrected with bitwise operations:
|
||||
The SheetJS `read` method[^1] can read arrays of *unsigned* bytes. Fortunately,
|
||||
the values in the array can be corrected with bitwise operations:
|
||||
|
||||
```js
|
||||
for(var i = 0; i < content.length; ++i) content[i] &= 0xFF;
|
||||
```
|
||||
|
||||
After converting each signed byte to unsigned byte, the array can be parsed with
|
||||
the `read` method:
|
||||
|
||||
```js
|
||||
const wb = XLSX.read(content, { type: "array" });
|
||||
```
|
||||
|
||||
### Returning data
|
||||
|
||||
`XLSX.utils.sheet_to_json` with the option `header: 1` returns arrays of arrays
|
||||
that play nice with Google Sheets:
|
||||
The SheetJS `sheet_to_json` method[^2] with the option `header: 1` returns
|
||||
arrays of arrays of data[^3]:
|
||||
|
||||
```js
|
||||
const first_worksheet = wb.Sheets[wb.SheetNames[0]];
|
||||
const aoa = XLSX.utils.sheet_to_json(first_worksheet, {header: 1});
|
||||
```
|
||||
|
||||
Google Sheets will spread arrays of arrays across rows and columns. The `AOA`
|
||||
function below returns an array that contains two arrays. The screenshot shows
|
||||
the result of setting cell `A1` to the formula `=AOA()`:
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Custom Function</th><th>Google Sheets</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
```js
|
||||
function AOA(url) {
|
||||
return [
|
||||
["Sheet", "JS"],
|
||||
[ 72, 62]
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
</td><td>
|
||||
|
||||
![Google Sheets result for AOA function](pathname:///gsheet/aoa-udf.png)
|
||||
|
||||
</td></tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Complete Demo
|
||||
|
||||
This demo creates a function `SHEETJS(url)` that fetches the specified URL,
|
||||
@ -99,14 +141,33 @@ extracts data from the first worksheet, and writes the data
|
||||
npx @google/clasp login
|
||||
```
|
||||
|
||||
A browser window should direct to an account selection page. Select the account
|
||||
from the previous step. In the next page, there will be a title like
|
||||
A browser window should direct to an account selection page.
|
||||
|
||||
> clasp – The Apps Script CLI wants to access your Google Account
|
||||
2) Select the account from step 0.
|
||||
|
||||
At the bottom of the screen, click "Allow".
|
||||
The next page will include the following title:
|
||||
|
||||
The terminal window should now state
|
||||
> Sign in to clasp – The Apps Script CLI
|
||||
|
||||
![clasp sign-in](pathname:///gsheet/clasp-signin.png)
|
||||
|
||||
3) At the bottom of the screen, click "Continue".
|
||||
|
||||
4) In the next screen, check every box that mentions "Google Apps Script". When
|
||||
the demo was last tested, the following were required:
|
||||
|
||||
- Create and update Google Apps Script deployments.
|
||||
- Create and update Google Apps Script projects.
|
||||
|
||||
![clasp permissions](pathname:///gsheet/clasp-perms.png)
|
||||
|
||||
5) Scroll to the bottom of the screen and click "Continue".
|
||||
|
||||
The browser will show the following message:
|
||||
|
||||
> Logged in! You may close this page.
|
||||
|
||||
The terminal window will show the following message:
|
||||
|
||||
```
|
||||
Authorization successful.
|
||||
@ -114,22 +175,26 @@ Authorization successful.
|
||||
|
||||
### Creating a Sheet
|
||||
|
||||
2) Sign into Google Sheets with the same account and create a new blank sheet
|
||||
6) Sign into Google Sheets with the same account.
|
||||
|
||||
3) Open up the apps script window (Extensions > Apps Script)
|
||||
7) Create a new Blank spreadsheet.
|
||||
|
||||
4) Click the gear icon (Project Settings) and copy the Script ID
|
||||
8) Open the apps script window (Extensions > Apps Script)
|
||||
|
||||
![extensions - apps script](pathname:///gsheet/apps-script.png)
|
||||
|
||||
9) Click the gear icon (Project Settings) and copy the Script ID
|
||||
|
||||
### Cloning the Apps Script
|
||||
|
||||
5) In the terminal window, create a new folder for your project:
|
||||
10) In the terminal window, create a new folder for your project:
|
||||
|
||||
```bash
|
||||
mkdir SheetJSGAS
|
||||
cd SheetJSGAS
|
||||
```
|
||||
|
||||
6) Clone the Apps Script project. The official command is:
|
||||
11) Clone the Apps Script project. The official command is:
|
||||
|
||||
```bash
|
||||
npx @google/clasp clone PASTE_YOUR_ID_HERE
|
||||
@ -141,7 +206,7 @@ and paste in the terminal. Press Enter after pasting the ID.
|
||||
|
||||
### Adding the SheetJS Library
|
||||
|
||||
7) Download the SheetJS Standalone script and move to the project directory:
|
||||
12) Download the SheetJS Standalone script and move to the project directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
@ -151,7 +216,7 @@ and paste in the terminal. Press Enter after pasting the ID.
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
8) Push the project to Apps Script:
|
||||
13) Push the project to Apps Script:
|
||||
|
||||
```bash
|
||||
npx @google/clasp push
|
||||
@ -185,13 +250,15 @@ After enabling the API, run `npx @google/clasp push` again.
|
||||
|
||||
:::
|
||||
|
||||
9) Reopen the Google Sheet and Apps Script editor (Extensions > Apps Script).
|
||||
14) Reopen the Google Sheet and Apps Script editor (Extensions > Apps Script).
|
||||
|
||||
In the Files listing, there should be a new entry `xlsx.full.min.gs`
|
||||
|
||||
![xlsx.full.min.gs in Apps Script](pathname:///gsheet/xlsx-full-min-gs.png)
|
||||
|
||||
### Creating a Custom Function
|
||||
|
||||
10) In Apps Script editor, select `Code.gs` and erase the code in the editor.
|
||||
15) In Apps Script editor, select `Code.gs` and erase the code in the editor.
|
||||
Replace with the following function:
|
||||
|
||||
```js title="Code.gs"
|
||||
@ -213,12 +280,16 @@ function SHEETJS(url) {
|
||||
}
|
||||
```
|
||||
|
||||
Click the "Save Project" icon (💾) to save the project.
|
||||
Click the "Save project to Drive" icon (💾) to save the project.
|
||||
|
||||
11) In the Google Sheets window, select cell A1 and enter the formula
|
||||
16) In the Google Sheets window, select cell A1 and enter the formula
|
||||
|
||||
```
|
||||
=SHEETJS("https://docs.sheetjs.com/pres.numbers")
|
||||
```
|
||||
|
||||
The file will be fetched and the contents will be written to the sheet.
|
||||
|
||||
[^1]: See ["Input Type" in "Reading Files"](/docs/api/parse-options#input-type) for more details.
|
||||
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^3]: See ["Array of Arrays" in "Utilities"](/docs/api/utilities/array#array-of-arrays) for more details.
|
@ -34,10 +34,10 @@ flowchart LR
|
||||
|
||||
This demo was tested by SheetJS users in the following deployments:
|
||||
|
||||
| Architecture | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| `darwin-x64` | 2024 | 2024-04-25 |
|
||||
| `win11-x64` | 2024 | 2024-12-19 |
|
||||
| Architecture | Version | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `2024.0` | 2024-04-25 |
|
||||
| `win11-x64` | `2024.0` | 2024-12-19 |
|
||||
|
||||
:::
|
||||
|
||||
@ -145,7 +145,10 @@ cd sheetjs-maple
|
||||
```
|
||||
|
||||
2) Copy the headers and `lib` files from the Maple folder to the project folder.
|
||||
For example, using Maple 2024 on Windows x64:
|
||||
The headers will be placed in the `extern/include/` folder in the Maple folder.
|
||||
The `lib` files are placed in a platform-specific `bin` folder.
|
||||
|
||||
The following commands apply to x64 versions of Windows:
|
||||
|
||||
```powershell
|
||||
copy "C:\Program Files\Maple 2024\extern\include\"*.h .
|
||||
|
@ -193,11 +193,11 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date | Comments |
|
||||
|:------------|:-----------|:----------------------------------------|
|
||||
| Chrome 122 | 2024-04-25 | |
|
||||
| Edge 122 | 2024-03-12 | |
|
||||
| Safari 17.3 | 2024-03-12 | File System Access API is not supported |
|
||||
| Brave 1.59 | 2024-03-12 | File System Access API is not supported |
|
||||
| Firefox 122 | 2024-03-12 | File System Access API is not supported |
|
||||
| Chrome 131 | 2024-12-31 | |
|
||||
| Edge 131 | 2024-12-31 | |
|
||||
| Safari 17.5 | 2024-12-31 | File System Access API is not supported |
|
||||
| Brave 1.63 | 2024-12-31 | File System Access API is not supported |
|
||||
| Firefox 133 | 2024-12-31 | File System Access API is not supported |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -128,11 +128,11 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| `darwin-x64` | `2.7.0` | 2024-04-04 |
|
||||
| `darwin-x64` | `2.7.0` | 2024-12-31 |
|
||||
| `darwin-arm` | `2.7.0` | 2024-05-23 |
|
||||
| `win11-x64` | `2.7.0` | 2024-12-20 |
|
||||
| `win11-arm` | `2.7.0` | 2024-05-25 |
|
||||
| `linux-x64` | `2.7.0` | 2024-03-21 |
|
||||
| `linux-x64` | `2.7.0` | 2024-12-31 |
|
||||
| `linux-arm` | `2.7.0` | 2024-05-23 |
|
||||
|
||||
:::
|
||||
@ -404,9 +404,9 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | PHP | Date |
|
||||
|:-------------|:--------|:---------|:-----------|
|
||||
| `darwin-x64` | `2.7.0` | `8.3.4` | 2024-03-15 |
|
||||
| `darwin-x64` | `2.7.0` | `8.4.2` | 2024-12-31 |
|
||||
| `darwin-arm` | `2.7.0` | `8.3.8` | 2024-06-30 |
|
||||
| `linux-x64` | `2.7.0` | `8.2.7` | 2024-03-21 |
|
||||
| `linux-x64` | `2.7.0` | `8.3.3` | 2024-12-31 |
|
||||
| `linux-arm` | `2.7.0` | `8.2.18` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
@ -419,14 +419,14 @@ This demo was tested in the following deployments:
|
||||
php --ini
|
||||
```
|
||||
|
||||
The following output is from the last macOS test:
|
||||
The following output is from the most recent `darwin-x64` test:
|
||||
|
||||
```text pass
|
||||
Configuration File (php.ini) Path: /usr/local/etc/php/8.3
|
||||
Configuration File (php.ini) Path: /usr/local/etc/php/8.4
|
||||
// highlight-next-line
|
||||
Loaded Configuration File: /usr/local/etc/php/8.3/php.ini
|
||||
Scan for additional .ini files in: /usr/local/etc/php/8.3/conf.d
|
||||
Additional .ini files parsed: /usr/local/etc/php/8.3/conf.d/ext-opcache.ini
|
||||
Loaded Configuration File: /usr/local/etc/php/8.4/php.ini
|
||||
Scan for additional .ini files in: /usr/local/etc/php/8.4/conf.d
|
||||
Additional .ini files parsed: /usr/local/etc/php/8.4/conf.d/ext-opcache.ini
|
||||
```
|
||||
|
||||
2) Edit the `php.ini` configuration file.
|
||||
@ -546,14 +546,14 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | Python | Date |
|
||||
|:-------------|:--------|:---------|:-----------|
|
||||
| `darwin-x64` | `2.7.0` | `3.12.2` | 2024-03-15 |
|
||||
| `darwin-x64` | `2.7.0` | `3.13.1` | 2024-12-31 |
|
||||
| `darwin-arm` | `2.7.0` | `3.12.3` | 2024-06-30 |
|
||||
| `linux-x64` | `2.7.0` | `3.11.3` | 2024-03-21 |
|
||||
| `linux-x64` | `2.7.0` | `3.11.7` | 2024-12-31 |
|
||||
| `linux-arm` | `2.7.0` | `3.11.2` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
|
||||
0) Ensure `python` is installed and available on the system path.
|
||||
0) Ensure `python3` is installed and available on the system path.
|
||||
|
||||
1) Build the Duktape shared library:
|
||||
|
||||
@ -779,11 +779,11 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | Zig | Date |
|
||||
|:-------------|:--------|:---------|:-----------|
|
||||
| `darwin-x64` | `2.7.0` | `0.11.0` | 2024-03-10 |
|
||||
| `darwin-x64` | `2.7.0` | `0.13.0` | 2024-12-31 |
|
||||
| `darwin-arm` | `2.7.0` | `0.12.0` | 2024-05-23 |
|
||||
| `win11-x64` | `2.7.0` | `0.13.0` | 2024-12-20 |
|
||||
| `win11-arm` | `2.7.0` | `0.12.0` | 2024-05-25 |
|
||||
| `linux-x64` | `2.7.0` | `0.12.0` | 2024-04-25 |
|
||||
| `linux-x64` | `2.7.0` | `0.13.0` | 2024-12-31 |
|
||||
| `linux-arm` | `2.7.0` | `0.12.0` | 2024-05-25 |
|
||||
|
||||
On Windows, due to incompatibilities between WSL and PowerShell, some commands
|
||||
@ -1014,15 +1014,26 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| `darwin-x64` | `2.2.0` | 2024-03-15 |
|
||||
| `darwin-x64` | `2.2.0` | 2024-12-31 |
|
||||
| `darwin-arm` | `2.2.0` | 2024-06-30 |
|
||||
| `linux-x64` | `2.2.0` | 2024-03-21 |
|
||||
| `linux-x64` | `2.2.0` | 2024-12-31 |
|
||||
| `linux-arm` | `2.2.0` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
|
||||
0) Ensure `perl` and `cpan` are installed and available on the system path.
|
||||
|
||||
:::caution pass
|
||||
|
||||
On Arch Linux and HoloOS (Steam Deck), `crypt.h` may be missing. The `libxcrypt`
|
||||
package must be explicitly installed:
|
||||
|
||||
```bash
|
||||
sudo pacman -S libxcrypt
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
1) Install the `JavaScript::Duktape::XS` library:
|
||||
|
||||
```bash
|
||||
|
@ -149,7 +149,7 @@ This demo was tested in the following deployments:
|
||||
| `13.3.228` | `darwin-x64` | macOS 15.1.1 | `clang 16.0.0` | 2024-12-03 |
|
||||
| `12.7.130` | `darwin-arm` | macOS 14.5 | `clang 15.0.0` | 2024-05-25 |
|
||||
| `12.7.130` | `win11-x64` | Windows 11 | `CL 19.42.34435` | 2024-12-20 |
|
||||
| `12.5.48` | `linux-x64` | HoloOS 3.5.17 | `gcc 13.1.1` | 2024-03-21 |
|
||||
| `12.7.130` | `linux-x64` | HoloOS 3.6.20 | `gcc 13.2.1` | 2025-01-02 |
|
||||
| `12.7.130` | `linux-arm` | Debian 12 | `gcc 12.2.0` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
@ -965,7 +965,7 @@ This demo was last tested in the following deployments:
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `0.92.0` | 2024-05-28 |
|
||||
| `darwin-arm` | `0.92.0` | 2024-05-25 |
|
||||
| `win11-x64` | `130.0.2` | 2024-03-24 |
|
||||
| `win11-x64` | `130.0.2` | 2024-12-20 |
|
||||
| `linux-x64` | `0.91.0` | 2024-04-25 |
|
||||
| `linux-arm` | `0.92.0` | 2024-05-25 |
|
||||
|
||||
@ -1499,7 +1499,7 @@ This demo was last tested in the following deployments:
|
||||
| `darwin-x64` | `12.6.228.3` | `0.92.0` | 2024-05-28 |
|
||||
| `darwin-arm` | `12.6.228.3` | `0.92.0` | 2024-12-20 |
|
||||
| `win11-x64` | `12.6.228.3` | `0.92.0` | 2024-12-20 |
|
||||
| `linux-x64` | `12.3.219.9` | `0.88.0` | 2024-03-18 |
|
||||
| `linux-x64` | `12.6.228.3` | `0.92.0` | 2025-01-02 |
|
||||
| `linux-arm` | `12.6.228.3` | `0.92.0` | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
@ -109,7 +109,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `ccbae20` | `1.22.3` | 2024-05-23 |
|
||||
| `win11-x64` | `79f3a7e` | `1.23.4` | 2024-12-20 |
|
||||
| `win11-arm` | `ccbae20` | `1.22.3` | 2024-05-25 |
|
||||
| `linux-x64` | `e401ed4` | `1.22.1` | 2024-03-21 |
|
||||
| `linux-x64` | `79f3a7e` | `1.22.0` | 2025-01-02 |
|
||||
| `linux-arm` | `ccbae20` | `1.19.8` | 2024-05-25 |
|
||||
|
||||
At the time of writing, Goja did not have proper version numbers. Versions are
|
||||
|
@ -366,7 +366,7 @@ This demo was tested in the following deployments:
|
||||
|:-------------|:-----------|:-----------|
|
||||
| `darwin-x64` | `d070c74` | 2024-12-17 |
|
||||
| `darwin-arm` | `d070c74` | 2024-05-23 |
|
||||
| `linux-x64` | `d217af8` | 2024-03-21 |
|
||||
| `linux-x64` | `388376f` | 2024-12-17 |
|
||||
| `linux-arm` | `d070c74` | 2024-05-25 |
|
||||
|
||||
The main Hermes source tree does not have Windows support. The `hermes-windows`
|
||||
@ -479,10 +479,17 @@ In some tests, the build failed with a message referencing a missing header:
|
||||
hermes/API/hermes/inspector/chrome/tests/SerialExecutor.cpp:34:16: note: ‘std::runtime_error’ is defined in header ‘<stdexcept>’; did you forget to ‘#include <stdexcept>’?
|
||||
```
|
||||
|
||||
```
|
||||
hermes/lib/SerialExecutor/SerialExecutor.cpp:9:1: note: ‘std::runtime_error’ is defined in header ‘<stdexcept>’; did you forget to ‘#include <stdexcept>’?
|
||||
```
|
||||
|
||||
**This error affects the official Hermes releases!**
|
||||
|
||||
The fix is to manually add a `#include` statement in the corresponding header
|
||||
file (`API/hermes/inspector/chrome/tests/SerialExecutor.h` in the repo):
|
||||
The `#include` statement should be added in the corresponding header file. In
|
||||
previous tests, the following files elicited errors:
|
||||
|
||||
- `hermes/API/hermes/inspector/chrome/tests/SerialExecutor.cpp` errors are fixed
|
||||
by patching `API/hermes/inspector/chrome/tests/SerialExecutor.h` in the repo:
|
||||
|
||||
```c title="hermes/API/hermes/inspector/chrome/tests/SerialExecutor.h (add highlighted line)"
|
||||
#include <memory>
|
||||
@ -495,6 +502,26 @@ file (`API/hermes/inspector/chrome/tests/SerialExecutor.h` in the repo):
|
||||
#include <thread>
|
||||
```
|
||||
|
||||
- `hermes/lib/SerialExecutor/SerialExecutor.cpp` errors are fixed by patching
|
||||
`include/hermes/SerialExecutor/SerialExecutor.h` in the repo:
|
||||
|
||||
```c title="hermes/include/hermes/SerialExecutor/SerialExecutor.h (add highlighted line)"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#if !defined(_WINDOWS) && !defined(__EMSCRIPTEN__)
|
||||
// highlight-next-line
|
||||
#include <stdexcept>
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#include <thread>
|
||||
```
|
||||
|
||||
After making the required patch, the build can be resumed by running `cmake`:
|
||||
|
||||
```bash
|
||||
cmake --build ./build_release`
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
5) Build the application:
|
||||
@ -776,6 +803,7 @@ This demo was tested in the following deployments:
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `0.13.0` | 2024-12-17 |
|
||||
| `win11-x64` | `0.13.0` | 2024-12-20 |
|
||||
| `linux-x64` | `0.13.0` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -91,7 +91,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `2.6.10` | `2.9.1` | 2024-05-25 |
|
||||
| `win11-x64` | `3.3.6` | `2.10.0` | 2024-12-20 |
|
||||
| `win11-arm` | `3.0.2` | `2.9.1` | 2024-05-25 |
|
||||
| `linux-x64` | `3.0.5` | `2.9.1` | 2024-03-21 |
|
||||
| `linux-x64` | `3.0.6` | `2.10.0` | 2024-12-31 |
|
||||
| `linux-arm` | `3.1.2` | `2.9.1` | 2024-05-25 |
|
||||
|
||||
When the demo was last tested, there was no official Ruby release for Windows
|
||||
|
@ -124,7 +124,7 @@ This demo was tested in the following deployments:
|
||||
| `darwin-arm` | `0.18.0` | 2024-05-23 |
|
||||
| `win11-x64` | `0.20.0` | 2024-12-19 |
|
||||
| `win11-arm` | `0.18.0` | 2024-05-25 |
|
||||
| `linux-x64` | `0.18.0` | 2024-03-21 |
|
||||
| `linux-x64` | `0.20.0` | 2024-12-31 |
|
||||
| `linux-arm` | `0.18.0` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
|
@ -40,7 +40,7 @@ This demo was tested in the following environments:
|
||||
| `darwin-arm` | `35465ed` | 2024-05-25 |
|
||||
| `win11-x64` | `d2d30df` | 2024-12-19 |
|
||||
| `win11-arm` | `35465ed` | 2024-05-25 |
|
||||
| `linux-x64` | `cefd391` | 2024-03-21 |
|
||||
| `linux-x64` | `d2d30df` | 2024-12-31 |
|
||||
| `linux-arm` | `35465ed` | 2024-05-25 |
|
||||
|
||||
The Windows tests were run in WSL.
|
||||
|
@ -367,7 +367,7 @@ This,is,a,Test
|
||||
The test suite is regularly run against a number of modern and legacy browsers
|
||||
using [Sauce Labs](https://saucelabs.com/).
|
||||
|
||||
The following chart shows test results on 2024 October 20 for version 0.20.3:
|
||||
The following chart shows test results on 2024-10-20 for version `0.20.3`:
|
||||
|
||||
[![Build Status](pathname:///test/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
|
||||
var n = "xlsx";
|
||||
var X = require('xlsx');
|
||||
try { require('exit-on-epipe'); } catch(e) {}
|
||||
try { require('exit-on-epipe'); } catch (e) {}
|
||||
var fs = require('fs'), program;
|
||||
try { program = require('commander'); } catch(e) {
|
||||
try { program = require('commander'); } catch (e) {
|
||||
[
|
||||
"The `xlsx` command line tool is deprecated in favor of `xlsx-cli`.",
|
||||
"",
|
||||
@ -13,9 +16,10 @@ try { program = require('commander'); } catch(e) {
|
||||
"For older versions of node, explicitly install `xlsx-cli` globally:",
|
||||
" $ npm i -g xlsx-cli",
|
||||
" $ xlsx-cli --help"
|
||||
].forEach(function(m) { console.error(m); });
|
||||
].forEach(function (m) { console.error(m); });
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
program
|
||||
.version(X.version)
|
||||
.usage('[options] <file> [sheetname]')
|
||||
@ -64,6 +68,7 @@ program
|
||||
.option('--date-format <string>', 'output date format, for example yyyy-mm-dd')
|
||||
.option('--codepage <cp>', 'default to specified codepage when ambiguous')
|
||||
.option('--sst', 'generate shared string table for XLS* formats')
|
||||
.option('-d, --no-dim', 'recalculate worksheet range')
|
||||
.option('--compress', 'use compression when writing XLSX/M/B and ODS')
|
||||
.option('--read', 'read but do not generate output')
|
||||
.option('--book', 'for single-sheet formats, emit a file per worksheet')
|
||||
@ -72,10 +77,7 @@ program
|
||||
.option('--sparse', 'sparse mode')
|
||||
.option('-q, --quiet', 'quiet mode');
|
||||
|
||||
program.on('--help', function() {
|
||||
console.log(' Default output format is CSV');
|
||||
console.log(' Support email: dev@sheetjs.com');
|
||||
console.log(' Web Demo: https://oss.sheetjs.com/js-'+n+'/');
|
||||
program.on('--help', function () {
|
||||
});
|
||||
|
||||
/* flag, bookType, default ext */
|
||||
@ -98,49 +100,50 @@ var wb_formats_2 = [
|
||||
program.parse(process.argv);
|
||||
|
||||
var filename = '', sheetname = '';
|
||||
if(program.args[0]) {
|
||||
if (program.args[0]) {
|
||||
filename = program.args[0];
|
||||
if(program.args[1]) sheetname = program.args[1];
|
||||
if (program.args[1]) sheetname = program.args[1];
|
||||
}
|
||||
if(program.sheet) sheetname = program.sheet;
|
||||
if(program.file) filename = program.file;
|
||||
if (program.sheet) sheetname = program.sheet;
|
||||
if (program.file) filename = program.file;
|
||||
|
||||
if(!filename) {
|
||||
if (!filename) {
|
||||
console.error(n + ": must specify a filename");
|
||||
process.exit(1);
|
||||
}
|
||||
if(!fs.existsSync(filename)) {
|
||||
if (!fs.existsSync(filename)) {
|
||||
console.error(n + ": " + filename + ": No such file or directory");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
var opts = {}, wb/*:?Workbook*/;
|
||||
if(program.listSheets) opts.bookSheets = true;
|
||||
if(program.sheetRows) opts.sheetRows = program.sheetRows;
|
||||
if(program.password) opts.password = program.password;
|
||||
if (program.listSheets) opts.bookSheets = true;
|
||||
if (program.sheetRows) opts.sheetRows = program.sheetRows;
|
||||
if (program.password) opts.password = program.password;
|
||||
if (program.dim != null) opts.nodim = !program.dim;
|
||||
var seen = false;
|
||||
function wb_fmt() {
|
||||
seen = true;
|
||||
opts.cellFormula = true;
|
||||
opts.cellNF = true;
|
||||
opts.xlfn = true;
|
||||
if(program.output) sheetname = program.output;
|
||||
if (program.output) sheetname = program.output;
|
||||
}
|
||||
function isfmt(m/*:string*/)/*:boolean*/ {
|
||||
if(!program.output) return false;
|
||||
if (!program.output) return false;
|
||||
var t = m.charAt(0) === "." ? m : "." + m;
|
||||
return program.output.slice(-t.length) === t;
|
||||
}
|
||||
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
|
||||
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
|
||||
if(seen) {
|
||||
} else if(program.formulae) opts.cellFormula = true;
|
||||
workbook_formats.forEach(function (m) { if (program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
|
||||
wb_formats_2.forEach(function (m) { if (program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
|
||||
if (seen) {
|
||||
} else if (program.formulae) opts.cellFormula = true;
|
||||
else opts.cellFormula = false;
|
||||
|
||||
var wopts = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
|
||||
if(program.compress) wopts.compression = true;
|
||||
var wopts = ({ WTF: opts.WTF, bookSST: program.sst }/*:any*/);
|
||||
if (program.compress) wopts.compression = true;
|
||||
|
||||
if(program.all) {
|
||||
if (program.all) {
|
||||
opts.cellFormula = true;
|
||||
opts.bookVBA = true;
|
||||
opts.cellNF = true;
|
||||
@ -153,73 +156,76 @@ if(program.all) {
|
||||
wopts.sheetStubs = true;
|
||||
wopts.bookVBA = true;
|
||||
}
|
||||
if(program.sparse) opts.dense = false; else opts.dense = true;
|
||||
if(program.codepage) opts.codepage = +program.codepage;
|
||||
if(program.dateFormat) opts.dateNF = program.dateFormat;
|
||||
if (program.sparse) opts.dense = false; else opts.dense = true;
|
||||
if (program.codepage) opts.codepage = +program.codepage;
|
||||
if (program.dateFormat) opts.dateNF = program.dateFormat;
|
||||
|
||||
if(program.dev) {
|
||||
if (program.dev) {
|
||||
opts.WTF = true;
|
||||
wb = X.readFile(filename, opts);
|
||||
} else try {
|
||||
wb = X.readFile(filename, opts);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
var msg = (program.quiet) ? "" : n + ": error parsing ";
|
||||
msg += filename + ": " + e;
|
||||
console.error(msg);
|
||||
process.exit(3);
|
||||
}
|
||||
if(program.read) process.exit(0);
|
||||
if(!wb) { console.error(n + ": error parsing " + filename + ": empty workbook"); process.exit(0); }
|
||||
/*:: if(!wb) throw new Error("unreachable"); */
|
||||
if(program.listSheets) {
|
||||
console.log((wb.SheetNames||[]).join("\n"));
|
||||
if (program.read) process.exit(0);
|
||||
if (!wb) { console.error(n + ": error parsing " + filename + ": empty workbook"); process.exit(0); }
|
||||
/*:: if (!wb) throw new Error("unreachable"); */
|
||||
if (program.listSheets) {
|
||||
console.log((wb.SheetNames || []).join("\n"));
|
||||
process.exit(0);
|
||||
}
|
||||
if(program.dump) {
|
||||
if (program.dump) {
|
||||
console.log(JSON.stringify(wb));
|
||||
process.exit(0);
|
||||
}
|
||||
if(program.props) {
|
||||
if(wb) dump_props(wb);
|
||||
if (program.props) {
|
||||
if (wb) dump_props(wb);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/* full workbook formats */
|
||||
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
|
||||
workbook_formats.forEach(function (m) {
|
||||
if (program[m[0]] || isfmt(m[0])) {
|
||||
wopts.bookType = m[1];
|
||||
if(wopts.bookType == "numbers") try {
|
||||
if (wopts.bookType == "numbers") try {
|
||||
var XLSX_ZAHL = require("xlsx/dist/xlsx.zahl");
|
||||
wopts.numbers = XLSX_ZAHL;
|
||||
} catch(e) {}
|
||||
if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
|
||||
} catch (e) {}
|
||||
if (wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
|
||||
process.exit(0);
|
||||
} });
|
||||
|
||||
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
|
||||
wb_formats_2.forEach(function (m) {
|
||||
if (program[m[0]] || isfmt(m[0])) {
|
||||
wopts.bookType = m[1];
|
||||
if(wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
|
||||
if (wb) X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
|
||||
process.exit(0);
|
||||
} });
|
||||
}
|
||||
});
|
||||
|
||||
var target_sheet = sheetname || '';
|
||||
if(target_sheet === '') {
|
||||
if(+program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[+program.sheetIndex];
|
||||
else target_sheet = (wb.SheetNames||[""])[0];
|
||||
if (target_sheet === '') {
|
||||
if (+program.sheetIndex < (wb.SheetNames || []).length) target_sheet = wb.SheetNames[+program.sheetIndex];
|
||||
else target_sheet = (wb.SheetNames || [""])[0];
|
||||
}
|
||||
|
||||
var ws;
|
||||
try {
|
||||
ws = wb.Sheets[target_sheet];
|
||||
if(!ws) {
|
||||
if (!ws) {
|
||||
console.error("Sheet " + target_sheet + " cannot be found");
|
||||
process.exit(3);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error(n + ": error parsing "+filename+" "+target_sheet+": " + e);
|
||||
} catch (e) {
|
||||
console.error(n + ": error parsing " + filename + " " + target_sheet + ": " + e);
|
||||
process.exit(4);
|
||||
}
|
||||
|
||||
if(!program.quiet && !program.book) console.error(target_sheet);
|
||||
if (!program.quiet && !program.book) console.error(target_sheet);
|
||||
|
||||
/* single worksheet file formats */
|
||||
[
|
||||
@ -235,33 +241,35 @@ if(!program.quiet && !program.book) console.error(target_sheet);
|
||||
['dbf', '.dbf'],
|
||||
['wk1', '.wk1'],
|
||||
['dif', '.dif']
|
||||
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {
|
||||
].forEach(function (m) {
|
||||
if (program[m[0]] || isfmt(m[1])) {
|
||||
wopts.bookType = m[0];
|
||||
if(program.book) {
|
||||
/*:: if(wb == null) throw new Error("Unreachable"); */
|
||||
wb.SheetNames.forEach(function(n, i) {
|
||||
if (program.book) {
|
||||
/*:: if (wb == null) throw new Error("Unreachable"); */
|
||||
wb.SheetNames.forEach(function (n, i) {
|
||||
wopts.sheet = n;
|
||||
X.writeFile(wb, (program.output || sheetname || filename || "") + m[1] + "." + i, wopts);
|
||||
});
|
||||
} else X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts);
|
||||
process.exit(0);
|
||||
} });
|
||||
}
|
||||
});
|
||||
|
||||
function outit(o, fn) { if(fn) fs.writeFileSync(fn, o); else console.log(o); }
|
||||
function outit(o, fn) { if (fn) fs.writeFileSync(fn, o); else console.log(o); }
|
||||
|
||||
function doit(cb) {
|
||||
/*:: if(!wb) throw new Error("unreachable"); */
|
||||
if(program.book) wb.SheetNames.forEach(function(n, i) {
|
||||
/*:: if(!wb) throw new Error("unreachable"); */
|
||||
/*:: if (!wb) throw new Error("unreachable"); */
|
||||
if (program.book) wb.SheetNames.forEach(function (n, i) {
|
||||
/*:: if (!wb) throw new Error("unreachable"); */
|
||||
outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i);
|
||||
});
|
||||
else outit(cb(ws), program.output);
|
||||
}
|
||||
|
||||
var jso = {};
|
||||
switch(true) {
|
||||
switch (true) {
|
||||
case program.formulae:
|
||||
doit(function(ws) { return X.utils.sheet_to_formulae(ws).join("\n"); });
|
||||
doit(function (ws) { return X.utils.sheet_to_formulae(ws).join("\n"); });
|
||||
break;
|
||||
|
||||
case program.arrays: jso.header = 1;
|
||||
@ -269,33 +277,33 @@ switch(true) {
|
||||
case program.rawJs: jso.raw = true;
|
||||
/* falls through */
|
||||
case program.json:
|
||||
doit(function(ws) { return JSON.stringify(X.utils.sheet_to_json(ws,jso)); });
|
||||
doit(function (ws) { return JSON.stringify(X.utils.sheet_to_json(ws, jso)); });
|
||||
break;
|
||||
|
||||
default:
|
||||
if(!program.book) {
|
||||
var stream = X.stream.to_csv(ws, {FS:program.fieldSep||",", RS:program.rowSep||"\n"});
|
||||
if(program.output) stream.pipe(fs.createWriteStream(program.output));
|
||||
if (!program.book) {
|
||||
var stream = X.stream.to_csv(ws, { FS: program.fieldSep || ",", RS: program.rowSep || "\n" });
|
||||
if (program.output) stream.pipe(fs.createWriteStream(program.output));
|
||||
else stream.pipe(process.stdout);
|
||||
} else doit(function(ws) { return X.utils.sheet_to_csv(ws,{FS:program.fieldSep, RS:program.rowSep}); });
|
||||
} else doit(function (ws) { return X.utils.sheet_to_csv(ws, { FS: program.fieldSep, RS: program.rowSep }); });
|
||||
break;
|
||||
}
|
||||
|
||||
function dump_props(wb/*:Workbook*/) {
|
||||
var propaoa = [];
|
||||
if(Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops));
|
||||
if (Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops));
|
||||
else {
|
||||
var Keys/*:: :Array<string> = []*/, pi;
|
||||
if(wb.Props) {
|
||||
if (wb.Props) {
|
||||
Keys = Object.keys(wb.Props);
|
||||
for(pi = 0; pi < Keys.length; ++pi) {
|
||||
if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
|
||||
for (pi = 0; pi < Keys.length; ++pi) {
|
||||
if (Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
|
||||
}
|
||||
}
|
||||
if(wb.Custprops) {
|
||||
if (wb.Custprops) {
|
||||
Keys = Object.keys(wb.Custprops);
|
||||
for(pi = 0; pi < Keys.length; ++pi) {
|
||||
if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
|
||||
for (pi = 0; pi < Keys.length; ++pi) {
|
||||
if (Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,12 @@
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "7.4.0",
|
||||
"@electron-forge/maker-deb": "7.4.0",
|
||||
"@electron-forge/maker-rpm": "7.4.0",
|
||||
"@electron-forge/maker-squirrel": "7.4.0",
|
||||
"@electron-forge/maker-zip": "7.4.0",
|
||||
"electron": "31.2.0"
|
||||
"@electron-forge/cli": "7.6.0",
|
||||
"@electron-forge/maker-deb": "7.6.0",
|
||||
"@electron-forge/maker-rpm": "7.6.0",
|
||||
"@electron-forge/maker-squirrel": "7.6.0",
|
||||
"@electron-forge/maker-zip": "7.6.0",
|
||||
"electron": "33.2.1"
|
||||
},
|
||||
"config": {
|
||||
"forge": {
|
||||
|
@ -1,5 +1,6 @@
|
||||
const UXP = require("uxp");
|
||||
const XLSX = require("./xlsx.full.min.js");
|
||||
if(typeof app == "undefined") app = require("indesign").app;
|
||||
const storage = UXP.storage, ufs = storage.localFileSystem;
|
||||
|
||||
/* show file picker (single file, no folders) */
|
||||
|
BIN
docz/static/extendscript/psauthor.png
Normal file
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
@ -1,5 +1,6 @@
|
||||
const UXP = require("uxp");
|
||||
const XLSX = require("./xlsx.full.min.js");
|
||||
if(typeof app == "undefined") app = require("indesign").app;
|
||||
const storage = UXP.storage, ufs = storage.localFileSystem;
|
||||
|
||||
function workbook_add_table(wb, table) {
|
||||
|
BIN
docz/static/gsheet/aoa-udf.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
docz/static/gsheet/apps-script.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
docz/static/gsheet/clasp-perms.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
docz/static/gsheet/clasp-signin.png
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
docz/static/gsheet/xlsx-full-min-gs.png
Normal file
After Width: | Height: | Size: 43 KiB |
@ -1,5 +1,5 @@
|
||||
# Note: The official Hermes documentation includes zero guidance on embedding.=
|
||||
# Tested against commit d070c749bcf6fb635579433421a976c29d7a2bb7 on darwin-x64
|
||||
# Tested against commit 388376f05d0c2c836c8761e372fdfafd9bf077fc on darwin-x64
|
||||
# History https://git.sheetjs.com/sheetjs/docs.sheetjs.com/commits/branch/master/docz/static/hermes/Makefile
|
||||
|
||||
MYCC=llvm-g++
|
||||
@ -71,5 +71,5 @@ sheetjs-hermes.cpp:
|
||||
|
||||
.PHONY: init
|
||||
init:
|
||||
if [ ! -e hermes ]; then git clone https://github.com/facebook/hermes.git; cd hermes; git checkout d070c749bcf6fb635579433421a976c29d7a2bb7; cd ..; fi
|
||||
if [ ! -e hermes ]; then git clone https://github.com/facebook/hermes.git; cd hermes; git checkout 388376f05d0c2c836c8761e372fdfafd9bf077fc; cd ..; fi
|
||||
if [ ! -e build_release ]; then cmake -S hermes -B build_release -G Ninja -DCMAKE_BUILD_TYPE=Release -DHERMES_BUILD_APPLE_FRAMEWORK=OFF; cmake --build ./build_release; fi
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 19 KiB |
@ -119,7 +119,7 @@ function export_xlsx() {
|
||||
var new_wb = xtos(xspr.getData());
|
||||
|
||||
/* write file and trigger a download */
|
||||
XLSX.writeFile(new_wb, 'sheetjs.xlsx', {});
|
||||
XLSX.writeFile(new_wb, 'SheetJSXSpreadsheetExport.xlsx', {});
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
@ -83,10 +83,13 @@ app.listen(7262, async() => {
|
||||
});
|
||||
EOF
|
||||
|
||||
npm i --save puppeteer express
|
||||
|
||||
node -e 'var pjson = JSON.parse(fs.readFileSync("./package.json")); console.log(pjson); delete pjson.main; fs.writeFileSync("package.json", JSON.stringify(pjson))'
|
||||
|
||||
for n in 1.12.4 2.12.0; do
|
||||
npx -y parcel build index.html
|
||||
for n in 1.12.3 2.13.3; do
|
||||
npm i --save parcel@$n
|
||||
npx -y parcel@$n build index.html
|
||||
node test.js
|
||||
npx -y xlsx-cli Presidents.xlsx | head -n 3
|
||||
rm -f Presidents.xlsx
|
||||
|
33
tests/data-postgres.sh
Normal file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
# https://docs.sheetjs.com/docs/demos/data/postgresql
|
||||
## NOTE: these steps are for darwin-arm
|
||||
|
||||
mkdir sheetjs-pg
|
||||
cd sheetjs-pg
|
||||
npm init -y
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz pg@8.13.1 pg-format@1.0.4
|
||||
|
||||
curl -LO https://docs.sheetjs.com/postgresql/SheetJSPG.js
|
||||
curl -L -O https://docs.sheetjs.com/pres.numbers
|
||||
|
||||
for n in 1{2..7}; do
|
||||
# brew install postgresql@$n
|
||||
echo $n
|
||||
|
||||
# "If you need to have postgresql@$n first in your PATH, run:"
|
||||
export PATH="/opt/homebrew/opt/postgresql@$n/bin:$PATH"
|
||||
|
||||
# "Or, if you don't want/need a background service you can just run:"
|
||||
nohup env LC_ALL="C" /opt/homebrew/opt/postgresql@$n/bin/postgres -D /opt/homebrew/var/postgresql@$n >/dev/null 2>&1 &
|
||||
sleep 5
|
||||
|
||||
dropdb SheetJSPG
|
||||
createdb SheetJSPG
|
||||
|
||||
node SheetJSPG.js
|
||||
npx xlsx-cli SheetJSPGExport.xlsx
|
||||
psql SheetJSPG -c 'SELECT * FROM "Presidents";'
|
||||
|
||||
kill $!
|
||||
done
|
||||
|
22
tests/static-eleventy.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# https://docs.sheetjs.com/docs/demos/static/eleventy
|
||||
# This script builds the Static Site. It does not test HMR!
|
||||
cd /tmp
|
||||
rm -rf sheetjs-11ty
|
||||
mkdir sheetjs-11ty
|
||||
cd sheetjs-11ty
|
||||
|
||||
npm init -y
|
||||
|
||||
mkdir _data
|
||||
curl -Lo _data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
curl -L -o .eleventy.js https://docs.sheetjs.com/eleventy/_eleventy.js
|
||||
curl -LO https://docs.sheetjs.com/eleventy/index.njk
|
||||
|
||||
for n in 2.0.1 3.0.0; do
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz @11ty/eleventy@$n
|
||||
npx @11ty/eleventy@$n
|
||||
|
||||
echo "Clinton" $(grep Clinton _site/index.html | wc -l) "BESSELJ" $(grep BESSELJ _site/index.html | wc -l) "JS" $(grep -F '.js' _site/index.html | wc -l)
|
||||
# Expected output: Clinton 1 BESSELJ 0 JS 0
|
||||
done
|