diff --git a/docz/docs/02-getting-started/02-examples/04-import.md b/docz/docs/02-getting-started/02-examples/04-import.md index b05bb27..7fb7d03 100644 --- a/docz/docs/02-getting-started/02-examples/04-import.md +++ b/docz/docs/02-getting-started/02-examples/04-import.md @@ -336,7 +336,7 @@ case it is easier to post-process the raw data: ```js let last_year = 0; -raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); +raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); ``` :::caution pass @@ -411,6 +411,32 @@ raw_data.forEach(r => { }); ``` +Observing that `r[0]` must equal `last_value`, the inner statement can be +rewritten to compute the final value and assign to both variables: + +```js +let last_value = null; +raw_data.forEach(r => { + last_value = r[0] = (r[0] != null ? r[0] : last_value); +}); +``` + +:::caution pass + +It is tempting to take advantage of implicit logical rules: + +```js +let last_value = null; +raw_data.forEach(r => { + last_value = r[0] = (r[0] || last_value); +}); +``` + +This is strongly discouraged since the value `0` is false. The explicit `null` +test distinguishes `null` and `undefined` from `0` + +::: + After post-processing, the rows now have proper year fields: @@ -443,7 +469,7 @@ function SheetJSAoAFilled() { const raw_data = XLSX.utils.sheet_to_json(worksheet, {header:1}); /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); /* pull Excel rows 13:16 (SheetJS 12:15) */ const rows_13_16 = raw_data.slice(12,16); @@ -479,7 +505,7 @@ function SheetJSAoAFiltered() { const raw_data = XLSX.utils.sheet_to_json(worksheet, {header:1}); /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); /* display data */ @@ -553,7 +579,7 @@ function SheetJSObjects() { const raw_data = XLSX.utils.sheet_to_json(worksheet, {header:1}); /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); /* generate row objects */ @@ -660,7 +686,7 @@ function StudentAidTotal() { /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); @@ -715,7 +741,7 @@ Save the following script to `SheetJSStandaloneDemo.html`: \n\ /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); \n\ /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); @@ -768,7 +794,7 @@ const XLSX = require("xlsx"); /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); @@ -783,7 +809,6 @@ const XLSX = require("xlsx"); console.log(`${o.FY}\t${o.FQ||""}\t${o.total}`); }); })(); - ``` After saving the script, run the script: @@ -829,7 +854,7 @@ Save the following script to `SheetJSNW.html`: \n\ /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); \n\ /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); @@ -923,7 +948,7 @@ const App = () => { /* fill years */ var last_year = 0; - raw_data.forEach(r => (r[0] != null) ? (last_year = r[0]) : (r[0] = last_year)); + raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year)); /* select data rows */ const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023); diff --git a/docz/docs/03-demos/01-frontend/01-react.md b/docz/docs/03-demos/01-frontend/01-react.md index 1052bc9..31b0ac3 100644 --- a/docz/docs/03-demos/01-frontend/01-react.md +++ b/docz/docs/03-demos/01-frontend/01-react.md @@ -453,7 +453,6 @@ const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({ /* column labels: encode_col translates 0 -> "A", 1 -> "B", 2 -> "C", ... */ name: XLSX.utils.encode_col(i) })); - ``` ![Column labels for headers](pathname:///react/cols.png) diff --git a/docz/docs/03-demos/01-frontend/08-bundler.md b/docz/docs/03-demos/01-frontend/08-bundler.md index 07d382c..2c652fc 100644 --- a/docz/docs/03-demos/01-frontend/08-bundler.md +++ b/docz/docs/03-demos/01-frontend/08-bundler.md @@ -94,7 +94,7 @@ npx browserify xlsxworker.js > worker.js 4) Spin up a local web server: -``` +```bash npx http-server ``` @@ -1191,7 +1191,7 @@ This demo was last tested on 2023 May 07 against ViteJS `4.3.5` 1) Create a new ViteJS project: -``` +```bash npm create vite@latest sheetjs-vite -- --template vue-ts cd sheetjs-vite npm i @@ -1258,7 +1258,7 @@ writeFileXLSX(workbook, "Presidents.xlsx"); 5) Run `npx vite build` and verify the generated pages work by running a local web server in the `dist` folder: -``` +```bash npx http-server dist/ ``` diff --git a/docz/docs/03-demos/04-static/05-vitejs.md b/docz/docs/03-demos/04-static/05-vitejs.md index db904f6..3d08ce3 100644 --- a/docz/docs/03-demos/04-static/05-vitejs.md +++ b/docz/docs/03-demos/04-static/05-vitejs.md @@ -265,7 +265,7 @@ Open that script. Searching for `Bill Clinton` reveals the following: -``` +```js {"Name":"Bill Clinton","Index":42} ``` diff --git a/docz/docs/03-demos/05-mobile/01-reactnative.md b/docz/docs/03-demos/05-mobile/01-reactnative.md index 886fb03..40cf09b 100644 --- a/docz/docs/03-demos/05-mobile/01-reactnative.md +++ b/docz/docs/03-demos/05-mobile/01-reactnative.md @@ -215,7 +215,7 @@ const wb = XLSX.read(ab); :::note -This demo was tested on an Intel Mac on 2023 July 02 with RN `0.72.1`. +This demo was tested on an Intel Mac on 2023 August 20 with RN `0.72.4`. The iOS simulator runs iOS 16.2 on an iPhone SE (3rd generation). @@ -226,7 +226,7 @@ The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3. 1) Create project: ```bash -npx -y react-native@0.72.1 init SheetJSRNFetch --version="0.72.1" +npx -y react-native@0.72.4 init SheetJSRNFetch --version="0.72.4" ``` 2) Install shared dependencies: @@ -253,9 +253,9 @@ curl -LO https://docs.sheetjs.com/reactnative/App.tsx When the demo was last tested on macOS, `java -version` displayed the following: ``` -openjdk version "11.0.19" 2023-04-18 LTS -OpenJDK Runtime Environment Zulu11.64+19-CA (build 11.0.19+7-LTS) -OpenJDK 64-Bit Server VM Zulu11.64+19-CA (build 11.0.19+7-LTS, mixed mode) +openjdk version "11.0.20" 2023-07-18 LTS +OpenJDK Runtime Environment Zulu11.66+15-CA (build 11.0.20+8-LTS) +OpenJDK 64-Bit Server VM Zulu11.66+15-CA (build 11.0.20+8-LTS, mixed mode) ``` ::: @@ -296,7 +296,7 @@ tapping "Import data from a spreadsheet", verify that the app shows new data: :::warning pass -iOS testing requires macOS. It does not work on Windows. +iOS testing requires macOS. It does not work on Windows or Linux. ::: diff --git a/docz/docs/03-demos/05-mobile/03-quasar.md b/docz/docs/03-demos/05-mobile/03-quasar.md index a0829f4..63dea30 100644 --- a/docz/docs/03-demos/05-mobile/03-quasar.md +++ b/docz/docs/03-demos/05-mobile/03-quasar.md @@ -253,7 +253,6 @@ This uses two functions that should be added to the component script: // highlight-end } }); - ``` The app should now show two buttons at the bottom: diff --git a/docz/docs/03-demos/07-data/09-alasql.md b/docz/docs/03-demos/07-data/09-alasql.md index d5a91b9..f593421 100644 --- a/docz/docs/03-demos/07-data/09-alasql.md +++ b/docz/docs/03-demos/07-data/09-alasql.md @@ -13,8 +13,11 @@ sidebar_custom_props: import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; -AlaSQL is a pure JavaScript in-memory SQL database. It has built-in support for -SheetJS through the `XLSX` target operator. +[AlaSQL](https://alasql.org/) is a pure JavaScript in-memory SQL database. It +has built-in support for SheetJS through the `XLSX` target operator. + +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. This demo covers basic concepts pertaining to data import and export. The official documentation includes advanced examples and deployment tips as well as @@ -27,7 +30,7 @@ This demo was tested in the following environments: | Environment | AlaSQL | Date | |:--------------------|:-------|:----------:| | NodeJS | 3.1.0 | 2023-07-24 | -| Standalone (Chrome) | 3.0.0 | 2023-04-09 | +| Standalone (Chrome) | 3.0.0 | 2023-08-20 | ::: diff --git a/docz/docs/03-demos/07-data/25-mongodb.md b/docz/docs/03-demos/07-data/25-mongodb.md index af7f017..95fffc5 100644 --- a/docz/docs/03-demos/07-data/25-mongodb.md +++ b/docz/docs/03-demos/07-data/25-mongodb.md @@ -47,8 +47,8 @@ const ws = utils.json_to_sheet(aoo); :::note -This demo was last tested on 2023 February 23 with MongoDB CE 6.0.4, MongoDB -connector module 5.1.0 and NodeJS 18.14.2. +This demo was last tested on 2023 August 20 with MongoDB CE 7.0.0, MongoDB +connector module 5.7.0 and NodeJS 20.5.1. ::: @@ -57,11 +57,11 @@ connector module 5.1.0 and NodeJS 18.14.2. ```bash brew tap mongodb/brew brew update -brew install mongodb-community@6.0 +brew install mongodb-community ``` -1) Start a MongoDB server on `localhost` (follow official instructions). To run -in the foreground on Intel MacOS: +1) Start a MongoDB server on `localhost` (follow official instructions). +If `brew` was used to install MongoDB, the following command starts a server: ```bash /usr/local/opt/mongodb-community/bin/mongod --config /usr/local/etc/mongod.conf @@ -73,7 +73,7 @@ in the foreground on Intel MacOS: mkdir sheetjs-mongo cd sheetjs-mongo npm init -y -npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz mongodb@5.1.0`} +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz mongodb@5.7.0`} 3) Save the following to `SheetJSMongoCRUD.mjs` (the key step is highlighted): diff --git a/docz/docs/03-demos/09-cloud/02-netsuite.md b/docz/docs/03-demos/09-cloud/02-netsuite.md index 08856b5..86317d5 100644 --- a/docz/docs/03-demos/09-cloud/02-netsuite.md +++ b/docz/docs/03-demos/09-cloud/02-netsuite.md @@ -24,7 +24,7 @@ This demo was verified by NetSuite consultants in the following deployments: | `@NScriptType` | `@NApiVersion` | Date | |:----------------|:---------------|:-----------| -| ScheduledScript | 2.1 | 2023-03-09 | +| ScheduledScript | 2.1 | 2023-08-18 | | Restlet | 2.1 | 2023-04-20 | | Suitelet | 2.1 | 2023-07-21 | | MapReduceScript | 2.1 | 2023-07-31 | diff --git a/docz/docs/03-demos/12-engines/02_v8.md b/docz/docs/03-demos/12-engines/02_v8.md index 81b955d..2ad3afd 100644 --- a/docz/docs/03-demos/12-engines/02_v8.md +++ b/docz/docs/03-demos/12-engines/02_v8.md @@ -350,7 +350,6 @@ fn eval_code_ab(scope: &mut v8::HandleScope, code: &str) -> Vec { result.byte_length() ).to_vec(); } } - ``` :::note diff --git a/docz/docs/03-demos/12-engines/20_chakra.md b/docz/docs/03-demos/12-engines/20_chakra.md index f06e0b6..d48bf93 100644 --- a/docz/docs/03-demos/12-engines/20_chakra.md +++ b/docz/docs/03-demos/12-engines/20_chakra.md @@ -299,7 +299,7 @@ curl -LO https://sheetjs.com/pres.numbers`} 6) Run the test program: -``` +```bash ./sheetjs.ch pres.numbers ``` @@ -361,6 +361,6 @@ ready, it will read the bundled test data and print the contents as CSV. 5) Run the script using the ChakraCore standalone binary: -``` +```bash ./ch xlsx.chakra.js ``` diff --git a/docz/docs/03-demos/index.md b/docz/docs/03-demos/index.md index 876a3ef..7925768 100644 --- a/docz/docs/03-demos/index.md +++ b/docz/docs/03-demos/index.md @@ -4,11 +4,18 @@ pagination_next: solutions/input hide_table_of_contents: true --- -# Demo Projects +# Demos Demos include complete examples and short discussions. For features that can run in the web browser, demos will include interactive examples. +:::tip pass + +If a demo for a library or framework is not included here, please leave a note +in the [issue tracker](https://git.sheetjs.com/sheetjs/docs.sheetjs.com/issues) + +::: + ### JavaScript APIs - [`XMLHttpRequest and fetch`](/docs/demos/net/network) @@ -66,6 +73,7 @@ run in the web browser, demos will include interactive examples. - [`NextJS`](/docs/demos/static/nextjs) - [`NuxtJS`](/docs/demos/static/nuxtjs) - [`SvelteKit`](/docs/demos/static/svelte) +- [`Webpack`](/docs/demos/static/webpack) ### App Extensions @@ -129,10 +137,3 @@ run in the web browser, demos will include interactive examples. - [`QuickJS (C)`](/docs/demos/engines/quickjs) - [`ExecJS (Ruby)`](/docs/demos/engines/rb) - [`JavaScript::Engine (Perl)`](/docs/demos/engines/perl) - - -:::note - -If a demo for a library or framework is not included here, please leave a note. - -::: diff --git a/docz/docs/06-solutions/01-input.md b/docz/docs/06-solutions/01-input.md index 609a700..207b1df 100644 --- a/docz/docs/06-solutions/01-input.md +++ b/docz/docs/06-solutions/01-input.md @@ -522,7 +522,7 @@ const workbook = XLSX.read(data);`} Deno must be run with the `--allow-net` flag to enable network requests: -``` +```bash deno run --allow-net test-fetch.ts ``` diff --git a/docz/docs/07-csf/04-book.md b/docz/docs/07-csf/04-book.md index 095d7a0..fbcfbad 100644 --- a/docz/docs/07-csf/04-book.md +++ b/docz/docs/07-csf/04-book.md @@ -88,3 +88,12 @@ discussed in more detail in ["Defined Names"](/docs/csf/features/names) | `CodeName` | [VBA Workbook Name](/docs/csf/features/vba) | | `date1904` | epoch: 0/false for 1900 system, 1/true for 1904 | | `filterPrivacy` | Warn or strip personally identifying info on save | + +### Sheet Metadata + +`wb.Workbook.Sheets` is an array of sheet metadata objects which have the keys: + +| Key | Description | +|:----------------|:----------------------------------------------------| +| `Hidden` | [Sheet Visibility](/docs/csf/features/visibility) | +| `CodeName` | [VBA Sheet Code Name](/docs/csf/features/vba) | diff --git a/docz/docs/07-csf/07-features/03-dates.md b/docz/docs/07-csf/07-features/01-dates.md similarity index 99% rename from docz/docs/07-csf/07-features/03-dates.md rename to docz/docs/07-csf/07-features/01-dates.md index 232c1e2..be03847 100644 --- a/docz/docs/07-csf/07-features/03-dates.md +++ b/docz/docs/07-csf/07-features/01-dates.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 1 --- # Dates and Times diff --git a/docz/docs/07-csf/07-features/01-formulae.md b/docz/docs/07-csf/07-features/02-formulae.md similarity index 94% rename from docz/docs/07-csf/07-features/01-formulae.md rename to docz/docs/07-csf/07-features/02-formulae.md index 018e4b5..0ee9cd9 100644 --- a/docz/docs/07-csf/07-features/01-formulae.md +++ b/docz/docs/07-csf/07-features/02-formulae.md @@ -1,5 +1,5 @@ --- -sidebar_position: 1 +sidebar_position: 2 --- # Formulae @@ -16,17 +16,17 @@ while the writer will translate from A1-Style strings to the file format. |:------------------|:-----:|:-----:|:-----:|:-------:|:-----------------------| | XLSX / XLSM | ✔ | ✔ | ✔ | ✔ | A1-Style strings | | XLSB | ✔ | | ✔ | ✔ | BIFF parsed tokens | -| XLS | ✔ | | ✔ | * | BIFF parsed tokens | -| XLML | ✔ | ✔ | ✔ | * | RC-style strings | -| SYLK | ✔ | ✔ | | * | A1/RC-style strings | -| CSV / TXT | ✔ | ✔ | * | * | A1-Style strings | -| ODS / FODS / UOS | ✔ | ✔ | | * | OpenFormula strings | -| WK\* | ✔ | | | * | Lotus parsed tokens | -| WQ\* / WB\* / QPW | | | | * | Quattro Pro tokens | -| NUMBERS | | | | * | Numbers parsed tokens | +| XLS | ✔ | | ✔ | ✕ | BIFF parsed tokens | +| XLML | ✔ | ✔ | ✔ | ✕ | RC-style strings | +| SYLK | ✔ | ✔ | | ✕ | A1/RC-style strings | +| CSV / TXT | ✔ | ✔ | ✕ | ✕ | A1-Style strings | +| ODS / FODS / UOS | ✔ | ✔ | | ✕ | OpenFormula strings | +| WK\* | ✔ | | | ✕ | Lotus parsed tokens | +| WQ\* / WB\* / QPW | | | | ✕ | Quattro Pro tokens | +| NUMBERS | | | | ✕ | Numbers parsed tokens | -Asterisks (*) mark features that are not supported by the file formats. There is -no way to mark a dynamic array formula in the XLS file format. +X (✕) marks features that are not supported by the file formats. There is no way +to mark a dynamic array formula in the XLS file format. @@ -163,7 +163,7 @@ function ConcatFormula(props) { }; return ( <>
- addr: + Cell: {!ws[addr] ? ( Cell {addr} not found ) : ( @@ -201,6 +201,8 @@ var worksheet = XLSX.utils.aoa_to_sheet([
Live Example (click to hide) +This demo creates a worksheet where `A1=1`, `A2=2`, and `A3=A1+A2`. + ```jsx live /* The live editor requires this function wrapper */ function ExportSimpleFormula(props) { @@ -238,10 +240,13 @@ var worksheet = XLSX.utils.aoa_to_sheet([ ]) ``` +:::note pass + If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro) offers a formula calculator component for evaluating expressions, updating values and dependent cells, and refreshing entire workbooks. +::: ## Array Formulae diff --git a/docz/docs/07-csf/07-features/02-hyperlinks.md b/docz/docs/07-csf/07-features/03-hyperlinks.md similarity index 81% rename from docz/docs/07-csf/07-features/02-hyperlinks.md rename to docz/docs/07-csf/07-features/03-hyperlinks.md index 41df815..7f10b6e 100644 --- a/docz/docs/07-csf/07-features/02-hyperlinks.md +++ b/docz/docs/07-csf/07-features/03-hyperlinks.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 --- # Hyperlinks @@ -124,7 +124,7 @@ function SheetJSParseLinks(props) { ## Remote Links -HTTP / HTTPS links can be used directly: +HTTP and HTTPS links can be used directly: ```js ws["A2"].l = { Target: "https://docs.sheetjs.com/docs/csf/features/hyperlinks" }; @@ -208,6 +208,14 @@ ws["C3"].l = { Target: "#SheetJSDName" }; /* Link to Defined Name */
Live Example (click to show) +This demo creates a workbook with two worksheets. In the first worksheet: + +- Cell `A1` ("Same") will link to the range `B2:D4` in the first sheet +- Cell `B1` ("Cross") will link to the range `B2:D4` in the second sheet +- Cell `C1` ("Name") will link to the range in the defined name `SheetJSDN` + +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 ( ); } - ```
diff --git a/docz/docs/07-csf/07-features/08-visibility.md b/docz/docs/07-csf/07-features/08-visibility.md new file mode 100644 index 0000000..37c305f --- /dev/null +++ b/docz/docs/07-csf/07-features/08-visibility.md @@ -0,0 +1,150 @@ +--- +title: Sheet Visibility +sidebar_position: 7 +--- + +
+ File Format Support (click to show) + +By default, all sheets in a workbook are "Visible". The standard "Hidden" state +is controlled through the context menu in the sheet tab bar. The "Very Hidden" +state is controlled through the "Visibility" property in the VBA editor. + +| Formats | Hidden | Very Hidden | +|:----------|:------:|:-----------:| +| XLSX/XLSM | ✔ | ✔ | +| XLSB | ✔ | ✔ | +| XLML | ✔ | ✔ | +| BIFF8 XLS | ✔ | ✔ | +| BIFF5 XLS | ✔ | ✔ | + +
+ +Excel enables hiding sheets in the lower tab bar. The sheet data is stored in +the file but the UI does not readily make it available. + +Standard "hidden" sheets are revealed in the "Unhide" menu. + +Excel also has "very hidden" sheets which cannot be revealed in the menu. They +are only accessible in the VB Editor! + +## Storage + +The visibility setting is stored in the `Hidden` property of the corresponding +[metadata in the `wb.Workbook.Sheets` array](/docs/csf/book#sheet-metadata) + +The recognized values are listed below: + +| Value | Definition | VB Editor "Visible" Property | +|:-----:|:------------|:-----------------------------| +| 0 | Visible | `-1 - xlSheetVisible` | +| 1 | Hidden | ` 0 - xlSheetHidden` | +| 2 | Very Hidden | ` 2 - xlSheetVeryHidden` | + +If the respective Sheet entry does not exist or if the `Hidden` property is not +set, the worksheet is visible. + +### Parsing + +Since worksheet visibility is stored in the workbook, both the workbook object +and the sheet name must be known to determine visibility setting. + +```js +function get_sheet_visibility(workbook, sheet_name) { + // if the metadata does not exist for the sheet, the sheet is visible + if(!workbook.Workbook) return 0; + if(!workbook.Workbook.Sheets) return 0; + + var idx = workbook.SheetNames.indexOf(sheet_name); + if(idx == -1) throw new Error(`Sheet ${sheet_name} missing from workbook`); + + var meta = workbook.Workbook.Sheets[idx]; + return meta && meta.Hidden || 0; +} +``` + +Typically the distinction between "hidden" and "very hidden" is not relevant for +applications. The values were chosen to make logical negation work as expected: + +```js +function is_sheet_visible(workbook, sheet_name) { + return !get_sheet_visibility(workbook, sheet_name); // true if visible +} +``` + +### Writing + +When assigning, the entire workbook metadata structure should be tested and +constructed if necessary: + +```js +function set_sheet_visibility(workbook, sheet_name, Hidden) { + var idx = workbook.SheetNames.indexOf(sheet_name); + if(idx == -1) throw new Error(`Sheet ${sheet_name} missing from workbook`); + + // if the metadata does not exist for the sheet, create it + if(!workbook.Workbook) workbook.Workbook = {}; + if(!workbook.Workbook.Sheets) workbook.Workbook.Sheets = []; + if(!workbook.Workbook.Sheets[idx]) workbook.Workbook.Sheets[idx] = {}; + + // set visibility + workbook.Workbook.Sheets[idx].Hidden = Hidden; +} +``` + +## Demo + +[This test file](pathname:///files/sheet_visibility.xlsx) has three sheets: + +- "Visible" is visible +- "Hidden" is hidden +- "VeryHidden" is very hidden + +![Screenshot](pathname:///files/sheet_visibility.png) + +The live demo fetches the test file and displays visibility information. + +```jsx live +function Visibility(props) { + const [wb, setWB] = React.useState({SheetNames:[]}); + const [sheets, setSheets] = React.useState([]); + const vis = [ "Visible", "Hidden", "Very Hidden" ]; + + React.useEffect(async() => { + const f = await fetch("/files/sheet_visibility.xlsx"); + const ab = await f.arrayBuffer(); + const wb = XLSX.read(ab); + setWB(wb); + /* State will be set to the `Sheets` property array */ + setSheets(wb.Workbook.Sheets); + }, []); + + return (
Formula{ws[addr].f}
Value{ws[addr].v}
+ + {wb.SheetNames.map((n,i) => { + const h = ((((wb||{}).Workbook||{}).Sheets||[])[i]||{}).Hidden||0; + return ( + + + + ); + })}
NameValueHidden
{n}{h} - {vis[h]}{!h ? "No" : "Yes"}
); +} +``` + +:::info pass + +The live codeblock tests for visibility with: + +```js +const h = ((((wb||{}).Workbook||{}).Sheets||[])[i]||{}).Hidden||0; +``` + +With modern JS, this can be written as + +```js +const h = wb?.Workbook?.Sheets?.[i]?.Hidden||0; +``` + +::: + diff --git a/docz/docs/07-csf/07-features/index.md b/docz/docs/07-csf/07-features/index.md index 2d5209b..d969e29 100644 --- a/docz/docs/07-csf/07-features/index.md +++ b/docz/docs/07-csf/07-features/index.md @@ -138,91 +138,3 @@ follow the priority order: 3) use `wch` character count if available - -## Sheet Visibility - -
- Format Support (click to show) - -**Hidden Sheets**: XLSX/M, XLSB, BIFF8/BIFF5 XLS, XLML - -**Very Hidden Sheets**: XLSX/M, XLSB, BIFF8/BIFF5 XLS, XLML - -
- -Excel enables hiding sheets in the lower tab bar. The sheet data is stored in -the file but the UI does not readily make it available. Standard hidden sheets -are revealed in the "Unhide" menu. Excel also has "very hidden" sheets which -cannot be revealed in the menu. It is only accessible in the VB Editor! - -The visibility setting is stored in the `Hidden` property of sheet props array. - -| Value | Definition | VB Editor "Visible" Property | -|:-----:|:------------|:-----------------------------| -| 0 | Visible | `-1 - xlSheetVisible` | -| 1 | Hidden | ` 0 - xlSheetHidden` | -| 2 | Very Hidden | ` 2 - xlSheetVeryHidden` | - -If the respective Sheet entry does not exist or if the `Hidden` property is not -set, the worksheet is visible. - -**List all worksheets and their visibility settings** - -```js -wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] }) -// [ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ] -``` - -**Check if worksheet is visible** - -Non-Excel formats do not support the Very Hidden state. The best way to test -if a sheet is visible is to check if the `Hidden` property is logical truth: - -```js -wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] }) -// [ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ] -``` - -
- Live Example (click to show) - - -[This test file](pathname:///files/sheet_visibility.xlsx) has three sheets: - -- "Visible" is visible -- "Hidden" is hidden -- "VeryHidden" is very hidden - -![Screenshot](pathname:///files/sheet_visibility.png) - -**Live demo** - -```jsx live -function Visibility(props) { - const [sheets, setSheets] = React.useState([]); - const names = [ "Visible", "Hidden", "Very Hidden" ]; - - React.useEffect(async() => { - const f = await fetch("/files/sheet_visibility.xlsx"); - const ab = await f.arrayBuffer(); - const wb = XLSX.read(ab); - - /* State will be set to the `Sheets` property array */ - setSheets(wb.Workbook.Sheets); - }, []); - - return ( - - {sheets.map((x,i) => ( - - - - - - - - ))}
NameValueHidden
{x.name}{x.Hidden} - {names[x.Hidden]}{!x.Hidden ? "No" : "Yes"}
); -} -``` - -
diff --git a/docz/static/mongodb/SheetJSMongoCRUD.mjs b/docz/static/mongodb/SheetJSMongoCRUD.mjs new file mode 100644 index 0000000..fc35441 --- /dev/null +++ b/docz/static/mongodb/SheetJSMongoCRUD.mjs @@ -0,0 +1,31 @@ +import { writeFile, set_fs, utils } from 'xlsx'; +import * as fs from 'fs'; set_fs(fs); +import { MongoClient } from 'mongodb'; + +const url = 'mongodb://localhost:27017/sheetjs'; +const db_name = 'sheetjs'; + +/* Connect to mongodb server */ +const client = await MongoClient.connect(url, { useUnifiedTopology: true }); + +/* Sample data table */ +const db = client.db(db_name); +try { await db.collection('pres').drop(); } catch(e) {} +const pres = db.collection('pres'); +await pres.insertMany([ + { name: "Barack Obama", idx: 44 }, + { name: "Donald Trump", idx: 45 }, + { name: "Joseph Biden", idx: 46 } +], {ordered: true}); + +/* Create worksheet from collection */ +const aoo = await pres.find({}, {projection:{_id:0}}).toArray(); +const ws = utils.json_to_sheet(aoo); + +/* Export to XLSX */ +const wb = utils.book_new(); +utils.book_append_sheet(wb, ws, "Presidents"); +writeFile(wb, "SheetJSMongoCRUD.xlsx"); + +/* Close connection */ +client.close(); \ No newline at end of file