forked from sheetjs/docs.sheetjs.com
electron
This commit is contained in:
parent
5d9b9d9a21
commit
f2e6365604
@ -433,7 +433,7 @@ click the "Click to Export!" button to generate a file.
|
||||
|
||||
## RequireJS
|
||||
|
||||
[Standalone scripts](../../installation/standalone) comply with AND `define`
|
||||
[Standalone scripts](../../installation/standalone) comply with AMD `define`
|
||||
semantics, enabling use in RequireJS out of the box.
|
||||
|
||||
To enable use of the alias `xlsx`, the RequireJS config should set an alias in
|
||||
@ -450,7 +450,7 @@ require.config({
|
||||
});
|
||||
// highlight-next-line
|
||||
require(["xlsx"], function(XLSX) {
|
||||
/* use XLSX here */
|
||||
/* use XLSX here */
|
||||
console.log(XLSX.version);
|
||||
});
|
||||
```
|
||||
|
@ -126,3 +126,223 @@ input.addEventListener('change',function(e){
|
||||
|
||||
input.click();
|
||||
```
|
||||
|
||||
## Electron
|
||||
|
||||
The [NodeJS Module](../../installation/nodejs) can be imported from the main or
|
||||
the renderer thread.
|
||||
|
||||
Electron presents a `fs` module. The `require('xlsx')` call loads the CommonJS
|
||||
module, so `XLSX.readFile` and `XLSX.writeFile` work in the renderer thread.
|
||||
|
||||
This demo was tested against Electron 19.0.5 on an Intel Mac (`darwin-x64`).
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
This demo includes a drag-and-drop box as well as a file input box, mirroring
|
||||
the [SheetJS Data Preview Live Demo](http://oss.sheetjs.com/sheetjs/)
|
||||
|
||||
The core data in this demo is an editable HTML table. The readers build up the
|
||||
table using `sheet_to_html` (with `editable:true` option) and the writers scrape
|
||||
the table using `table_to_book`.
|
||||
|
||||
The demo project is wired for `electron-forge` to build the standalone binary.
|
||||
|
||||
1) Download the demo files:
|
||||
|
||||
- [`package.json`](pathname:///electron/package.json) : project structure
|
||||
- [`main.js`](pathname:///electron/main.js) : entrypoint
|
||||
- [`index.html`](pathname:///electron/index.html) : window page
|
||||
- [`index.js`](pathname:///electron/index.js) : script loaded in render context
|
||||
|
||||
:::caution
|
||||
|
||||
Right-click each link and select "Save Link As...". Left-clicking a link will
|
||||
try to load the page in your browser. The goal is to save the file contents.
|
||||
|
||||
:::
|
||||
|
||||
2) Run `npm install` to install dependencies.
|
||||
|
||||
3) To verify the app works, run in the test environment:
|
||||
|
||||
```bash
|
||||
npx -y electron .
|
||||
```
|
||||
|
||||
The app will show and you should be able to verify reading and writing by using
|
||||
the relevant buttons to open files and clicking the export button.
|
||||
|
||||
4) To build a standalone app, run the builder:
|
||||
|
||||
```bash
|
||||
npm run make
|
||||
```
|
||||
|
||||
This will generate the standalone app in the `out\sheetjs-electron-...` folder.
|
||||
For a recent Intel Mac, the path will be `out/sheetjs-electron-darwin-x64/`
|
||||
|
||||
</details>
|
||||
|
||||
### Writing Files
|
||||
|
||||
[`XLSX.writeFile`](../../api/write-options) writes workbooks to the filesystem.
|
||||
`showSaveDialog` shows a Save As dialog and returns the selected file name:
|
||||
|
||||
```js
|
||||
/* from the renderer thread */
|
||||
const electron = require('@electron/remote');
|
||||
|
||||
/* this function will show the save dialog and try to write the workbook */
|
||||
async function exportFile(workbook) {
|
||||
/* show Save As dialog */
|
||||
const result = await electron.dialog.showSaveDialog({
|
||||
title: 'Save file as',
|
||||
filters: [{
|
||||
name: "Spreadsheets",
|
||||
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
|
||||
}]
|
||||
});
|
||||
/* write file */
|
||||
// highlight-next-line
|
||||
XLSX.writeFile(workbook, result.filePath);
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
In older versions of Electron, `showSaveDialog` returned the path directly:
|
||||
|
||||
```js
|
||||
var dialog = require('electron').remote.dialog;
|
||||
|
||||
function exportFile(workbook) {
|
||||
var result = dialog.showSaveDialog();
|
||||
XLSX.writeFile(workbook, result);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Reading Files
|
||||
|
||||
Electron offers 3 different ways to read files, two of which use Web APIs.
|
||||
|
||||
**File Input Element**
|
||||
|
||||
File input elements automatically map to standard Web APIs.
|
||||
|
||||
For example, assuming a file input element on the page:
|
||||
|
||||
```html
|
||||
<input type="file" name="xlfile" id="xlf" />
|
||||
```
|
||||
|
||||
The event handler would process the event as if it were a web event:
|
||||
|
||||
```js
|
||||
async function handleFile(e) {
|
||||
const file = e.target.files[0];
|
||||
const data = await file.arrayBuffer();
|
||||
/* data is an ArrayBuffer */
|
||||
const workbook = XLSX.read(data);
|
||||
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
}
|
||||
document.getElementById("xlf").addEventListener("change", handleFile, false);
|
||||
```
|
||||
|
||||
**Drag and Drop**
|
||||
|
||||
The [drag and drop snippet](../../solutions/input#example-user-submissions)
|
||||
applies to DIV elements on the page.
|
||||
|
||||
For example, assuming a DIV on the page:
|
||||
|
||||
```html
|
||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
|
||||
```
|
||||
|
||||
The event handler would process the event as if it were a web event:
|
||||
|
||||
```js
|
||||
async function handleDrop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
const file = e.dataTransfer.files[0];
|
||||
const data = await file.arrayBuffer();
|
||||
/* data is an ArrayBuffer */
|
||||
const workbook = XLSX.read(data);
|
||||
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
}
|
||||
document.getElementById("drop").addEventListener("drop", handleDrop, false);
|
||||
```
|
||||
|
||||
**Electron API**
|
||||
|
||||
[`XLSX.readFile`](../../api/parse-options) reads workbooks from the filesystem.
|
||||
`showOpenDialog` shows a Save As dialog and returns the selected file name.
|
||||
Unlike the Web APIs, the `showOpenDialog` flow can be initiated by app code:
|
||||
|
||||
```js
|
||||
/* from the renderer thread */
|
||||
const electron = require('@electron/remote');
|
||||
|
||||
/* this function will show the open dialog and try to parse the workbook */
|
||||
async function importFile() {
|
||||
/* show Save As dialog */
|
||||
const result = await electron.dialog.showOpenDialog({
|
||||
title: 'Select a file',
|
||||
filters: [{
|
||||
name: "Spreadsheets",
|
||||
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
|
||||
}]
|
||||
});
|
||||
/* result.filePaths is an array of selected files */
|
||||
if(result.filePaths.length == 0) throw new Error("No file was selected!");
|
||||
// highlight-next-line
|
||||
return XLSX.readFile(result.filePaths[0]);
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
In older versions of Electron, `showOpenDialog` returned the path directly:
|
||||
|
||||
```js
|
||||
var dialog = require('electron').remote.dialog;
|
||||
|
||||
function importFile(workbook) {
|
||||
var result = dialog.showOpenDialog({ properties: ['openFile'] });
|
||||
return XLSX.readFile(result[0]);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Electron Breaking Changes
|
||||
|
||||
The first version of this demo used Electron 1.7.5. The current demo includes
|
||||
the required changes for Electron 19.0.5.
|
||||
|
||||
There are no Electron-specific workarounds in the library, but Electron broke
|
||||
backwards compatibility multiple times. A summary of changes is noted below.
|
||||
|
||||
:::caution
|
||||
|
||||
Electron 6.x changed the `dialog` API. Methods like `showSaveDialog` originally
|
||||
returned an array of strings, but now returns a `Promise`. This change was not
|
||||
documented. [Electron issue](https://github.com/electron/electron/issues/24438)
|
||||
|
||||
Electron 9.0.0 and later require the preference `nodeIntegration: true` in order
|
||||
to `require('xlsx')` in the renderer process.
|
||||
|
||||
Electron 12.0.0 and later also require `worldSafeExecuteJavascript: true` and
|
||||
`contextIsolation: true`.
|
||||
|
||||
Electron 14+ must use `@electron/remote` instead of `remote`. An `initialize`
|
||||
call is required to enable DevTools in the window.
|
||||
|
||||
:::
|
||||
|
@ -37,7 +37,7 @@ The demo projects include small runnable examples and short explainers.
|
||||
|
||||
- [`Command-Line Tools`](./cli)
|
||||
- [`NodeJS Server-Side Processing`](https://github.com/SheetJS/SheetJS/tree/master/demos/server/)
|
||||
- [`Electron`](https://github.com/SheetJS/SheetJS/tree/master/demos/electron/)
|
||||
- [`Electron`](./desktop#electron)
|
||||
- [`NW.js`](./desktop#nwjs)
|
||||
- [`Chrome / Chromium Extension`](./chromium)
|
||||
- [`Google Sheets API`](./gsheet)
|
||||
@ -63,7 +63,6 @@ The demo projects include small runnable examples and short explainers.
|
||||
- [`snowpack`](./bundler#snowpack)
|
||||
- [`swc`](./bundler#swc)
|
||||
- [`systemjs`](https://github.com/SheetJS/SheetJS/tree/master/demos/systemjs/)
|
||||
- [`typescript`](https://github.com/SheetJS/SheetJS/tree/master/demos/typescript/)
|
||||
- [`vite`](./bundler#vite)
|
||||
- [`webpack 2.x`](https://github.com/SheetJS/SheetJS/tree/master/demos/webpack/)
|
||||
- [`wmr`](./bundler#wmr)
|
||||
|
@ -90,7 +90,7 @@ var XLSX = require("xlsx");
|
||||
var workbook = XLSX.readFile(path);
|
||||
```
|
||||
|
||||
Electron APIs have changed over time. The [`electron` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/electron/)
|
||||
Electron APIs have changed over time. The [`electron` demo](../getting-started/demos/desktop#electron)
|
||||
shows a complete example and details the required version-specific settings.
|
||||
|
||||
</TabItem>
|
||||
|
@ -235,7 +235,7 @@ var XLSX = require("xlsx");
|
||||
XLSX.writeFile(workbook, "out.xlsb");
|
||||
```
|
||||
|
||||
Electron APIs have changed over time. The [`electron` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/electron/)
|
||||
Electron APIs have changed over time. The [`electron` demo](../getting-started/demos/desktop#electron)
|
||||
shows a complete example and details the required version-specific settings.
|
||||
|
||||
</TabItem>
|
||||
|
@ -80,8 +80,8 @@ function Table2XLSX(props) {
|
||||
return (<>
|
||||
<table id="Table2XLSX"><tbody>
|
||||
<tr><td colSpan="3">SheetJS Table Export</td></tr>
|
||||
<tr><td>Author</td><td>ID</td><td>Note</td></tr>
|
||||
<tr><td>SheetJS</td><td>7262</td><td>Hi!</td></tr>
|
||||
<tr><td>Author</td><td>ID</td><td>你好!</td></tr>
|
||||
<tr><td>SheetJS</td><td>7262</td><td>வணக்கம்!</td></tr>
|
||||
<tr><td colSpan="3">
|
||||
<a href="//sheetjs.com">Powered by SheetJS</a>
|
||||
</td></tr>
|
||||
|
@ -14,20 +14,20 @@
|
||||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cmfcmf/docusaurus-search-local": "^0.10.0",
|
||||
"@docusaurus/core": "2.0.0-beta.20",
|
||||
"@docusaurus/preset-classic": "2.0.0-beta.20",
|
||||
"@docusaurus/theme-common": "2.0.0-beta.20",
|
||||
"@docusaurus/theme-live-codeblock": "2.0.0-beta.20",
|
||||
"@mdx-js/react": "1.6.22",
|
||||
"clsx": "1.1.1",
|
||||
"prism-react-renderer": "1.3.1",
|
||||
"@cmfcmf/docusaurus-search-local": "0.11.0",
|
||||
"@docusaurus/core": "2.0.1",
|
||||
"@docusaurus/preset-classic": "2.0.1",
|
||||
"@docusaurus/theme-common": "2.0.1",
|
||||
"@docusaurus/theme-live-codeblock": "2.0.1",
|
||||
"@mdx-js/react": "2.1.2",
|
||||
"clsx": "1.2.1",
|
||||
"prism-react-renderer": "1.3.5",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.20"
|
||||
"@docusaurus/module-type-aliases": "2.0.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
36
docz/static/electron/index.html
Normal file
36
docz/static/electron/index.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- sheetjs (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' https:">
|
||||
<title>SheetJS Electron Demo</title>
|
||||
<style>
|
||||
#drop{
|
||||
border:2px dashed #bbb;
|
||||
-moz-border-radius:5px;
|
||||
-webkit-border-radius:5px;
|
||||
border-radius:5px;
|
||||
padding:25px;
|
||||
text-align:center;
|
||||
font:20pt bold,"Vollkorn";color:#bbb
|
||||
}
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="https://sheetjs.com">SheetJS Electron Demo</a></b>
|
||||
<br />
|
||||
<button id="readBtn">Click here to select a file from your computer</button><br />
|
||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
|
||||
<input type="file" name="xlfile" id="readIn" /> ... or click here to select a file
|
||||
|
||||
</pre>
|
||||
<p><input type="submit" value="Export Data!" id="exportBtn" disabled="true"></p>
|
||||
<div id="htmlout"></div>
|
||||
<br />
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
73
docz/static/electron/index.js
Normal file
73
docz/static/electron/index.js
Normal file
@ -0,0 +1,73 @@
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
const XLSX = require('xlsx');
|
||||
const electron = require('@electron/remote');
|
||||
|
||||
/* list of supported extensions */
|
||||
const EXTENSIONS = "xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html|numbers".split("|");
|
||||
|
||||
/* write file with Electron API */
|
||||
async function exportFile() {
|
||||
const HTMLOUT = document.getElementById('htmlout');
|
||||
const wb = XLSX.utils.table_to_book(HTMLOUT.getElementsByTagName("TABLE")[0]);
|
||||
const o = await electron.dialog.showSaveDialog({
|
||||
title: 'Save file as',
|
||||
filters: [{
|
||||
name: "Spreadsheets",
|
||||
extensions: EXTENSIONS
|
||||
}]
|
||||
});
|
||||
XLSX.writeFile(wb, o.filePath);
|
||||
electron.dialog.showMessageBox({ message: "Exported data to " + o.filePath, buttons: ["OK"] });
|
||||
}
|
||||
document.getElementById('exportBtn').addEventListener('click', exportFile, false);
|
||||
|
||||
/* common handler to create HTML tables on the page */
|
||||
function process_wb(wb) {
|
||||
const HTMLOUT = document.getElementById('htmlout');
|
||||
const XPORT = document.getElementById('exportBtn');
|
||||
XPORT.disabled = false;
|
||||
HTMLOUT.innerHTML = "";
|
||||
wb.SheetNames.forEach(function(sheetName) {
|
||||
const htmlstr = XLSX.utils.sheet_to_html(wb.Sheets[sheetName],{editable:true});
|
||||
HTMLOUT.innerHTML += htmlstr;
|
||||
});
|
||||
}
|
||||
|
||||
/* read file with Electron API */
|
||||
async function handleReadBtn() {
|
||||
const o = await electron.dialog.showOpenDialog({
|
||||
title: 'Select a file',
|
||||
filters: [{
|
||||
name: "Spreadsheets",
|
||||
extensions: EXTENSIONS
|
||||
}],
|
||||
properties: ['openFile']
|
||||
});
|
||||
if(o.filePaths.length == 0) throw new Error("No file was selected!");
|
||||
process_wb(XLSX.readFile(o.filePaths[0]));
|
||||
}
|
||||
document.getElementById('readBtn').addEventListener('click', handleReadBtn, false);
|
||||
|
||||
/* read file with Web APIs */
|
||||
async function readFile(files) {
|
||||
const f = files[0];
|
||||
const data = await f.arrayBuffer();
|
||||
process_wb(XLSX.read(data));
|
||||
}
|
||||
|
||||
// file input element
|
||||
document.getElementById('readIn').addEventListener('change', (e) => { readFile(e.target.files); }, false);
|
||||
|
||||
// drag and drop
|
||||
const drop = document.getElementById('drop');
|
||||
drop.addEventListener('drop', (e) => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
readFile(e.dataTransfer.files);
|
||||
}, false);
|
||||
|
||||
const handleDrag = (e) => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
};
|
||||
drop.addEventListener('dragenter', handleDrag, false);
|
||||
drop.addEventListener('dragover', handleDrag, false);
|
29
docz/static/electron/main.js
Normal file
29
docz/static/electron/main.js
Normal file
@ -0,0 +1,29 @@
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
var electron = require('electron');
|
||||
var XLSX = require('xlsx');
|
||||
var app = electron.app;
|
||||
require('@electron/remote/main').initialize(); // required for Electron 14+
|
||||
|
||||
var win = null;
|
||||
|
||||
function createWindow() {
|
||||
if (win) return;
|
||||
win = new electron.BrowserWindow({
|
||||
width: 800, height: 600,
|
||||
webPreferences: {
|
||||
worldSafeExecuteJavaScript: true, // required for Electron 12+
|
||||
contextIsolation: false, // required for Electron 12+
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
});
|
||||
win.loadURL("file://" + __dirname + "/index.html");
|
||||
require('@electron/remote/main').enable(win.webContents); // required for Electron 14+
|
||||
win.webContents.openDevTools();
|
||||
win.on('closed', function () { win = null; });
|
||||
}
|
||||
if (app.setAboutPanelOptions) app.setAboutPanelOptions({ applicationName: 'sheetjs-electron', applicationVersion: "XLSX " + XLSX.version, copyright: "(C) 2017-present SheetJS LLC" });
|
||||
app.on('open-file', function () { console.log(arguments); });
|
||||
app.on('ready', createWindow);
|
||||
app.on('activate', createWindow);
|
||||
app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });
|
51
docz/static/electron/package.json
Normal file
51
docz/static/electron/package.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "sheetjs-electron",
|
||||
"author": "sheetjs",
|
||||
"version": "0.0.0",
|
||||
"main": "main.js",
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.0.8",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-forge/cli": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-deb": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-rpm": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.64",
|
||||
"@electron-forge/maker-zip": "^6.0.0-beta.64",
|
||||
"electron": "19.0.5"
|
||||
},
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {},
|
||||
"makers": [
|
||||
{
|
||||
"name": "@electron-forge/maker-squirrel",
|
||||
"config": {
|
||||
"name": "sheetjs_electron"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-zip",
|
||||
"platforms": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-deb",
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"name": "@electron-forge/maker-rpm",
|
||||
"config": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user