mirror of
https://github.com/ljcoder2015/obsidian-excel.git
synced 2026-07-22 08:30:28 +00:00
feat: 编辑模式也能预览sheet, 文件格式变为 .sheet.md
This commit is contained in:
parent
b5d9f413fd
commit
f166222309
14 changed files with 1047 additions and 1660 deletions
|
|
@ -16,7 +16,7 @@ const context = await esbuild.context({
|
||||||
banner: {
|
banner: {
|
||||||
js: banner,
|
js: banner,
|
||||||
},
|
},
|
||||||
entryPoints: ["main.ts"],
|
entryPoints: ["src/main.ts"],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
external: [
|
external: [
|
||||||
"obsidian",
|
"obsidian",
|
||||||
|
|
|
||||||
130
main.ts
130
main.ts
|
|
@ -1,130 +0,0 @@
|
||||||
import {
|
|
||||||
TFile,
|
|
||||||
Plugin,
|
|
||||||
WorkspaceLeaf,
|
|
||||||
normalizePath,
|
|
||||||
} from "obsidian";
|
|
||||||
import { ExcelSettings, DEFAULT_SETTINGS } from "./src/utils/Settings";
|
|
||||||
import {
|
|
||||||
PaneTarget,
|
|
||||||
} from "./src/utils/ModifierkeyHelper";
|
|
||||||
import { ExcelView, VIEW_TYPE_EXCEL } from "./src/ExcelView";
|
|
||||||
import {
|
|
||||||
getExcelFilename,
|
|
||||||
} from "./src/utils/FileUtils";
|
|
||||||
|
|
||||||
import {
|
|
||||||
initializeMarkdownPostProcessor,
|
|
||||||
markdownPostProcessor,
|
|
||||||
} from "./src/MarkdownPostProcessor";
|
|
||||||
|
|
||||||
export default class ExcelPlugin extends Plugin {
|
|
||||||
public settings: ExcelSettings;
|
|
||||||
|
|
||||||
async onload() {
|
|
||||||
this.registerView(
|
|
||||||
VIEW_TYPE_EXCEL,
|
|
||||||
(leaf: WorkspaceLeaf) => new ExcelView(leaf, this)
|
|
||||||
);
|
|
||||||
this.registerExtensions(["sheet"], VIEW_TYPE_EXCEL);
|
|
||||||
|
|
||||||
// This creates an icon in the left ribbon.
|
|
||||||
this.addRibbonIcon(
|
|
||||||
"table",
|
|
||||||
"Excel",
|
|
||||||
(e: MouseEvent) => {
|
|
||||||
// Called when the user clicks the icon.
|
|
||||||
this.createAndOpenExcel(getExcelFilename(this.settings));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// markdwon后处理
|
|
||||||
this.addMarkdownPostProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private addMarkdownPostProcessor() {
|
|
||||||
initializeMarkdownPostProcessor(this);
|
|
||||||
this.registerMarkdownPostProcessor(markdownPostProcessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
onunload() {}
|
|
||||||
|
|
||||||
async loadSettings() {
|
|
||||||
this.settings = Object.assign(
|
|
||||||
{},
|
|
||||||
DEFAULT_SETTINGS,
|
|
||||||
await this.loadData()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveSettings() {
|
|
||||||
await this.saveData(this.settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createExcel(
|
|
||||||
filename: string,
|
|
||||||
foldername?: string,
|
|
||||||
initData?: string
|
|
||||||
): Promise<TFile> {
|
|
||||||
// const folderpath = normalizePath(
|
|
||||||
// foldername ? foldername : "Excel"
|
|
||||||
// );
|
|
||||||
// await checkAndCreateFolder(folderpath); //create folder if it does not exist
|
|
||||||
const fname = normalizePath(filename);
|
|
||||||
const file = await this.app.vault.create(fname, initData ?? "{}");
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createAndOpenExcel(
|
|
||||||
filename: string,
|
|
||||||
foldername?: string,
|
|
||||||
initData?: string
|
|
||||||
): Promise<string> {
|
|
||||||
const file = await this.createExcel(filename, foldername, initData);
|
|
||||||
this.openExcel(file, "new-pane", true, undefined);
|
|
||||||
return file.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public openExcel(
|
|
||||||
excelFile: TFile,
|
|
||||||
location: PaneTarget,
|
|
||||||
active = false,
|
|
||||||
subpath?: string
|
|
||||||
) {
|
|
||||||
if (location === "md-properties") {
|
|
||||||
location = "new-tab";
|
|
||||||
}
|
|
||||||
var leaf: WorkspaceLeaf | null = null;
|
|
||||||
if (location === "popout-window") {
|
|
||||||
leaf = this.app.workspace.openPopoutLeaf();
|
|
||||||
}
|
|
||||||
if (location === "new-tab") {
|
|
||||||
leaf = this.app.workspace.getLeaf("tab");
|
|
||||||
}
|
|
||||||
if (!leaf) {
|
|
||||||
leaf = this.app.workspace.getLeaf(false);
|
|
||||||
if (
|
|
||||||
leaf.view.getViewType() !== "empty" &&
|
|
||||||
location === "new-pane"
|
|
||||||
) {
|
|
||||||
leaf = this.app.workspace.getMostRecentLeaf();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
leaf?.openFile(
|
|
||||||
excelFile,
|
|
||||||
!subpath || subpath === ""
|
|
||||||
? { active }
|
|
||||||
: { active, eState: { subpath } }
|
|
||||||
).then(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
public isExcelFile(f: TFile) {
|
|
||||||
if (!f) return false;
|
|
||||||
if (f.extension === "sheet") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "excel",
|
"id": "excel",
|
||||||
"name": "Excel",
|
"name": "Excel",
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"minAppVersion": "0.15.0",
|
"minAppVersion": "0.15.0",
|
||||||
"description": "Create spreadsheets and easily embed them in Markdown",
|
"description": "Create spreadsheets and easily embed them in Markdown",
|
||||||
"author": "ljcoder",
|
"author": "ljcoder",
|
||||||
|
|
|
||||||
1820
package-lock.json
generated
1820
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,7 @@
|
||||||
"typescript": "4.7.4"
|
"typescript": "4.7.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"monkey-around": "^2.3.0",
|
||||||
"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"
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
src/Excel.ts
38
src/Excel.ts
|
|
@ -1,38 +0,0 @@
|
||||||
import { MarkdownRenderChild } from "obsidian";
|
|
||||||
import Spreadsheet from "x-data-spreadsheet";
|
|
||||||
|
|
||||||
export class Excel extends MarkdownRenderChild {
|
|
||||||
data: string;
|
|
||||||
index: number;
|
|
||||||
|
|
||||||
constructor(containerEl: HTMLElement, data: string, index: number) {
|
|
||||||
super(containerEl);
|
|
||||||
this.data = data;
|
|
||||||
this.index = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
onload(): void {
|
|
||||||
console.log
|
|
||||||
const sheetEle = this.containerEl.createDiv({
|
|
||||||
cls: 'sheet-iframe',
|
|
||||||
attr: {
|
|
||||||
id: `x-spreadsheet-${this.index}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const jsonData = JSON.parse(this.data || "{}") || {};
|
|
||||||
//@ts-ignore
|
|
||||||
const sheet = new Spreadsheet(sheetEle, {
|
|
||||||
mode: "read",
|
|
||||||
showToolbar: false,
|
|
||||||
showBottomBar: true,
|
|
||||||
view: {
|
|
||||||
height: () => 300,
|
|
||||||
width: () => this.containerEl.clientWidth,
|
|
||||||
},
|
|
||||||
}).loadData(jsonData); // load data
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
sheet.validate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import { syntaxTree } from "@codemirror/language";
|
|
||||||
import {
|
|
||||||
Extension,
|
|
||||||
RangeSetBuilder,
|
|
||||||
StateField,
|
|
||||||
Transaction,
|
|
||||||
} from "@codemirror/state";
|
|
||||||
import {
|
|
||||||
Decoration,
|
|
||||||
DecorationSet,
|
|
||||||
EditorView,
|
|
||||||
} from "@codemirror/view";
|
|
||||||
import { ExcelWidget } from "./ExcelWidget";
|
|
||||||
|
|
||||||
export const ExcelField = StateField.define<DecorationSet>({
|
|
||||||
create(state): DecorationSet {
|
|
||||||
return Decoration.none;
|
|
||||||
},
|
|
||||||
update(oldState: DecorationSet, transaction: Transaction): DecorationSet {
|
|
||||||
const builder = new RangeSetBuilder<Decoration>();
|
|
||||||
|
|
||||||
syntaxTree(transaction.state).iterate({
|
|
||||||
enter(node) {
|
|
||||||
console.log(node)
|
|
||||||
// if (node.type.name.startsWith("list")) {
|
|
||||||
// // Position of the '-' or the '*'.
|
|
||||||
// const listCharFrom = node.from - 2;
|
|
||||||
|
|
||||||
// builder.add(
|
|
||||||
// listCharFrom,
|
|
||||||
// listCharFrom + 1,
|
|
||||||
// Decoration.replace({
|
|
||||||
// widget: new EmojiWidget(),
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return builder.finish();
|
|
||||||
},
|
|
||||||
provide(field: StateField<DecorationSet>): Extension {
|
|
||||||
return EditorView.decorations.from(field);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
162
src/ExcelView.ts
162
src/ExcelView.ts
|
|
@ -1,10 +1,9 @@
|
||||||
import ExcelPlugin from "main";
|
import ExcelPlugin from "src/main";
|
||||||
import { TextFileView, WorkspaceLeaf, Platform, Notice } from "obsidian";
|
import { TextFileView, WorkspaceLeaf, Platform, Notice } from "obsidian";
|
||||||
import Spreadsheet from "x-data-spreadsheet";
|
import Spreadsheet from "x-data-spreadsheet";
|
||||||
import * as XLSX from "xlsx";
|
import * as XLSX from "xlsx";
|
||||||
import { stox, xtos } from "./utils/xlsxspread";
|
import { stox, xtos } from "./utils/xlsxspread";
|
||||||
|
import { VIEW_TYPE_EXCEL, FRONTMATTER } from "./constants";
|
||||||
export const VIEW_TYPE_EXCEL = "excel-view";
|
|
||||||
|
|
||||||
export class ExcelView extends TextFileView {
|
export class ExcelView extends TextFileView {
|
||||||
public plugin: ExcelPlugin;
|
public plugin: ExcelPlugin;
|
||||||
|
|
@ -16,18 +15,18 @@ export class ExcelView extends TextFileView {
|
||||||
public copyHTMLEle: HTMLElement;
|
public copyHTMLEle: HTMLElement;
|
||||||
public sheetEle: HTMLElement;
|
public sheetEle: HTMLElement;
|
||||||
public cellsSelected: {
|
public cellsSelected: {
|
||||||
sheet: Record<string, any> | null,
|
sheet: Record<string, any> | null;
|
||||||
sri: number | null, // 选中开始行 index
|
sri: number | null; // 选中开始行 index
|
||||||
sci: number | null, // 选中开始列 index
|
sci: number | null; // 选中开始列 index
|
||||||
eri: number | null, // 选中结束行 index
|
eri: number | null; // 选中结束行 index
|
||||||
eci: number | null, // 选中结束列 index
|
eci: number | null; // 选中结束列 index
|
||||||
} = {
|
} = {
|
||||||
sheet: null,
|
sheet: null,
|
||||||
sri: null,
|
sri: null,
|
||||||
sci: null,
|
sci: null,
|
||||||
eri: null,
|
eri: null,
|
||||||
eci: null,
|
eci: null,
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(leaf: WorkspaceLeaf, plugin: ExcelPlugin) {
|
constructor(leaf: WorkspaceLeaf, plugin: ExcelPlugin) {
|
||||||
super(leaf);
|
super(leaf);
|
||||||
|
|
@ -38,6 +37,31 @@ export class ExcelView extends TextFileView {
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getExcelData(): string {
|
||||||
|
const tagText = "# Excel\n";
|
||||||
|
const trimLocation = this.data.search(tagText);
|
||||||
|
if (trimLocation == -1) return this.data;
|
||||||
|
const excelData = this.data.substring(
|
||||||
|
trimLocation + tagText.length,
|
||||||
|
this.data.length
|
||||||
|
);
|
||||||
|
// console.log("trimLocation", trimLocation, excelData, this.data);
|
||||||
|
return excelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerData() {
|
||||||
|
return FRONTMATTER + "\n# Excel\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
saveData(data: string) {
|
||||||
|
this.data = this.headerData() + data;
|
||||||
|
// console.log("saveData", this.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.data = this.headerData();
|
||||||
|
}
|
||||||
|
|
||||||
setViewData(data: string, clear: boolean): void {
|
setViewData(data: string, clear: boolean): void {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
|
||||||
|
|
@ -57,8 +81,8 @@ export class ExcelView extends TextFileView {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const files = e.target?.files;
|
const files = e.target?.files;
|
||||||
if (!files) {
|
if (!files) {
|
||||||
new Notice('Failed to get file')
|
new Notice("Failed to get file");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const f = files[0];
|
const f = files[0];
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
@ -68,7 +92,7 @@ export class ExcelView extends TextFileView {
|
||||||
if (data) {
|
if (data) {
|
||||||
this.process_wb(XLSX.read(data));
|
this.process_wb(XLSX.read(data));
|
||||||
} else {
|
} else {
|
||||||
new Notice('Read file error')
|
new Notice("Read file error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(f);
|
reader.readAsArrayBuffer(f);
|
||||||
|
|
@ -80,7 +104,7 @@ export class ExcelView extends TextFileView {
|
||||||
this.sheet.loadData(sheetData);
|
this.sheet.loadData(sheetData);
|
||||||
this.data = JSON.stringify(sheetData);
|
this.data = JSON.stringify(sheetData);
|
||||||
} else {
|
} else {
|
||||||
new Notice('Data parsing error')
|
new Notice("Data parsing error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,14 +116,12 @@ export class ExcelView extends TextFileView {
|
||||||
XLSX.writeFile(new_wb, title + ".xlsx", {});
|
XLSX.writeFile(new_wb, title + ".xlsx", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEmbedLink(e:Event) {
|
handleEmbedLink(e: Event) {
|
||||||
if (this.file) {
|
if (this.file) {
|
||||||
navigator.clipboard.writeText(
|
navigator.clipboard.writeText(`![[${this.file.path}]]`);
|
||||||
`![[${this.file.path}]]`,
|
new Notice("Copy embed link to clipboard");
|
||||||
);
|
|
||||||
new Notice('Copy embed link to clipboard')
|
|
||||||
} else {
|
} else {
|
||||||
new Notice('Copy embed link failed')
|
new Notice("Copy embed link failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,9 +148,7 @@ export class ExcelView extends TextFileView {
|
||||||
super.onload();
|
super.onload();
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(): void {
|
|
||||||
this.data = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
getViewType(): string {
|
getViewType(): string {
|
||||||
return VIEW_TYPE_EXCEL;
|
return VIEW_TYPE_EXCEL;
|
||||||
|
|
@ -159,96 +179,96 @@ export class ExcelView extends TextFileView {
|
||||||
);
|
);
|
||||||
|
|
||||||
// 初始化 sheet
|
// 初始化 sheet
|
||||||
const jsonData = JSON.parse(this.data || "{}") || {};
|
const jsonData = JSON.parse(this.getExcelData() || "{}") || {};
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
this.sheet = new Spreadsheet(this.sheetEle, {
|
this.sheet = new Spreadsheet(this.sheetEle, {
|
||||||
showBottomBar: true,
|
showBottomBar: true,
|
||||||
view: {
|
view: {
|
||||||
height: () => this.contentEl.clientHeight,
|
height: () => this.contentEl.clientHeight,
|
||||||
width: () => this.contentEl.clientWidth,
|
width: () => this.contentEl.clientWidth,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.loadData(jsonData) // load data
|
.loadData(jsonData) // load data
|
||||||
.change(() => {
|
.change(() => {
|
||||||
// save data to db
|
// save data to db
|
||||||
const data = this.sheet.getData()
|
const data = this.sheet.getData();
|
||||||
console.log('save data to db', data)
|
// console.log("save data to db", data);
|
||||||
this.data = JSON.stringify(data);
|
this.saveData(JSON.stringify(data))
|
||||||
})
|
})
|
||||||
.onAddSheet(()=> {
|
.onAddSheet(() => {
|
||||||
const data = this.sheet.getData()
|
const data = this.sheet.getData();
|
||||||
// console.log('onAddSheet', data)
|
// console.log('onAddSheet', data)
|
||||||
this.data = JSON.stringify(data);
|
this.saveData(JSON.stringify(data))
|
||||||
})
|
})
|
||||||
.onRenameSheet(()=> {
|
.onRenameSheet(() => {
|
||||||
const data = this.sheet.getData()
|
const data = this.sheet.getData();
|
||||||
// console.log('onRenameSheet', data)
|
// console.log('onRenameSheet', data)
|
||||||
this.data = JSON.stringify(data);
|
this.saveData(JSON.stringify(data))
|
||||||
})
|
});
|
||||||
|
|
||||||
this.sheet.on('cells-selected', (sheetData, {sri, sci, eri, eci}) => {
|
this.sheet.on("cells-selected", (sheetData, { sri, sci, eri, eci }) => {
|
||||||
// console.log('cells-selected',sheetData, sri, sci, eri, eci)
|
// console.log('cells-selected',sheetData, sri, sci, eri, eci)
|
||||||
this.cellsSelected.sheet = sheetData
|
this.cellsSelected.sheet = sheetData;
|
||||||
this.cellsSelected.sri = sri
|
this.cellsSelected.sri = sri;
|
||||||
this.cellsSelected.sci = sci
|
this.cellsSelected.sci = sci;
|
||||||
this.cellsSelected.eri = eri
|
this.cellsSelected.eri = eri;
|
||||||
this.cellsSelected.eci = eci
|
this.cellsSelected.eci = eci;
|
||||||
|
});
|
||||||
|
|
||||||
})
|
this.sheet.on("cell-selected", (sheetData, ri, ci) => {
|
||||||
|
|
||||||
this.sheet.on('cell-selected', (sheetData, ri, ci) => {
|
|
||||||
// console.log('cell-selected',sheetData, ri, ci)
|
// console.log('cell-selected',sheetData, ri, ci)
|
||||||
this.cellsSelected.sheet = sheetData
|
this.cellsSelected.sheet = sheetData;
|
||||||
this.cellsSelected.sri = ri
|
this.cellsSelected.sri = ri;
|
||||||
this.cellsSelected.sci = ci
|
this.cellsSelected.sci = ci;
|
||||||
this.cellsSelected.eri = ri
|
this.cellsSelected.eri = ri;
|
||||||
this.cellsSelected.eci = ci
|
this.cellsSelected.eci = ci;
|
||||||
})
|
});
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.sheet.validate();
|
this.sheet.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
copyToHTML() {
|
copyToHTML() {
|
||||||
const data = this.cellsSelected.sheet
|
const data = this.cellsSelected.sheet;
|
||||||
const sri = this.cellsSelected.sri
|
const sri = this.cellsSelected.sri;
|
||||||
const sci = this.cellsSelected.sci
|
const sci = this.cellsSelected.sci;
|
||||||
const eri = this.cellsSelected.eri
|
const eri = this.cellsSelected.eri;
|
||||||
const eci = this.cellsSelected.eci
|
const eci = this.cellsSelected.eci;
|
||||||
|
|
||||||
// console.log('data', data, sri, sci, eri, eci)
|
// console.log('data', data, sri, sci, eri, eci)
|
||||||
|
|
||||||
var html = "<table>"
|
var html = "<table>";
|
||||||
|
|
||||||
if (data && sri && sci && eri && eci) {
|
if (data && sri && sci && eri && eci) {
|
||||||
for (var row = sri; row <= eri; row ++) {
|
for (var row = sri; row <= eri; row++) {
|
||||||
html += "<tr>"
|
html += "<tr>";
|
||||||
const cells = data.rows._[`${row}`]
|
const cells = data.rows._[`${row}`];
|
||||||
// console.log('cells', row, cells.cells)
|
// console.log('cells', row, cells.cells)
|
||||||
if (cells) {
|
if (cells) {
|
||||||
for (var col = sci; col <= eci; col ++ ) {
|
for (var col = sci; col <= eci; col++) {
|
||||||
const cell = cells.cells[`${col}`]
|
const cell = cells.cells[`${col}`];
|
||||||
// console.log('cell', row, col, cell)
|
// console.log('cell', row, col, cell)
|
||||||
if (cell) {
|
if (cell) {
|
||||||
if (cell.merge) {
|
if (cell.merge) {
|
||||||
html += `<td rowspan="${cell.merge[0]}" colspan="${cell.merge[1]}">${cell.text}</td>`
|
html += `<td rowspan="${cell.merge[0]}" colspan="${cell.merge[1]}">${cell.text}</td>`;
|
||||||
} else {
|
} else {
|
||||||
html += `<td>${cell.text}</td>`
|
html += `<td>${cell.text}</td>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html += "</tr>"
|
html += "</tr>";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
new Notice("Please first select the data to copy")
|
new Notice("Please first select the data to copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
html +="</table>"
|
html += "</table>";
|
||||||
|
|
||||||
navigator.clipboard.writeText(html);
|
navigator.clipboard.writeText(html);
|
||||||
new Notice("copied")
|
new Notice("copied");
|
||||||
}
|
}
|
||||||
|
|
||||||
onResize() {
|
onResize() {
|
||||||
|
|
@ -256,6 +276,6 @@ export class ExcelView extends TextFileView {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
// console.log('resize')
|
// console.log('resize')
|
||||||
super.onResize()
|
super.onResize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
import { EditorView, WidgetType } from "@codemirror/view"
|
|
||||||
import Spreadsheet from "x-data-spreadsheet";
|
|
||||||
|
|
||||||
export class ExcelWidget extends WidgetType {
|
|
||||||
data: string
|
|
||||||
constructor(data: string) {
|
|
||||||
super()
|
|
||||||
this.data = data
|
|
||||||
}
|
|
||||||
|
|
||||||
toDOM(view: EditorView): HTMLElement {
|
|
||||||
const time = new Date().getTime()
|
|
||||||
const sheetEle = document.createDiv({
|
|
||||||
cls: 'sheet-iframe',
|
|
||||||
attr: {
|
|
||||||
id: `x-spreadsheet-${time}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const jsonData = JSON.parse(this.data || "{}") || {};
|
|
||||||
//@ts-ignore
|
|
||||||
const sheet = new Spreadsheet(sheetEle, {
|
|
||||||
mode: "read",
|
|
||||||
showToolbar: false,
|
|
||||||
showBottomBar: true,
|
|
||||||
view: {
|
|
||||||
height: () => 300,
|
|
||||||
width: () => document.body.clientWidth,
|
|
||||||
},
|
|
||||||
}).loadData(jsonData); // load data
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
sheet.validate();
|
|
||||||
|
|
||||||
return sheetEle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,8 +4,8 @@ import {
|
||||||
TFile,
|
TFile,
|
||||||
Vault,
|
Vault,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import ExcelPlugin from "../main";
|
import ExcelPlugin from "./main";
|
||||||
import { Excel } from "./Excel";
|
import Spreadsheet from "x-data-spreadsheet";
|
||||||
|
|
||||||
let plugin: ExcelPlugin;
|
let plugin: ExcelPlugin;
|
||||||
let vault: Vault;
|
let vault: Vault;
|
||||||
|
|
@ -23,7 +23,7 @@ const tmpObsidianWYSIWYG = async (
|
||||||
ctx: MarkdownPostProcessorContext
|
ctx: MarkdownPostProcessorContext
|
||||||
) => {
|
) => {
|
||||||
const file = plugin.app.vault.getAbstractFileByPath(ctx.sourcePath);
|
const file = plugin.app.vault.getAbstractFileByPath(ctx.sourcePath);
|
||||||
console.log('tmpObsidianWYSIWYG',file, el, ctx.sourcePath)
|
console.log("tmpObsidianWYSIWYG");
|
||||||
if (!(file instanceof TFile)) return;
|
if (!(file instanceof TFile)) return;
|
||||||
if (!plugin.isExcelFile(file)) return;
|
if (!plugin.isExcelFile(file)) return;
|
||||||
|
|
||||||
|
|
@ -72,19 +72,81 @@ const tmpObsidianWYSIWYG = async (
|
||||||
//the excalidraw file in markdown preview mode
|
//the excalidraw file in markdown preview mode
|
||||||
const isFrontmatterDiv = Boolean(el.querySelector(".frontmatter"));
|
const isFrontmatterDiv = Boolean(el.querySelector(".frontmatter"));
|
||||||
el.empty();
|
el.empty();
|
||||||
|
if (!isFrontmatterDiv) {
|
||||||
|
if (el.parentElement === containerEl) containerEl.removeChild(el);
|
||||||
|
return;
|
||||||
|
}
|
||||||
internalEmbedDiv.empty();
|
internalEmbedDiv.empty();
|
||||||
const data = await vault.read(file);
|
const data = await vault.read(file);
|
||||||
const excel = new Excel(el, data, new Date().getTime());
|
const sheetDiv = createSheetEl(
|
||||||
ctx.addChild(excel);
|
getExcelData(data),
|
||||||
|
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();
|
el.empty();
|
||||||
|
|
||||||
|
if (internalEmbedDiv.hasAttribute("ready")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
internalEmbedDiv.setAttribute("ready", "");
|
||||||
|
|
||||||
internalEmbedDiv.empty();
|
internalEmbedDiv.empty();
|
||||||
const data = await vault.read(file);
|
const data = await vault.read(file);
|
||||||
const excel = new Excel(el, data, 0);
|
const sheetDiv = createSheetEl(
|
||||||
ctx.addChild(excel);
|
getExcelData(data),
|
||||||
|
internalEmbedDiv.clientWidth
|
||||||
|
);
|
||||||
|
if (markdownEmbed) {
|
||||||
|
//display image on canvas without markdown frame
|
||||||
|
internalEmbedDiv.removeClass("markdown-embed");
|
||||||
|
internalEmbedDiv.removeClass("inline-embed");
|
||||||
|
}
|
||||||
|
internalEmbedDiv.appendChild(sheetDiv);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createSheetEl = (data: string, width: number): HTMLDivElement => {
|
||||||
|
const sheetEle = createDiv({
|
||||||
|
cls: "sheet-iframe",
|
||||||
|
attr: {
|
||||||
|
id: `x-spreadsheet-${new Date().getTime()}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const jsonData = JSON.parse(data || "{}") || {};
|
||||||
|
//@ts-ignore
|
||||||
|
const sheet = new Spreadsheet(sheetEle, {
|
||||||
|
mode: "read",
|
||||||
|
showToolbar: false,
|
||||||
|
showBottomBar: true,
|
||||||
|
view: {
|
||||||
|
height: () => 300,
|
||||||
|
width: () => width,
|
||||||
|
},
|
||||||
|
}).loadData(jsonData); // load data
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
sheet.validate();
|
||||||
|
return sheetEle;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getExcelData = (data: string): string => {
|
||||||
|
const tagText = "# Excel\n";
|
||||||
|
const trimLocation = data.search(tagText);
|
||||||
|
if (trimLocation == -1) return data;
|
||||||
|
const excelData = data.substring(
|
||||||
|
trimLocation + tagText.length,
|
||||||
|
data.length
|
||||||
|
);
|
||||||
|
// console.log("trimLocation", trimLocation, excelData, this.data);
|
||||||
|
return excelData;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -99,7 +161,9 @@ export const markdownPostProcessor = async (
|
||||||
//check to see if we are rendering in editing mode or live preview
|
//check to see if we are rendering in editing mode or live preview
|
||||||
//if yes, then there should be no .internal-embed containers
|
//if yes, then there should be no .internal-embed containers
|
||||||
const embeddedItems = el.querySelectorAll(".internal-embed");
|
const embeddedItems = el.querySelectorAll(".internal-embed");
|
||||||
|
console.log("markdownPostProcessor", embeddedItems.length);
|
||||||
if (embeddedItems.length === 0) {
|
if (embeddedItems.length === 0) {
|
||||||
|
tmpObsidianWYSIWYG(el, ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,6 +174,7 @@ const processReadingMode = async (
|
||||||
embeddedItems: NodeListOf<Element> | [HTMLElement],
|
embeddedItems: NodeListOf<Element> | [HTMLElement],
|
||||||
ctx: MarkdownPostProcessorContext
|
ctx: MarkdownPostProcessorContext
|
||||||
) => {
|
) => {
|
||||||
|
console.log("processReadingMode");
|
||||||
//We are processing a non-excalidraw file in reading mode
|
//We are processing a non-excalidraw file in reading mode
|
||||||
//Embedded files will be displayed in an .internal-embed container
|
//Embedded files will be displayed in an .internal-embed container
|
||||||
|
|
||||||
|
|
@ -123,21 +188,31 @@ const processReadingMode = async (
|
||||||
if (!fname) return true;
|
if (!fname) return true;
|
||||||
|
|
||||||
const file = metadataCache.getFirstLinkpathDest(fname, ctx.sourcePath);
|
const file = metadataCache.getFirstLinkpathDest(fname, ctx.sourcePath);
|
||||||
console.log("forEach", file, ctx.sourcePath);
|
// console.log("forEach", file, ctx.sourcePath);
|
||||||
|
|
||||||
//if the embeddedFile exits and it is an Excalidraw file
|
//if the embeddedFile exits and it is an Excalidraw file
|
||||||
//then lets replace the .internal-embed with the generated PNG or SVG image
|
//then lets replace the .internal-embed with the generated PNG or SVG image
|
||||||
if (file && file instanceof TFile && plugin.isExcelFile(file)) {
|
if (file && file instanceof TFile && plugin.isExcelFile(file)) {
|
||||||
const data = await vault.read(file);
|
|
||||||
const parent = maybeDrawing.parentElement;
|
maybeDrawing.parentElement?.replaceChild(
|
||||||
if (data && parent) {
|
await processInternalEmbed(maybeDrawing,file),
|
||||||
const excel = new Excel(
|
maybeDrawing
|
||||||
maybeDrawing.parentElement,
|
);
|
||||||
data,
|
|
||||||
index
|
|
||||||
);
|
|
||||||
ctx.addChild(excel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const processInternalEmbed = async (internalEmbedEl: Element, file: TFile ):Promise<HTMLDivElement> => {
|
||||||
|
|
||||||
|
const src = internalEmbedEl.getAttribute("src");
|
||||||
|
//@ts-ignore
|
||||||
|
if (!src) return;
|
||||||
|
|
||||||
|
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1059
|
||||||
|
internalEmbedEl.removeClass("markdown-embed");
|
||||||
|
internalEmbedEl.removeClass("inline-embed");
|
||||||
|
|
||||||
|
const data = await vault.read(file);
|
||||||
|
|
||||||
|
return await createSheetEl(getExcelData(data), internalEmbedEl.clientWidth);
|
||||||
|
}
|
||||||
|
|
|
||||||
5
src/constants.ts
Normal file
5
src/constants.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const VIEW_TYPE_EXCEL = "excel-view";
|
||||||
|
export const FRONTMATTER_KEY = "excel-plugin";
|
||||||
|
export const RERENDER_EVENT = "excel-embed-rerender";
|
||||||
|
export const FRONTMATTER = ["---","",`${FRONTMATTER_KEY}: parsed`,"","---", "", ""].join("\n");
|
||||||
|
|
||||||
336
src/main.ts
Normal file
336
src/main.ts
Normal file
|
|
@ -0,0 +1,336 @@
|
||||||
|
import {
|
||||||
|
TFile,
|
||||||
|
Plugin,
|
||||||
|
WorkspaceLeaf,
|
||||||
|
normalizePath,
|
||||||
|
ViewState,
|
||||||
|
MarkdownView,
|
||||||
|
Workspace,
|
||||||
|
} from "obsidian";
|
||||||
|
import { ExcelSettings, DEFAULT_SETTINGS } from "./utils/Settings";
|
||||||
|
import { PaneTarget } from "./utils/ModifierkeyHelper";
|
||||||
|
import { ExcelView } from "./ExcelView";
|
||||||
|
import { getExcelFilename } from "./utils/FileUtils";
|
||||||
|
import { around, dedupe } from "monkey-around";
|
||||||
|
|
||||||
|
import {
|
||||||
|
initializeMarkdownPostProcessor,
|
||||||
|
markdownPostProcessor,
|
||||||
|
} from "./MarkdownPostProcessor";
|
||||||
|
import { FRONTMATTER_KEY, FRONTMATTER, VIEW_TYPE_EXCEL } from "src/constants";
|
||||||
|
|
||||||
|
export default class ExcelPlugin extends Plugin {
|
||||||
|
public settings: ExcelSettings;
|
||||||
|
public excelFileModes: { [file: string]: string } = {};
|
||||||
|
private _loaded: boolean = false;
|
||||||
|
|
||||||
|
async onload() {
|
||||||
|
this.registerView(
|
||||||
|
VIEW_TYPE_EXCEL,
|
||||||
|
(leaf: WorkspaceLeaf) => new ExcelView(leaf, this)
|
||||||
|
);
|
||||||
|
this.registerExtensions(["sheet"], VIEW_TYPE_EXCEL);
|
||||||
|
|
||||||
|
// This creates an icon in the left ribbon.
|
||||||
|
this.addRibbonIcon("table", "Excel", (e: MouseEvent) => {
|
||||||
|
// Called when the user clicks the icon.
|
||||||
|
this.createAndOpenExcel(getExcelFilename(this.settings), undefined, this.getBlackData());
|
||||||
|
});
|
||||||
|
|
||||||
|
// markdwon后处理
|
||||||
|
this.addMarkdownPostProcessor();
|
||||||
|
|
||||||
|
//inspiration taken from kanban: https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
|
||||||
|
this.registerMonkeyPatches();
|
||||||
|
|
||||||
|
this.switchToExcelAfterLoad();
|
||||||
|
|
||||||
|
this.registerEventListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
onunload() {}
|
||||||
|
|
||||||
|
private getBlackData() {
|
||||||
|
return FRONTMATTER + "\n# Excel\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private addMarkdownPostProcessor() {
|
||||||
|
initializeMarkdownPostProcessor(this);
|
||||||
|
this.registerMarkdownPostProcessor(markdownPostProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerEventListeners() {
|
||||||
|
// const self = this;
|
||||||
|
// //save Excalidraw leaf and update embeds when switching to another leaf
|
||||||
|
// const activeLeafChangeEventHandler = async (leaf: WorkspaceLeaf) => {
|
||||||
|
// console.log('activeLeafChangeEventHandler', leaf)
|
||||||
|
// // this.switchToExcelAfterLoad()
|
||||||
|
// };
|
||||||
|
// self.registerEvent(
|
||||||
|
// this.app.workspace.on(
|
||||||
|
// "active-leaf-change",
|
||||||
|
// activeLeafChangeEventHandler
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
private switchToExcelAfterLoad() {
|
||||||
|
const self = this;
|
||||||
|
this.app.workspace.onLayoutReady(() => {
|
||||||
|
let leaf: WorkspaceLeaf;
|
||||||
|
let markdownLeaf = this.app.workspace.getLeavesOfType("markdown")
|
||||||
|
console.log("switchToExcelAfterLoad", markdownLeaf);
|
||||||
|
for (leaf of markdownLeaf) {
|
||||||
|
if (
|
||||||
|
leaf.view instanceof MarkdownView &&
|
||||||
|
leaf.view.file &&
|
||||||
|
self.isExcelFile(leaf.view.file)
|
||||||
|
) {
|
||||||
|
self.excelFileModes[
|
||||||
|
(leaf as any).id || leaf.view.file?.path
|
||||||
|
] = VIEW_TYPE_EXCEL;
|
||||||
|
self.setExcelView(leaf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadSettings() {
|
||||||
|
this.settings = Object.assign(
|
||||||
|
{},
|
||||||
|
DEFAULT_SETTINGS,
|
||||||
|
await this.loadData()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveSettings() {
|
||||||
|
await this.saveData(this.settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerMonkeyPatches() {
|
||||||
|
const key =
|
||||||
|
"https://github.com/zsviczian/obsidian-excalidraw-plugin/issues";
|
||||||
|
this.register(
|
||||||
|
around(Workspace.prototype, {
|
||||||
|
getActiveViewOfType(old) {
|
||||||
|
console.log("Workspace.prototype", old);
|
||||||
|
return dedupe(key, old, function (...args) {
|
||||||
|
const result = old && old.apply(this, args);
|
||||||
|
const maybeSheetView =
|
||||||
|
this.app?.workspace?.activeLeaf?.view;
|
||||||
|
if (
|
||||||
|
!maybeSheetView ||
|
||||||
|
!(maybeSheetView instanceof ExcelView)
|
||||||
|
)
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
//@ts-ignore
|
||||||
|
if (!this.app.plugins?.plugins?.["obsidian-hover-editor"]) {
|
||||||
|
this.register(
|
||||||
|
//stolen from hover editor
|
||||||
|
around(WorkspaceLeaf.prototype, {
|
||||||
|
getRoot(old) {
|
||||||
|
console.log("stolen from hover editor");
|
||||||
|
return function () {
|
||||||
|
const top = old.call(this);
|
||||||
|
return top.getRoot === this.getRoot
|
||||||
|
? top
|
||||||
|
: top.getRoot();
|
||||||
|
};
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.workspace.on("editor-menu", (menu, editor, view) => {
|
||||||
|
if (!view || !(view instanceof MarkdownView)) return;
|
||||||
|
const file = view.file;
|
||||||
|
const leaf = view.leaf;
|
||||||
|
if (!file) return;
|
||||||
|
const cache = this.app.metadataCache.getFileCache(file);
|
||||||
|
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEY])
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu.addItem((item) =>
|
||||||
|
item
|
||||||
|
.setTitle("OPEN_AS_EXCEL")
|
||||||
|
.setIcon("grid")
|
||||||
|
.setSection("excel")
|
||||||
|
.onClick(() => {
|
||||||
|
//@ts-ignore
|
||||||
|
this.excelFileModes[leaf.id || file.path] =
|
||||||
|
VIEW_TYPE_EXCEL;
|
||||||
|
this.setExcelView(leaf);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.registerEvent(
|
||||||
|
this.app.workspace.on("file-menu", (menu, file, source, leaf) => {
|
||||||
|
if (!leaf || !(leaf.view instanceof MarkdownView)) return;
|
||||||
|
if (!(file instanceof TFile)) return;
|
||||||
|
const cache = this.app.metadataCache.getFileCache(file);
|
||||||
|
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEY])
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu.addItem((item) => {
|
||||||
|
item.setTitle("OPEN_AS_EXCEL")
|
||||||
|
.setIcon("grid")
|
||||||
|
.setSection("pane")
|
||||||
|
.onClick(() => {
|
||||||
|
//@ts-ignore
|
||||||
|
this.excelFileModes[leaf.id || file.path] =
|
||||||
|
VIEW_TYPE_EXCEL;
|
||||||
|
this.setExcelView(leaf);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//@ts-ignore
|
||||||
|
menu.items.unshift(menu.items.pop());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
// Monkey patch WorkspaceLeaf to open Excalidraw drawings with ExcalidrawView by default
|
||||||
|
this.register(
|
||||||
|
around(WorkspaceLeaf.prototype, {
|
||||||
|
// Drawings can be viewed as markdown or Excalidraw, and we keep track of the mode
|
||||||
|
// while the file is open. When the file closes, we no longer need to keep track of it.
|
||||||
|
detach(next) {
|
||||||
|
return function () {
|
||||||
|
const state = this.view?.getState();
|
||||||
|
console.log('state--', state.file)
|
||||||
|
if (
|
||||||
|
state?.file &&
|
||||||
|
self.excelFileModes[this.id || state.file]
|
||||||
|
) {
|
||||||
|
delete self.excelFileModes[this.id || state.file];
|
||||||
|
}
|
||||||
|
|
||||||
|
return next.apply(this);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
setViewState(next) {
|
||||||
|
return function (state: ViewState, ...rest: any[]) {
|
||||||
|
if (
|
||||||
|
// Don't force excalidraw mode during shutdown
|
||||||
|
self._loaded &&
|
||||||
|
// If we have a markdown file
|
||||||
|
state.type === "markdown" &&
|
||||||
|
state.state?.file &&
|
||||||
|
// And the current mode of the file is not set to markdown
|
||||||
|
self.excelFileModes[this.id || state.state.file] !==
|
||||||
|
"markdown"
|
||||||
|
) {
|
||||||
|
// Then check for the excalidraw frontMatterKey
|
||||||
|
const cache = app.metadataCache.getCache(
|
||||||
|
state.state.file
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
cache?.frontmatter &&
|
||||||
|
cache.frontmatter[FRONTMATTER_KEY]
|
||||||
|
) {
|
||||||
|
// If we have it, force the view type to excalidraw
|
||||||
|
const newState = {
|
||||||
|
...state,
|
||||||
|
type: VIEW_TYPE_EXCEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.excelFileModes[state.state.file] =
|
||||||
|
VIEW_TYPE_EXCEL;
|
||||||
|
|
||||||
|
return next.apply(this, [newState, ...rest]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next.apply(this, [state, ...rest]);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setExcelView(leaf: WorkspaceLeaf) {
|
||||||
|
await leaf.setViewState({
|
||||||
|
type: VIEW_TYPE_EXCEL,
|
||||||
|
state: leaf.view.getState(),
|
||||||
|
popstate: true,
|
||||||
|
} as ViewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createExcel(
|
||||||
|
filename: string,
|
||||||
|
foldername?: string,
|
||||||
|
initData?: string
|
||||||
|
): Promise<TFile> {
|
||||||
|
|
||||||
|
const fname = normalizePath(filename);
|
||||||
|
const file = await this.app.vault.create(fname, initData ?? "{}");
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createAndOpenExcel(
|
||||||
|
filename: string,
|
||||||
|
foldername?: string,
|
||||||
|
initData?: string
|
||||||
|
): Promise<string> {
|
||||||
|
const file = await this.createExcel(filename, foldername, initData);
|
||||||
|
this.openExcel(file, "new-pane", true, undefined);
|
||||||
|
return file.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public openExcel(
|
||||||
|
excelFile: TFile,
|
||||||
|
location: PaneTarget,
|
||||||
|
active = false,
|
||||||
|
subpath?: string
|
||||||
|
) {
|
||||||
|
if (location === "md-properties") {
|
||||||
|
location = "new-tab";
|
||||||
|
}
|
||||||
|
var leaf: WorkspaceLeaf | null = null;
|
||||||
|
if (location === "popout-window") {
|
||||||
|
leaf = this.app.workspace.openPopoutLeaf();
|
||||||
|
}
|
||||||
|
if (location === "new-tab") {
|
||||||
|
leaf = this.app.workspace.getLeaf("tab");
|
||||||
|
}
|
||||||
|
if (!leaf) {
|
||||||
|
leaf = this.app.workspace.getLeaf(false);
|
||||||
|
if (
|
||||||
|
leaf.view.getViewType() !== "empty" &&
|
||||||
|
location === "new-pane"
|
||||||
|
) {
|
||||||
|
leaf = this.app.workspace.getMostRecentLeaf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaf?.openFile(
|
||||||
|
excelFile,
|
||||||
|
!subpath || subpath === ""
|
||||||
|
? { active, state: { type: VIEW_TYPE_EXCEL } }
|
||||||
|
: { active, eState: { subpath }, state: { type: VIEW_TYPE_EXCEL } }
|
||||||
|
).then(() => {
|
||||||
|
if (leaf) {
|
||||||
|
this.setExcelView(leaf)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public isExcelFile(f: TFile) {
|
||||||
|
if (!f) return false;
|
||||||
|
if (f.extension === "sheet") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const fileCache = f ? this.app.metadataCache.getFileCache(f) : null;
|
||||||
|
return (
|
||||||
|
!!fileCache?.frontmatter && !!fileCache.frontmatter[FRONTMATTER_KEY]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -79,8 +79,8 @@ export function getNewUniqueFilepath(
|
||||||
let fname = normalizePath(`${folderpath}/${filename}`);
|
let fname = normalizePath(`${folderpath}/${filename}`);
|
||||||
let file: TAbstractFile | null = vault.getAbstractFileByPath(fname);
|
let file: TAbstractFile | null = vault.getAbstractFileByPath(fname);
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const extension = filename.endsWith(".xlsx.md")
|
const extension = filename.endsWith(".sheet.md")
|
||||||
? ".xlsx.md"
|
? ".sheet.md"
|
||||||
: filename.slice(filename.lastIndexOf("."));
|
: filename.slice(filename.lastIndexOf("."));
|
||||||
while (file) {
|
while (file) {
|
||||||
fname = normalizePath(
|
fname = normalizePath(
|
||||||
|
|
@ -99,7 +99,7 @@ export function getExcelFilename(settings: ExcelSettings): string {
|
||||||
return (
|
return (
|
||||||
"Excel " +
|
"Excel " +
|
||||||
window.moment().format('YYYY-MM-DD HH.mm.ss') +
|
window.moment().format('YYYY-MM-DD HH.mm.ss') +
|
||||||
".sheet"
|
".sheet.md"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import ExcelPlugin from "main";
|
import ExcelPlugin from "src/main";
|
||||||
import { WorkspaceLeaf } from "obsidian";
|
import { WorkspaceLeaf } from "obsidian";
|
||||||
|
|
||||||
const getLeafLoc = (
|
const getLeafLoc = (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue