mirror of
https://github.com/ljcoder2015/obsidian-excel.git
synced 2026-07-22 08:30:28 +00:00
feat: merge feature/import
This commit is contained in:
commit
d8a7bd240e
9 changed files with 1290 additions and 7 deletions
|
|
@ -5,8 +5,14 @@ The Obsidian-Excel plugin integrates [x-spreadsheet](https://github.com/myliang/
|
|||
|
||||

|
||||
|
||||
### import/export xlsx file
|
||||
If you are using Microsoft Office 365 to create xlsx files, you need to import the display.
|
||||
|
||||

|
||||
|
||||
|
||||
## TODO
|
||||
- [X] import/export excel
|
||||
✅ import/export excel
|
||||
- [X] link to markdown
|
||||
|
||||
|
||||
|
|
|
|||
BIN
doc/img/import.png
Normal file
BIN
doc/img/import.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 308 KiB |
1066
main.css
Normal file
1066
main.css
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "excel",
|
||||
"name": "Excel",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "This is a Excel plugin for Obsidian.",
|
||||
"author": "ljcoder",
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1344,6 +1344,10 @@
|
|||
"opencollective-postinstall": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"xlsx": {
|
||||
"version": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz",
|
||||
"integrity": "sha512-adg5edVTkXXGTnb0iWrc3Z47ViGgwmD47yx6VfSCZhfdKPtHcElYGs48OtcO4nwOu90Pjz5mmyl0HLcvbSRYTQ=="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"x-data-spreadsheet": "^1.1.9"
|
||||
"x-data-spreadsheet": "^1.1.9",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import ExcelPlugin from "main";
|
||||
import { TextFileView, WorkspaceLeaf } from "obsidian";
|
||||
import Spreadsheet from "x-data-spreadsheet";
|
||||
import * as XLSX from "xlsx";
|
||||
import { stox, xtos } from "./utils/xlsxspread";
|
||||
|
||||
export const VIEW_TYPE_EXCEL = "excel-view";
|
||||
|
||||
export class ExcelView extends TextFileView {
|
||||
public plugin: ExcelPlugin;
|
||||
public ownerWindow: Window;
|
||||
public ownerDocument: Document;
|
||||
public sheet: any;
|
||||
public importEle: HTMLElement;
|
||||
public exportEle: HTMLElement;
|
||||
|
||||
constructor(leaf: WorkspaceLeaf, plugin: ExcelPlugin) {
|
||||
super(leaf);
|
||||
|
|
@ -46,6 +49,71 @@ export class ExcelView extends TextFileView {
|
|||
});
|
||||
|
||||
this.sheet.validate();
|
||||
|
||||
// 导入导出
|
||||
const importInput = this.contentEl.createEl("input", {
|
||||
cls: "import-excel",
|
||||
type: "file",
|
||||
attr: { id: "import" },
|
||||
});
|
||||
importInput.addEventListener(
|
||||
"change",
|
||||
this.handleFile.bind(this),
|
||||
false
|
||||
);
|
||||
|
||||
// 添加顶部导入按钮
|
||||
if (!this.importEle) {
|
||||
this.importEle = this.addAction(
|
||||
"download",
|
||||
"import xlsx file",
|
||||
(ev) => this.handleImportClick(ev)
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.exportEle) {
|
||||
this.exportEle = this.addAction(
|
||||
"upload",
|
||||
"export xlsx file",
|
||||
(ev) => this.handleExportClick(ev)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理顶部导入按钮点击事件
|
||||
handleImportClick(ev: MouseEvent) {
|
||||
const importEle = document.getElementById("import");
|
||||
importEle?.click();
|
||||
// 打开文件
|
||||
console.log("handleImportClick", importEle);
|
||||
}
|
||||
|
||||
handleFile(e: Event) {
|
||||
console.log("handleFile", e);
|
||||
//@ts-ignore
|
||||
const files = e.target?.files;
|
||||
var f = files[0];
|
||||
var reader = new FileReader();
|
||||
var instance = this;
|
||||
reader.onload = (e) => {
|
||||
const data = e.target?.result;
|
||||
console.log(data, instance);
|
||||
|
||||
instance.process_wb(XLSX.read(data));
|
||||
};
|
||||
reader.readAsArrayBuffer(f);
|
||||
}
|
||||
|
||||
process_wb(wb: XLSX.WorkBook) {
|
||||
const sheetData = stox(wb);
|
||||
this.sheet.loadData(sheetData);
|
||||
}
|
||||
|
||||
handleExportClick(ev: MouseEvent) {
|
||||
var new_wb = xtos(this.sheet.getData()) as XLSX.WorkBook;
|
||||
var title = this.file?.basename ?? "sheet"
|
||||
/* write file and trigger a download */
|
||||
XLSX.writeFile(new_wb, title + '.xlsx', {});
|
||||
}
|
||||
|
||||
onload(): void {
|
||||
|
|
|
|||
133
src/utils/xlsxspread.js
Normal file
133
src/utils/xlsxspread.js
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*! xlsxspread.js (C) SheetJS LLC -- https://sheetjs.com/ */
|
||||
/* eslint-env browser */
|
||||
/*global XLSX */
|
||||
/*exported stox, xtos */
|
||||
import * as XLSX from 'xlsx'
|
||||
|
||||
/**
|
||||
* Converts data from SheetJS to x-spreadsheet
|
||||
*
|
||||
* @param {Object} wb SheetJS workbook object
|
||||
*
|
||||
* @returns {Object[]} An x-spreadsheet data
|
||||
*/
|
||||
export function stox(wb) {
|
||||
var out = [];
|
||||
wb.SheetNames.forEach(function (name) {
|
||||
var o = { name: name, rows: {} };
|
||||
var ws = wb.Sheets[name];
|
||||
if(!ws || !ws["!ref"]) return;
|
||||
var range = XLSX.utils.decode_range(ws['!ref']);
|
||||
// sheet_to_json will lost empty row and col at begin as default
|
||||
range.s = { r: 0, c: 0 };
|
||||
var aoa = XLSX.utils.sheet_to_json(ws, {
|
||||
raw: false,
|
||||
header: 1,
|
||||
range: range
|
||||
});
|
||||
|
||||
aoa.forEach(function (r, i) {
|
||||
var cells = {};
|
||||
r.forEach(function (c, j) {
|
||||
cells[j] = { text: c };
|
||||
|
||||
var cellRef = XLSX.utils.encode_cell({ r: i, c: j });
|
||||
|
||||
if ( ws[cellRef] != null && ws[cellRef].f != null) {
|
||||
cells[j].text = "=" + ws[cellRef].f;
|
||||
}
|
||||
});
|
||||
o.rows[i] = { cells: cells };
|
||||
});
|
||||
|
||||
o.merges = [];
|
||||
(ws["!merges"]||[]).forEach(function (merge, i) {
|
||||
//Needed to support merged cells with empty content
|
||||
if (o.rows[merge.s.r] == null) {
|
||||
o.rows[merge.s.r] = { cells: {} };
|
||||
}
|
||||
if (o.rows[merge.s.r].cells[merge.s.c] == null) {
|
||||
o.rows[merge.s.r].cells[merge.s.c] = {};
|
||||
}
|
||||
|
||||
o.rows[merge.s.r].cells[merge.s.c].merge = [
|
||||
merge.e.r - merge.s.r,
|
||||
merge.e.c - merge.s.c
|
||||
];
|
||||
|
||||
o.merges[i] = XLSX.utils.encode_range(merge);
|
||||
});
|
||||
|
||||
out.push(o);
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts data from x-spreadsheet to SheetJS
|
||||
*
|
||||
* @param {Object[]} sdata An x-spreadsheet data object
|
||||
*
|
||||
* @returns {Object} A SheetJS workbook object
|
||||
*/
|
||||
export function xtos(sdata) {
|
||||
var out = XLSX.utils.book_new();
|
||||
sdata.forEach(function (xws) {
|
||||
var ws = {};
|
||||
var rowobj = xws.rows;
|
||||
var minCoord = { r: 0, c: 0 }, maxCoord = { r: 0, c: 0 };
|
||||
for (var ri = 0; ri < rowobj.len; ++ri) {
|
||||
var row = rowobj[ri];
|
||||
if (!row) continue;
|
||||
|
||||
Object.keys(row.cells).forEach(function (k) {
|
||||
var idx = +k;
|
||||
if (isNaN(idx)) return;
|
||||
|
||||
var lastRef = XLSX.utils.encode_cell({ r: ri, c: idx });
|
||||
if (ri > maxCoord.r) maxCoord.r = ri;
|
||||
if (idx > maxCoord.c) maxCoord.c = idx;
|
||||
|
||||
var cellText = row.cells[k].text, type = "s";
|
||||
if (!cellText) {
|
||||
cellText = "";
|
||||
type = "z";
|
||||
} else if (!isNaN(Number(cellText))) {
|
||||
cellText = Number(cellText);
|
||||
type = "n";
|
||||
} else if (cellText.toLowerCase() === "true" || cellText.toLowerCase() === "false") {
|
||||
cellText = Boolean(cellText);
|
||||
type = "b";
|
||||
}
|
||||
|
||||
ws[lastRef] = { v: cellText, t: type };
|
||||
|
||||
if (type == "s" && cellText[0] == "=") {
|
||||
ws[lastRef].f = cellText.slice(1);
|
||||
}
|
||||
|
||||
if (row.cells[k].merge != null) {
|
||||
if (ws["!merges"] == null) ws["!merges"] = [];
|
||||
|
||||
ws["!merges"].push({
|
||||
s: { r: ri, c: idx },
|
||||
e: {
|
||||
r: ri + row.cells[k].merge[0],
|
||||
c: idx + row.cells[k].merge[1]
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
ws["!ref"] = minCoord ? XLSX.utils.encode_range({
|
||||
s: minCoord,
|
||||
e: maxCoord
|
||||
}) : "A1";
|
||||
|
||||
XLSX.utils.book_append_sheet(out, ws, xws.name);
|
||||
});
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
11
styles.css
11
styles.css
|
|
@ -1,13 +1,18 @@
|
|||
.sheet-box {
|
||||
/* position: absolute;
|
||||
left: 0;
|
||||
top: 40px; */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: -16px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.import-excel {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* node_modules/x-data-spreadsheet/src/index.less */
|
||||
body {
|
||||
margin: 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue