react-native mobile refresh

This commit is contained in:
SheetJS 2024-04-01 06:44:10 -04:00
parent 9230a968c3
commit ad27e3a947
25 changed files with 1208 additions and 377 deletions

@ -46,11 +46,11 @@ This demo was tested in the following environments:
| Version | Platform | Date |
|:----------|:---------|:-----------|
| `0.19.47` | NodeJS | 2023-10-18 |
| `0.20.16` | Browser | 2023-12-04 |
| `0.20.19` | NodeJS | 2023-10-18 |
| `0.21.6` | NodeJS | 2023-10-18 |
| `6.14.2` | NodeJS | 2023-12-04 |
| `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 |
:::
@ -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.2`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz systemjs@6.14.3`}
</CodeBlock>
2) Download [`SheetJSystem.js`](pathname:///systemjs/SheetJSystem.js) and move
@ -215,7 +215,7 @@ curl -LO https://docs.sheetjs.com/systemjs/SheetJSystem.js
:::info pass
The script is handles both old-style and new-style SystemJS loaders.
The script handles old-style and new-style SystemJS loaders.
:::

@ -2,7 +2,7 @@
title: Sheets in PST Mailboxes
sidebar_label: PST Mailboxes
pagination_prev: demos/net/server/index
pagination_next: demos/net/headless
pagination_next: demos/net/headless/index
---
import current from '/version.js';

@ -1,7 +1,7 @@
---
title: Electronic Mail
pagination_prev: demos/net/server/index
pagination_next: demos/net/headless
pagination_next: demos/net/headless/index
---
import current from '/version.js';

@ -0,0 +1,4 @@
{
"label": "Browser Automation",
"position": 8
}

@ -1,6 +1,7 @@
---
title: Browser Automation
pagination_prev: demos/net/email/index
pagination_next: demos/net/dom
---
import current from '/version.js';
@ -406,7 +407,7 @@ This demo was tested in the following environments:
|:-------------|:----------|:-----------|
| `darwin-x64` | `2.1.1` | 2024-03-15 |
| `win10-x64` | `2.1.1` | 2024-03-24 |
| `linux-x64` | `2.1.1` | 2024-03-29 |
:::
1) [Download and extract PhantomJS](https://phantomjs.org/download.html)
@ -425,4 +426,30 @@ will be placed in `phantomjs-2.1.1-macosx/bin/` and the command will be:
When the script finishes, the file `SheetJSPhantomJS.xlsb` will be created.
This file can be opened with Excel.
:::caution pass
When this demo was last tested on Linux, there were multiple errors.
```
This application failed to start because it could not find or load the Qt platform plugin "xcb".
```
The environment variable `QT_QPA_PLATFORM=phantom` resolves the issue. There is
a different error after assignment:
```
140412268664640:error:25066067:DSO support routines:DLFCN_LOAD:could not load the shared library:dso_dlfcn.c:185:filename(libproviders.so): libproviders.so: cannot open shared object file: No such file or directory
140412268664640:error:25070067:DSO support routines:DSO_load:could not load the shared library:dso_lib.c:244:
140412268664640:error:0E07506E:configuration file routines:MODULE_LOAD_DSO:error loading dso:conf_mod.c:285:module=providers, path=providers
140412268664640:error:0E076071:configuration file routines:MODULE_RUN:unknown module name:conf_mod.c:222:module=providers
```
This error is resolved by ignoring SSL errors. The complete command is:
```bash
env OPENSSL_CONF=/dev/null QT_QPA_PLATFORM=phantom ./phantomjs-2.1.1-linux-x86_64/bin/phantomjs --ignore-ssl-errors=true test.js
```
:::
</details>

@ -1,5 +1,6 @@
---
title: Synthetic DOM
pagination_prev: demos/net/headless/index
---
import current from '/version.js';

@ -141,7 +141,7 @@ Consider the following worksheet:
Assuming the file name is `pres.xlsx` and the data is stored in "Sheet1", the
following nodes will be created:
```js
```js title="GraphQL Nodes"
[
{ Name: "Bill Clinton", Index: 42, type: "PresXlsxSheet1" },
{ Name: "GeorgeW Bush", Index: 43, type: "PresXlsxSheet1" },
@ -155,7 +155,7 @@ The type is a proper casing of the file name concatenated with the sheet name.
The following query pulls the `Name` and `Index` fields from each row:
```graphql
```graphql title="GraphQL Query to pull Name and Index fields from each row"
{
allPresXlsxSheet1 { # "all" followed by type
edges {
@ -172,8 +172,12 @@ The following query pulls the `Name` and `Index` fields from each row:
:::note Tested Deployments
This demo was tested on 2023 December 04 against `create-gatsby@3.12.3`. The
generated project used `gatsby@5.12.11` and `react@18.2.0`.
This demo was tested in the following environments:
| GatsbyJS | Date |
|:---------|:-----------|
| `5.12.1` | 2023-12-04 |
| `4.25.8` | 2024-03-27 |
:::
@ -188,9 +192,26 @@ npx gatsby telemetry --disable
1) Create a template site:
```bash
npm init gatsby -- -y sheetjs-gatsby
npx gatsby new sheetjs-gatsby
```
:::info pass
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:
```bash
git clone https://github.com/gatsbyjs/gatsby-starter-default sheetjs-gatsby
cd sheetjs-gatsby
git checkout 6bc4466090845f20650117b3d27e68e6e46dc8d5
npm install
cd ..
```
:::
2) Follow the on-screen instructions for starting the local development server:
```bash
@ -222,6 +243,18 @@ npm i --save gatsby-transformer-excel gatsby-source-filesystem
`}
</CodeBlock>
:::info pass
For older versions of Gatsby, older versions of the dependencies must be used.
For GatsbyJS 4, the plugin version numbers align with the Gatsby version:
```bash
npm i --save gatsby-transformer-excel@4 gatsby-source-filesystem@4
```
:::
5) Make a `src/data` directory, download <https://sheetjs.com/pres.xlsx>, and
move the downloaded file into the new folder:
@ -253,6 +286,27 @@ module.exports = {
}
```
:::note pass
If the `plugins` array exists, the two plugins should be added at the beginning:
```js title="gatsby-config.js (add highlighted lines)"
plugins: [
// highlight-start
{
resolve: `gatsby-source-filesystem`,
options: {
name: `data`,
path: `${__dirname}/src/data/`,
},
},
`gatsby-transformer-excel`,
// highlight-end
// ...
```
:::
Stop and restart the development server process (`npm run develop`).
### GraphiQL test
@ -322,7 +376,7 @@ displayed JSON is the data that the component receives:
9) Change `PageComponent` to display a table based on the data:
```jsx title="src/pages/pres.js"
```jsx title="src/pages/pres.js (replace PageComponent)"
import { graphql } from "gatsby"
import * as React from "react"

File diff suppressed because it is too large Load Diff

@ -159,6 +159,7 @@ This demo was tested in the following deployments:
| Architecture | NodeJS | Date |
|:-------------|:----------|:-----------|
| `darwin-x64` | `20.11.1` | 2024-03-17 |
| `win10-x64` | `20.12.0` | 2024-03-26 |
| `linux-x64` | `20.11.1` | 2024-03-18 |
:::
@ -224,7 +225,7 @@ local NodeJS platform.
4) Download the test file <https://sheetjs.com/pres.numbers>:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -o pres.numbers https://sheetjs.com/pres.numbers
```
5) Run the script and pass `pres.numbers` as the first argument:
@ -257,24 +258,54 @@ node --experimental-sea-config sheet2csv.json
### SEA Injection
8) Create a local copy of the NodeJS binary. On macOS and Linux:
8) Create a local copy of the NodeJS binary:
<Tabs groupId="triple">
<TabItem value="darwin-x64" label="MacOS">
```bash
cp `which node` sheet2csv
```
<Tabs groupId="triple">
<TabItem value="darwin-x64" label="MacOS">
9) Remove the code signature.
```bash
codesign --remove-signature ./sheet2csv
```
</TabItem>
<TabItem value="win10-x64" label="Windows">
In PowerShell, the `Get-Command` command displays the location to `node.exe`:
```powershell
PS C:\sheetjs-sea> get-command node
CommandType Name Version Source
----------- ---- ------- ------
Application node.exe 20.12.0.0 C:\Program Files\nodejs\node.exe
```
Copy the program (listed in the "Source" column) to `sheet2csv.exe`:
```powershell
PS C:\sheetjs-sea> copy "C:\Program Files\nodejs\node.exe" sheet2csv.exe
```
9) Remove the code signature.
```powershell
signtool remove /s .\sheet2csv.exe
```
</TabItem>
<TabItem value="linux-x64" label="Linux">
```bash
cp `which node` sheet2csv
```
9) Observe that many Linux distributions do not enforce code signatures.
</TabItem>
@ -293,6 +324,29 @@ npx -y postject --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 -
```bash
codesign -s - ./sheet2csv
```
</TabItem>
<TabItem value="win10-x64" label="Windows">
```bash
npx -y postject --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 sheet2csv.exe NODE_SEA_BLOB sheet2csv.blob
```
11) Resign the binary.
The following sequence generates a self-signed certificate:
```powershell
$cert = New-SelfSignedCertificate -Type CodeSigning -DnsName www.onlyspans.net -CertStoreLocation Cert:\CurrentUser\My
$pass = ConvertTo-SecureString -String "hunter2" -Force -AsPlainText
Export-PfxCertificate -Cert "cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath "mycert.pfx" -Password $pass
```
After creating a cert, sign the binary:
```powershell
signtool sign /v /f mycert.pfx /p hunter2 /fd SHA256 sheet2csv.exe
```
</TabItem>
@ -321,7 +375,7 @@ The program should display the same CSV contents as the script (from step 5)
<Tabs groupId="triple">
<TabItem value="darwin-x64" label="MacOS">
13) Validate the binary signature. On macOS:
13) Validate the binary signature:
```bash
codesign -dv ./sheet2csv
@ -333,6 +387,24 @@ Inspecting the output, the following line confirms ad-hoc signing was used:
Signature=adhoc
```
</TabItem>
<TabItem value="win10-x64" label="Windows">
13) Validate the binary signature:
```powershell
signtool verify sheet2csv.exe
```
If the certificate is self-signed, there may be an error:
```
SignTool Error: A certificate chain processed, but terminated in a root
certificate which is not trusted by the trust provider.
```
This error is expected.
</TabItem>
<TabItem value="linux-x64" label="Linux">

@ -36,8 +36,9 @@ This demo was tested in the following environments:
| Postgres | Connector Library | Date |
|:---------|:------------------|:-----------|
| `16.0.1` | `pg` (`8.11.3`) | 2023-10-30 |
| `15.5` | `pg` (`8.11.3`) | 2023-12-04 |
| `16.2.1` | `pg` (`8.11.4`) | 2024-03-31 |
| `15.6` | `pg` (`8.11.4`) | 2024-03-31 |
| `14.11` | `pg` (`8.11.4`) | 2024-03-31 |
:::
@ -275,7 +276,7 @@ npm init -y
4) Install the `pg` connector module:
```bash
npm i --save pg@8.11.3
npm i --save pg@8.11.4
```
5) Save the following example codeblock to `PGTest.js`:

@ -1,6 +1,6 @@
---
title: Sheets with MongoDB
sidebar_label: MongoDB
sidebar_label: MongoDB / FerretDB
pagination_prev: demos/cli/index
pagination_next: demos/local/index
sidebar_custom_props:
@ -24,10 +24,11 @@ to add data from spreadsheets into a collection.
This demo was tested in the following environments:
| MongoDB CE | Connector Library | Date |
|:-----------|:--------------------|:-----------|
| `6.0.10` | `mongodb` (`5.7.0`) | 2023-12-04 |
| `7.0.2` | `mongodb` (`5.7.0`) | 2023-12-04 |
| Server | Connector Library | Date |
|:--------------------|:--------------------|:-----------|
| FerretDB `1.21.0` | `mongodb` (`5.9.2`) | 2024-03-30 |
| MongoDB CE `6.0.10` | `mongodb` (`5.7.0`) | 2023-12-04 |
| MongoDB CE `7.0.2` | `mongodb` (`5.7.0`) | 2023-12-04 |
:::
@ -81,7 +82,14 @@ This workbook is typically exported to the filesystem with `writeFile`[^8].
## Complete Example
0) Install MongoDB 7.0 Community Edition[^9]. The macOS steps required `brew`:
0) Install a MongoDB-compatible server. Options include MongoDB CE[^9] and
FerretDB[^10]
1) Start a server on `localhost` (follow official instructions).
<details><summary><b>MongoDB CE Setup</b> (click to show)</summary>
For MongoDB 7.0 Community Edition, the macOS steps required `brew`:
```bash
brew tap mongodb/brew
@ -89,8 +97,6 @@ brew update
brew install mongodb-community
```
1) Start a MongoDB server on `localhost` (follow official instructions).
:::note pass
If `brew` was used to install MongoDB, the following command starts a server:
@ -107,6 +113,8 @@ If Homebrew is configured to use `/opt/homebrew`, the command is:
:::
</details>
2) Create base project and install the dependencies:
<CodeBlock language="bash">{`\
@ -179,4 +187,5 @@ There should be no errors in the terminal. The script will generate the file
[^6]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
[^8]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
[^9]: See ["Install MongoDB Community Edition"](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) in the MongoDB documentation.
[^9]: See ["Install MongoDB Community Edition"](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) in the MongoDB documentation.
[^10]: See ["SQLite Setup with Docker Compose"](https://docs.ferretdb.io/quickstart-guide/docker/#sqlite-setup-with-docker-compose) in the FerretDB documentation.

@ -17,8 +17,10 @@ import CodeBlock from '@theme/CodeBlock';
**Redis has relicensed away from open source!**
The original BSD-3-Clause applies to version `7.2.4`. This discussion applies to
KeyDB and other servers that support the "Redis serialization protocol" (RESP).
The original BSD-3-Clause still applies to version `7.2.4`.
This demo has been tested with KeyDB and other servers that support the "Redis
serialization protocol" (RESP).
:::
@ -40,7 +42,7 @@ This demo was tested in the following environments:
|:--------------|:-------------------|:----------:|
| KeyDB `6.3.4` | `redis` (`4.6.13`) | 2024-03-25 |
| Redis `6.2.9` | `redis` (`4.6.11`) | 2023-12-04 |
| Redis `7.2.3` | `redis` (`4.6.11`) | 2023-12-04 |
| Redis `7.2.4` | `redis` (`4.6.11`) | 2024-03-26 |
:::

@ -4,6 +4,11 @@ pagination_prev: demos/cloud/index
pagination_next: demos/bigdata/index
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be integrated in a Chromium extension.
@ -14,7 +19,7 @@ tables with a content script and a background script.
:::note Tested Deployments
This demo was last tested on 2024 March 11 against Chrome 122.
This demo was last tested on 2024 March 30 against Chrome 122.
:::
@ -131,7 +136,8 @@ for(var i = 0; i < tables.length; ++i) {
The demo extension includes multiple features to demonstrate sample usage.
Production extensions should include proper error handling.
<details open><summary><b>Testing Unpacked Extension</b> (click to hide)</summary>
<Tabs>
<TabItem name="zip" value="Prepared Extension">
1) Download the zip for the desired Manifest version:
@ -142,13 +148,186 @@ Production extensions should include proper error handling.
3) Drag and drop the downloaded zip file into the window.
</details>
</TabItem>
<TabItem name="crx" value="Extension from Scratch">
1) Create a new extension using `create-chrome-ext`[^1]:
```bash
npm create chrome-ext@latest sheetjs-crx -- --template vanilla-ts
cd sheetjs-crx
npm install
```
2) Edit the highlighted lines in `package.json`:
```js title="package.json" (edit highlighted lines)
{
"name": "sheetjs-crx",
// highlight-next-line
"displayName": "SheetJS Demo",
"version": "0.0.0",
"author": "**",
// highlight-next-line
"description": "Sample Extension using SheetJS to interact with Chrome",
```
3) Edit `manifest.ts` and add to the `permissions` array:
```ts title="manifest.ts"
permissions: ['sidePanel', 'storage',
"activeTab",
"bookmarks",
"contextMenus",
"downloads",
"tabs"
],
```
4) Install the SheetJS dependency and start the dev server:
<CodeBlock language="bash">{`\
curl -o .\public\img\logo-48.png https://docs.sheetjs.com/logo.png
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
npm run dev`}
</CodeBlock>
The build step will create a `build` subfolder.
5) Replace `src/popup/index.ts` with the following codeblock:
```ts title="src/popup/index.ts"
import { version, utils, writeFileXLSX } from 'xlsx';
import './index.css'
/* recursively walk the bookmark tree */
const recurse_bookmarks = (data, tree, path) => {
if(tree.url) data.push({Name: tree.title, Location: tree.url, Path:path});
var T = path ? (path + "::" + tree.title) : tree.title;
(tree.children||[]).forEach(function(C) { recurse_bookmarks(data, C, T); });
};
const export_bookmarks = () => {
chrome.bookmarks.getTree(function(res) {
var data = [];
res.forEach(function(t) { recurse_bookmarks(data, t, ""); });
/* create worksheet */
var ws = utils.json_to_sheet(data, { header: ['Name', 'Location', 'Path'] });
/* create workbook and export */
var wb = utils.book_new();
utils.book_append_sheet(wb, ws, 'Bookmarks');
writeFileXLSX(wb, "bookmarks.xlsx");
});
};
document.addEventListener('DOMContentLoaded', () => {
const root = document.getElementById('app')!
const xprt = document.createElement("button"); // sjsdownload
xprt.type = "button"; xprt.innerHTML = "Export Bookmarks";
root.appendChild(xprt);
xprt.addEventListener("click", export_bookmarks);
const vers = document.createElement("a");
vers.innerHTML = "SheetJS " + version;
root.appendChild(vers);
vers.addEventListener("click", () => { chrome.tabs.create({url: "https://sheetjs.com/"}); });
});
```
6) Replace `src/background/index.ts` with the following codeblock:
```ts title="src/background/index.ts"
chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({
type: "normal",
id: "sjsexport",
title: "Export Table to XLSX",
contexts: ["page", "selection"]
});
chrome.contextMenus.create({
type: "normal",
id: "sj5export",
title: "Export All Tables in Page",
contexts: ["page", "selection"]
});
chrome.contextMenus.onClicked.addListener(function(info/*, tab*/) {
var mode = "";
switch(info.menuItemId) {
case 'sjsexport': mode = "JS"; break;
case 'sj5export': mode = "J5"; break;
default: return;
}
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {Sheet:mode}, sjsexport_cb);
});
});
chrome.contextMenus.create({
id: "sjsabout",
title: "About",
contexts: ["browser_action"]
});
chrome.contextMenus.onClicked.addListener(function(info/*, tab*/) {
if(info.menuItemId !== "sjsabout") return;
chrome.tabs.create({url: "https://sheetjs.com/"});
});
});
function sjsexport_cb(wb) {
if(!wb || !wb.SheetNames || !wb.Sheets) { return alert("Error in exporting table"); }
const b64 = XLSX.write(wb, {bookType: "xlsx", type: "base64"});
chrome.downloads.download({
url: `data:application/octet-stream;base64,${b64}`,
filename: `SheetJSTables.xlsx`
})
}
```
7) Replace `src/contentScript/index.ts` with the following codeblock:
```ts title="src/contentScript/index.ts"
import { utils } from 'xlsx';
var coords = [0,0];
document.addEventListener('mousedown', function(mouse) {
if(mouse && mouse.button == 2) coords = [mouse.clientX, mouse.clientY];
});
chrome.runtime.onMessage.addListener(function(msg, sender, cb) {
if(!msg || !msg['Sheet']) return;
if(msg.Sheet == "JS") {
var elt = document.elementFromPoint(coords[0], coords[1]);
while(elt != null) {
if(elt.tagName.toLowerCase() == "table") return cb(utils.table_to_book(elt));
elt = elt.parentElement;
}
} else if(msg.Sheet == "J5") {
var tables = document.getElementsByTagName("table");
var wb = utils.book_new();
for(var i = 0; i < tables.length; ++i) {
var ws = utils.table_to_sheet(tables[i]);
utils.book_append_sheet(wb, ws, "Table" + i);
}
return cb(wb);
}
cb(coords);
});
```
8) Open `chrome://extensions/` in the browser and enable Developer mode
9) Click "Load unpacked" and select the `build` folder within the project.
</TabItem>
</Tabs>
### Bookmark Exporter
<details open><summary><b>Testing</b> (click to hide)</summary>
0) Go to <https://sheetjs.com> and create a bookmark in the browser.
0) Open <https://sheetjs.com> in the browser and create a bookmark.
1) Click the Extensions icon (puzzle icon to the right of the address bar) and
select "SheetJS Demo".
@ -203,7 +382,7 @@ chrome.bookmarks.getTree(function(res) {
<details open><summary><b>Testing</b> (click to hide)</summary>
1) Go to <https://sheetjs.com/demo/table>
1) Open <https://sheetjs.com/demo/table> in the browser.
2) Right-click anywhere in the page and select "SheetJS Demo" > "Export All Tables in Page"
@ -255,3 +434,5 @@ sequenceDiagram
Note over P: Create Data URL
P->>U: `chrome.downloads.download`
```
[^1]: See the [`create-chrome-ext` package](https://github.com/guocaoyi/create-chrome-ext) for more details.

@ -30,7 +30,7 @@ flowchart LR
:::note Tested Deployments
This demo was last tested by SheetJS users on 2023 October 3 in Maple 2023.
This demo was last tested by SheetJS users on 2024 March 31 in Maple 2024.
:::
@ -54,8 +54,8 @@ The extension function ultimately pairs the SheetJS `read`[^2] and `write`[^3]
methods to read data from the old file and write a new file:
```js
var wb = XLSX.read(original_file_data, {type: "buffer"});
var new_file_data = XLSX.write(wb, {type: "array", bookType: "xlsx"});
var workbook = XLSX.read(original_file_data, { type: "buffer" });
var new_file_data = XLSX.write(workbook, { type: "array", bookType: "xlsx" });
```
The extension function will receive a file name and perform the following steps:
@ -81,8 +81,9 @@ flowchart LR
### C Extensions
Maple C extensions are shared libraries or DLLs that use special Maple methods
for parsing arguments and returning values.
Maple extensions are shared libraries or DLLs that use special Maple methods for
parsing arguments and returning values. They are typically written in the C
programming language.
To simplify the flow, the new function will take one argument (the original file
name) and return one value (the new file name).
@ -125,7 +126,7 @@ with(ExcelTools);
Import(SheetToXLSX("pres.numbers"))
```
0) Ensure "Windows Subsystem for Linux" (WSL) and Visual Studio are installed.
0) Install "Windows Subsystem for Linux" (WSL)[^5] and Visual Studio[^6].
1) Open a new "x64 Native Tools Command Prompt" window and create a project
folder `c:\sheetjs-maple`:
@ -137,11 +138,11 @@ cd sheetjs-maple
```
2) Copy the headers and `lib` files from the Maple folder to the project folder.
For example, using Maple 2023 on Windows x64:
For example, using Maple 2024 on Windows x64:
```powershell
copy "C:\Program Files\Maple 2023\extern\include\"*.h .
copy "c:\Program Files\Maple 2023\bin.x86_64_WINDOWS"\*.lib .
copy "C:\Program Files\Maple 2024\extern\include\"*.h .
copy "c:\Program Files\Maple 2024\bin.x86_64_WINDOWS"\*.lib .
```
3) Run `bash` to enter WSL
@ -206,4 +207,6 @@ The result will show the data from `pres.numbers`
[^1]: See ["ExcelTools"](https://www.maplesoft.com/support/help/Maple/view.aspx?path=ExcelTools) in the Maple documentation.
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^3]: See [`write` in "Writing Files"](/docs/api/write-options)
[^4]: See ["C OpenMaple and ExternalCalling Application Program Interface (API)"](https://www.maplesoft.com/support/help/maple/view.aspx?path=OpenMaple%2FC%2FAPI) in the Maple documentation.
[^4]: See ["C OpenMaple and ExternalCalling Application Program Interface (API)"](https://www.maplesoft.com/support/help/maple/view.aspx?path=OpenMaple%2FC%2FAPI) in the Maple documentation.
[^5]: In a PowerShell terminal window, run `wsl --install Ubuntu`
[^6]: See [the Visual Studio website](https://visualstudio.microsoft.com/#vs-section) for download links. In the Visual Studio Installer, install the "Desktop development with C++" workflow.

@ -6,8 +6,7 @@ sidebar_position: 1
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
Dates are a core concept in nearly every spreadsheet application in existence.
Some legacy spreadsheet apps only supported dates. Others supported times as a
@ -254,7 +253,7 @@ if(!(wb?.Workbook?.WBProps?.date1904)) {
}
```
:::note Why does the 1904 date system exist?
<details><summary><b>Why does the 1904 date system exist?</b> (click to show) </summary>
1900 was not a leap year. For the Gregorian calendar, the general rules are:
- every multiple of 400 is a leap year
@ -268,13 +267,13 @@ the `@date` function:
```
@date(0,2,28) -> 59 // Lotus accepts 2/28/1900
@date(0,2,29) -> 60 // <--2/29/1900 was not a real date
@date(0.2,30) -> ERR // Lotus rejects 2/30/1900
@date(0,2,30) -> ERR // Lotus rejects 2/30/1900
```
Excel extends the tradition in the default date system. The 1904 date system
starts the count in 1904, skipping the bad date.
:::
</details>
### Relative Epochs
@ -292,6 +291,8 @@ of universal time.
## How Files Store Dates and Times
<details><summary><b>Technical Details</b> (click to show)</summary>
XLS, XLSB, and most binary formats store the raw date codes. Special number
formats are used to indicate that the values are intended to be dates/times.
@ -310,6 +311,8 @@ Numbers uses a calendar date system, but records pure time values as if they are
absolute times in 1904 January 01. It is spiritually equivalent to the 1904 mode
in Excel and other spreadsheet applications.
</details>
## How JavaScript Engines Understand Time
JavaScript provides a `Date` object which represents an *absolute* time. Under
@ -632,4 +635,22 @@ A single `Array#map` operation can create a fixed dataset:
```js
const new_rows = rows.map(({birthday, ...rest}) => ({birthday: new Date(birthday), ...rest}))
```
```
The `Date` constructor interprets the dates in local time.
:::caution pass
Excel and other spreadsheet software do not typically support dates before 1900.
If there are dates before the threshold, it is strongly recommended to pass
strings instead of `Date` objects.
:::
:::warning pass
JavaScript string to `Date` conversion is "implementation-dependent" and may
misinterpret some date formats. When designing APIs, it is strongly recommended
to pass ISO 8601 strings when possible.
:::

@ -4,8 +4,7 @@ sidebar_label: Hyperlinks
sidebar_position: 3
---
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
Traditional spreadsheet software, including Excel, support "Cell Links". The
entire cell text is clickable.
@ -31,17 +30,34 @@ and writers apply the hyperlink to the entire cell text.
</details>
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
hyperlink object is the target of the link, including the URI fragment. Tooltips
are stored in the `Tooltip` field and are displayed when hovering over the text.
Spreadsheet hyperlinks are clickable references to other locations. They serve
the same role as the HTML `<a>` tag.
Spreadsheet applications can process "internal" (cells, ranges, and defined
names) and "external" (websites, email addresses, and local files) references.
SheetJS hyperlink objects are stored in the `l` key of cell objects. Hyperlink
objects include the following fields:
- `Target` (required) describes the reference.
- `Tooltip` is the tooltip text. Tooltips are shown when hovering over the text.
For example, the following snippet creates a link from cell `A1` to
<https://sheetjs.com> with the tip `"Find us @ SheetJS.com!"`:
```js
ws["A1"].l = { Target: "https://sheetjs.com", Tooltip: "Find us @ SheetJS.com!" };
/* create worksheet with cell A1 = "https://sheetjs.com" */
var ws = XLSX.utils.aoa_to_sheet([["https://sheetjs.com"]]);
/* add hyperlink */
ws["A1"].l = {
Target: "https://sheetjs.com",
Tooltip: "Find us @ SheetJS.com!"
};
```
![Cell A1 is a hyperlink with a custom tooltip](pathname:///hyperlink/tooltip.png)
:::note pass
Following traditional software, hyperlinks are applied to entire cell objects.
@ -60,11 +76,26 @@ general hyperlink styling.
:::
## External Hyperlinks
Spreadsheet software will typically launch other programs to handle external
hyperlinks. For example, clicking a "Web Link" will open a new browser window.
### Web Links
HTTP and HTTPS links can be used directly:
```js
ws["A2"].l = { Target: "https://docs.sheetjs.com/docs/csf/features/hyperlinks#web-links" };
ws["A3"].l = { Target: "http://localhost:7262/yes_localhost_works" };
```
<details open><summary><b>Live Example</b> (click to hide)</summary>
```jsx live
/* The live editor requires this function wrapper */
function ExportSimpleLink(props) { return ( <button onClick={() => {
function ExportSimpleLink() { return ( <button onClick={() => {
/* Create worksheet */
var ws = XLSX.utils.aoa_to_sheet([ [ "Link", "No Link" ] ]);
/* Add link */
@ -82,54 +113,7 @@ function ExportSimpleLink(props) { return ( <button onClick={() => {
</details>
<details><summary><b>Extract all links from a file</b> (click to show)</summary>
The following example iterates through each worksheet and each cell to find all
links. The table shows sheet name, cell address, and target for each link.
```jsx live
function SheetJSParseLinks(props) {
const [rows, setRows] = React.useState([]);
return ( <>
<input type="file" onChange={async(e) => {
let rows = [];
/* parse workbook */
const file = e.target.files[0];
const data = await file.arrayBuffer();
const wb = XLSX.read(data);
const html = [];
wb.SheetNames.forEach(n => {
var ws = wb.Sheets[n]; if(!ws) return;
var ref = XLSX.utils.decode_range(ws["!ref"]);
for(var R = 0; R <= ref.e.r; ++R) for(var C = 0; C <= ref.e.c; ++C) {
var addr = XLSX.utils.encode_cell({r:R,c:C});
if(!ws[addr] || !ws[addr].l) continue;
var link = ws[addr].l;
rows.push({ws:n, addr, Target: link.Target});
}
});
setRows(rows);
}}/>
<table><tr><th>Sheet</th><th>Address</th><th>Link Target</th></tr>
{rows.map(r => (<tr><td>{r.ws}</td><td>{r.addr}</td><td>{r.Target}</td></tr>))}
</table>
</> );
}
```
</details>
## Remote Links
HTTP and HTTPS links can be used directly:
```js
ws["A2"].l = { Target: "https://docs.sheetjs.com/docs/csf/features/hyperlinks" };
ws["A3"].l = { Target: "http://localhost:7262/yes_localhost_works" };
```
### Mail Links
Excel also supports `mailto` email links with subject line:
@ -145,7 +129,7 @@ address input in the form never leaves your machine.**
```jsx live
/* The live editor requires this function wrapper */
function ExportRemoteLink(props) {
function ExportRemoteLink() {
const [email, setEmail] = React.useState("ignored@dev.null");
const set_email = React.useCallback((evt) => setEmail(evt.target.value));
@ -172,7 +156,7 @@ function ExportRemoteLink(props) {
</details>
## Local Links
### Local Links
Links to absolute paths should use the `file://` URI scheme:
@ -195,7 +179,7 @@ Relative Paths have undefined behavior in the SpreadsheetML 2003 format. Excel
:::
## Internal Links
## Internal Hyperlinks
Links where the target is a cell or range or defined name in the same workbook
("Internal Links") are marked with a leading hash character:
@ -218,7 +202,7 @@ The defined name `SheetJSDN` points to the range `A1:B2` in the second sheet.
```jsx live
/* The live editor requires this function wrapper */
function ExportInternalLink(props) { return ( <button onClick={() => {
function ExportInternalLink() { return ( <button onClick={() => {
/* Create empty workbook */
var wb = XLSX.utils.book_new();
@ -279,7 +263,7 @@ HTML table. The hyperlink in the second row will be parsed as a cell-level link.
```jsx live
/* The live editor requires this function wrapper */
function ExportHyperlink(props) {
function ExportHyperlink() {
/* Callback invoked when the button is clicked */
const xport = React.useCallback(() => {
@ -314,7 +298,7 @@ has a standard HTML link.
```jsx live
/* The live editor requires this function wrapper */
function ExportALinks(props) {
function ExportALinks() {
const [ __html, setHTML ] = React.useState("");
React.useEffect(() => {
/* Create worksheet */
@ -335,5 +319,46 @@ function ExportALinks(props) {
</details>
#### Miscellany
<details><summary><b>Extract all links from a file</b> (click to show)</summary>
The following example iterates through each worksheet and each cell to find all
links. The table shows sheet name, cell address, and target for each link.
```jsx live
function SheetJSParseLinks() {
const [rows, setRows] = React.useState([]);
return ( <>
<input type="file" onChange={async(e) => {
let rows = [];
/* parse workbook */
const file = e.target.files[0];
const data = await file.arrayBuffer();
const wb = XLSX.read(data);
const html = [];
wb.SheetNames.forEach(n => {
var ws = wb.Sheets[n]; if(!ws) return;
var ref = XLSX.utils.decode_range(ws["!ref"]);
for(var R = 0; R <= ref.e.r; ++R) for(var C = 0; C <= ref.e.c; ++C) {
var addr = XLSX.utils.encode_cell({r:R,c:C});
if(!ws[addr] || !ws[addr].l) continue;
var link = ws[addr].l;
rows.push({ws:n, addr, Target: link.Target});
}
});
setRows(rows);
}}/>
<table><tr><th>Sheet</th><th>Address</th><th>Link Target</th></tr>
{rows.map(r => (<tr><td>{r.ws}</td><td>{r.addr}</td><td>{r.Target}</td></tr>))}
</table>
</> );
}
```
</details>
[^1]: The primary SheetJS DOM parsing methods are [`table_to_book`, `table_to_sheet`, and `sheet_add_dom`](/docs/api/utilities/html#html-table-input)
[^2]: HTML strings can be written using [`bookType: "html"` in the `write` or `writeFile` methods](/docs/api/write-options) or by using the [dedicated `sheet_to_html` utility function](/docs/api/utilities/html#html-table-output)

@ -1,11 +1,10 @@
---
title: Cell Comments and Notes
sidebar_label: Cell Comments
sidebar_position: 4
---
# Cell Comments
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
Comments and Notes have evolved over the years.
@ -42,6 +41,33 @@ The letter R (R) marks features parsed but not written in the format.
</details>
Comments and notes are cell annotations. Cells with comments or notes are marked
with a small triangle or `¬` in the upper-right corner.
Excel notes are standalone text boxes with adjustable background colors and
support for rich text. Historically people "replied" to comments by adding text
to the end of existing comments.
Excel comments are simple text boxes that allow users to enter plain text. Users
can reply to comments.
The following screenshot shows a spreadsheet with comments and a note.
- The note is associated with cell A1 (the cell with the red triangle). It has
a green gradient background fill.
- The comments are associated with cell A2 (the cell with the blue `¬`). There
are 2 comments from different authors. A "Reply" box appears below the thread.
![Excel comments and notes](pathname:///comments/types.png)
:::info pass
Google Sheets "notes" do not currently support rich text or background colors.
Apple Numbers supports "comments" but does not support "notes".
:::
## Basic Structure
Cell comments are objects stored in the `c` array of cell objects.

@ -1,11 +1,9 @@
---
title: Defined Names
sidebar_position: 5
---
# Defined Names
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
Defined names have evolved over the decades, with new features added over time:
@ -27,7 +25,62 @@ no way to specify a Unicode defined name in the SYLK format.
</details>
`wb.Workbook.Names` is an array of defined name objects which have the keys:
Defined names (sometimes called "named ranges") are labeled references to cells,
ranges, constants or formulae. Meaningful labels can make formula expressions
more readable and more robust to worksheet changes.
<details><summary><b>Why are Defined Names useful?</b> (click to show)</summary>
For example, the `NPV` formula function calculates the net present value of a
series of cashflows. In large workbooks, raw data will be stored in separate
worksheets and the interest rate will be stored in a separate "Model Parameters"
worksheet. Formulae may have references to multiple sheets:
```
=NPV('Model Parameters'!B2,Data!B2:F2)
^^^^^^^^^^^^^^^^^^^^^ --- interest rate
```
A defined name `Interest` referencing `'Model Parameters'!B2` would greatly
simplify the formula:
```
=NPV(Interest,Data!B2:F2)
^^^^^^^^ --- interest rate
```
Judicious use of Defined Names generally lead to fewer formula errors.
</details>
## Storage
The `Workbook` property of SheetJS workbook objects store workbook attributes.
The `Names` property of `Workbook` is an array of SheetJS defined name objects.
:::caution pass
Parsers do not always create the `Names` array or `Workbook` structure. Code
should test for the existence of the defined names array before use:
```js
var wb = XLSX.utils.book_new();
/* ensure the workbook structure exists */
/* highlight-start */
if(!wb.Workbook) wb.Workbook = {};
if(!wb.Workbook.Names) wb.Workbook.Names = [];
/* highlight-end */
/* add a new defined name */
wb.Workbook.Names.push({ Name: "MyData", Ref: "Sheet1!$A$1:$A$2" });
```
:::
## Defined Name Object
SheetJS defined name objects support the following properties:
| Key | Name in app | Description |
|:----------|:------------|:---------------------------------------------------|
@ -36,19 +89,7 @@ no way to specify a Unicode defined name in the SYLK format.
| `Ref` | "Refers To" | A1-Style Reference (`"Sheet1!$A$1:$D$20"`) |
| `Comment` | "Comment" | Comment (for supported file formats) |
Parsers do not always create the `Names` structure. Parsing and writing code
should test for the existence of the defined names array before use:
```js
/* ensure the workbook structure exists */
if(!wb.Workbook) wb.Workbook = {};
if(!wb.Workbook.Names) wb.Workbook.Names = [];
/* add a new defined name */
wb.Workbook.Names.push({ Name: "MyData", Ref: "Sheet1!$A$1:$A$2" });
```
## Ranges
### Ranges
Defined name references in formulae are internally shifted to the cell address.
For example, given the defined name
@ -73,7 +114,7 @@ The recommended approach is to fix the rows and columns of the reference:
{ Name: "MyData", Ref: "Sheet1!$A$1:$A$2" } // absolute reference
```
## Scoped Defined Names
### Scope
Excel allows two sheet-scoped defined names to share the same name. However, a
sheet-scoped name cannot collide with a workbook-scope name. Workbook writers

@ -1,11 +1,9 @@
---
title: Number Formats
sidebar_position: 6
---
# Number Formats
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
Modern applications separate "content" from "presentation". A value like `$3.50`
is typically stored as the underlying value (`3.50`) with a format (`$0.00`).
@ -64,19 +62,19 @@ To simplify editing, the applications will store the underlying values and the
number formats separately. For example, `$3.50` will be represented as the value
`3.5` with a number format that mandates a `$` sigil and 2 decimal places.
Number format metadata can be attached to each cell object in the `z` property:
The `z` property of SheetJS cell objects stores the number format metadata:
```js
/* set the format of cell B2 to "0.00%" */
worksheet["B2"].z = "0.00%";
```
When requested, the cell formatted text will be stored in the `w` property.
When requested, the formatted text will be stored in the `w` property.
## Live Demo
This example generates a worksheet with common number formats.
The number formats are explicitly assigned:
This example generates a worksheet with common number formats. The number
formats are explicitly assigned:
```js
/* assign number formats */

@ -1,4 +1,5 @@
---
title: VBA and Macros
sidebar_position: 7
---
@ -7,13 +8,10 @@ import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
# VBA and Macros
<details><summary><b>File Format Support</b> (click to show)</summary>
<details>
<summary><b>File Format Support</b> (click to show)</summary>
Note that XLSX does not support macros. The XLSM file format is nearly
identical to XLSX and supports macros.
XLSX does not support macros. The XLSM file format is nearly identical to XLSX
and supports macros.
| Formats | Basic | Storage Representation |
|:--------|:-----:|:-----------------------------------|
@ -27,13 +25,39 @@ no way to embed VBA in the XLSX format.
</details>
VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
property of the workbook object when the `bookVBA` option is `true`. They are
supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The supported format
writers automatically insert the data blobs if it is present in the workbook and
associate with the worksheet names.
Visual Basic for Applications (VBA) is a scripting platform embedded in Excel.
Users can include user-defined functions and macro code within spreadsheets.
:::note pass
The `vbaraw` property of the SheetJS workbook object is an encoded data blob
which includes the VBA macros and other metadata.
The SheetJS `read` and `readFile` methods do not pull VBA metadata by default.
If the `bookVBA` option is set to true, the `vbaraw` blob is created.
```js
var workbook = XLSX.read(data, { bookVBA: true });
var encoded_vba_blob = workbook.vbaraw;
```
The SheetJS `write` and `writeFile` methods will save the `vbaraw` blob if it is
present in the workbook object and if the output file format supports macros.
```js
workbook.vbaraw = encoded_vba_blob;
XLSX.writeFile(workbook, "SheetJSNewMacro.xlsm");
```
:::info pass
Newer versions of Excel support a new JavaScript API for writing user-defined
functions. Those addins are not stored in the spreadsheet files.
[The "Excel JavaScript API" demo](/docs/demos/extensions/excelapi) covers usage
of SheetJS libraries within the API.
:::
:::tip pass
The `vbaraw` property stores raw bytes. [SheetJS Pro](https://sheetjs.com/pro)
offers a special component for extracting macro text from the VBA blob, editing
@ -89,7 +113,7 @@ function SheetJSVBAFormula() { return ( <button onClick={async () => {
workbook.vbaraw = blob;
/* create an XLSM file and try to save to SheetJSVBANeu.xlsm */
XLSX.writeFile(workbook, "SheetJSVBANeu.xlsm", { bookVBA: true });
XLSX.writeFile(workbook, "SheetJSVBANeu.xlsm");
}}><b>Click to Generate file!</b></button> ); }
```
@ -129,7 +153,7 @@ XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
workbook.vbaraw = blob;
/* create an XLSM file and try to save to SheetJSVBANeu.xlsm */
XLSX.writeFile(workbook, "SheetJSVBANeu.xlsm", { bookVBA: true });
XLSX.writeFile(workbook, "SheetJSVBANeu.xlsm");
})();
```
@ -214,7 +238,6 @@ To ensure the writers export the VBA blob:
- The output format must support VBA (`xlsm` or `xlsb` or `xls` or `biff8`)
- The workbook object must have a valid `vbaraw` field
- The `write` or `writeFile` call must include the option `bookVBA: true`
This example uses [`vbaProject.bin`](pathname:///vba/vbaProject.bin) from the
[sample file](pathname:///vba/SheetJSVBAFormula.xlsm):
@ -241,7 +264,7 @@ function SheetJSVBAPrepared() { return ( <button onClick={async () => {
workbook.vbaraw = blob;
/* create an XLSM file and try to save to SheetJSVBAPreparedNeu.xlsm */
XLSX.writeFile(workbook, "SheetJSVBAPreparedNeu.xlsm", { bookVBA: true });
XLSX.writeFile(workbook, "SheetJSVBAPreparedNeu.xlsm");
}}><b>Click to Generate file!</b></button> ); }
```

@ -3,8 +3,7 @@ title: Row Properties
sidebar_position: 8
---
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
By default, all rows in a workbook are "Visible" and have a standard height.

@ -3,8 +3,7 @@ title: Column Properties
sidebar_position: 9
---
<details>
<summary><b>File Format Support</b> (click to show)</summary>
<details><summary><b>File Format Support</b> (click to show)</summary>
By default, all columns in a workbook are "Visible" and have a standard width.