diff --git a/docz/docs/02-getting-started/02-examples/02-export.mdx b/docz/docs/02-getting-started/02-examples/02-export.mdx index 4b88522..a4e737e 100644 --- a/docz/docs/02-getting-started/02-examples/02-export.mdx +++ b/docz/docs/02-getting-started/02-examples/02-export.mdx @@ -484,8 +484,14 @@ The data is in the workbook and can be exported. ![Rough export](pathname:///example/rough.png) There are multiple opportunities for improvement: the headers can be renamed and -the column widths can be adjusted. [SheetJS Pro](https://sheetjs.com/pro) offers -additional styling options like cell styling and frozen rows. +the column widths can be adjusted. + +:::tip pass + +[SheetJS Pro](https://sheetjs.com/pro) offers additional styling options like +cell styling and frozen rows. + +:::
Changing Header Names (click to show) @@ -957,10 +963,17 @@ of the React Native documentation before testing the demo. ::: +:::caution pass + +For Android testing, React Native requires Java 11. It will not work with +current Java releases. + +::: + Create a new project by running the following commands in the Terminal: {`\ -npx react-native@0.71 init SheetJSPres --version="0.72.0-rc.1" +npx -y react-native@0.72.4 init SheetJSPres --version="0.72.4" cd SheetJSPres \n\ npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-native-blob-util@0.17.1`} diff --git a/docz/docs/03-demos/01-frontend/08-bundler.md b/docz/docs/03-demos/01-frontend/08-bundler.md index 2c652fc..fee1bf4 100644 --- a/docz/docs/03-demos/01-frontend/08-bundler.md +++ b/docz/docs/03-demos/01-frontend/08-bundler.md @@ -1266,7 +1266,7 @@ Access `http://localhost:8080` in your web browser and click the export button.
-:::note +:::note pass The [Vite section of the Content demo](/docs/demos/static/vitejs) covers asset loaders. They are ideal for static sites pulling data from sheets at build time. diff --git a/docz/docs/03-demos/03-net/09-dom.md b/docz/docs/03-demos/03-net/09-dom.md index 083c490..52d9797 100644 --- a/docz/docs/03-demos/03-net/09-dom.md +++ b/docz/docs/03-demos/03-net/09-dom.md @@ -5,10 +5,16 @@ title: Synthetic DOM import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; -`table_to_book` / `table_to_sheet` / `sheet_add_dom` act on HTML DOM elements. -Traditionally there is no DOM in server-side environments. +SheetJS offers three methods to directly process HTML DOM TABLE elements[^1]: -:::note +- `table_to_sheet` generates a SheetJS worksheet[^2] from a TABLE element +- `table_to_book` generates a SheetJS workbook[^3] from a TABLE element +- `sheet_add_dom` adds data from a TABLE element to an existing worksheet + +These methods work in the web browser. NodeJS and other server-side platforms +traditionally lack a DOM implementation, but third-party modules fill the gap. + +:::tip pass The most robust approach for server-side processing is to automate a headless web browser. ["Browser Automation"](/docs/demos/net/headless) includes demos. @@ -17,23 +23,60 @@ web browser. ["Browser Automation"](/docs/demos/net/headless) includes demos. This demo covers synthetic DOM implementations for non-browser platforms. +## Integration Details + +SheetJS API methods use DOM features that may not be available. + +### Table rows + +The `rows` property of TABLE elements is a list of TR row children. This list +automatically updates when rows are added and deleted. + +SheetJS does not mutate `rows`. Assuming there are no nested tables, the `rows` +property can be created using `getElementsByTagName`: + +```js +tbl.rows = Array.from(tbl.getElementsByTagName("tr")); +``` + +### Row cells + +The `cells` property of TR elements is a list of TD cell children. This list +automatically updates when cells are added and deleted. + +SheetJS does not mutate `cells`. Assuming there are no nested tables, the +`cells` property can be created using `getElementsByTagName`: + +```js +tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td"))); +``` + ## NodeJS ### JSDOM -JSDOM is a DOM implementation for NodeJS. Given an HTML string, a reference to -the table element plays nice with the SheetJS DOM methods: +JSDOM is a DOM implementation for NodeJS. The synthetic DOM elements are +compatible with SheetJS methods. -```js +The following example scrapes the first table from the file `SheetJSTable.html` +and generates a XLSX workbook: + +```js title="SheetJSDOM.js" const XLSX = require("xlsx"); +const { readFileSync } = require("fs"); const { JSDOM } = require("jsdom"); -/* parse HTML */ -const dom = new JSDOM(html_string); +/* obtain HTML string. This example reads from SheetJSTable.html */ +const html_str = readFileSync("SheetJSTable.html", "utf8"); + +// highlight-start /* get first TABLE element */ -const tbl = dom.window.document.querySelector("table"); +const doc = new JSDOM(html_str).window.document.querySelector("table"); + /* generate workbook */ -const workbook = XLSX.utils.table_to_book(tbl); +const workbook = XLSX.utils.table_to_book(doc); +// highlight-end + XLSX.writeFile(workbook, "SheetJSDOM.xlsx"); ``` @@ -41,7 +84,7 @@ XLSX.writeFile(workbook, "SheetJSDOM.xlsx"); :::note -This demo was last tested on 2023 May 18 against JSDOM `22.0.0` +This demo was last tested on 2023 September 10 against JSDOM `22.1.0` ::: @@ -51,21 +94,7 @@ This demo was last tested on 2023 May 18 against JSDOM `22.0.0` npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz jsdom@22.0.0`} -2) Save the following script to `SheetJSDOM.js`: - -```js title="SheetJSDOM.js" -const XLSX = require("xlsx"); -const { readFileSync } = require("fs"); -const { JSDOM } = require("jsdom"); - -/* obtain HTML string. This example reads from SheetJSTable.html */ -const html_str = readFileSync("SheetJSTable.html", "utf8"); -/* get first TABLE element */ -const doc = new JSDOM(html_str).window.document.querySelector("table"); -/* generate workbook */ -const workbook = XLSX.utils.table_to_book(doc); -XLSX.writeFile(workbook, "SheetJSDOM.xlsx"); -``` +2) Save the previous codeblock to `SheetJSDOM.js`. 3) Download [the sample `SheetJSTable.html`](pathname:///dom/SheetJSTable.html): @@ -83,48 +112,79 @@ The script will create a file `SheetJSDOM.xlsx` that can be opened. -### XMLDOM +### HappyDOM -XMLDOM provides a DOM framework for NodeJS. Given an HTML string, a reference to -the table element works with the SheetJS DOM methods after patching the object. +HappyDOM provides a DOM framework for NodeJS. For the tested version (`11.0.2`), +the following patches were needed: + +- TABLE `rows` property (explained above) +- TR `cells` property (explained above)
Complete Demo (click to show) :::note -This demo was last tested on 2023 May 18 against XMLDOM `0.8.7` +This demo was last tested on 2023 September 10 against HappyDOM `11.0.2` + +::: + +1) Install SheetJS and HappyDOM libraries: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz happy-dom@11.0.2`} + + +2) Download [the sample script `SheetJSHappyDOM.js`](pathname:///dom/SheetJSHappyDOM.js): + +```bash +curl -LO https://docs.sheetjs.com/dom/SheetJSHappyDOM.js +``` + +3) Run the script: + +```bash +node SheetJSHappyDOM.js +``` + +The script will create a file `SheetJSHappyDOM.xlsx` that can be opened. + +
+ +### XMLDOM + +XMLDOM provides a DOM framework for NodeJS. For the tested version (`0.8.10`), +the following patches were needed: + +- TABLE `rows` property (explained above) +- TR `cells` property (explained above) +- Element `innerHTML` property: + +```js +Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() { + var outerHTML = new XMLSerializer().serializeToString(this); + if(outerHTML.match(/]*(("[^"]*"|'[^']*')[^"'>]*)*>/, ""); +}}); +``` + +
Complete Demo (click to show) + +:::note + +This demo was last tested on 2023 September 10 against XMLDOM `0.8.10` ::: 1) Install SheetJS and XMLDOM libraries: {`\ -npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @xmldom/xmldom@0.8.7`} +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @xmldom/xmldom@0.8.10`} -2) Save the following codeblock to `SheetJSXMLDOM.js`: +2) Download [the sample script `SheetJSXMLDOM.js`](pathname:///dom/SheetJSXMLDOM.js): -```js title="SheetJSXMLDOM.js" -const XLSX = require("xlsx"); -const { DOMParser, XMLSerializer } = require("@xmldom/xmldom"); - -(async() => { -const text = await (await fetch('https://docs.sheetjs.com/dom/SheetJSTable.html')).text(); -const doc = new DOMParser().parseFromString( text, "text/html"); -const tbl = doc.getElementsByTagName("table")[0]; - -/* patch XMLDOM */ -tbl.rows = Array.from(tbl.getElementsByTagName("tr")); -tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td"))) -Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() { - var outerHTML = new XMLSerializer().serializeToString(this); - if(outerHTML.match(/]*(("[^"]*"|'[^']*')[^"'>]*)*>/, ""); -}}); - -const workbook = XLSX.utils.table_to_book(tbl); -XLSX.writeFile(workbook, "SheetJSXMLDOM.xlsx"); -})(); +```bash +curl -LO https://docs.sheetjs.com/dom/SheetJSXMLDOM.js ``` 3) Run the script: @@ -135,28 +195,26 @@ node SheetJSXMLDOM.js The script will create a file `SheetJSXMLDOM.xlsx` that can be opened. -
### CheerioJS -:::caution +:::caution pass Cheerio does not support a number of fundamental properties out of the box. They can be shimmed, but it is strongly recommended to use a more compliant library. ::: -CheerioJS provides a DOM-like framework for NodeJS. Given an HTML string, a -reference to the table element works with the SheetJS DOM methods with some -prototype fixes. [`SheetJSCheerio.js`](pathname:///dom/SheetJSCheerio.js) is a -complete script. +CheerioJS provides a DOM-like framework for NodeJS. Many features were missing. +[`SheetJSCheerio.js`](pathname:///dom/SheetJSCheerio.js) implements the missing +features to ensure that SheetJS DOM methods can process TABLE elements.
Complete Demo (click to show) :::note -This demo was last tested on 2023 May 18 against Cheerio `1.0.0-rc.12` +This demo was last tested on 2023 September 10 against Cheerio `1.0.0-rc.12` ::: @@ -192,8 +250,11 @@ The script will create a file `SheetJSCheerio.xlsx` that can be opened. ### DenoDOM -DenoDOM provides a DOM framework for Deno. Given an HTML string, a reference to -the table element works with the SheetJS DOM methods after patching the object. +DenoDOM provides a DOM framework for Deno. For the tested version (`0.1.38`), +the following patches were needed: + +- TABLE `rows` property (explained above) +- TR `cells` property (explained above) This example fetches [a sample table](pathname:///dom/SheetJSTable.html): @@ -220,11 +281,11 @@ const workbook = XLSX.utils.table_to_book(tbl); XLSX.writeFile(workbook, "SheetJSDenoDOM.xlsx");`} -
Complete Demo (click to hide) +
Complete Demo (click to show) :::note -This demo was last tested on 2023 May 18 against DenoDOM `0.1.38` +This demo was last tested on 2023 September 10 against DenoDOM `0.1.38` ::: @@ -238,4 +299,8 @@ deno run --allow-net --allow-write SheetJSDenoDOM.ts The script will create a file `SheetJSDenoDOM.xlsx` that can be opened. -
\ No newline at end of file +
+ +[^1]: See ["HTML Table Input" in "Utilities"](/docs/api/utilities/html#html-table-input) +[^2]: See ["Worksheet Object" in "SheetJS Data Model"](/docs/csf/book) for more details. +[^3]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details. diff --git a/docz/docs/03-demos/05-mobile/04-ionic.md b/docz/docs/03-demos/05-mobile/04-ionic.md index 8369cbb..c5d7b37 100644 --- a/docz/docs/03-demos/05-mobile/04-ionic.md +++ b/docz/docs/03-demos/05-mobile/04-ionic.md @@ -1,5 +1,7 @@ --- -title: Ionic +title: Data Conduction in Ionic Apps +sidebar_label: Ionic +description: Build data-intensive mobile apps with Ionic and Cordova. Seamlessly integrate spreadsheets into your app using SheetJS. Let data in your Excel spreadsheets shine. pagination_prev: demos/static/index pagination_next: demos/desktop/index sidebar_position: 4 @@ -10,10 +12,17 @@ sidebar_custom_props: import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; -The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported -from the main entrypoint or any script in the project. +[Ionic](https://ionicframework.com/) is a mobile app framework for building iOS +and Android apps with the Cordova platform. -The "Complete Example" creates an app that looks like the screenshots below: +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. + +This demo uses Ionic and SheetJS to process data and generate spreadsheets. +We'll explore how to load SheetJS in an Ionic app and use Ionic APIs and plugins +to extract data from, and write data to, spreadsheet files on the device. + +The ["Demo"](#demo) creates an app that looks like the screenshots below: @@ -28,6 +37,13 @@ The "Complete Example" creates an app that looks like the screenshots below:
iOS
+:::info pass + +This demo covers Ionic apps using the Cordova platform. + +The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps. + +::: :::warning Telemetry @@ -57,18 +73,36 @@ npx @capacitor/cli telemetry ## Integration Details -:::caution pass +The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be +imported from the main entrypoint or any script in the project. -The latest version of Ionic uses CapacitorJS. These notes are for Cordova apps. -The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps. +### Internal State -::: +The ["Angular" demo](/docs/demos/frontend/angular) discusses a number of state +representations and preview strategies. -### Angular +For this demo, the internal state is an "array of arrays"[^1] (`any[][]`): -`Array>` neatly maps to a table with `ngFor`: +```ts title="Array of Arrays state" +import { Component } from '@angular/core'; +type AOA = any[][]; -```html +@Component({...}) +export class SheetJSTablePage { + data: AOA = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] + ]; + // ... +} +``` + +### Displaying Data + +`ion-grid`[^2] is a display grid component. The Angular `ngFor` directive[^3] +simplifies iteration over the array of arrays: + +```html title="Template for displaying an array of arrays" @@ -78,29 +112,62 @@ The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps. ``` -### Cordova +### File Operations -`@ionic-native/file` reads and writes files on devices. +`@awesome-cordova-plugins/file` reads and writes files on devices. -_Reading Files_ +:::info pass -`readAsArrayBuffer` returns `ArrayBuffer` objects suitable for `array` type: +The plugins in the `@ionic-native` scope have been deprecated. The community +modules in the `@awesome-cordova-plugins` scope should be used. + +::: + +#### Reading Files + +`this.file.readAsArrayBuffer` reads file data from a specified URL and resolves +to `ArrayBuffer` objects. + +These objects can be parsed with the SheetJS `read` method[^4]. The SheetJS +`sheet_to_json` method[^5] with the option `header: 1` generates an array of +arrays which can be assigned to the page state: ```ts -/* read a workbook */ +/* read a workbook file */ const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, filename); +/* parse */ const wb: XLSX.WorkBook = XLSX.read(ab, {type: 'array'}); +/* generate an array of arrays from the first worksheet */ +const ws: XLSX.WorkSheet = wb.SheetNames[wb.Sheets[0]]; +const aoa: AOA = XLSX.utils.sheet_to_json(ws, {header: 1}); +/* update state */ +this.data = aoa; ``` -_Writing Files_ +#### Writing Files -`array` type can be converted to blobs that can be exported with `writeFile`: +`this.file.writeFile` writes file data stored in `Blob` objects to the device. +From the array of arrays, the SheetJS `aoa_to_sheet` method[^6] generates a +worksheet object. The `book_new` and `book_append_sheet` helpers[^7] generate a +workbook object. The SheetJS `write` method[^8] with the option `type: "array"` +will generate an `ArrayBuffer`, from which a `Blob` can be created: ```ts -/* write a workbook */ -const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); -let blob = new Blob([wbout], {type: 'application/octet-stream'}); +/* generate worksheet */ +const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data); + +/* generate workbook and add the worksheet */ +const wb: XLSX.WorkBook = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, 'SheetJS'); + +/* write XLSX to ArrayBuffer */ +const ab: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); + +/* generate Blob */ +let blob = new Blob([ab], {type: 'application/octet-stream'}); + +/* write Blob to device */ this.file.writeFile(url, filename, blob, {replace: true}); ``` @@ -108,47 +175,72 @@ this.file.writeFile(url, filename, blob, {replace: true}); :::note -This demo was tested on an Intel Mac on 2023 March 28 with Cordova. -The file integration uses `@ionic-native/file` version `5.36.0`. +The project was last tested in 2023 September 10. `ionic info` showed: -The iOS simulator runs iOS 15.5 on an iPhone SE (3rd Generation). +- Ionic: `@ionic/angular 7.3.3`, `@ionic/angular-toolkit 9.0.0` +- Cordova: `cordova-lib@12.0.1`, `android 12.0.1, ios 7.0.1` -The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3. +The file integration uses `@awesome-cordova-plugins/file` version `6.4.0`. + +The iOS demo was last tested on 2023 September 10 on an emulated iPhone SE +(3rd generation) + iOS 16.4 + +The Android demo was last tested on 2023 September 10 on an emulated Pixel 3 + +Android 13 ("Tiramisu") API 33. ::: +The app in this demo will display data in a table. + +On load, a [test file](https://sheetjs.com/pres.numbers) will be processed. + +When a document is selected with the file picker, it will be processed and the +table will refresh to show the contents. + +"Import Data" will attempt to read `SheetJSIonic.xlsx` from a known location. An +alert will display the expected location. + +"Export Data" will attempt to export the table data to `SheetJSIonic.xlsx` in a +known location. After writing, an alert will display the location of the file. + + +### Platform Setup + 0) Disable telemetry as noted in the warning. -Install required global dependencies: +1) Follow the official instructions for iOS and Android development[^9]. + +2) Install required global dependencies: ```bash npm i -g cordova-res @angular/cli native-run @ionic/cli ``` -Follow the [React Native demo](/docs/demos/mobile/reactnative) to ensure iOS and Android sims are ready. +### Base Project - -1) Create a new project: +3) Create a new project: ```bash ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm ``` +When asked to select `NgModules` or `Standalone Components`, select `NgModules` + If a prompt asks to confirm Cordova use, enter `Yes` to continue. If a prompt asks about creating an Ionic account, enter `N` to opt out. -2) Set up Cordova: +4) Set up Cordova: ```bash cd SheetJSIonic ionic cordova plugin add cordova-plugin-file ionic cordova platform add ios --confirm ionic cordova platform add android --confirm -npm i --save @ionic-native/core @ionic-native/file @ionic/cordova-builders +npm i --save @awesome-cordova-plugins/core @awesome-cordova-plugins/file @ionic/cordova-builders ``` -:::note +:::note pass If `cordova-plugin-file` is added before the platforms, installation may fail: @@ -165,9 +257,9 @@ ionic cordova platform add ios --confirm ::: -:::caution +:::caution pass -If the `npm i` fails due to `rxjs` resolution, add the highlighted lines +If the `npm i` step fails due to `rxjs` resolution, add the highlighted lines to `package.json` to force a resolution: ```js title="package.json" @@ -180,24 +272,26 @@ to `package.json` to force a resolution: "dependencies": { ``` +Note that the required `rxjs` version will be displayed in the error log. + After adding the lines, the `npm i` command will succeed. ::: -3) Install dependencies: +5) Install dependencies: {`\ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} -4) Add `@ionic-native/file` to the module. Differences highlighted below: +6) Add `@awesome-cordova-plugins/file` to the module. Differences highlighted below: ```ts title="src/app/app.module.ts" import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; // highlight-next-line -import { File } from '@ionic-native/file/ngx'; +import { File } from '@awesome-cordova-plugins/file/ngx'; @NgModule({ declarations: [AppComponent], @@ -210,19 +304,41 @@ import { File } from '@ionic-native/file/ngx'; export class AppModule {} ``` -5) Download [`home.page.ts`](pathname:///ionic/home.page.ts) and replace: +7) Download [`home.page.ts`](pathname:///ionic/home.page.ts) and replace: ```bash curl -o src/app/home/home.page.ts -L https://docs.sheetjs.com/ionic/home.page.ts ``` -**iOS Testing** +### iOS + +8) Enable file sharing and make the documents folder visible in the iOS app. +Add the following lines to `platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist`: + +```xml title="platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist (add to file)" + + + + UIFileSharingEnabled + + LSSupportsOpeningDocumentsInPlace + + + CFBundleDevelopmentRegion +``` + +(The root element of the document is `plist` and it contains one `dict` child) + +9) Build the app and start the simulator ```bash ionic cordova emulate ios ``` -:::caution +When the app is loaded, a list of Presidents should be displayed. This list is +dynamically generated by fetching and parsing a test file. + +:::caution pass In some test runs, the `cordova build ios --emulator` step failed with error: @@ -239,13 +355,54 @@ npm i --save cordova-ios ::: -**Android Testing** +:::info pass + +In the most recent test, the `native-run ios` command failed with + +``` +[native-run] ERR_UNKNOWN: Path 'platforms/ios/build/emulator/SheetJSIonic.app' not found +``` + +Inspecting `platforms/ios/build/`, the actual folder name was: + +```bash +% ls platforms/ios/build +#highlight-next-line +Debug-iphonesimulator +``` + +The iOS simulator can be launched manually: + +```bash +native-run ios --app platforms/ios/build/Debug-iphonesimulator/SheetJSIonic.app --virtual +``` + +::: + +### Android + +10) Enable file reading and writing in the Android app. + +Edit `platforms/android/app/src/main/AndroidManifest.xml` and add the following +two lines before the `application` tag: + +```xml title="platforms/android/app/src/main/AndroidManifest.xml (add to file)" + + +``` + +In the `application` tag, add the attribute `android:requestLegacyExternalStorage="true"`. + +11) Build the app and start the emulator ```bash ionic cordova emulate android ``` -:::caution +When the app is loaded, a list of Presidents should be displayed. This list is +dynamically generated by fetching and parsing a test file. + +:::caution pass In some test runs, `cordova build android --emulator` step failed with error: @@ -260,3 +417,40 @@ npm i --save cordova-android ``` ::: + +:::caution pass + +In some tests, the build failed with a Gradle error: + +``` +Could not find an installed version of Gradle either in Android Studio, +or on your system to install the gradle wrapper. Please include gradle +in your path or install Android Studio +``` + +On macOS, this issue was resolved by installing gradle with Homebrew manager: + +```bash +brew install gradle +``` + +::: + +:::warning pass + +When the demo was last tested on Android, reading files worked as expected. +However, the generated files were not externally visible from the Files app. + +**This is a known bug with Android SDK 33 and the underlying file plugins!** + +::: + +[^1]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays) +[^2]: See [`ion-grid`](https://ionicframework.com/docs/api/grid) in the Ionic documentation. +[^3]: See [`ngFor`](https://angular.io/api/common/NgFor) in the Angular documentation. +[^4]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^5]: See ["Array Output" in "Utility Functions"](/docs/api/utilities/array#array-output) +[^6]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input) +[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`. +[^8]: See [`write` in "Writing Files"](/docs/api/write-options) +[^9]: See ["Developing for iOS"](https://ionicframework.com/docs/v6/developing/ios) and ["Developing for Android"](https://ionicframework.com/docs/v6/developing/android) in the v6 Ionic framework documentation. \ No newline at end of file diff --git a/docz/docs/03-demos/05-mobile/05-capacitor.md b/docz/docs/03-demos/05-mobile/05-capacitor.md index d7252b3..bd26b1c 100644 --- a/docz/docs/03-demos/05-mobile/05-capacitor.md +++ b/docz/docs/03-demos/05-mobile/05-capacitor.md @@ -200,7 +200,7 @@ after the `Permissions` comment: - + diff --git a/docz/static/dom/SheetJSDOM.js b/docz/static/dom/SheetJSDOM.js new file mode 100644 index 0000000..7120a54 --- /dev/null +++ b/docz/static/dom/SheetJSDOM.js @@ -0,0 +1,11 @@ +const XLSX = require("xlsx"); +const { readFileSync } = require("fs"); +const { JSDOM } = require("jsdom"); + +/* obtain HTML string. This example reads from SheetJSTable.html */ +const html_str = readFileSync("SheetJSTable.html", "utf8"); +/* get first TABLE element */ +const doc = new JSDOM(html_str).window.document.querySelector("table"); +/* generate workbook */ +const workbook = XLSX.utils.table_to_book(doc); +XLSX.writeFile(workbook, "SheetJSDOM.xlsx"); \ No newline at end of file diff --git a/docz/static/dom/SheetJSHappyDOM.js b/docz/static/dom/SheetJSHappyDOM.js new file mode 100644 index 0000000..5c1c6e0 --- /dev/null +++ b/docz/static/dom/SheetJSHappyDOM.js @@ -0,0 +1,23 @@ +const XLSX = require("xlsx"); +const { readFileSync } = require("fs"); +const { Window } = require("happy-dom"); + +/* obtain HTML string. This example reads from SheetJSTable.html */ +const html_str = readFileSync("SheetJSTable.html", "utf8"); + +/* get table element */ +const window = new Window({ + url: "https://localhost:8080", + width: 1024, + height: 768 +}); +window.document.body.innerHTML = html_str; +const tbl = window.document.body.getElementsByTagName("table")[0]; + +/* add `rows` and `cells` properties */ +tbl.rows = Array.from(tbl.getElementsByTagName("tr")); +tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td"))) + +/* generate workbook */ +const workbook = XLSX.utils.table_to_book(tbl); +XLSX.writeFile(workbook, "SheetJSHappyDOM.xlsx"); \ No newline at end of file diff --git a/docz/static/dom/SheetJSXMLDOM.js b/docz/static/dom/SheetJSXMLDOM.js new file mode 100644 index 0000000..dc53342 --- /dev/null +++ b/docz/static/dom/SheetJSXMLDOM.js @@ -0,0 +1,20 @@ +const XLSX = require("xlsx"); +const { DOMParser, XMLSerializer } = require("@xmldom/xmldom"); + +(async() => { +const text = await (await fetch('https://docs.sheetjs.com/dom/SheetJSTable.html')).text(); +const doc = new DOMParser().parseFromString( text, "text/html"); +const tbl = doc.getElementsByTagName("table")[0]; + +/* patch XMLDOM */ +tbl.rows = Array.from(tbl.getElementsByTagName("tr")); +tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td"))); +Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() { + var outerHTML = new XMLSerializer().serializeToString(this); + if(outerHTML.match(/]*(("[^"]*"|'[^']*')[^"'>]*)*>/, ""); +}}); + +const workbook = XLSX.utils.table_to_book(tbl); +XLSX.writeFile(workbook, "SheetJSXMLDOM.xlsx"); +})(); \ No newline at end of file diff --git a/docz/static/flutter/ios.png b/docz/static/flutter/ios.png index c5ba8b7..9b5e8c3 100644 Binary files a/docz/static/flutter/ios.png and b/docz/static/flutter/ios.png differ diff --git a/docz/static/ionic/home.page.ts b/docz/static/ionic/home.page.ts index 1be82e7..83e254d 100644 --- a/docz/static/ionic/home.page.ts +++ b/docz/static/ionic/home.page.ts @@ -1,7 +1,7 @@ /* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ /* vim: set ts=2: */ import { Component, OnInit } from '@angular/core'; -import { File } from '@ionic-native/file/ngx'; +import { File } from '@awesome-cordova-plugins/file/ngx'; import * as XLSX from 'xlsx'; type AOA = any[][]; @@ -42,7 +42,7 @@ type AOA = any[][]; }) export class HomePage implements OnInit { - data: any[][] = [[1,2,3],[4,5,6]]; + data: AOA = [[1,2,3],[4,5,6]]; constructor(public file: File) {} async ngOnInit(): Promise {