diff --git a/docz/docs/03-demos/04-cloud/08-airtable.md b/docz/docs/03-demos/04-cloud/08-airtable.md index 86ac191..17fd292 100644 --- a/docz/docs/03-demos/04-cloud/08-airtable.md +++ b/docz/docs/03-demos/04-cloud/08-airtable.md @@ -4,8 +4,10 @@ pagination_prev: demos/desktop/index pagination_next: demos/grid --- -At the time of writing (2023 February 15), Airtable recommends Personal Access -Tokens for interacting with the official API. +Airtable recommends Personal Access Tokens for interacting with their API. When +fetching data from the API, the result will include an array of row objects that +can be converted to a worksheet with `XLSX.utils.json_to_sheet`. The API methods +to write data will accept row objects generated by `XLSX.utils.sheet_to_json`. ## NodeJS Integration @@ -76,6 +78,13 @@ async function airtable_load_worksheet(table, worksheet) { ## Complete Example +:::note + +This demo was last tested on 2023 February 15. At the time, it was possible to +create a free account with API access. + +::: + 0) Create a free Airtable account. ### Personal Access Token diff --git a/docz/docs/03-demos/06-data/02-storageapi.md b/docz/docs/03-demos/06-data/02-storageapi.md index cb691d5..43097ae 100644 --- a/docz/docs/03-demos/06-data/02-storageapi.md +++ b/docz/docs/03-demos/06-data/02-storageapi.md @@ -9,23 +9,80 @@ sidebar_custom_props: The Storage API, encompassing `localStorage` and `sessionStorage`, describes simple key-value stores that only support string values and keys. -Arrays of objects can be stored using `JSON.stringify` using row index as key: +This demo covers two common use patterns: + +- "Row Objects" shows a simple convention for loading and storing row objects +- "Simple Strings" discusses how to persist and recover a raw Storage + +## Row Objects + +Consider the following array of objects of data: ```js -const aoo = XLSX.utils.sheet_to_json(ws); -for(var i = 0; i < aoo.length; ++i) localStorage.setItem(i, JSON.stringify(aoo[i])); +[ + { Name: "Barack Obama", Index: 44 }, + { Name: "Donald Trump", Index: 45 }, + { Name: "Joseph Biden", Index: 46 } +] ``` -Recovering the array of objects is possible by using `JSON.parse`: +Storage API expects values to be strings. The simplest approach is to stringify +row objects using `JSON.stringify` and store using the row index as a key: + +| Key | Value | +|:---:|:-------------------------------------| +| 0 | `{"Name":"Barack Obama","Index":44}` | +| 1 | `{"Name":"Donald Trump","Index":45}` | +| 2 | `{"Name":"Joseph Biden","Index":46}` | + +#### 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: ```js -const aoo = []; -for(var i = 0; i < localStorage.length; ++i) aoo.push(JSON.parse(localStorage.getItem(i))); -const ws = XLSX.utils.json_to_sheet(aoo); +function sheet_to_localStorage(worksheet) { + const aoo = XLSX.utils.sheet_to_json(worksheet); + for(let i = 0; i < aoo.length; ++i) { + localStorage.setItem(i, JSON.stringify(aoo[i])); + } +} ``` -This example will fetch , fill `localStorage` with -rows, then generate a worksheet from the rows and write to a new file. +#### Exporting Data + +`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: + +```js +function localStorage_to_sheet() { + const aoo = []; + for(let i = 0; i < localStorage.length; ++i) { + aoo.push(JSON.parse(localStorage.getItem(i))); + } + return XLSX.utils.json_to_sheet(aoo); +} +``` + +### Live Demo + +:::note + +This demo was last tested on 2023 February 26. + +::: + +This example will fetch , fill `localStorage` +with rows, then generate a worksheet from the rows and write to a new file. + +After saving the exported file, the Local Storage can be inspected in the +"Local Storage" section of the "Application" Tab of Developer Tools: + +![Local Storage view in Developer Tools](pathname:///storageapi/lstorage.png) :::caution @@ -36,14 +93,13 @@ is strongly recommended to convert that array to a worksheet directly. ```jsx live function SheetJStorage() { - const [url, setUrl] = React.useState("https://sheetjs.com/data/cd.xls"); + const [url, setUrl] = React.useState("https://sheetjs.com/pres.numbers"); const set_url = React.useCallback((evt) => setUrl(evt.target.value)); const [out, setOut] = React.useState(""); const xport = React.useCallback(async() => { // get first worksheet data as array of objects - const ab = await (await fetch(url)).arrayBuffer(); - const wb = XLSX.read(ab), wsname = wb.SheetNames[0]; - const aoo = XLSX.utils.sheet_to_json(wb.Sheets[wsname]); + const wb = XLSX.read(await (await fetch(url)).arrayBuffer()); + const aoo = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); // reset and populate localStorage localStorage.clear(); @@ -65,9 +121,59 @@ function SheetJStorage() { XLSX.writeFile(new_wb, "SheetJStorage.xlsx"); }); - return ( <> {out && (<>{url}
{out}
)} + return ( <> + {out && (<>{url}
{out}
)} URL:
); } ``` + +## Simple Strings + +The ["Row Objects" approach](#row-objects) is strongly recommended when trying +to store or recover arrays of row objects. + +When the goal is to save an existing Storage, the general representation is an +array of pairs. Consider the following data in Local Storage: + +| Key | Value | +|:---:|:----------| +| "b" | "Logical" | +| "n" | "Numeric" | +| "s" | "Textual" | + +The natural representation is an array of arrays: + +```js +[ + [ "b", "Logical" ], + [ "n", "Numeric" ], + [ "s", "Textual" ] +] +``` + +#### Exporting Storage + +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: + +```js +function localStorage_to_ws() { + const aoa = Object.entries(localStorage); + return XLSX.utils.aoa_to_sheet(aoa); +} +``` + +#### 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: + +```js +function ws_to_localStorage(ws) { + const aoa = XLSX.utils.sheet_to_json(ws, { header: 1 }); + aoa.forEach(([key, val]) => localStorage.setItem(key, val)); +} +``` diff --git a/docz/docs/03-demos/07-worker.md b/docz/docs/03-demos/07-worker.md index 3b1c4e1..6d22f85 100644 --- a/docz/docs/03-demos/07-worker.md +++ b/docz/docs/03-demos/07-worker.md @@ -125,23 +125,34 @@ importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js For production use, it is highly encouraged to download and host the script. -
ECMAScript Module Support (click to show) +
ECMAScript Module Support (click to hide) :::note Browser Compatibility ESM is supported in Web Workers in the Chromium family of browsers (including Chrome and Edge) as well as in browsers powered by WebKit (including Safari). -For support in legacy browsers like Firefox, `importScripts` should be used. +For legacy browsers like Firefox and IE, `importScripts` should be used. ::: +Browser ESM imports require a complete URL including the `.mjs` extension: + ```js import * as XLSX from "https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs"; ``` -When using modules, the script must be served with the correct MIME type and the -Worker constructor must set the `type` option: +When using Worker ESM, the Worker constructor must set the `type` option: + +```js +const worker = new Worker( + url_to_worker_script, + // highlight-next-line + { type: "module" } // second argument to Worker constructor +); +``` + +Inline workers additionally require the Blob MIME type `text/javascript`: ```js const worker_code = `\ @@ -158,13 +169,15 @@ const worker = new Worker( ) ), // highlight-next-line - {type: "module"} // second argument to Worker constructor + { type: "module" } // second argument to Worker constructor ); ```
-## Downloading a Remote File +## Live Demos + +### Downloading a Remote File :::note fetch in Web Workers @@ -252,7 +265,7 @@ self.addEventListener('message', async(e) => {
-## Creating a Local File +### Creating a Local File :::caution Writing files from Web Workers @@ -357,7 +370,7 @@ self.addEventListener('message', async(e) => { -## User-Submitted File +### User-Submitted File :::note FileReaderSync @@ -375,9 +388,9 @@ sequenceDiagram actor User participant Page participant Worker - User->>Page: click button + User->>Page: submit file activate Page - Page->>Worker: send URL + Page->>Worker: send pointer deactivate Page activate Worker Note over Worker: fetch file @@ -454,7 +467,7 @@ self.addEventListener('message', (e) => { -## Streaming Write +### Streaming Write A more general discussion, including row-oriented processing demos, is included in the ["Large Datasets"](/docs/demos/stream#browser) demo. diff --git a/docz/static/storageapi/lstorage.png b/docz/static/storageapi/lstorage.png new file mode 100644 index 0000000..89e161f Binary files /dev/null and b/docz/static/storageapi/lstorage.png differ