Compare commits

..

40 commits

Author SHA1 Message Date
ljcoder
d9df140382
Update README.md 2024-06-04 15:27:46 +08:00
雷军
04dc273d80 feat: readme 2024-05-08 14:59:00 +08:00
雷军
5e149efaa7 feat: readme 2024-05-06 18:29:15 +08:00
雷军
583c46a828 feat: readme 2024-05-06 18:24:21 +08:00
雷军
5397aade29 feat: excel plus readme 2024-05-06 14:50:12 +08:00
雷军
82a6a7d1f9 feat: excel plus readme 2024-05-06 14:48:55 +08:00
雷军
56ca68dde1 feat: excel plus readme 2024-05-06 14:47:50 +08:00
雷军
5380c7a6e9 feat: Obsidian Excel Pro Plugin doc 2024-04-29 11:24:25 +08:00
雷军
b018f956a7 feat: Obsidian Excel Pro Plugin doc 2024-04-29 11:20:50 +08:00
雷军
ff08a53c06 feat: Obsidian Excel Pro Plugin doc 2024-04-29 11:19:15 +08:00
雷军
05ea79123b feat: Obsidian Excel Pro Plugin doc 2024-04-29 11:17:35 +08:00
雷军
2135848b38 feat: 1.3.24 2024-03-20 10:45:10 +08:00
雷军
8d2a44df50 feat: 1.3.23 2024-02-18 15:00:40 +08:00
雷军
34f35f9822 feat: github action 2024-02-18 15:00:01 +08:00
雷军
42cbe19ad0 feat: github action 2024-02-18 14:03:22 +08:00
雷军
6dc364519b feat: selected all 2024-02-18 13:49:48 +08:00
雷军
9898398afc feat: selected all 2024-02-18 10:48:51 +08:00
雷军
ae4426b24f fix: input hidden 2023-12-29 11:04:28 +08:00
雷军
0346ab7ca3 feat: add sheet default rows stting 2023-12-29 10:57:11 +08:00
雷军
63c041ba05 feat: add sheet default rows stting 2023-12-29 10:54:09 +08:00
雷军
a1c620d4e2 fix: import excel bug 2023-12-29 10:27:56 +08:00
雷军
578a3388c6 fix: import excel bug 2023-12-29 10:20:28 +08:00
雷军
1bb57398d2 fix: cut paste bug 2023-12-27 17:38:14 +08:00
雷军
4d784ac627 fix: copy paste bug 2023-12-27 14:58:43 +08:00
雷军
2e8ee0f5ac fix: copy paste bug 2023-12-27 14:58:20 +08:00
雷军
231ab55de6 fix: import excel file bug 2023-12-15 16:29:36 +08:00
雷军
8908dd9da4 fix: import excel file bug 2023-12-15 16:29:14 +08:00
雷军
5e98093f49 feat: show sheet button config 2023-12-15 15:22:39 +08:00
雷军
3aa557087a feat: show sheet button config 2023-12-15 15:17:06 +08:00
雷军
8bbebb9a6f feat: 1.3.16 2023-12-15 14:00:03 +08:00
雷军
ed685da21c fix: import bug 2023-12-15 13:58:47 +08:00
雷军
2457eff3d1 fix: 1.3.15 search dark model 2023-12-08 18:13:21 +08:00
雷军
8ad8fe21e6 fix: 1.3.15 search dark model 2023-12-08 18:05:02 +08:00
雷军
a8ce218640 feat: 1.3.14 css update 2023-12-08 17:51:55 +08:00
雷军
10f2e6742a feat: 1.3.14 2023-12-08 17:38:08 +08:00
雷军
c70a1aa080 feat: search 2023-12-08 17:37:15 +08:00
雷军
c3c97b9204 feat: readme update 2023-12-08 09:38:17 +08:00
雷军
914a90021b feat: embed link show html 2023-12-06 15:52:02 +08:00
雷军
9aa99436b9 fix: row col resize not save 2023-12-04 15:57:11 +08:00
雷军
d31a59c76a feat: change dark mode default text color 2023-11-06 16:49:03 +08:00
16 changed files with 2791 additions and 1147 deletions

View file

@ -19,6 +19,7 @@ jobs:
- name: Build plugin
run: |
npm config set strict-ssl false
npm install
npm run build

View file

@ -1,3 +1,6 @@
> ### The Obsidian-Excel plugin will no longer be maintained or updated. To download Obsidian-Sheet-Plus, please visit [https://github.com/ljcoder2015/obsidian-sheet-plus](https://github.com/ljcoder2015/obsidian-sheet-plus)
> ### Obsidian-Excel插件不再更新维护旧功能不满足可以尝试使用新插件Obsidian-Sheet-Plus。下载地址 [https://github.com/ljcoder2015/obsidian-sheet-plus](https://github.com/ljcoder2015/obsidian-sheet-plus)
# Obsidian Excel Plugin
## Excel
@ -15,7 +18,15 @@ If you are using Microsoft Office 365 to create xlsx files, you need to import t
embed link rule:
> ![[`file-folder`/`file-name`#`sheet-name`|`sri`-`sci`:`eri`-`eci`<`sheet-height`>]]
```![[file-folder/file-name#sheet-name|sri-sci:eri-eci<sheet-height>{html}]]```
- `sri`: Start row index
- `eri`: End row index
- `sci`: Start column index
- `eci`: End column index
- `{html}`: Whether to display as HTML
- `<sheet-height>`: Sheet height, dispaly HTML not work
![link](./doc/img/link.gif)
@ -23,6 +34,8 @@ embed link rule:
![link](./doc//img/embed-link-height.gif)
![link](./doc//img/embed_html.gif)
### copy selected cells to HTML
![html](./doc/img/html.gif)
@ -39,4 +52,7 @@ embed link rule:
- ljcoder@163.com
### buy a Coffee
[https://ko-fi.com/ljcoder](https://ko-fi.com/ljcoder)

BIN
doc/img/embed_html.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

File diff suppressed because one or more lines are too long

View file

@ -1,10 +1,11 @@
{
"id": "excel",
"name": "Excel",
"version": "1.3.11",
"version": "1.3.24",
"minAppVersion": "0.15.0",
"description": "Create spreadsheets and easily embed them in Markdown",
"author": "ljcoder",
"authorUrl": "https://github.com/ljcoder2015",
"fundingUrl": "https://ko-fi.com/ljcoder",
"isDesktopOnly": false
}

2859
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,8 +6,7 @@
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json",
"postinstall": "patch-package"
"version": "node version-bump.mjs && git add manifest.json versions.json"
},
"keywords": [],
"author": "",
@ -24,13 +23,12 @@
"esbuild": "0.17.3",
"esbuild-plugin-less": "^1.2.4",
"obsidian": "latest",
"patch-package": "^8.0.0",
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {
"monkey-around": "^2.3.0",
"x-data-spreadsheet": "^1.1.9",
"x-data-spreadsheet": "git+ssh://git@github.com:ljcoder2015/x-spreadsheet.git#1.1.4",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz"
}
}

View file

@ -1,319 +0,0 @@
diff --git a/node_modules/x-data-spreadsheet/src/component/event.js b/node_modules/x-data-spreadsheet/src/component/event.js
index cdbc0fa..cb2a9db 100644
--- a/node_modules/x-data-spreadsheet/src/component/event.js
+++ b/node_modules/x-data-spreadsheet/src/component/event.js
@@ -74,6 +74,7 @@ export function bindTouch(target, { move, end }) {
starty = pageY;
}
evt.preventDefault();
+ evt.stopPropagation();
});
bind(target, 'touchend', (evt) => {
if (!end) return;
diff --git a/node_modules/x-data-spreadsheet/src/component/sheet.js b/node_modules/x-data-spreadsheet/src/component/sheet.js
index 086b8c4..264823c 100644
--- a/node_modules/x-data-spreadsheet/src/component/sheet.js
+++ b/node_modules/x-data-spreadsheet/src/component/sheet.js
@@ -77,11 +77,11 @@ function selectorSet(multiple, ri, ci, indexesUpdated = true, moving = false) {
const cell = data.getCell(ri, ci);
if (multiple) {
selector.setEnd(ri, ci, moving);
- this.trigger('cells-selected', cell, selector.range);
+ this.trigger('cells-selected', this.data, selector.range);
} else {
// trigger click event
selector.set(ri, ci, indexesUpdated);
- this.trigger('cell-selected', cell, ri, ci);
+ this.trigger('cell-selected', this.data, ri, ci);
}
toolbar.reset();
table.render();
@@ -854,7 +854,7 @@ function sheetInitEvents() {
}
export default class Sheet {
- constructor(targetEl, data) {
+ constructor(targetEl, data, isDark) {
this.eventMap = createEventEmitter();
const { view, showToolbar, showContextmenu } = data.settings;
this.el = h('div', `${cssPrefix}-sheet`);
@@ -904,7 +904,7 @@ export default class Sheet {
this.sortFilter.el,
);
// table
- this.table = new Table(this.tableEl.el, data);
+ this.table = new Table(this.tableEl.el, data, isDark);
sheetInitEvents.call(this);
sheetReset.call(this);
// init selector [0, 0]
diff --git a/node_modules/x-data-spreadsheet/src/component/table.js b/node_modules/x-data-spreadsheet/src/component/table.js
index 41e1e14..09ac678 100644
--- a/node_modules/x-data-spreadsheet/src/component/table.js
+++ b/node_modules/x-data-spreadsheet/src/component/table.js
@@ -7,22 +7,23 @@ import { formatm } from '../core/format';
import {
Draw, DrawBox, thinLineWidth, npx,
} from '../canvas/draw';
+import { idText } from 'typescript';
// gobal var
const cellPaddingWidth = 5;
const tableFixedHeaderCleanStyle = { fillStyle: '#f4f5f8' };
-const tableGridStyle = {
+var tableGridStyle = {
fillStyle: '#fff',
lineWidth: thinLineWidth,
strokeStyle: '#e6e6e6',
};
-function tableFixedHeaderStyle() {
+function tableFixedHeaderStyle(isDark) {
return {
textAlign: 'center',
textBaseline: 'middle',
font: `500 ${npx(12)}px Source Sans Pro`,
- fillStyle: '#585757',
+ fillStyle: isDark ? '#dcdcdc' : '#585757',
lineWidth: thinLineWidth(),
- strokeStyle: '#e6e6e6',
+ strokeStyle: isDark ? '#c0c0c0': '#e6e6e6',
};
}
@@ -184,13 +185,18 @@ function renderSelectedHeaderCell(x, y, w, h) {
// h: the fixed height of header
// tx: moving distance on x-axis
// ty: moving distance on y-axis
-function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
+function renderFixedHeaders(type, viewRange, w, h, tx, ty, isDark) {
const { draw, data } = this;
const sumHeight = viewRange.h; // rows.sumHeight(viewRange.sri, viewRange.eri + 1);
const sumWidth = viewRange.w; // cols.sumWidth(viewRange.sci, viewRange.eci + 1);
const nty = ty + h;
const ntx = tx + w;
+ if (isDark) {
+ tableFixedHeaderCleanStyle.fillStyle = '#595d88'
+ tableFixedHeaderCleanStyle.strokeStyle = '#5d5d5d'
+ }
+
draw.save();
// draw rect background
draw.attr(tableFixedHeaderCleanStyle);
@@ -203,7 +209,7 @@ function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
// console.log(data.selectIndexes);
// draw text
// text font, align...
- draw.attr(tableFixedHeaderStyle());
+ draw.attr(tableFixedHeaderStyle(isDark));
// y-header-text
if (type === 'all' || type === 'left') {
data.rowEach(viewRange.sri, viewRange.eri, (i, y1, rowHeight) => {
@@ -247,21 +253,25 @@ function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
draw.restore();
}
-function renderFixedLeftTopCell(fw, fh) {
+function renderFixedLeftTopCell(fw, fh, isDark) {
const { draw } = this;
draw.save();
// left-top-cell
- draw.attr({ fillStyle: '#f4f5f8' })
+ draw.attr({ fillStyle: isDark ? '#595d88' : '#f4f5f8', strokeStyle: isDark ? '#5d5d5d' : '#e6e6e6' })
.fillRect(0, 0, fw, fh);
draw.restore();
}
function renderContentGrid({
sri, sci, eri, eci, w, h,
-}, fw, fh, tx, ty) {
+}, fw, fh, tx, ty, isDark) {
const { draw, data } = this;
const { settings } = data;
+ if (isDark) {
+ tableGridStyle.strokeStyle = '#5d5d5d'
+ }
+
draw.save();
draw.attr(tableGridStyle)
.translate(fw + tx, fh + ty);
@@ -300,10 +310,11 @@ function renderFreezeHighlightLine(fw, fh, ftw, fth) {
/** end */
class Table {
- constructor(el, data) {
+ constructor(el, data, isDark) {
this.el = el;
this.draw = new Draw(el, data.viewWidth(), data.viewHeight());
this.data = data;
+ this.isDark = isDark
}
resetData(data) {
@@ -329,10 +340,10 @@ class Table {
const ty = data.freezeTotalHeight();
const { x, y } = data.scroll;
// 1
- renderContentGrid.call(this, viewRange, fw, fh, tx, ty);
+ renderContentGrid.call(this, viewRange, fw, fh, tx, ty, this.isDark);
renderContent.call(this, viewRange, fw, fh, -x, -y);
- renderFixedHeaders.call(this, 'all', viewRange, fw, fh, tx, ty);
- renderFixedLeftTopCell.call(this, fw, fh);
+ renderFixedHeaders.call(this, 'all', viewRange, fw, fh, tx, ty, this.isDark);
+ renderFixedLeftTopCell.call(this, fw, fh, this.isDark);
const [fri, fci] = data.freeze;
if (fri > 0 || fci > 0) {
// 2
@@ -343,7 +354,7 @@ class Table {
vr.h = ty;
renderContentGrid.call(this, vr, fw, fh, tx, 0);
renderContent.call(this, vr, fw, fh, -x, 0);
- renderFixedHeaders.call(this, 'top', vr, fw, fh, tx, 0);
+ renderFixedHeaders.call(this, 'top', vr, fw, fh, tx, 0, this.isDark);
}
// 3
if (fci > 0) {
@@ -352,13 +363,13 @@ class Table {
vr.eci = fci - 1;
vr.w = tx;
renderContentGrid.call(this, vr, fw, fh, 0, ty);
- renderFixedHeaders.call(this, 'left', vr, fw, fh, 0, ty);
+ renderFixedHeaders.call(this, 'left', vr, fw, fh, 0, ty, this.isDark);
renderContent.call(this, vr, fw, fh, 0, -y);
}
// 4
const freezeViewRange = data.freezeViewRange();
renderContentGrid.call(this, freezeViewRange, fw, fh, 0, 0);
- renderFixedHeaders.call(this, 'all', freezeViewRange, fw, fh, 0, 0);
+ renderFixedHeaders.call(this, 'all', freezeViewRange, fw, fh, 0, 0, this.isDark);
renderContent.call(this, freezeViewRange, fw, fh, 0, 0);
// 5
renderFreezeHighlightLine.call(this, fw, fh, tx, ty);
diff --git a/node_modules/x-data-spreadsheet/src/index.d.ts b/node_modules/x-data-spreadsheet/src/index.d.ts
index 948a8e9..7c99ef0 100644
--- a/node_modules/x-data-spreadsheet/src/index.d.ts
+++ b/node_modules/x-data-spreadsheet/src/index.d.ts
@@ -34,6 +34,7 @@ declare module 'x-data-spreadsheet' {
italic: false;
};
};
+ isDark: boolean;
}
export type CELL_SELECTED = 'cell-selected';
@@ -45,18 +46,18 @@ declare module 'x-data-spreadsheet' {
export interface SpreadsheetEventHandler {
(
envt: CELL_SELECTED,
- callback: (cell: Cell, rowIndex: number, colIndex: number) => void
+ callback: (sheetData: Record<string, any>, rowIndex: number, colIndex: number) => void
): void;
(
envt: CELLS_SELECTED,
callback: (
- cell: Cell,
+ sheetData: Record<string, any>,
parameters: { sri: number; sci: number; eri: number; eci: number }
) => void
): void;
(
evnt: CELL_EDITED,
- callback: (text: string, rowIndex: number, colIndex: number) => void
+ callback: (sheetData: Record<string, any>, rowIndex: number, colIndex: number) => void
): void;
}
@@ -182,6 +183,25 @@ declare module 'x-data-spreadsheet' {
* @param callback
*/
change(callback: (json: Record<string, any>) => void): this;
+
+ /**
+ * 添加sheet监听回调
+ * @param callback
+ */
+ onAddSheet(callback: () => void): this;
+
+ /**
+ * 重命名Sheet
+ * @param callback
+ */
+ onRenameSheet(callback: () => void): this;
+
+ /**
+ * 删除Sheet
+ * @param callback
+ */
+ onDeleteSheet(callback: () => void): this;
+
/**
* set locale
* @param lang
diff --git a/node_modules/x-data-spreadsheet/src/index.js b/node_modules/x-data-spreadsheet/src/index.js
index 479a0b7..165880e 100644
--- a/node_modules/x-data-spreadsheet/src/index.js
+++ b/node_modules/x-data-spreadsheet/src/index.js
@@ -11,8 +11,8 @@ import './index.less';
class Spreadsheet {
constructor(selectors, options = {}) {
let targetEl = selectors;
- this.options = { showBottomBar: true, ...options };
- this.sheetIndex = 1;
+ this.options = { isDark: false, showBottomBar: true, ...options };
+ this.sheetIndex = 0;
this.datas = [];
if (typeof selectors === 'string') {
targetEl = document.querySelector(selectors);
@@ -20,6 +20,7 @@ class Spreadsheet {
this.bottombar = this.options.showBottomBar ? new Bottombar(() => {
const d = this.addSheet();
this.sheet.resetData(d);
+ this.sheet.trigger('add-sheet', "")
}, (index) => {
const d = this.datas[index];
this.sheet.resetData(d);
@@ -27,13 +28,14 @@ class Spreadsheet {
this.deleteSheet();
}, (index, value) => {
this.datas[index].name = value;
+ this.sheet.trigger('rename-sheet', value)
}) : null;
this.data = this.addSheet();
const rootEl = h('div', `${cssPrefix}`)
.on('contextmenu', evt => evt.preventDefault());
// create canvas element
targetEl.appendChild(rootEl.el);
- this.sheet = new Sheet(rootEl, this.data);
+ this.sheet = new Sheet(rootEl, this.data, options.isDark);
if (this.bottombar !== null) {
rootEl.child(this.bottombar.el);
}
@@ -60,6 +62,7 @@ class Spreadsheet {
const [oldIndex, nindex] = this.bottombar.deleteItem();
if (oldIndex >= 0) {
this.datas.splice(oldIndex, 1);
+ this.sheet.trigger('delete-sheet', "")
if (nindex >= 0) this.sheet.resetData(this.datas[nindex]);
}
}
@@ -120,6 +123,21 @@ class Spreadsheet {
return this;
}
+ onAddSheet(cb) {
+ this.sheet.on('add-sheet', cb);
+ return this;
+ }
+
+ onRenameSheet(cb) {
+ this.sheet.on('rename-sheet', cb);
+ return this;
+ }
+
+ onDeleteSheet(cb) {
+ this.sheet.on('delete-sheet', cb)
+ return this
+ }
+
static locale(lang, message) {
locale(lang, message);
}

View file

@ -114,5 +114,46 @@ export class ExcelSettingTab extends PluginSettingTab {
this.plugin.saveSettings()
})
)
new Setting(containerEl)
.setName(t("DEFAULT_ROWS_LEN"))
.setDesc(t("DEFAULT_ROWS_LEN_DESC"))
.addText((text) =>
text
.setPlaceholder("100")
.setValue(this.plugin.settings.defaultRowsLen)
.onChange(async (value) => {
this.plugin.settings.defaultRowsLen = value
this.plugin.saveSettings()
})
)
new Setting(containerEl)
.setName(t("DEFAULT_COLS_LEN"))
.setDesc(t("DEFAULT_COLS_LEN_DESC"))
.addText((text) =>
text
.setPlaceholder("26")
.setValue(this.plugin.settings.defaultColsLen)
.onChange(async (value) => {
this.plugin.settings.defaultColsLen = value
this.plugin.saveSettings()
})
)
new Setting(containerEl)
.setName(t("SHOW_SHEET_BUTTON"))
.setDesc(t("SHOW_SHEET_BUTTON_DESC"))
.addDropdown((dropdown) =>
dropdown
.addOption("true","True")
.addOption("false","False")
.setValue(this.plugin.settings.showSheetButton)
.onChange(async (value) => {
this.plugin.settings.showSheetButton = value
this.plugin.saveSettings()
}),
);
}
}

View file

@ -1,5 +1,5 @@
import ExcelPlugin from "src/main";
import { TextFileView, WorkspaceLeaf, Platform, Notice, moment } from "obsidian";
import { TextFileView, WorkspaceLeaf, Platform, Notice, moment, TFile } from "obsidian";
import Spreadsheet from "x-data-spreadsheet";
import * as XLSX from "xlsx";
import { stox, xtos } from "./utils/xlsxspread";
@ -49,6 +49,13 @@ export class ExcelView extends TextFileView {
saveData(data: string) {
this.data = this.headerData() + data;
// console.log("saveData", this.data)
this.save(false)
.then(() => {
console.log("save data success", this.file)
})
.catch((e) => {
console.log("save data error", e)
})
}
clear(): void {
@ -59,8 +66,8 @@ export class ExcelView extends TextFileView {
this.data = data;
this.app.workspace.onLayoutReady(async () => {
// console.log('setViewData')
await this.refresh();
// console.log('setViewData', this.file)
this.refresh();
});
}
@ -79,11 +86,12 @@ export class ExcelView extends TextFileView {
}
const f = files[0];
const reader = new FileReader();
const self = this
reader.onload = (e) => {
const data = e.target?.result;
console.log('handleFile', self.file)
if (data) {
this.process_wb(XLSX.read(data));
self.process_wb(XLSX.read(data));
} else {
new Notice(t("READ_FILE_FAILED"));
}
@ -94,8 +102,16 @@ export class ExcelView extends TextFileView {
process_wb(wb: XLSX.WorkBook) {
const sheetData = stox(wb);
if (sheetData) {
this.sheet.loadData(sheetData);
this.saveData(JSON.stringify(sheetData));
sheetData.forEach((sheet) => {
var sheetAny = sheet as any
if (sheetAny.rows) {
const last = Object.keys(sheetAny.rows).last() || "100"
const max = parseInt(this.plugin.settings.defaultRowsLen)
sheetAny.rows.len = Math.max(max, parseInt(last) + 20)
}
})
this.saveData(JSON.stringify(sheetData))
this.refresh()
} else {
new Notice(t("DATA_PARSING_ERROR"));
}
@ -129,6 +145,7 @@ export class ExcelView extends TextFileView {
onload(): void {
this.ownerWindow = this.containerEl.win;
console.log("onload", this.file)
// 添加顶部导入按钮
this.importEle = this.addAction("download", t("IMPORT_XLSX_FILE"), (ev) =>
@ -180,6 +197,7 @@ export class ExcelView extends TextFileView {
// 初始化 sheet
const jsonData = JSON.parse(getExcelData(this.data) || "{}") || {};
// console.log("refresh", jsonData, this.file)
// 设置多语言
if (moment.locale() === 'zh-cn') {
@ -213,7 +231,7 @@ export class ExcelView extends TextFileView {
textwrap: false,
strike: false,
underline: false,
color: '#fff',
color: '#e6e6e6',
font: {
name: 'Helvetica',
size: 10,
@ -231,11 +249,11 @@ export class ExcelView extends TextFileView {
width: () => this.contentEl.clientWidth - 32,
},
row: {
len: 100,
len: parseInt(this.plugin.settings.defaultRowsLen),
height: parseInt(this.plugin.settings.rowHeight),
},
col: {
len: 26,
len: parseInt(this.plugin.settings.defaultColsLen),
width: parseInt(this.plugin.settings.colWidth),
indexWidth: 60,
minWidth: 60,
@ -248,7 +266,6 @@ export class ExcelView extends TextFileView {
.change(() => {
// save data to db
const data = this.sheet.getData();
// console.log("save data to db", data);
this.saveData(JSON.stringify(data));
})
.onAddSheet(() => {

View file

@ -6,8 +6,13 @@ import {
} from "obsidian";
import ExcelPlugin from "./main";
import Spreadsheet from "x-data-spreadsheet";
import { getExcelData, getExcelAreaData } from "./utils/DataUtils";
import {
getExcelData,
getExcelAreaData,
getExcelAreaHtml,
} from "./utils/DataUtils";
import { updateSheetTheme } from "./utils/ThemeUtils";
import da from "./lang/locale/da";
let plugin: ExcelPlugin;
let vault: Vault;
@ -81,26 +86,45 @@ const tmpObsidianWYSIWYG = async (
internalEmbedDiv.empty();
const data = await vault.read(file);
const src = internalEmbedDiv.getAttribute("src") ?? "";
const alt = internalEmbedDiv.getAttribute("alt") ?? "";
var src = internalEmbedDiv.getAttribute("src") ?? "";
// 是否转换成HTML
var toHTML = false;
if (src.includes("{html}")) {
toHTML = true;
src = src.replace("{html}", "");
}
alt = internalEmbedDiv.getAttribute("alt") ?? "";
if (alt.includes("{html}")) {
// 单 sheet 中的某一区域
toHTML = true;
alt = alt.replace("{html}", "");
}
const split = src.split("#");
var excelData = getExcelData(data);
if (split.length > 1) {
excelData = getExcelAreaData(
data,
split[1],
alt
excelData = getExcelAreaData(data, split[1], alt);
}
// 生成内容
if (toHTML) {
const table = createEditSheetHtml(data, file, split[1], alt)
internalEmbedDiv.appendChild(table);
} else {
const sheetDiv = createSheetEl(
excelData,
file,
internalEmbedDiv.clientWidth
);
internalEmbedDiv.appendChild(sheetDiv);
}
const sheetDiv = createSheetEl(excelData, file, internalEmbedDiv.clientWidth);
if (markdownEmbed) {
//display image on canvas without markdown frame
internalEmbedDiv.removeClass("markdown-embed");
internalEmbedDiv.removeClass("inline-embed");
}
internalEmbedDiv.appendChild(sheetDiv);
// console.log('internalEmbedDiv', internalEmbedDiv, markdownEmbed)
}
el.empty();
@ -113,68 +137,193 @@ const tmpObsidianWYSIWYG = async (
internalEmbedDiv.empty();
const data = await vault.read(file);
const src = internalEmbedDiv.getAttribute("src") ?? "";
const alt = internalEmbedDiv.getAttribute("alt") ?? "";
var range = alt
var src = internalEmbedDiv.getAttribute("src") ?? "";
var heigh = parseInt(plugin.settings.sheetHeight)
// 是否转换成HTML
var toHTML = false;
if (src.includes("{html}")) {
// 单 sheet
toHTML = true;
src = src.replace("{html}", "");
}
var alt = internalEmbedDiv.getAttribute("alt") ?? "";
if (alt.includes("{html}")) {
// 单 sheet 中的某一区域
toHTML = true;
alt = alt.replace("{html}", "");
}
var heigh = parseInt(plugin.settings.sheetHeight);
const matchResult = alt.match(/<(\d+)>/);
if (matchResult && matchResult.length > 1) {
const extractedValue = matchResult[1]; // 获取匹配到的数字
// console.log("Extracted value:", extractedValue);
heigh = parseInt(extractedValue)
range = range.replace(/<\d+>/, '');
const extractedValue = matchResult[1]; // 获取匹配到的数字
// console.log("Extracted value:", extractedValue);
heigh = parseInt(extractedValue);
alt = alt.replace(/<\d+>/, "");
} else {
// console.log("No match found.");
// console.log("No match found.");
}
const split = src.split("#");
var excelData = getExcelData(data);
if (split.length > 1) {
excelData = getExcelAreaData(
data,
split[1],
range
);
excelData = getExcelAreaData(data, split[1], alt);
}
// console.log('internalEmbedDiv', excelData, src, alt)
const sheetDiv = createSheetEl(excelData, file, internalEmbedDiv.clientWidth, heigh);
if (toHTML) {
const table = createEditSheetHtml(data, file, split[1], alt)
internalEmbedDiv.appendChild(table);
} else {
const sheetDiv = createSheetEl(
excelData,
file,
internalEmbedDiv.clientWidth,
heigh
);
internalEmbedDiv.appendChild(sheetDiv);
}
if (markdownEmbed) {
//display image on canvas without markdown frame
internalEmbedDiv.removeClass("markdown-embed");
internalEmbedDiv.removeClass("inline-embed");
}
internalEmbedDiv.appendChild(sheetDiv);
};
const createSheetEl = (data: string, file: TFile, width: number, height: number = 300): HTMLDivElement => {
const sheetDiv = createDiv()
/**
* HTML
* @param data markdown data
* @param sheet sheet
* @param cells cells 格式为: sri-sci:eri-eci 6-6:7-8
* @returns
*/
const createEditSheetHtml = (
excelData: string,
file: TFile,
sheet: string,
cells: string
): HTMLDivElement => {
const sheetDiv = createDiv();
if (plugin.settings.showSheetButton == "true") {
const fileEmbed = sheetDiv.createDiv({
cls: "internal-embed file-embed mod-generic is-loaded",
text: file.basename,
attr: {
src: file.basename,
alt: file.basename,
contenteditable: false,
tabindex: -1,
},
});
// 点击按钮打开 sheet
fileEmbed.onClickEvent((e) => {
e.stopPropagation();
plugin.app.workspace.getLeaf().openFile(file);
});
}
// <div class="internal-embed file-embed mod-generic is-loaded" tabindex="-1" src="Excel 2023-09-07 17.18.19.sheet" alt="Excel 2023-09-07 17.18.19.sheet" contenteditable="false"><div class="file-embed-title"><span class="file-embed-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-file"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline></svg></span> Excel 2023-09-07 17.18.19.sheet</div></div>
const fileEmbed = sheetDiv.createDiv({
cls: "internal-embed file-embed mod-generic is-loaded",
text: file.basename,
var table = getExcelAreaHtml(excelData, sheet, cells);
var div = createDiv({
cls: "sheet-html",
attr: {
src: file.basename,
alt: file.basename,
contenteditable: false,
tabindex: -1
tabindex: "-1",
contenteditable: "false"
}
})
div.appendChild(table)
sheetDiv.appendChild(div);
return sheetDiv;
};
// 点击按钮打开 sheet
fileEmbed.onClickEvent((e) => {
e.stopPropagation()
plugin.app.workspace.getLeaf().openFile(file)
})
/**
* HTML
* @param data markdown data
* @param sheet sheet
* @param cells cells 格式为: sri-sci:eri-eci 6-6:7-8
* @returns
*/
const createSheetHtml = (
data: string,
file: TFile,
sheet: string,
cells: string
): HTMLDivElement => {
const sheetDiv = createDiv();
if (plugin.settings.showSheetButton == "true") {
const fileEmbed = sheetDiv.createDiv({
cls: "internal-embed file-embed mod-generic is-loaded",
text: file.basename,
attr: {
src: file.basename,
alt: file.basename,
contenteditable: false,
tabindex: -1,
},
});
// 点击按钮打开 sheet
fileEmbed.onClickEvent((e) => {
e.stopPropagation();
plugin.app.workspace.getLeaf().openFile(file);
});
}
const sheetEl = createDiv({
attr: {
style: "overflow-x: auto;"
},
});
const table = getExcelAreaHtml(data, sheet, cells);
sheetEl.appendChild(table);
sheetDiv.appendChild(sheetEl);
return sheetDiv;
};
/**
* bembed link
*/
const createSheetEl = (
data: string,
file: TFile,
width: number,
height: number = 300
): HTMLDivElement => {
const sheetDiv = createDiv();
if (plugin.settings.showSheetButton == "true") {
const fileEmbed = sheetDiv.createDiv({
cls: "internal-embed file-embed mod-generic is-loaded",
text: file.basename,
attr: {
src: file.basename,
alt: file.basename,
contenteditable: false,
tabindex: -1,
},
});
// 点击按钮打开 sheet
fileEmbed.onClickEvent((e) => {
e.stopPropagation();
plugin.app.workspace.getLeaf().openFile(file);
});
}
// <div class="internal-embed file-embed mod-generic is-loaded" tabindex="-1" src="Excel 2023-09-07 17.18.19.sheet" alt="Excel 2023-09-07 17.18.19.sheet" contenteditable="false"><div class="file-embed-title"><span class="file-embed-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-file"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path><polyline points="14 2 14 8 20 8"></polyline></svg></span> Excel 2023-09-07 17.18.19.sheet</div></div>
const sheetEl = createDiv({
cls: "sheet-iframe",
attr: {
id: `x-spreadsheet-${new Date().getTime()}`,
style: `height: ${height}px`
style: `height: ${height}px`,
},
});
@ -183,37 +332,37 @@ const createSheetEl = (data: string, file: TFile, width: number, height: number
// 设置 sheet 样式
var style = {
bgcolor: '#ffffff',
align: 'left',
valign: 'middle',
bgcolor: "#ffffff",
align: "left",
valign: "middle",
textwrap: false,
strike: false,
underline: false,
color: '#0a0a0a',
color: "#0a0a0a",
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
name: "Helvetica",
size: 10,
bold: false,
italic: false,
},
}
};
if (plugin.settings.theme === "dark") {
style = {
bgcolor: '#363636',
align: 'left',
valign: 'middle',
bgcolor: "#363636",
align: "left",
valign: "middle",
textwrap: false,
strike: false,
underline: false,
color: '#fff',
color: "#e6e6e6",
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
name: "Helvetica",
size: 10,
bold: false,
italic: false,
},
}
};
}
//@ts-ignore
@ -226,11 +375,11 @@ const createSheetEl = (data: string, file: TFile, width: number, height: number
width: () => width - 10,
},
row: {
len: 100,
len: parseInt(plugin.settings.defaultRowsLen),
height: parseInt(plugin.settings.rowHeight),
},
col: {
len: 26,
len: parseInt(plugin.settings.defaultColsLen),
width: parseInt(plugin.settings.colWidth),
indexWidth: 60,
minWidth: 60,
@ -240,11 +389,11 @@ const createSheetEl = (data: string, file: TFile, width: number, height: number
isDark: plugin.settings.theme === "dark",
}).loadData(jsonData); // load data
updateSheetTheme(plugin.settings.theme === "dark")
updateSheetTheme(plugin.settings.theme === "dark");
// @ts-ignore
sheet.validate();
sheetDiv.appendChild(sheetEl)
sheetDiv.appendChild(sheetEl);
return sheetDiv;
};
@ -304,7 +453,7 @@ const processInternalEmbed = async (
internalEmbedEl: Element,
file: TFile
): Promise<HTMLDivElement> => {
const src = internalEmbedEl.getAttribute("src");
var src = internalEmbedEl.getAttribute("src");
//@ts-ignore
if (!src) return;
@ -314,16 +463,36 @@ const processInternalEmbed = async (
const data = await vault.read(file);
const alt = internalEmbedEl.getAttribute("alt") ?? "";
// 是否转换成HTML
var toHTML = false;
if (src.includes("{html}")) {
toHTML = true;
src = src.replace("{html}", "");
}
var alt = internalEmbedEl.getAttribute("alt") ?? "";
if (alt.includes("{html}")) {
// 单 sheet 中的某一区域
toHTML = true;
alt = alt.replace("{html}", "");
}
const split = src.split("#");
var excelData = getExcelData(data);
if (split.length > 1) {
excelData = getExcelAreaData(
data,
split[1],
alt
);
excelData = getExcelAreaData(data, split[1], alt);
}
return await createSheetEl(excelData, file, internalEmbedEl.clientWidth);
// console.log('internalEmbedDiv', excelData, src, alt, toHTML)
if (toHTML) {
return await createSheetHtml(data, file, split[1], alt);
} else {
return await createSheetEl(
excelData,
file,
internalEmbedEl.clientWidth
);
}
};

View file

@ -42,4 +42,10 @@ export default {
ROW_HEIGHT_DESC: "Default row height",
COLUMN_WIDTH: "Column Width",
COLUMN_WIDTH_DESC: "Default column width",
DEFAULT_ROWS_LEN: 'Default render rows',
DEFAULT_ROWS_LEN_DESC: 'Default number of render rows',
DEFAULT_COLS_LEN: 'Default render columns',
DEFAULT_COLS_LEN_DESC: 'Default number of rendered columns',
SHOW_SHEET_BUTTON: "Show Sheet Button",
SHOW_SHEET_BUTTON_DESC: "Show Sheet Button",
};

View file

@ -41,4 +41,10 @@ export default {
ROW_HEIGHT_DESC: "设置表格的默认行高",
COLUMN_WIDTH: "列宽",
COLUMN_WIDTH_DESC: "设置表格的默认列宽",
DEFAULT_ROWS_LEN: '默认渲染行数',
DEFAULT_ROWS_LEN_DESC: '创建表格时默认渲染最大行数',
DEFAULT_COLS_LEN: '默认渲染列数',
DEFAULT_COLS_LEN_DESC: '创建表格时默认渲染最大列数',
SHOW_SHEET_BUTTON: "显示标题按钮",
SHOW_SHEET_BUTTON_DESC: "是否显示标题按钮",
};

View file

@ -1,6 +1,7 @@
import { Notice } from "obsidian";
import { t } from "../lang/helpers"
import { expr2expr } from "../utils/alphabet"
import { t } from "../lang/helpers";
import { expr2expr } from "../utils/alphabet";
import da from "src/lang/locale/da";
/**
* sheet
* @param data markdown data
@ -33,15 +34,6 @@ export const getExcelAreaData = (
const excelData = getExcelData(data) || "{}";
const jsonData = JSON.parse(excelData) || [];
var cellArray = cells.split(":");
const start = cellArray[0].split("-");
var sri = parseInt(start[0]); // 开始行
var sci = parseInt(start[1]); // 开始列
const end = cellArray[1].split("-");
var eri = parseInt(end[0]); // 结束行
var eci = parseInt(end[1]); // 结束列
var newData = new Map<string, any>();
if (jsonData instanceof Array) {
@ -49,15 +41,39 @@ export const getExcelAreaData = (
return item.name === sheet;
})[0];
newData.set("name", sheet);
newData.set("autofilter", sheetData.autofilter);
newData.set("freeze", sheetData.freeze);
newData.set("styles", sheetData.styles);
newData.set("validations", sheetData.validations);
newData.set("merges", sheetData.merges);
var rowLen = eri - sri + 1;
if (sheetData) {
newData.set("name", sheet);
newData.set("autofilter", sheetData.autofilter);
newData.set("freeze", sheetData.freeze);
newData.set("styles", sheetData.styles);
newData.set("validations", sheetData.validations);
newData.set("merges", sheetData.merges);
console.log("------", jsonData, cells, sheetData);
var sri = 0;
var sci = 0;
var eri = 100;
var eci = 26;
if (cells.includes(":")) {
var cellArray = cells.split(":");
const start = cellArray[0].split("-");
var sri = parseInt(start[0]); // 开始行
var sci = parseInt(start[1]); // 开始列
const end = cellArray[1].split("-");
var eri = parseInt(end[0]); // 结束行
var eci = parseInt(end[1]); // 结束列
} else {
if (sheetData.rows && sheetData.rows.len) {
eri = sheetData.rows.len - 1;
}
if (sheetData.cols && sheetData.cols.len) {
eci = sheetData.cols.len - 1;
}
}
var rowLen = eri - sri + 1;
// 用来存储新数据
var rows = new Map<string, any>();
// 解析 row并重 0 开始排数据
@ -75,10 +91,19 @@ export const getExcelAreaData = (
if (cell) {
// 如果当前cell是公式
if (cell.text) {
var text = cell.text as String
if (text && text[0] === '=') {
var text = cell.text as String;
if (text && text[0] === "=") {
// console.log('cell text', text, sri, sci)
cell.text = text.replace(/[a-zA-Z]{1,3}\d+/g, word => expr2expr(word, -sci, -sri, (x, y) => true));
cell.text = text.replace(
/[a-zA-Z]{1,3}\d+/g,
(word) =>
expr2expr(
word,
-sci,
-sri,
(x, y) => true
)
);
// console.log('update cell text', cell.text)
}
}
@ -100,7 +125,7 @@ export const getExcelAreaData = (
}
// const rowLen = Math.max(9, eri - sri + 1)
console.log("rows", sheetData, rows);
// console.log("rows", sheetData, rows);
rows.set("len", rowLen);
newData.set("rows", Object.fromEntries(rows));
// const colLen = Math.max(Math.ceil(clientWidth / 91), eci - sci + 1)
@ -115,3 +140,124 @@ export const getExcelAreaData = (
// console.log("newData", Object.fromEntries(newData))
return newJsonData;
};
/**
* sheet cells HTML
* @param data markdown data
* @param sheet sheet
* @param cells cells 格式为: sri-sci:eri-eci 6-6:7-8
* @returns
*/
export const getExcelAreaHtml = (
data: string,
sheet: string,
cells: string
): HTMLElement => {
const excelData = getExcelData(data) || "{}";
const jsonData = JSON.parse(excelData) || [];
var table = createEl("table");
if (jsonData instanceof Array) {
const sheetData = jsonData.filter((item) => {
return item.name === sheet;
})[0];
if (sheetData) {
var sri = 0;
var sci = 0;
var eri = 100;
var eci = 26;
if (cells.includes(":")) {
var cellArray = cells.split(":");
const start = cellArray[0].split("-");
var sri = parseInt(start[0]); // 开始行
var sci = parseInt(start[1]); // 开始列
const end = cellArray[1].split("-");
var eri = parseInt(end[0]); // 结束行
var eci = parseInt(end[1]); // 结束列
} else {
if (sheetData.rows && sheetData.rows.len) {
eri = sheetData.rows.len - 1;
}
if (sheetData.cols && sheetData.cols.len) {
eci = sheetData.cols.len - 1;
}
}
// console.log("getExcelAreaHtml", cells, sri, sci, eri, eci);
// 记录合并单元格数量
var mergeMap: Map<string, boolean> = new Map();
for (var row = sri; row <= eri; row++) {
var tr = createEl("tr");
table.appendChild(tr);
for (var col = sci; col <= eci; col++) {
// 获取当前行的数据
const cells = sheetData.rows[`${row}`];
if (cells) {
// 如果当前行有数据
// 获取单元格数据
const cell = cells.cells[`${col}`];
if (cell) {
// 如果单元格有数据展示数据
if (cell.merge) {
// 是否有合并单元格的操作
var mergeRow = cell.merge[0] + 1;
var mergeCol = cell.merge[1] + 1;
// 记录合并的行跟列
for (var r = 0; r < mergeRow; r++) {
const index = `${row + r}-${col}`;
mergeMap.set(index, true);
for (var c = 0; c < mergeCol; c++) {
const index = `${row + r}-${col + c}`;
mergeMap.set(index, true);
}
}
var td = createEl("td", {
text: cell.text || "",
attr: {
rowspan: mergeRow,
colspan: mergeCol,
},
});
tr.appendChild(td);
} else {
// 无合并单元格直接添加
var td = createEl("td", {
text: cell.text || "",
});
tr.appendChild(td);
}
} else {
// 添加空白单元格需要判断是否被合并了
const index = `${row}-${col}`;
if (!mergeMap.get(index)) {
// 单元格没数据添加空白单元格 & 没有被合并单元格
var td = createEl("td");
tr.appendChild(td);
}
}
} else {
const index = `${row}-${col}`;
// 添加空白单元格需要判断是否被合并了
if (!mergeMap.get(index)) {
// 单元格没数据添加空白单元格 & 没有被合并单元格
var td = createEl("td");
tr.appendChild(td);
}
}
}
}
} else {
}
}
return table;
};

View file

@ -5,7 +5,10 @@ export interface ExcelSettings {
sheetHeight: string,
rowHeight: string,
colWidth: string,
theme: string
theme: string,
showSheetButton: string,
defaultRowsLen: string,
defaultColsLen: string,
}
export const DEFAULT_SETTINGS: ExcelSettings = {
@ -15,5 +18,8 @@ export const DEFAULT_SETTINGS: ExcelSettings = {
sheetHeight: "300",
rowHeight: "25",
colWidth: "100",
theme: "light"
theme: "light",
showSheetButton: "true",
defaultRowsLen: "100",
defaultColsLen: "26",
};

File diff suppressed because one or more lines are too long