forked from sheetjs/docs.sheetjs.com
		
	dndemo
This commit is contained in:
		
							parent
							
								
									af187640fa
								
							
						
					
					
						commit
						4f548c4646
					
				| @ -7,15 +7,23 @@ sidebar_custom_props: | ||||
|   summary: JS + Web View | ||||
| --- | ||||
| 
 | ||||
| ## CapacitorJS | ||||
| The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported | ||||
| from the main entrypoint or any script in the project. | ||||
| 
 | ||||
| :::note | ||||
| The "Complete Example" creates an app that looks like the screenshots below: | ||||
| 
 | ||||
| This demo was tested on an Intel Mac on 2022 August 26 with Svelte. | ||||
| <table><thead><tr> | ||||
|   <th><a href="#demo">iOS</a></th> | ||||
|   <th><a href="#demo">Android</a></th> | ||||
| </tr></thead><tbody><tr><td> | ||||
| 
 | ||||
| The iOS simulator runs iOS 15.5 on an iPhone 13 Pro Max. | ||||
|  | ||||
| 
 | ||||
| ::: | ||||
| </td><td> | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| :::warning Telemetry | ||||
| 
 | ||||
| @ -33,7 +41,7 @@ npx @capacitor/cli telemetry | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Integration Details | ||||
| ## Integration Details | ||||
| 
 | ||||
| This example uses Svelte, but the same principles apply to other frameworks. | ||||
| 
 | ||||
| @ -100,93 +108,150 @@ async function exportFile() { | ||||
| </main> | ||||
| ``` | ||||
| 
 | ||||
| ### Demo | ||||
| ## Demo | ||||
| 
 | ||||
| <details><summary><b>Complete Example</b> (click to show)</summary> | ||||
| :::note | ||||
| 
 | ||||
| 0) Disable telemetry as noted in the warning. | ||||
| This demo was tested on an Intel Mac on 2023 April 01 with Capacitor 4.7.3 and | ||||
| `@capacitor/filesystem` 4.1.4 | ||||
| 
 | ||||
| Follow the [React Native demo](#demo) to ensure iOS and Android sims are ready. | ||||
| The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max. | ||||
| 
 | ||||
| The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3. | ||||
| 
 | ||||
| 1) Create a new Svelte project: | ||||
| ::: | ||||
| 
 | ||||
| ### Base Project | ||||
| 
 | ||||
| 1) Disable telemetry. | ||||
| 
 | ||||
| ```bash | ||||
| npx @capacitor/cli telemetry off | ||||
| ``` | ||||
| 
 | ||||
| Verify that telemetry is disabled by running | ||||
| 
 | ||||
| ```bash | ||||
| npx @capacitor/cli telemetry | ||||
| ``` | ||||
| 
 | ||||
| (it should print `Telemetry is off`) | ||||
| 
 | ||||
| 2) Create a new Svelte project: | ||||
| 
 | ||||
| ```bash | ||||
| npm create vite@latest sheetjs-cap -- --template svelte | ||||
| cd sheetjs-cap | ||||
| ``` | ||||
| 
 | ||||
| 2) Install dependencies: | ||||
| 3) Install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz | ||||
| npm i --save @capacitor/core @capacitor/cli @capacitor/ios @capacitor/filesystem | ||||
| npm i --save @capacitor/core @capacitor/cli @capacitor/filesystem | ||||
| ``` | ||||
| 
 | ||||
| 3) Create CapacitorJS structure: | ||||
| 4) Create CapacitorJS structure: | ||||
| 
 | ||||
| ```bash | ||||
| npx cap init sheetjs-cap com.sheetjs.cap --web-dir=dist | ||||
| npm run build | ||||
| ``` | ||||
| 
 | ||||
| 5) Download [`src/App.svelte`](pathname:///cap/App.svelte) and replace: | ||||
| 
 | ||||
| ```bash | ||||
| curl -o src/App.svelte -L https://docs.sheetjs.com/cap/App.svelte | ||||
| ``` | ||||
| 
 | ||||
| ### iOS | ||||
| 
 | ||||
| 6) Follow the [React Native demo](/docs/demos/mobile/reactnative#demo) to | ||||
| ensure the iOS simulator is ready. | ||||
| 
 | ||||
| 7) Create iOS app | ||||
| 
 | ||||
| ```bash | ||||
| npm i --save @capacitor/ios | ||||
| npx cap add ios | ||||
| ``` | ||||
| 
 | ||||
| 4) Replace the contents of `src/App.svelte` with the following: | ||||
| 8) Enable file sharing and make the documents folder visible in the iOS app. | ||||
| The following lines must be added to `ios/App/App/Info.plist`: | ||||
| 
 | ||||
| ```html title="src/App.svelte" | ||||
| <script> | ||||
| import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; | ||||
| import { onMount } from 'svelte'; | ||||
| import { read, utils, version, writeXLSX } from 'xlsx'; | ||||
| 
 | ||||
| let html = ""; | ||||
| let tbl; | ||||
| 
 | ||||
| /* Fetch and update the state once */ | ||||
| onMount(async() => { | ||||
|   const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | ||||
|   const wb = read(f); // parse the array buffer | ||||
|   const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | ||||
|   html = utils.sheet_to_html(ws); // generate HTML and update state | ||||
| }); | ||||
| 
 | ||||
| /* get state data and export to XLSX */ | ||||
| async function exportFile() { | ||||
|   const elt = tbl.getElementsByTagName("TABLE")[0]; | ||||
|   const wb = utils.table_to_book(elt); | ||||
|   /* generate Base64 string for Capacitor */ | ||||
|   const data = writeXLSX(wb, { type: "base64" }); | ||||
|   /* write */ | ||||
|   await Filesystem.writeFile({ | ||||
|     path: "SheetJSCap.xlsx", | ||||
|     data, | ||||
|     directory: Directory.Documents | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| /* show file picker, read file, load table */ | ||||
| async function importFile(evt) { | ||||
|   const f = evt.target.files[0]; | ||||
|   const wb = read(await f.arrayBuffer()); | ||||
|   const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | ||||
|   html = utils.sheet_to_html(ws); // generate HTML and update state | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <main> | ||||
|   <h3>SheetJS × CapacitorJS { version }</h3> | ||||
|   <input type="file" on:change={importFile}/> | ||||
|   <button on:click={exportFile}>Export XLSX</button> | ||||
|   <div bind:this={tbl}>{@html html}</div> | ||||
| </main> | ||||
| ```xml title="ios/App/App/Info.plist" | ||||
| <plist version="1.0"> | ||||
| <dict> | ||||
| <!-- highlight-start --> | ||||
| 	<key>UIFileSharingEnabled</key> | ||||
| 	<true/> | ||||
| 	<key>LSSupportsOpeningDocumentsInPlace</key> | ||||
| 	<true/> | ||||
| <!-- highlight-end --> | ||||
|   <key>CFBundleDevelopmentRegion</key> | ||||
| ``` | ||||
| 
 | ||||
| 5) Test the app: | ||||
| (The root element of the document is `plist` and it contains one `dict` child) | ||||
| 
 | ||||
| 9) Run the app in the simulator | ||||
| 
 | ||||
| ```bash | ||||
| npm run build; npx cap sync; npx cap run ios | ||||
| npm run build | ||||
| npx cap sync | ||||
| npx cap run ios | ||||
| ``` | ||||
| 
 | ||||
| There are 3 steps: build the Svelte app, sync with CapacitorJS, and run sim. | ||||
| This sequence must be run every time to ensure changes are propagated. | ||||
| 10) Test the app | ||||
| 
 | ||||
| </details> | ||||
| Open the app and observe that presidents are listed in the table. | ||||
| 
 | ||||
| Touch "Export XLSX" and a popup will be displayed. | ||||
| 
 | ||||
| To see the generated file, switch to the "Files" app in the simulator and look | ||||
| for `SheetJSCap.xlsx` in "On My iPhone" > "`sheetjs-cap`" | ||||
| 
 | ||||
| ### Android | ||||
| 
 | ||||
| 11) Follow the [React Native demo](/docs/demos/mobile/reactnative#demo) to | ||||
| ensure the Android simulator is ready. | ||||
| 
 | ||||
| 12) Create Android app | ||||
| 
 | ||||
| ```bash | ||||
| npm i --save @capacitor/android | ||||
| npx cap add android | ||||
| ``` | ||||
| 
 | ||||
| 13) Enable file reading and writing in the Android app. | ||||
| The following lines must be added to `android/app/src/main/AndroidManifest.xml` | ||||
| after the `Permissions` comment: | ||||
| 
 | ||||
| ```xml title="android/app/src/main/AndroidManifest.xml" | ||||
|     <!-- Permissions --> | ||||
| 
 | ||||
| <!-- highlight-start --> | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||||
| <!-- highlight-end --> | ||||
| 
 | ||||
|     <uses-permission android:name="android.permission.INTERNET" /> | ||||
| ``` | ||||
| 
 | ||||
| 14) Run the app in the simulator | ||||
| 
 | ||||
| ```bash | ||||
| npm run build | ||||
| npx cap sync | ||||
| npx cap run android | ||||
| ``` | ||||
| 
 | ||||
| 15) Test the app | ||||
| 
 | ||||
| Open the app and observe that presidents are listed in the table. | ||||
| 
 | ||||
| Touch "Export XLSX" and the emulator will ask for permission: | ||||
| 
 | ||||
| Tap "Allow" and a popup will be displayed with a path. | ||||
| 
 | ||||
| To see the generated file, switch to the "Files" app in the simulator, tap the | ||||
| `≡` icon and tap "Documents". Tap "Documents" folder to find `SheetJSCap.xlsx`. | ||||
|  | ||||
| @ -59,7 +59,7 @@ Writers will process the `Props` key of the options object: | ||||
| 
 | ||||
| ```js | ||||
| /* force the Author to be "SheetJS" */ | ||||
| XLSX.write(wb, {Props:{Author:"SheetJS"}}); | ||||
| XLSX.write(wb, { Props: { Author: "SheetJS" } }); | ||||
| ``` | ||||
| 
 | ||||
| ## Workbook-Level Attributes | ||||
| @ -92,6 +92,63 @@ 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 | ||||
| may not enforce this constraint. | ||||
| 
 | ||||
| The following snippet creates a worksheet-level defined name `"Global"` and a | ||||
| local defined name `"Local"` with distinct values for first and second sheets: | ||||
| 
 | ||||
| ```js | ||||
| /* ensure the workbook structure exists */ | ||||
| if(!wb.Workbook) wb.Workbook = {}; | ||||
| if(!wb.Workbook.Names) wb.Workbook.Names = []; | ||||
| 
 | ||||
| /* "Global" workbook-level -> Sheet1 A1:A2 */ | ||||
| wb.Workbook.Names.push({ Name: "Global", Ref: "Sheet1!$A$1:$A$2" }); | ||||
| 
 | ||||
| /* "Local" scoped to the first worksheet -> Sheet1 B1:B2 */ | ||||
| wb.Workbook.Names.push({ Name: "Local",  Ref: "Sheet1!$B$1:$B$2", Sheet: 0 }); | ||||
| 
 | ||||
| /* "Local" scoped to the second worksheet -> Sheet1 C1:C2 */ | ||||
| wb.Workbook.Names.push({ Name: "Local",  Ref: "Sheet1!$C$1:$C$2", Sheet: 1 }); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Example</b> (click to show)</summary> | ||||
| 
 | ||||
| ```jsx live | ||||
| /* The live editor requires this function wrapper */ | ||||
| function DefinedNameExport() { return ( <button onClick={() => { | ||||
|   /* Create empty workbook */ | ||||
|   var wb = XLSX.utils.book_new(); | ||||
| 
 | ||||
|   /* Create worksheet Sheet1 */ | ||||
|   var ws1 = XLSX.utils.aoa_to_sheet([[1,2,3],[4,5,6],["Global",0],["Local",0]]); | ||||
|   XLSX.utils.book_append_sheet(wb, ws1, "Sheet1"); | ||||
| 
 | ||||
|   /* Create worksheet Sheet2 */ | ||||
|   var ws2 = XLSX.utils.aoa_to_sheet([["Global",0],["Local",0]]); | ||||
|   XLSX.utils.book_append_sheet(wb, ws2, "Sheet2"); | ||||
| 
 | ||||
|   /* Create defined names */ | ||||
|   if(!wb.Workbook) wb.Workbook = {}; | ||||
|   if(!wb.Workbook.Names) wb.Workbook.Names = []; | ||||
|   /* "Global" workbook-level -> Sheet1 A1:A2 */ | ||||
|   wb.Workbook.Names.push({ Name: "Global", Ref: "Sheet1!$A$1:$A$2" }); | ||||
|   /* "Local" scoped to the first worksheet -> Sheet1 B1:B2 */ | ||||
|   wb.Workbook.Names.push({ Name: "Local", Sheet: 0, Ref: "Sheet1!$B$1:$B$2" }); | ||||
|   /* "Local" scoped to the second worksheet -> Sheet1 C1:C2 */ | ||||
|   wb.Workbook.Names.push({ Name: "Local", Sheet: 1, Ref: "Sheet1!$C$1:$C$2" }); | ||||
| 
 | ||||
|   /* Create formulae */ | ||||
|   ws1["B3"].f = "SUM(Global)"; // Sheet1 B3 =SUM(Global)  1 + 4 = 5 | ||||
|   ws1["B4"].f = "SUM(Local)";  // Sheet1 B4 =SUM(Local)   2 + 5 = 7 | ||||
|   ws2["B1"].f = "SUM(Global)"; // Sheet2 B1 =SUM(Global)  1 + 4 = 5 | ||||
|   ws2["B2"].f = "SUM(Local)";  // Sheet2 B2 =SUM(Local)   3 + 6 = 9 | ||||
| 
 | ||||
|   /* Export to file (start a download) */ | ||||
|   XLSX.writeFile(wb, "SheetJSDNExport.xlsx"); | ||||
| }}><b>Export XLSX!</b></button> ); } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Workbook Views | ||||
| 
 | ||||
| `wb.Workbook.Views` is an array of workbook view objects which have the keys: | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| { | ||||
|   "label": "Spreadsheet Features", | ||||
|   "collapsed": false, | ||||
|   "position": 7 | ||||
| } | ||||
|  | ||||
							
								
								
									
										46
									
								
								docz/static/cap/App.svelte
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										46
									
								
								docz/static/cap/App.svelte
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| <script> | ||||
| import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; | ||||
| import { onMount } from 'svelte'; | ||||
| import { read, utils, version, writeXLSX } from 'xlsx'; | ||||
| 
 | ||||
| let html = ""; | ||||
| let tbl; | ||||
| 
 | ||||
| /* Fetch and update the state once */ | ||||
| onMount(async() => { | ||||
|   const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer(); | ||||
|   const wb = read(f); // parse the array buffer | ||||
|   const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | ||||
|   html = utils.sheet_to_html(ws); // generate HTML and update state | ||||
| }); | ||||
| 
 | ||||
| /* get state data and export to XLSX */ | ||||
| async function exportFile() { | ||||
|   const elt = tbl.getElementsByTagName("TABLE")[0]; | ||||
|   const wb = utils.table_to_book(elt); | ||||
|   /* generate Base64 string for Capacitor */ | ||||
|   const data = writeXLSX(wb, { type: "base64" }); | ||||
|   /* write */ | ||||
|   await Filesystem.writeFile({ | ||||
|     path: "SheetJSCap.xlsx", | ||||
|     data, | ||||
|     directory: Directory.Documents | ||||
|   }); | ||||
|   alert(`Exported to ${Directory.Documents}/SheetJSCap.xlsx`); | ||||
| } | ||||
| 
 | ||||
| /* show file picker, read file, load table */ | ||||
| async function importFile(evt) { | ||||
|   const f = evt.target.files[0]; | ||||
|   const wb = read(await f.arrayBuffer()); | ||||
|   const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | ||||
|   html = utils.sheet_to_html(ws); // generate HTML and update state | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <main> | ||||
|   <h3>SheetJS × CapacitorJS { version }</h3> | ||||
|   <input type="file" on:change={importFile}/> | ||||
|   <button on:click={exportFile}>Export XLSX</button> | ||||
|   <div bind:this={tbl}>{@html html}</div> | ||||
| </main> | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/cap/and.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/cap/and.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 89 KiB | 
							
								
								
									
										
											BIN
										
									
								
								docz/static/cap/ios.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/cap/ios.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 98 KiB | 
		Loading…
	
		Reference in New Issue
	
	Block a user