vue
This commit is contained in:
parent
d4a38231dd
commit
2d5f8ebce4
@ -27,6 +27,86 @@ suitable for a number of libraries. When more advanced shapes are needed,
|
||||
it is easier to munge the output of an array of arrays.
|
||||
|
||||
|
||||
### x-spreadsheet
|
||||
|
||||
With a familiar UI, [`x-spreadsheet`](https://myliang.github.io/x-spreadsheet/)
|
||||
is an excellent choice for developers looking for a modern editor.
|
||||
|
||||
[Click here for a live integration demo.](pathname:///xspreadsheet/)
|
||||
|
||||
<details><summary><b>Full Exposition</b> (click to show)</summary>
|
||||
|
||||
**Obtaining the Library**
|
||||
|
||||
The `x-data-spreadsheet` NodeJS packages include a minified script that can be
|
||||
directly inserted as a script tag. The unpkg CDN also serves this script:
|
||||
|
||||
```html
|
||||
<!-- x-spreadsheet stylesheet -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.css"/>
|
||||
<!-- x-spreadsheet library -->
|
||||
<script src="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.js"></script>
|
||||
```
|
||||
|
||||
**Previewing and Editing Data**
|
||||
|
||||
The HTML document needs a container element:
|
||||
|
||||
```html
|
||||
<div id="gridctr"></div>
|
||||
```
|
||||
|
||||
Grid initialization is a one-liner:
|
||||
|
||||
```js
|
||||
var grid = x_spreadsheet(document.getElementById("gridctr"));
|
||||
```
|
||||
|
||||
`x-spreadsheet` handles the entire edit cycle. No intervention is necessary.
|
||||
|
||||
**SheetJS and x-spreadsheet**
|
||||
|
||||
The integration library can be downloaded from the SheetJS CDN:
|
||||
|
||||
[Development Use](https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js)
|
||||
|
||||
[Production Use](https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js)
|
||||
|
||||
|
||||
When used in a browser tag, it exposes two functions: `xtos` and `stox`.
|
||||
|
||||
- `stox(worksheet)` returns a data structure suitable for `grid.loadData`
|
||||
- `xtos(data)` accepts the result of `grid.getData` and generates a workbook
|
||||
|
||||
_Reading Data_
|
||||
|
||||
The following snippet fetches a spreadsheet and loads the grid:
|
||||
|
||||
```js
|
||||
(async() => {
|
||||
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
|
||||
grid.loadData(stox(XLSX.read(ab)));
|
||||
})();
|
||||
```
|
||||
|
||||
The same pattern can be used in file input elements and other data sources.
|
||||
|
||||
_Writing Data_
|
||||
|
||||
The following snippet exports the grid data to a file:
|
||||
|
||||
```js
|
||||
/* build workbook from the grid data */
|
||||
XLSX.writeFile(xtos(grid.getData()), "SheetJS.xlsx");
|
||||
```
|
||||
|
||||
**Additional Features**
|
||||
|
||||
This demo barely scratches the surface. The underlying grid component includes
|
||||
many additional features that work with [SheetJS Pro](https://sheetjs.com/pro).
|
||||
|
||||
</details>
|
||||
|
||||
### Canvas DataGrid
|
||||
|
||||
After extensive testing, [`canvas-datagrid`](https://canvas-datagrid.js.org/demo.html)
|
||||
@ -120,7 +200,6 @@ many additional features including massive data streaming, sorting and styling.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### Angular UI Grid
|
||||
|
||||
:::warning
|
||||
@ -223,7 +302,7 @@ import { WorkSheet, utils } from 'xlsx';
|
||||
|
||||
type Row = any[];
|
||||
|
||||
function ws_to_rdg(rows: Row[]): WorkSheet {
|
||||
function rdg_to_ws(rows: Row[]): WorkSheet {
|
||||
return utils.aoa_to_sheet(rows);
|
||||
}
|
||||
```
|
||||
@ -361,8 +440,135 @@ export default function App() {
|
||||
4) run `npm start`. When you load the dev page in the browser, it will attempt
|
||||
to fetch <https://sheetjs.com/pres.numbers> and load the data.
|
||||
|
||||
</details>
|
||||
|
||||
The following screenshot was taken from the demo:
|
||||
|
||||
![react-data-grid screenshot](pathname:///react/rdg1.png)
|
||||
|
||||
</details>
|
||||
|
||||
### vue3-table-lite
|
||||
|
||||
:::note
|
||||
|
||||
This demo was tested against `vue3-table-lite 1.2.4`, VueJS `3.2.37`, ViteJS
|
||||
3.0.7, and `@vitejs/plugin-vue` 3.0.3 on 2022 August 18
|
||||
|
||||
:::
|
||||
|
||||
[`vue3-table-lite`](https://vue3-lite-table.vercel.app/) is a data grid built
|
||||
for Vue
|
||||
|
||||
[A complete example is included below.](#vte-demo)
|
||||
|
||||
#### Rows and Columns Bindings
|
||||
|
||||
`vue3-table-lite` presents two bindable attributes: an array of column metadata
|
||||
(`columns`) and an array of objects representing the displayed data (`rows`).
|
||||
Typically both are `ref` objects:
|
||||
|
||||
|
||||
```html
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import VueTableLite from "vue3-table-lite/ts";
|
||||
|
||||
/* rows */
|
||||
type Row = any[];
|
||||
const rows = ref<Row[]>([]);
|
||||
|
||||
/* columns */
|
||||
type Column = { field: string; label: string; };
|
||||
const columns = ref<Column[]>([]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<vue-table-lite :columns="columns" :rows="rows"></vue-table-lite>
|
||||
</template>
|
||||
```
|
||||
|
||||
These can be mutated through the `value` property in Vue lifecycle methods:
|
||||
|
||||
```ts
|
||||
import { onMounted } from "vue";
|
||||
onMounted(() => {
|
||||
columns.value = [ { field: "name", label: "Names" }];
|
||||
rows.value = [ { name: "SheetJS" }, { name: "VueJS" } ];
|
||||
})
|
||||
```
|
||||
|
||||
The most generic data representation is an array of arrays. To sate the grid,
|
||||
the columns must be objects whose `field` property is the stringified number:
|
||||
|
||||
```js
|
||||
import { ref } from "vue";
|
||||
import { utils } from 'xlsx';
|
||||
|
||||
/* generate row and column data */
|
||||
function ws_to_vte(ws) {
|
||||
/* create an array of arrays */
|
||||
const rows = utils.sheet_to_json(ws, { header: 1 });
|
||||
|
||||
/* create column array */
|
||||
const range = utils.decode_range(ws["!ref"]||"A1");
|
||||
const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({
|
||||
field: String(i), // VTE will access row["0"], row["1"], etc
|
||||
label: utils.encode_col(i), // the column labels will be A, B, etc
|
||||
}));
|
||||
|
||||
return { rows, columns };
|
||||
}
|
||||
|
||||
const rows = ref([]);
|
||||
const columns = ref([]);
|
||||
|
||||
/* update refs */
|
||||
function update_refs(ws) {
|
||||
const data = ws_to_vte(ws);
|
||||
rows.value = data.rows;
|
||||
columns.value = data.columns;
|
||||
}
|
||||
```
|
||||
|
||||
In the other direction, a worksheet can be generated with `aoa_to_sheet`:
|
||||
|
||||
```js
|
||||
import { utils } from 'xlsx';
|
||||
|
||||
const rows = ref([]);
|
||||
|
||||
function vte_to_ws(rows) {
|
||||
return utils.aoa_to_sheet(rows.value);
|
||||
}
|
||||
```
|
||||
|
||||
#### VTE Demo
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
1) Create a new ViteJS App using the Vue + TypeScript template:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-vue -- --template vue-ts
|
||||
cd sheetjs-vue
|
||||
```
|
||||
|
||||
2) Install dependencies:
|
||||
|
||||
```bash
|
||||
npm i
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz vue3-table-lite
|
||||
```
|
||||
|
||||
3) Download [`src/App.vue`](pathname:///vtl/App.vue) and replace the contents:
|
||||
|
||||
```bash
|
||||
cd src
|
||||
rm -f App.vue
|
||||
curl -LO https://docs.sheetjs.com/vtl/App.vue
|
||||
cd ..
|
||||
```
|
||||
|
||||
4) run `npm run dev`. When you load the dev page in the browser, it will try
|
||||
to fetch <https://sheetjs.com/pres.numbers> and load the data.
|
||||
|
||||
</details>
|
||||
|
@ -434,7 +434,7 @@ ready, it will read the hardcoded test file and print the contents as CSV.
|
||||
|
||||
5) Run the script using the Hermes standalone binary:
|
||||
|
||||
```
|
||||
```bash
|
||||
hermes xlsx.hermes.js
|
||||
```
|
||||
|
||||
@ -540,6 +540,93 @@ to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers.
|
||||
|
||||
</details>
|
||||
|
||||
## JerryScript
|
||||
|
||||
JerryScript is a lightweight JavaScript engine designed for use in low-memory
|
||||
environments like microcontrollers. As part of the build suite, the project
|
||||
generates a C library and a standalone CLI tool.
|
||||
|
||||
The simplest way to interact with the engine is to pass Base64 strings.
|
||||
|
||||
:::note
|
||||
|
||||
While applications should link against the official libraries, the standalone tool
|
||||
is useful for verifying functionality.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
This demo requires a much larger heap size than is normally used in JerryScript
|
||||
deployments! In local testing, the following sizes were needed:
|
||||
|
||||
- 8192 (8M) for <https://sheetjs.com/pres.xlsx>
|
||||
- 65536 (64M) for <https://sheetjs.com/pres.numbers>
|
||||
|
||||
This works on a Raspberry Pi.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
Due to limitations of the standalone binary, this demo will encode a test file
|
||||
as a Base64 string and directly add it to an amalgamated script.
|
||||
|
||||
0) Build the library and command line tool with required options:
|
||||
|
||||
```bash
|
||||
git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git
|
||||
cd jerryscript
|
||||
python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON
|
||||
```
|
||||
|
||||
1) Download the standalone script, shim, and test file:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
||||
</ul>
|
||||
|
||||
2) Bundle the test file and create `payload.js`:
|
||||
|
||||
```bash
|
||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')"
|
||||
```
|
||||
|
||||
3) Create support scripts:
|
||||
|
||||
- `global.js` creates a `global` variable and defines a fake `console`:
|
||||
|
||||
```js title="global.js"
|
||||
var global = (function(){ return this; }).call(null);
|
||||
var console = { log: function(x) { print(x); } };
|
||||
```
|
||||
|
||||
- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
|
||||
|
||||
```js title="jerry.js"
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
var wb = XLSX.read(payload, {type:'base64'});
|
||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||||
```
|
||||
|
||||
4) Create the amalgamation `xlsx.jerry.js`:
|
||||
|
||||
```bash
|
||||
cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js
|
||||
```
|
||||
|
||||
The final script defines `global` before loading the standalone library. Once
|
||||
ready, it will read the hardcoded test file and print the contents as CSV.
|
||||
|
||||
5) Run the script using the `jerry` standalone binary:
|
||||
|
||||
```bash
|
||||
build/bin/jerry xlsx.jerry.js; echo $?
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## QuickJS
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 20
|
||||
sidebar_position: 21
|
||||
title: ReactJS
|
||||
---
|
||||
|
||||
@ -38,7 +38,7 @@ Typically, some users will create a spreadsheet with source data that should be
|
||||
loaded into the site. This sheet will have known columns. For example, our
|
||||
[presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns:
|
||||
|
||||
![`pres.xlsx` data](pathname:///react/pres.png)
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
This naturally maps to an array of typed objects, as in the TS example below:
|
||||
|
||||
|
184
docz/docs/03-demos/22-vue.md
Normal file
184
docz/docs/03-demos/22-vue.md
Normal file
@ -0,0 +1,184 @@
|
||||
---
|
||||
sidebar_position: 22
|
||||
title: VueJS
|
||||
---
|
||||
|
||||
[VueJS](https://vuejs.org/) is a JS library for building user interfaces.
|
||||
|
||||
This demo tries to cover common Vue data flow ideas and strategies. Single-File
|
||||
Components (SFC) and VueJS familiarity is assumed.
|
||||
|
||||
Other demos cover general VueJS deployments, including:
|
||||
|
||||
- [Static Site Generation powered by NuxtJS](./content#nuxtjs)
|
||||
- [iOS and Android applications powered by Quasar](./mobile#quasar)
|
||||
- [`vue3-table-lite` UI component](./grid#vue3-table-lite)
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
[The "Frameworks" section](../getting-started/installation/frameworks) covers
|
||||
installation with Yarn and other package managers.
|
||||
|
||||
The library can be imported directly from JS or JSX code with:
|
||||
|
||||
```js
|
||||
import { read, utils, writeFile } from 'xlsx';
|
||||
```
|
||||
|
||||
|
||||
## Internal State
|
||||
|
||||
The various SheetJS APIs work with various data shapes. The preferred state
|
||||
depends on the application.
|
||||
|
||||
### Array of Objects
|
||||
|
||||
Typically, some users will create a spreadsheet with source data that should be
|
||||
loaded into the site. This sheet will have known columns. For example, our
|
||||
[presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns:
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
This naturally maps to an array of typed objects, as in the TS example below:
|
||||
|
||||
```ts
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
interface President {
|
||||
Name: string;
|
||||
Index: number;
|
||||
}
|
||||
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f);
|
||||
const data = utils.sheet_to_json<President>(wb.Sheets[wb.SheetNames[0]]);
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
`data` will be an array of objects:
|
||||
|
||||
```js
|
||||
[
|
||||
{ Name: "Bill Clinton", Index: 42 },
|
||||
{ Name: "GeorgeW Bush", Index: 43 },
|
||||
{ Name: "Barack Obama", Index: 44 },
|
||||
{ Name: "Donald Trump", Index: 45 },
|
||||
{ Name: "Joseph Biden", Index: 46 }
|
||||
]
|
||||
```
|
||||
|
||||
A component will typically map over the data. The following example generates
|
||||
a TABLE with a row for each President:
|
||||
|
||||
```html title="src/SheetJSVueAoO.vue"
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
const rows = ref([]);
|
||||
|
||||
onMounted(async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
const wb = read(ab);
|
||||
|
||||
/* update data */
|
||||
rows.value = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table><thead><th>Name</th><th>Index</th></thead><tbody>
|
||||
<tr v-for="(row, idx) in rows" :key="idx">
|
||||
<td>{{ row.Name }}</td>
|
||||
<td>{{ row.Index }}</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</template>
|
||||
```
|
||||
|
||||
### HTML
|
||||
|
||||
The main disadvantage of the Array of Objects approach is the specific nature
|
||||
of the columns. For more general use, passing around an Array of Arrays works.
|
||||
However, this does not handle merge cells well!
|
||||
|
||||
The `sheet_to_html` function generates HTML that is aware of merges and other
|
||||
worksheet features. VueJS `v-html` attribute allows assignment of `innerHTML`
|
||||
attribute, effectively inserting the code into the page:
|
||||
|
||||
```html title="src/SheetJSVueHTML.vue"
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
const html = ref("");
|
||||
|
||||
onMounted(async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
const wb = read(ab);
|
||||
|
||||
/* update data */
|
||||
html.value = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-html="html"></div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Rows and Columns
|
||||
|
||||
Some data grids and UI components split worksheet state in two parts: an array
|
||||
of column attribute objects and an array of row objects. The former is used to
|
||||
generate column headings and for indexing into the row objects.
|
||||
|
||||
The safest approach is to use an array of arrays for state and to generate
|
||||
column objects that map to A1-style column headers.
|
||||
|
||||
The [Vue Table Lite demo](./grid#rows-and-columns-bindings) uses this approach
|
||||
with the following column and row structure:
|
||||
|
||||
```js
|
||||
/* rows are generated with a simple array of arrays */
|
||||
rows.value = utils.sheet_to_json(worksheet, { header: 1 });
|
||||
|
||||
/* column objects are generated based on the worksheet range */
|
||||
const range = utils.decode_range(ws["!ref"]||"A1");
|
||||
columns.value = Array.from({ length: range.e.c + 1 }, (_, i) => ({
|
||||
/* for an array of arrays, the keys are "0", "1", "2", ... */
|
||||
field: String(i),
|
||||
/* column labels: encode_col translates 0 -> "A", 1 -> "B", 2 -> "C", ... */
|
||||
label: XLSX.utils.encode_col(i)
|
||||
}));
|
||||
```
|
||||
|
||||
|
||||
## Legacy Deployments
|
||||
|
||||
[The Standalone Scripts](../getting-started/installation/standalone) play nice
|
||||
with legacy deployments that do not use a bundler.
|
||||
|
||||
The legacy demos show a simple VueJS component. It is written in ES5 syntax.
|
||||
The pages are not minified and "View Source" should be used to inspect.
|
||||
|
||||
- [VueJS version 2](pathname:///vue/index2.html)
|
||||
- [VueJS version 3](pathname:///vue/index3.html)
|
||||
|
||||
There is a shared component [`SheetJS-vue.js`](pathname:///vue/SheetJS-vue.js)
|
||||
|
||||
:::caution
|
||||
|
||||
The entire demo is designed to run in Internet Explorer and does not reflect
|
||||
modern design patterns.
|
||||
|
||||
:::
|
@ -18,18 +18,18 @@ The demo projects include small runnable examples and short explainers.
|
||||
|
||||
### Frameworks
|
||||
|
||||
- [`Angular.JS`](./legacy#angularjs)
|
||||
- [`Angular 2+ and Ionic`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular2/)
|
||||
- [`Knockout`](./legacy#knockout)
|
||||
- [`React`](./react)
|
||||
- [`VueJS`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/)
|
||||
- [`VueJS`](./vue)
|
||||
- [`Angular.JS`](./legacy#angularjs)
|
||||
- [`Knockout`](./legacy#knockout)
|
||||
|
||||
### Front-End UI Components
|
||||
|
||||
- [`canvas-datagrid`](./grid#canvas-datagrid)
|
||||
- [`x-spreadsheet`](https://github.com/SheetJS/SheetJS/tree/master/demos/xspreadsheet/)
|
||||
- [`react-data-grid`](https://github.com/SheetJS/SheetJS/tree/master/demos/react/modify/)
|
||||
- [`vue3-table-light`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/modify/)
|
||||
- [`x-spreadsheet`](./grid#x-spreadsheet)
|
||||
- [`react-data-grid`](./grid#react-data-grid)
|
||||
- [`vue3-table-lite`](./grid#vue3-table-lite)
|
||||
- [`angular-ui-grid`](./grid#angular-ui-grid)
|
||||
|
||||
### Platforms and Integrations
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
var XLSX = require('xlsx');
|
||||
/*jshint browser:true */
|
||||
/*global require */
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- sheetjs (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
var XLSX = require('xlsx');
|
||||
|
||||
postMessage({t:"ready"});
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- sheetjs (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- xlsx.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- sheetjs (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html ng-app="sjs">
|
||||
<head>
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@ -3,156 +3,156 @@
|
||||
<!-- vim: set ts=2: -->
|
||||
<html lang="en" style="height: 100%">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS React Demo</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
|
||||
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
<style>body, #app { height: 100%; }</style>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS React Demo</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
|
||||
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
<style>body, #app { height: 100%; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid"><h1><a href="http://sheetjs.com">SheetJS × React Demo</a></h1><br /></div>
|
||||
<div id="app" class="container-fluid"></div>
|
||||
<script type="text/babel">
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* Notes:
|
||||
- usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );`
|
||||
- xlsx.full.min.js is loaded in the head of the HTML page
|
||||
- this script should be referenced with type="text/babel"
|
||||
- babel.js in-browser transpiler should be loaded before this script
|
||||
*/
|
||||
const { read, writeFile } = XLSX;
|
||||
const { decode_range, encode_col, sheet_to_json, aoa_to_sheet, book_new, book_append_sheet } = XLSX.utils;
|
||||
<div class="container-fluid"><h1><a href="http://sheetjs.com">SheetJS × React Demo</a></h1><br /></div>
|
||||
<div id="app" class="container-fluid"></div>
|
||||
<script type="text/babel">
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* Notes:
|
||||
- usage: `ReactDOM.render( <SheetJSApp />, document.getElementById('app') );`
|
||||
- xlsx.full.min.js is loaded in the head of the HTML page
|
||||
- this script should be referenced with type="text/babel"
|
||||
- babel.js in-browser transpiler should be loaded before this script
|
||||
*/
|
||||
const { read, writeFile } = XLSX;
|
||||
const { decode_range, encode_col, sheet_to_json, aoa_to_sheet, book_new, book_append_sheet } = XLSX.utils;
|
||||
|
||||
/* generate an array of column objects */
|
||||
const make_cols = refstr => Array.from({length: decode_range(refstr).e.c + 1}, (_, i) => ({ name: encode_col(i), key: i}));
|
||||
/* generate an array of column objects */
|
||||
const make_cols = refstr => Array.from({length: decode_range(refstr).e.c + 1}, (_, i) => ({ name: encode_col(i), key: i}));
|
||||
|
||||
/* main component */
|
||||
function SheetJSApp() {
|
||||
const [data, setData] = React.useState([]);
|
||||
const [cols, setCols] = React.useState([]);
|
||||
/* main component */
|
||||
function SheetJSApp() {
|
||||
const [data, setData] = React.useState([]);
|
||||
const [cols, setCols] = React.useState([]);
|
||||
|
||||
const handleFile = (file) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
/* Parse data */
|
||||
const ab = e.target.result;
|
||||
const wb = read(ab, { type: 'array' });
|
||||
/* Get first worksheet */
|
||||
const wsname = wb.SheetNames[0];
|
||||
const ws = wb.Sheets[wsname];
|
||||
/* Convert array of arrays */
|
||||
const data = sheet_to_json(ws, { header: 1 });
|
||||
/* Update state */
|
||||
setData(data);
|
||||
setCols(make_cols(ws['!ref']))
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
const handleFile = (file) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
/* Parse data */
|
||||
const ab = e.target.result;
|
||||
const wb = read(ab, { type: 'array' });
|
||||
/* Get first worksheet */
|
||||
const wsname = wb.SheetNames[0];
|
||||
const ws = wb.Sheets[wsname];
|
||||
/* Convert array of arrays */
|
||||
const data = sheet_to_json(ws, { header: 1 });
|
||||
/* Update state */
|
||||
setData(data);
|
||||
setCols(make_cols(ws['!ref']))
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
const exportFile = () => {
|
||||
/* convert state to workbook */
|
||||
const ws = aoa_to_sheet(data);
|
||||
const wb = book_new();
|
||||
book_append_sheet(wb, ws, "SheetJS");
|
||||
/* generate XLSX file and send to client */
|
||||
writeFile(wb, "sheetjs.xlsx")
|
||||
};
|
||||
const exportFile = () => {
|
||||
/* convert state to workbook */
|
||||
const ws = aoa_to_sheet(data);
|
||||
const wb = book_new();
|
||||
book_append_sheet(wb, ws, "SheetJS");
|
||||
/* generate XLSX file and send to client */
|
||||
writeFile(wb, "sheetjs.xlsx")
|
||||
};
|
||||
|
||||
return (
|
||||
<DragDropFile handleFile={handleFile}>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<DataInput handleFile={handleFile} />
|
||||
</div></div>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
{data.length ? <button className="btn btn-success" onClick={exportFile}>Export</button> : ""}
|
||||
</div></div>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<OutTable data={data} cols={cols} />
|
||||
</div></div>
|
||||
</DragDropFile>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<DragDropFile handleFile={handleFile}>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<DataInput handleFile={handleFile} />
|
||||
</div></div>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
{data.length ? <button className="btn btn-success" onClick={exportFile}>Export</button> : ""}
|
||||
</div></div>
|
||||
<div className="row"><div className="col-xs-12">
|
||||
<OutTable data={data} cols={cols} />
|
||||
</div></div>
|
||||
</DragDropFile>
|
||||
);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
Simple HTML5 file drag-and-drop wrapper
|
||||
usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
|
||||
handleFile(file:File):void;
|
||||
*/
|
||||
/*
|
||||
Simple HTML5 file drag-and-drop wrapper
|
||||
usage: <DragDropFile handleFile={handleFile}>...</DragDropFile>
|
||||
handleFile(file:File):void;
|
||||
*/
|
||||
|
||||
function DragDropFile({ handleFile, children }) {
|
||||
const suppress = (e) => { e.stopPropagation(); e.preventDefault(); };
|
||||
const handleDrop = (e) => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
const files = e.dataTransfer.files;
|
||||
if (files && files[0]) handleFile(files[0]);
|
||||
};
|
||||
function DragDropFile({ handleFile, children }) {
|
||||
const suppress = (e) => { e.stopPropagation(); e.preventDefault(); };
|
||||
const handleDrop = (e) => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
const files = e.dataTransfer.files;
|
||||
if (files && files[0]) handleFile(files[0]);
|
||||
};
|
||||
|
||||
return ( <div onDrop={handleDrop} onDragEnter={suppress} onDragOver={suppress}>{children}</div> );
|
||||
}
|
||||
return ( <div onDrop={handleDrop} onDragEnter={suppress} onDragOver={suppress}>{children}</div> );
|
||||
}
|
||||
|
||||
/*
|
||||
Simple HTML5 file input wrapper
|
||||
usage: <DataInput handleFile={callback} />
|
||||
handleFile(file:File):void;
|
||||
*/
|
||||
/*
|
||||
Simple HTML5 file input wrapper
|
||||
usage: <DataInput handleFile={callback} />
|
||||
handleFile(file:File):void;
|
||||
*/
|
||||
|
||||
function DataInput({ handleFile }) {
|
||||
const handleChange = (e) => {
|
||||
const files = e.target.files;
|
||||
if (files && files[0]) handleFile(files[0]);
|
||||
};
|
||||
function DataInput({ handleFile }) {
|
||||
const handleChange = (e) => {
|
||||
const files = e.target.files;
|
||||
if (files && files[0]) handleFile(files[0]);
|
||||
};
|
||||
|
||||
return (
|
||||
<form className="form-inline">
|
||||
<div className="form-group">
|
||||
<label htmlFor="file">Drag or choose a spreadsheet file</label><br />
|
||||
<input type="file" className="form-control" id="file" accept={SheetJSFT} onChange={handleChange} />
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
/* list of supported file types */
|
||||
const SheetJSFT = [
|
||||
"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm"
|
||||
].map(x => `.${x}`).join(",");
|
||||
return (
|
||||
<form className="form-inline">
|
||||
<div className="form-group">
|
||||
<label htmlFor="file">Drag or choose a spreadsheet file</label><br />
|
||||
<input type="file" className="form-control" id="file" accept={SheetJSFT} onChange={handleChange} />
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
/* list of supported file types */
|
||||
const SheetJSFT = [
|
||||
"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm"
|
||||
].map(x => `.${x}`).join(",");
|
||||
|
||||
/*
|
||||
Simple HTML Table
|
||||
usage: <OutTable data={data} cols={cols} />
|
||||
data:Array<Array<any> >;
|
||||
cols:Array<{name:string, key:number|string}>;
|
||||
*/
|
||||
function OutTable({ data, cols }) {
|
||||
return (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((r, i) => <tr key={i}>
|
||||
{cols.map(c => <td key={c.key}>{r[c.key]}</td>)}
|
||||
</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
/*
|
||||
Simple HTML Table
|
||||
usage: <OutTable data={data} cols={cols} />
|
||||
data:Array<Array<any> >;
|
||||
cols:Array<{name:string, key:number|string}>;
|
||||
*/
|
||||
function OutTable({ data, cols }) {
|
||||
return (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((r, i) => <tr key={i}>
|
||||
{cols.map(c => <td key={c.key}>{r[c.key]}</td>)}
|
||||
</tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* React 18 uses ReactDOM.createRoot; < 18 should use ReactDOM.render */
|
||||
const root_elt = document.getElementById('app');
|
||||
if(typeof ReactDOM.createRoot !== "undefined") {
|
||||
const root = ReactDOM.createRoot(root_elt);
|
||||
root.render(<SheetJSApp/>);
|
||||
} else {
|
||||
ReactDOM.render(<SheetJSApp />, root_elt);
|
||||
}
|
||||
</script>
|
||||
/* React 18 uses ReactDOM.createRoot; < 18 should use ReactDOM.render */
|
||||
const root_elt = document.getElementById('app');
|
||||
if(typeof ReactDOM.createRoot !== "undefined") {
|
||||
const root = ReactDOM.createRoot(root_elt);
|
||||
root.render(<SheetJSApp/>);
|
||||
} else {
|
||||
ReactDOM.render(<SheetJSApp />, root_elt);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
219
docz/static/vtl/App.vue
Normal file
219
docz/static/vtl/App.vue
Normal file
@ -0,0 +1,219 @@
|
||||
<script setup lang="ts">
|
||||
/*! sheetjs (C) SheetJS -- http://sheetjs.com */
|
||||
import { ref, onMounted } from "vue";
|
||||
import VueTableLite from "vue3-table-lite/ts";
|
||||
import { read, utils, WorkSheet, writeFile } from "xlsx";
|
||||
|
||||
type DataSet = { [index: string]: WorkSheet; };
|
||||
type Row = any[];
|
||||
type RowCB = (row: Row) => string;
|
||||
type Column = { field: string; label: string; display: RowCB; };
|
||||
type RowCol = { rows: Row[]; cols: Column[]; };
|
||||
|
||||
const currFileName = ref<string>("");
|
||||
const currSheet = ref<string>("");
|
||||
const sheets = ref<string[]>([]);
|
||||
const workBook = ref<DataSet>({} as DataSet);
|
||||
const rows = ref<Row[]>([]);
|
||||
const columns = ref<Column[]>([]);
|
||||
|
||||
const exportTypes: string[] = ["xlsx", "xlsb", "csv", "html"];
|
||||
|
||||
let cell = 0;
|
||||
|
||||
function resetCell() {
|
||||
cell = 0;
|
||||
}
|
||||
|
||||
const getRowsCols = ( data: DataSet, sheetName: string ): RowCol => ({
|
||||
rows: utils.sheet_to_json<Row>(data[sheetName], {header:1}),
|
||||
cols: Array.from({
|
||||
length: utils.decode_range(data[sheetName]["!ref"]||"A1").e.c + 1
|
||||
}, (_, i) => (<Column>{ field: String(i), label: utils.encode_col(i), display: makeDisplay(i) }))
|
||||
});
|
||||
|
||||
const makeDisplay = (col: number): RowCB => (row: Row) => `<span
|
||||
style="user-select: none; display: block"
|
||||
onblur="endEdit(event)" ondblclick="startEdit(event)"
|
||||
position="${Math.floor(cell++ / columns.value.length)}.${col}"
|
||||
onkeydown="endEdit(event)">${row?.[col] ?? " "}</span>`;
|
||||
|
||||
(window as any).startEdit = function (ev: MouseEvent) {
|
||||
(ev?.target as HTMLSpanElement).contentEditable = "true";
|
||||
(ev?.target as HTMLSpanElement).focus();
|
||||
};
|
||||
|
||||
(window as any).endEdit = function (ev: FocusEvent | KeyboardEvent) {
|
||||
if (typeof (ev as KeyboardEvent).key == "undefined" || (ev as KeyboardEvent).key === "Enter") {
|
||||
const pos = (ev.target as HTMLSpanElement)?.getAttribute("position")?.split(".");
|
||||
if(!pos) return;
|
||||
|
||||
(ev?.target as HTMLSpanElement).contentEditable = "true";
|
||||
|
||||
rows.value[+pos[0]][+pos[1]] = (ev.target as HTMLSpanElement).innerText;
|
||||
|
||||
workBook.value[currSheet.value] = utils.json_to_sheet(rows.value, {
|
||||
header: columns.value.map((col: Column) => col.field),
|
||||
skipHeader: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
async function importAB(ab: ArrayBuffer, name: string): Promise<void> {
|
||||
const data = read(ab);
|
||||
|
||||
currFileName.value = name;
|
||||
currSheet.value = data.SheetNames?.[0];
|
||||
sheets.value = data.SheetNames;
|
||||
workBook.value = data.Sheets;
|
||||
|
||||
selectSheet(currSheet.value);
|
||||
}
|
||||
|
||||
async function importFile(ev: Event): Promise<void> {
|
||||
const file = (ev.target as HTMLInputElement)?.files?.[0];
|
||||
if(!file) return;
|
||||
await importAB(await file.arrayBuffer(), file.name);
|
||||
}
|
||||
|
||||
function exportFile(type: string): void {
|
||||
const wb = utils.book_new();
|
||||
|
||||
sheets.value.forEach((sheet) => {
|
||||
utils.book_append_sheet(wb, workBook.value[sheet], sheet);
|
||||
});
|
||||
|
||||
writeFile(wb, `sheet.${type}`);
|
||||
}
|
||||
|
||||
function selectSheet(sheet: string): void {
|
||||
const { rows: newRows, cols: newCols } = getRowsCols(workBook.value, sheet);
|
||||
|
||||
resetCell();
|
||||
|
||||
rows.value = newRows;
|
||||
columns.value = newCols;
|
||||
currSheet.value = sheet;
|
||||
}
|
||||
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
onMounted(async() => {
|
||||
const response = await fetch("https://sheetjs.com/pres.numbers");
|
||||
await importAB(await response.arrayBuffer(), "pres.numbers");
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="imp-exp">
|
||||
<div class="import">
|
||||
<input type="file" id="import" @change="importFile" />
|
||||
<label for="import">import</label>
|
||||
</div>
|
||||
<span v-if="currFileName">{{ currFileName }}</span>
|
||||
<div class="export" v-if="currFileName">
|
||||
<span>export</span>
|
||||
<ul>
|
||||
<li v-for="(type, idx) in exportTypes" :key="idx" @click="exportFile(type)">
|
||||
{{ `.${type}` }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
<div class="sheets">
|
||||
<span
|
||||
v-for="(sheet, idx) in sheets"
|
||||
:key="idx"
|
||||
@click="selectSheet(sheet)"
|
||||
:class="[currSheet === sheet ? 'selected' : '']"
|
||||
>
|
||||
{{ sheet }}
|
||||
</span>
|
||||
</div>
|
||||
<vue-table-lite :is-static-mode="true" :page-size="50" :columns="columns" :rows="rows"></vue-table-lite>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.imp-exp {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem;
|
||||
font-family: mono;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.import {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.import input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.import label {
|
||||
background-color: white;
|
||||
border: 1px solid;
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.export:hover {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.export:hover ul {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.export span {
|
||||
padding: 0.3rem;
|
||||
border: 1px solid;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.export ul {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
background-color: white;
|
||||
list-style: none;
|
||||
padding: 0.3rem;
|
||||
border: 1px solid;
|
||||
margin-top: 0.3rem;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.export ul li {
|
||||
padding: 0.3rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.export ul li:hover {
|
||||
background-color: lightgray;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sheets {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0.3rem;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.sheets span {
|
||||
border: 1px solid;
|
||||
padding: 0.5rem;
|
||||
margin: 0.3rem;
|
||||
}
|
||||
|
||||
.sheets span:hover:not(.selected) {
|
||||
background-color: lightgray;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #343a40;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
60
docz/static/vue/SheetJS-vue.js
Normal file
60
docz/static/vue/SheetJS-vue.js
Normal file
@ -0,0 +1,60 @@
|
||||
/* sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
var SheetJSFT = [
|
||||
"xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm", "numbers"
|
||||
].map(function(x) { return "." + x; }).join(",");
|
||||
|
||||
var SJSTemplate = [
|
||||
'<div>',
|
||||
'<input type="file" multiple="false" id="sheetjs-input" accept="' + SheetJSFT + '" @change="onchange" />',
|
||||
'<br/>',
|
||||
'<button type="button" id="export-table" style="visibility:hidden" @click="onexport">Export to XLSX</button>',
|
||||
'<br/>',
|
||||
'<div id="out-table"></div>',
|
||||
'</div>'
|
||||
].join("");
|
||||
var component_struct = {
|
||||
template: SJSTemplate,
|
||||
methods: {
|
||||
onchange: function(evt) {
|
||||
var files = evt.target.files;
|
||||
if (!files || files.length == 0) return;
|
||||
|
||||
var file = files[0];
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
// get data
|
||||
var bytes = new Uint8Array(e.target.result);
|
||||
|
||||
/* read workbook */
|
||||
var wb = XLSX.read(bytes);
|
||||
|
||||
/* grab first sheet */
|
||||
var wsname = wb.SheetNames[0];
|
||||
var ws = wb.Sheets[wsname];
|
||||
|
||||
/* generate HTML */
|
||||
var HTML = XLSX.utils.sheet_to_html(ws);
|
||||
|
||||
/* update table */
|
||||
document.getElementById('out-table').innerHTML = HTML;
|
||||
/* show export button */
|
||||
document.getElementById('export-table').style.visibility = "visible";
|
||||
};
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
},
|
||||
onexport: function(evt) {
|
||||
/* generate workbook object from table */
|
||||
var wb = XLSX.utils.table_to_book(document.getElementById('out-table').getElementsByTagName("TABLE")[0]);
|
||||
/* generate file and force a download*/
|
||||
XLSX.writeFile(wb, "sheetjs.xlsx");
|
||||
}
|
||||
}
|
||||
};
|
||||
if(Vue.component) {
|
||||
Vue.component('html-preview', component_struct);
|
||||
} else {
|
||||
var app = Vue.createApp({});
|
||||
app.component('html-preview', component_struct);
|
||||
}
|
56
docz/static/vue/index2.html
Normal file
56
docz/static/vue/index2.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- sheetjs (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<title>SheetJS + VueJS2</title>
|
||||
<!-- Vue 2 -->
|
||||
<script src="https://unpkg.com/vue@2.x"></script>
|
||||
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
|
||||
<!-- SheetJS Vue components -->
|
||||
<script src="SheetJS-vue.js"></script>
|
||||
|
||||
<style>
|
||||
.grid1 {
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
};
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS + VueJS2 demo</a></b>
|
||||
|
||||
This demo shows a sample Vue component "html-preview" that:
|
||||
- displays a file input that accepts a spreadsheet file
|
||||
- draws the first worksheet of a submitted file as HTML
|
||||
- presents an export button to generate XLSX files
|
||||
|
||||
<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
|
||||
</pre>
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div id="app">
|
||||
<html-preview></html-preview>
|
||||
</div>
|
||||
|
||||
<script lang="javascript">
|
||||
if(Vue.component) var app = new Vue({ el: '#app' });
|
||||
else app.mount('#app');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
56
docz/static/vue/index3.html
Normal file
56
docz/static/vue/index3.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- sheetjs (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<title>SheetJS + VueJS3</title>
|
||||
<!-- Vue 2 -->
|
||||
<script src="https://unpkg.com/vue@3.x"></script>
|
||||
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
|
||||
<!-- SheetJS Vue components -->
|
||||
<script src="SheetJS-vue.js"></script>
|
||||
|
||||
<style>
|
||||
.grid1 {
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
};
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS + VueJS3 demo</a></b>
|
||||
|
||||
This demo shows a sample Vue component "html-preview" that:
|
||||
- displays a file input that accepts a spreadsheet file
|
||||
- draws the first worksheet of a submitted file as HTML
|
||||
- presents an export button to generate XLSX files
|
||||
|
||||
<a href="https://obamawhitehouse.archives.gov/sites/default/files/omb/budget/fy2014/assets/receipts.xls">Sample Spreadsheet</a>
|
||||
</pre>
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div id="app">
|
||||
<html-preview></html-preview>
|
||||
</div>
|
||||
|
||||
<script lang="javascript">
|
||||
if(Vue.component) var app = new Vue({ el: '#app' });
|
||||
else app.mount('#app');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
142
docz/static/xspreadsheet/index.html
Normal file
142
docz/static/xspreadsheet/index.html
Normal file
@ -0,0 +1,142 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- sheetjs (C) SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>SheetJS + x-spreadsheet Live 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
|
||||
}
|
||||
#b64data{
|
||||
width:100%;
|
||||
}
|
||||
a { text-decoration: none }
|
||||
</style>
|
||||
<!-- x-spreadsheet stylesheet -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
|
||||
|
||||
<a href="https://github.com/myliang/x-spreadsheet">x-spreadsheet component library</a>
|
||||
|
||||
<a href="https://github.com/SheetJS/sheetjs">Source Code Repo</a>
|
||||
<a href="https://github.com/SheetJS/sheetjs/issues">Issues? Something look weird? Click here and report an issue</a>
|
||||
|
||||
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
|
||||
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
|
||||
<textarea id="b64data">... or paste a base64-encoding here</textarea>
|
||||
</pre>
|
||||
<p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();"></p>
|
||||
<div id="htmlout"></div>
|
||||
<br />
|
||||
<script src="https://unpkg.com/x-data-spreadsheet/dist/xspreadsheet.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js"></script>
|
||||
<script>
|
||||
/*jshint browser:true */
|
||||
/* eslint-env browser */
|
||||
/* eslint no-use-before-define:0 */
|
||||
/*global Uint8Array, Uint16Array, ArrayBuffer */
|
||||
/*global XLSX */
|
||||
|
||||
var HTMLOUT = document.getElementById('htmlout');
|
||||
var xspr = x_spreadsheet(HTMLOUT);
|
||||
HTMLOUT.style.height = (window.innerHeight - 400) + "px";
|
||||
HTMLOUT.style.width = (window.innerWidth - 50) + "px";
|
||||
|
||||
var process_wb = (function() {
|
||||
var XPORT = document.getElementById('xport');
|
||||
|
||||
return function process_wb(wb) {
|
||||
/* convert to x-spreadsheet form */
|
||||
var data = stox(wb);
|
||||
|
||||
/* update x-spreadsheet */
|
||||
xspr.loadData(data);
|
||||
XPORT.disabled = false;
|
||||
|
||||
if(typeof console !== 'undefined') console.log("output", new Date());
|
||||
};
|
||||
})();
|
||||
|
||||
var do_file = (function() {
|
||||
return function do_file(files) {
|
||||
var f = files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
if(typeof console !== 'undefined') console.log("onload", new Date());
|
||||
var data = e.target.result;
|
||||
process_wb(XLSX.read(data));
|
||||
};
|
||||
reader.readAsArrayBuffer(f);
|
||||
};
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var drop = document.getElementById('drop');
|
||||
if(!drop.addEventListener) return;
|
||||
|
||||
function handleDrop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
do_file(e.dataTransfer.files);
|
||||
}
|
||||
|
||||
function handleDragover(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
}
|
||||
|
||||
drop.addEventListener('dragenter', handleDragover, false);
|
||||
drop.addEventListener('dragover', handleDragover, false);
|
||||
drop.addEventListener('drop', handleDrop, false);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var xlf = document.getElementById('xlf');
|
||||
if(!xlf.addEventListener) return;
|
||||
function handleFile(e) { do_file(e.target.files); }
|
||||
xlf.addEventListener('change', handleFile, false);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
try {
|
||||
fetch("https://sheetjs.com/pres.numbers")
|
||||
.then(function(res) { return res.arrayBuffer(); })
|
||||
.then(function(ab) { process_wb(XLSX.read(ab)); });
|
||||
} catch(e) {}
|
||||
})();
|
||||
|
||||
function export_xlsx() {
|
||||
var new_wb = xtos(xspr.getData());
|
||||
|
||||
/* write file and trigger a download */
|
||||
XLSX.writeFile(new_wb, 'sheetjs.xlsx', {});
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
/* eslint no-use-before-define:0 */
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user