forked from sheetjs/docs.sheetjs.com
		
	
		
			
				
	
	
		
			319 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			319 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ---
 | |
| title: Spreadsheets in Dropbox
 | |
| sidebar_label: Dropbox
 | |
| pagination_prev: demos/local/index
 | |
| pagination_next: demos/extensions/index
 | |
| ---
 | |
| 
 | |
| <head>
 | |
|   <script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="6msofx0wc1zd7da"></script>
 | |
| </head>
 | |
| 
 | |
| [Dropbox](https://www.dropbox.com/) is a file hosting service that offers APIs
 | |
| for programmatic file access.
 | |
| 
 | |
| [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
 | |
| data from spreadsheets.
 | |
| 
 | |
| This demo uses SheetJS to read and write spreadsheets stored on Dropbox. We'll
 | |
| explore two Dropbox API workflows:
 | |
| 
 | |
| - A "Chooser"[^1] application allows users to select files from their Dropbox
 | |
| accounts. This demo will fetch and parse the selected file.
 | |
| 
 | |
| - A "Saver"[^2] application allows users to save a generated spreadsheet to
 | |
| their Dropbox account. This demo will generate a XLS workbook using SheetJS.
 | |
| 
 | |
| ## Integration Details
 | |
| 
 | |
| "Dropbox Apps" are the standard way to interact with the service.  The
 | |
| ["Dropbox App"](#dropbox-app) section describes how this demo was configured.
 | |
| 
 | |
| :::info pass
 | |
| 
 | |
| The Dropbox API script is loaded in this page with
 | |
| 
 | |
| ```html
 | |
| <script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="6msofx0wc1zd7da"></script>
 | |
| ```
 | |
| 
 | |
| The `data-app-key` used in this demo is a "Development" key associated with the
 | |
| `localhost` and `docs.sheetjs.com` domains.  Dropbox API does not require
 | |
| "Production" approval for the Chooser or Saver.
 | |
| 
 | |
| :::
 | |
| 
 | |
| The live demos require a Dropbox account.
 | |
| 
 | |
| ### Reading Files
 | |
| 
 | |
| "Chooser" is a small library that lets users select a file from their account.
 | |
| `Dropbox.createChooseButton` is a function that accepts an options argument and
 | |
| returns a DOM element that should be added to the page:
 | |
| 
 | |
| ```js
 | |
| var button = Dropbox.createChooseButton({
 | |
|   /* ... options described below ... */
 | |
| });
 | |
| document.appendChild(button);
 | |
| ```
 | |
| 
 | |
| The following options must be set:
 | |
| 
 | |
| - `multiselect: false` ensures only one file can be selected
 | |
| - `folderselect: false` limits selection to real files
 | |
| - `linkType: "direct"` ensures the link points to a raw file
 | |
| - `success` method is called when the user selects a file
 | |
| 
 | |
| The following options are optional:
 | |
| 
 | |
| - `extensions: ['.xlsx', '.xls']` limits the file types for selection
 | |
| 
 | |
| #### Chooser Callback
 | |
| 
 | |
| The `success` callback method receives an array of File objects even if only one
 | |
| file is selected. This file object has the following properties:
 | |
| 
 | |
| - `name` is the name of the selected file
 | |
| - `link` is a temporary URL that can be fetched
 | |
| 
 | |
| This demo fetches the link using the `fetch` API, parses the raw data using the
 | |
| SheetJS `read` function[^3] and generates a HTML table using `sheet_to_html`[^4]
 | |
| 
 | |
| ```js
 | |
| async(files) => {
 | |
|   /* get file entry -- note that dropbox API always passes an array */
 | |
|   var file = files[0];
 | |
|   console.log(`Selected ${file.name} ID=${file.id}`);
 | |
| 
 | |
|   /* fetch file and parse */
 | |
|   var wb = XLSX.read(await (await fetch(file.link)).arrayBuffer());
 | |
| 
 | |
|   /* convert first sheet to HTML table and add to page */
 | |
|   var html = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
 | |
|   console.log(html);
 | |
| }
 | |
| ```
 | |
| 
 | |
| #### Chooser Live Demo
 | |
| 
 | |
| :::caution pass
 | |
| 
 | |
| If the live demo shows a message
 | |
| 
 | |
| ```
 | |
| ReferenceError: Dropbox is not defined
 | |
| ```
 | |
| 
 | |
| please refresh the page.  This is a known bug in the documentation generator.
 | |
| 
 | |
| :::
 | |
| 
 | |
| ```jsx live
 | |
| function SheetJSChoisissez() {
 | |
|   const [msg, setMsg] = React.useState("Press the button to show a Chooser");
 | |
|   const btn = useRef(), tbl = useRef();
 | |
|   React.useEffect(() => {
 | |
|     if(typeof Dropbox == "undefined") return setMsg("Dropbox is not defined");
 | |
|     /* create button */
 | |
|     var button = Dropbox.createChooseButton({
 | |
|       /* required settings */
 | |
|       multiselect: false,
 | |
|       folderselect: false,
 | |
|       linkType: "direct",
 | |
|       /* optional settings */
 | |
|       extensions: ['.xlsx', '.xls', '.numbers'], // list of extensions
 | |
| 
 | |
|       /* event handlers */
 | |
|       cancel: () => setMsg("User Canceled Selection!"),
 | |
|       success: async(files) => {
 | |
|         /* get file entry -- note that dropbox API always passes an array */
 | |
|         var file = files[0];
 | |
|         setMsg(`Selected ${file.name} ID=${file.id}`);
 | |
| 
 | |
|         /* fetch file and parse */
 | |
|         var wb = XLSX.read(await (await fetch(file.link)).arrayBuffer());
 | |
| 
 | |
|         /* convert first sheet to HTML table and add to page */
 | |
|         tbl.current.innerHTML = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
 | |
|       }
 | |
|     });
 | |
|     /* add button to page */
 | |
|     btn.current.appendChild(button);
 | |
|   }, []);
 | |
|   return ( <><b>{msg}</b><br/><div ref={btn}/><div ref={tbl}/></> );
 | |
| }
 | |
| ```
 | |
| 
 | |
| ### Writing Files
 | |
| 
 | |
| "Saver" is a small library that lets users save files to their account.
 | |
| `Dropbox.createSaveButton` is a function that accepts three arguments and
 | |
| returns a DOM element that should be added to the page:
 | |
| 
 | |
| ```js
 | |
| var button = Dropbox.createSaveButton(url, filename, options);
 | |
| /* add button to page */
 | |
| btn.current.appendChild(button);
 | |
| ```
 | |
| 
 | |
| `filename` will be the recommended filename in the Save window.
 | |
| 
 | |
| The options object supports two callbacks: `success` (if the save succeeded) and
 | |
| `cancel` (if the user cancels without saving).
 | |
| 
 | |
| #### URL
 | |
| 
 | |
| :::caution pass
 | |
| 
 | |
| The Dropbox API was not designed for writing files that are created in the web
 | |
| browser.  The Data URI approach is a neat workaround but should not be used in
 | |
| production for larger files.  It is better to create the files in the server
 | |
| using NodeJS and generate a proper URL for Dropbox to fetch.
 | |
| 
 | |
| :::
 | |
| 
 | |
| The Dropbox API is designed to fetch data from a user-specified URL. Files are
 | |
| not included in the request!
 | |
| 
 | |
| The SheetJS workaround involves the Data URI scheme[^5]. The main steps are:
 | |
| 
 | |
| 1) Write a workbook using the SheetJS `write`[^6] method. The `type: "base64"`
 | |
| option instructs the method to return a Base64-encoded string.
 | |
| 
 | |
| ```js
 | |
| /* write XLS workbook (Base64 string) */
 | |
| const b64 = XLSX.write(workbook, { type: "base64", bookType: "xls" });
 | |
| ```
 | |
| 
 | |
| 2) Construct a Data URL by prepending the `data` header:
 | |
| 
 | |
| ```js
 | |
| /* create data URI */
 | |
| const url = "data:application/vnd.ms-excel;base64," + b64;
 | |
| ```
 | |
| 
 | |
| 3) Create a button and add it to the page:
 | |
| 
 | |
| ```js
 | |
| /* create save button using the concise function call */
 | |
| var button = Dropbox.createSaveButton( url, "SheetJSDropbox.xls", {
 | |
|   success: () => setMsg("File saved successfully!"),
 | |
|   cancel: () => setMsg("User Canceled Selection!"),
 | |
| });
 | |
| document.appendChild(button);
 | |
| ```
 | |
| 
 | |
| :::info pass
 | |
| 
 | |
| The file must be written before the Save button is created.
 | |
| 
 | |
| :::
 | |
| 
 | |
| #### Saver Live Demo
 | |
| 
 | |
| This demo seeds data by fetching a file and writing to HTML table. The generated
 | |
| table is scraped to create a new workbook that is written to XLS.
 | |
| 
 | |
| :::caution pass
 | |
| 
 | |
| If the live demo shows a message
 | |
| 
 | |
| ```
 | |
| ReferenceError: Dropbox is not defined
 | |
| ```
 | |
| 
 | |
| please refresh the page.  This is a known bug in the documentation generator.
 | |
| 
 | |
| :::
 | |
| 
 | |
| ```jsx live
 | |
| function SheetJSEnregistrez() {
 | |
|   const [msg, setMsg] = React.useState("Press the button to write XLS file");
 | |
|   const btn = useRef(), tbl = useRef();
 | |
|   React.useEffect(async() => {
 | |
|     if(typeof Dropbox == "undefined") return setMsg("Dropbox is not defined");
 | |
|     /* fetch data and write table (sample data) */
 | |
|     const f = await(await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
 | |
|     const wb = XLSX.read(f);
 | |
|     tbl.current.innerHTML = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
 | |
| 
 | |
|     /* create workbook from table */
 | |
|     const table = tbl.current.getElementsByTagName("TABLE")[0];
 | |
|     const new_wb = XLSX.utils.table_to_book(table);
 | |
| 
 | |
|     /* write XLS workbook (Base64 string) */
 | |
|     const b64 = XLSX.write(new_wb, { type: "base64", bookType: "xls" });
 | |
| 
 | |
|     /* create data URI */
 | |
|     const url = "data:application/vnd.ms-excel;base64," + b64;
 | |
| 
 | |
|     /* create save button using the concise function call */
 | |
|     var button = Dropbox.createSaveButton( url, "SheetJSDropbox.xls", {
 | |
|       success: () => setMsg("File saved successfully!"),
 | |
|       cancel: () => setMsg("User Canceled Selection!"),
 | |
|     });
 | |
|     /* add button to page */
 | |
|     btn.current.appendChild(button);
 | |
|   }, []);
 | |
|   return ( <><b>{msg}</b><br/><div ref={btn}/><div ref={tbl}/></> );
 | |
| }
 | |
| ```
 | |
| 
 | |
| ## Dropbox App
 | |
| 
 | |
| :::note Tested Deployments
 | |
| 
 | |
| This demo was last tested on 2023 November 30.
 | |
| 
 | |
| :::
 | |
| 
 | |
| This demo requires a "Dropbox app":
 | |
| 
 | |
| 0) Create a Dropbox account and verify the associated email address. This demo
 | |
| has been tested with a free Dropbox Basic plan account. The app installation
 | |
| step can be safely skipped.
 | |
| 
 | |
| 1) Create a Dropbox app in the Developer panel.
 | |
| 
 | |
| Click the `᎒᎒᎒` icon > App Center. In the next page, click "Build an App". In
 | |
| the next page, click "Create Apps".
 | |
| 
 | |
| In the App creation wizard, select the following options:
 | |
| 
 | |
| - "Choose an API": "Scoped access"
 | |
| - "Choose the type of access you need": "Full Dropbox"
 | |
| - "Name": (enter any name) "SheetJS Docs"
 | |
| 
 | |
| :::caution pass
 | |
| 
 | |
| The Dropbox API Terms and Conditions should be reviewed before acceptance.
 | |
| 
 | |
| :::
 | |
| 
 | |
| Click "Create App" to create the app.
 | |
| 
 | |
| 2) Configure the Dropbox app in the Developer tools.
 | |
| 
 | |
| The following permissions should be selected in the "Permissions" tab
 | |
| 
 | |
| - `files.metadata.write` (View and edit information about your Dropbox files and folders)
 | |
| - `files.metadata.read` (View information about your Dropbox files and folders)
 | |
| - `files.content.write` (Edit content of your Dropbox files and folders)
 | |
| - `files.content.read` (View content of your Dropbox files and folders)
 | |
| 
 | |
| In the settings tab, under "Chooser / Saver / Embedder domains", the desired
 | |
| public domains should be added. `localhost` must also be added for development
 | |
| use (it is not automatically enabled).
 | |
| 
 | |
| For public use, select "Enable Additional Users".
 | |
| 
 | |
| 3) Copy the "App key" and add it to the `data-app-key` attribute of the Dropbox
 | |
| integration script reference.
 | |
| 
 | |
| [^1]: See ["Chooser"](https://www.dropbox.com/developers/chooser) in the Dropbox Developers Documentation
 | |
| [^2]: See ["Saver"](https://www.dropbox.com/developers/saver) in the Dropbox Developers Documentation
 | |
| [^3]: See [`read` in "Reading Files"](/docs/api/parse-options)
 | |
| [^4]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
 | |
| [^5]: See ["Data URLs"](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) in the "MDN web docs"
 | |
| [^6]: See [`writeFile` in "Writing Files"](/docs/api/write-options) |