mirror of
https://github.com/ljcoder2015/obsidian-excel.git
synced 2026-07-22 08:30:28 +00:00
feat: 新建Excel
This commit is contained in:
parent
2c3dd57786
commit
176131376a
11 changed files with 534 additions and 108 deletions
|
|
@ -2,7 +2,7 @@ import esbuild from "esbuild";
|
|||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
import { lessLoader } from "esbuild-plugin-less";
|
||||
import svg from 'esbuild-plugin-svg';
|
||||
import { svgo } from "@hyrious/esbuild-plugin-svgo";
|
||||
|
||||
const banner = `/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
|
|
@ -40,7 +40,8 @@ const context = await esbuild.context({
|
|||
sourcemap: prod ? false : "inline",
|
||||
treeShaking: true,
|
||||
outfile: "main.js",
|
||||
plugins: [lessLoader(), svg()],
|
||||
plugins: [lessLoader(), svgo()],
|
||||
loader: { '.svg': 'dataurl' },
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
|
|
|
|||
2
main.css
2
main.css
File diff suppressed because one or more lines are too long
135
main.ts
135
main.ts
|
|
@ -1,46 +1,139 @@
|
|||
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, WorkspaceLeaf } from 'obsidian';
|
||||
import { TFile, Plugin, WorkspaceLeaf, normalizePath } from "obsidian";
|
||||
import { ExcelSettings, DEFAULT_SETTINGS } from "./src/utils/Settings";
|
||||
import {
|
||||
emulateCTRLClickForLinks,
|
||||
linkClickModifierType,
|
||||
PaneTarget,
|
||||
} from "./src/utils/ModifierkeyHelper";
|
||||
import { ExcelView, VIEW_TYPE_EXCEL } from "./src/ExcelView";
|
||||
import {
|
||||
checkAndCreateFolder,
|
||||
getNewUniqueFilepath,
|
||||
getExcelFilename,
|
||||
} from "./src/utils/FileUtils";
|
||||
|
||||
import { ExcelView, VIEW_TYPE_EXCEL } from './src/ExcelView';
|
||||
import { getNewOrAdjacentLeaf } from "./src/utils/ObsidianUtils";
|
||||
|
||||
declare const PLUGIN_VERSION: string;
|
||||
|
||||
export default class ExcelPlugin extends Plugin {
|
||||
public settings: ExcelSettings;
|
||||
|
||||
async onload() {
|
||||
|
||||
this.registerView(VIEW_TYPE_EXCEL, (leaf: WorkspaceLeaf) => new ExcelView(leaf, this));
|
||||
this.registerView(
|
||||
VIEW_TYPE_EXCEL,
|
||||
(leaf: WorkspaceLeaf) => new ExcelView(leaf, this)
|
||||
);
|
||||
this.registerExtensions(["xlsx"], VIEW_TYPE_EXCEL);
|
||||
|
||||
// This creates an icon in the left ribbon.
|
||||
const ribbonIconEl = this.addRibbonIcon('table', 'Excel', (evt: MouseEvent) => {
|
||||
// Called when the user clicks the icon.
|
||||
new Notice('This is a notice!');
|
||||
});
|
||||
const ribbonIconEl = this.addRibbonIcon(
|
||||
"table",
|
||||
"Excel",
|
||||
(e: MouseEvent) => {
|
||||
// Called when the user clicks the icon.
|
||||
this.createAndOpenExcel(
|
||||
getExcelFilename(this.settings)
|
||||
);
|
||||
}
|
||||
);
|
||||
// Perform additional things with the ribbon
|
||||
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
||||
ribbonIconEl.addClass("my-plugin-ribbon-class");
|
||||
|
||||
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
|
||||
const statusBarItemEl = this.addStatusBarItem();
|
||||
statusBarItemEl.setText('Status Bar Text');
|
||||
|
||||
statusBarItemEl.setText("Status Bar Text");
|
||||
|
||||
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
||||
// Using this function will automatically remove the event listener when this plugin is disabled.
|
||||
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
|
||||
console.log('click', evt);
|
||||
this.registerDomEvent(document, "click", (evt: MouseEvent) => {
|
||||
console.log("click", evt);
|
||||
});
|
||||
|
||||
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
||||
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
|
||||
this.registerInterval(
|
||||
window.setInterval(() => console.log("setInterval"), 5 * 60 * 1000)
|
||||
);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
onunload() {}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign(
|
||||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
await this.loadData()
|
||||
);
|
||||
}
|
||||
|
||||
// async loadSettings() {
|
||||
// this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
// }
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
// 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: boolean = false,
|
||||
subpath?: string
|
||||
) {
|
||||
if (location === "md-properties") {
|
||||
location = "new-tab";
|
||||
}
|
||||
var leaf: WorkspaceLeaf;
|
||||
if (location === "popout-window") {
|
||||
leaf = app.workspace.openPopoutLeaf();
|
||||
}
|
||||
if (location === "new-tab") {
|
||||
leaf = app.workspace.getLeaf("tab");
|
||||
}
|
||||
if (!leaf) {
|
||||
leaf = this.app.workspace.getLeaf(false);
|
||||
if (
|
||||
leaf.view.getViewType() !== "empty" &&
|
||||
location === "new-pane"
|
||||
) {
|
||||
leaf = app.workspace.getMostRecentLeaf();
|
||||
}
|
||||
}
|
||||
|
||||
leaf.openFile(
|
||||
excelFile,
|
||||
!subpath || subpath === ""
|
||||
? { active }
|
||||
: { active, eState: { subpath } }
|
||||
).then(() => {});
|
||||
}
|
||||
|
||||
public isExcelFile(f: TFile) {
|
||||
if (!f) return false;
|
||||
if (f.extension === "xlsx") {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
141
package-lock.json
generated
141
package-lock.json
generated
|
|
@ -158,6 +158,15 @@
|
|||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@hyrious/esbuild-plugin-svgo": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@hyrious/esbuild-plugin-svgo/-/esbuild-plugin-svgo-0.2.0.tgz",
|
||||
"integrity": "sha512-wg7OTGS/eOsV/+EXsFnnfyhdjGMsLtMlgbB0fdV8fM/5BZQ0VwJ561+IwzX9xEcTrFe8UBIUAH4xb4Xf+0j+dg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"svgo": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
|
@ -446,26 +455,26 @@
|
|||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
|
||||
},
|
||||
"css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
|
||||
"integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.0.1",
|
||||
"domhandler": "^4.3.1",
|
||||
"domutils": "^2.8.0",
|
||||
"css-what": "^6.1.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"domutils": "^3.0.1",
|
||||
"nth-check": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
|
||||
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
"mdn-data": "2.0.30",
|
||||
"source-map-js": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
|
|
@ -475,12 +484,30 @@
|
|||
"dev": true
|
||||
},
|
||||
"csso": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
|
||||
"integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
|
||||
"integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css-tree": "^1.1.2"
|
||||
"css-tree": "~2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"css-tree": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
|
||||
"integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mdn-data": "2.0.28",
|
||||
"source-map-js": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"mdn-data": {
|
||||
"version": "2.0.28",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
|
||||
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
|
|
@ -502,14 +529,14 @@
|
|||
}
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"domelementtype": {
|
||||
|
|
@ -519,23 +546,23 @@
|
|||
"dev": true
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "^2.2.0"
|
||||
"domelementtype": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
}
|
||||
},
|
||||
"encoding": {
|
||||
|
|
@ -557,9 +584,9 @@
|
|||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"dev": true
|
||||
},
|
||||
"errno": {
|
||||
|
|
@ -612,15 +639,6 @@
|
|||
"less": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"esbuild-plugin-svg": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-svg/-/esbuild-plugin-svg-0.1.0.tgz",
|
||||
"integrity": "sha512-/9ZhvIpl+Ovl6glVK3BedvIwrOwSQnECw4Fy6ZwysWib3Ns7UkX6WNGjMOWtvQ1Cnm0uc7sptiKGm0BthKCAJA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"svgo": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
|
|
@ -853,11 +871,6 @@
|
|||
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
|
||||
"dev": true
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
|
||||
"integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ=="
|
||||
},
|
||||
"less": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz",
|
||||
|
|
@ -911,9 +924,9 @@
|
|||
}
|
||||
},
|
||||
"mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||
"version": "2.0.30",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
|
||||
"dev": true
|
||||
},
|
||||
"merge2": {
|
||||
|
|
@ -1211,12 +1224,13 @@
|
|||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"stable": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
|
||||
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
|
||||
"source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
|
|
@ -1257,18 +1271,17 @@
|
|||
"integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="
|
||||
},
|
||||
"svgo": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
|
||||
"integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz",
|
||||
"integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@trysound/sax": "0.2.0",
|
||||
"commander": "^7.2.0",
|
||||
"css-select": "^4.1.3",
|
||||
"css-tree": "^1.1.3",
|
||||
"csso": "^4.2.0",
|
||||
"picocolors": "^1.0.0",
|
||||
"stable": "^0.1.8"
|
||||
"css-select": "^5.1.0",
|
||||
"css-tree": "^2.2.1",
|
||||
"csso": "^5.0.5",
|
||||
"picocolors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"through": {
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@hyrious/esbuild-plugin-svgo": "^0.2.0",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.17.3",
|
||||
"esbuild-plugin-less": "^1.2.4",
|
||||
"esbuild-plugin-svg": "^0.1.0",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
|
|
|
|||
|
|
@ -30,22 +30,22 @@ export class ExcelView extends TextFileView {
|
|||
},
|
||||
});
|
||||
|
||||
console.log(this.ownerWindow.document.documentElement.clientWidth);
|
||||
const jsonData = JSON.parse(this.data || "{}") || {}
|
||||
const jsonData = JSON.parse(this.data || "{}") || {};
|
||||
|
||||
//@ts-ignore
|
||||
this.sheet = new Spreadsheet("#x-spreadsheet", {
|
||||
view: {
|
||||
height: () => this.contentEl.clientHeight,
|
||||
width: () => this.contentEl.clientWidth,
|
||||
},
|
||||
},
|
||||
})
|
||||
.loadData(jsonData) // load data
|
||||
.change(data => {
|
||||
// save data to db
|
||||
this.data = JSON.stringify(data);
|
||||
});
|
||||
.loadData(jsonData) // load data
|
||||
.change((data) => {
|
||||
// save data to db
|
||||
this.data = JSON.stringify(data);
|
||||
});
|
||||
|
||||
this.sheet.validate()
|
||||
this.sheet.validate();
|
||||
}
|
||||
|
||||
onload(): void {
|
||||
|
|
|
|||
124
src/utils/FileUtils.ts
Normal file
124
src/utils/FileUtils.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
import { normalizePath, Notice, TAbstractFile, TFile, TFolder, Vault } from "obsidian";
|
||||
import { ExcelSettings } from "./Settings";
|
||||
|
||||
/**
|
||||
* Splits a full path including a folderpath and a filename into separate folderpath and filename components
|
||||
* @param filepath
|
||||
*/
|
||||
|
||||
export function splitFolderAndFilename(filepath: string): {
|
||||
folderpath: string;
|
||||
filename: string;
|
||||
basename: string;
|
||||
} {
|
||||
const lastIndex = filepath.lastIndexOf("/");
|
||||
const filename = lastIndex == -1 ? filepath : filepath.substring(lastIndex + 1);
|
||||
return {
|
||||
folderpath: normalizePath(filepath.substring(0, lastIndex)),
|
||||
filename,
|
||||
basename: filename.replace(/\.[^/.]+$/, ""),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Download data as file from Obsidian, to store on local device
|
||||
* @param encoding
|
||||
* @param data
|
||||
* @param filename
|
||||
*/
|
||||
export const download = (encoding: string, data: any, filename: string) => {
|
||||
const element = document.createElement("a");
|
||||
element.setAttribute("href", (encoding ? `${encoding},` : "") + data);
|
||||
element.setAttribute("download", filename);
|
||||
element.style.display = "none";
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the image filename based on the excalidraw filename
|
||||
* @param excalidrawPath - Full filepath of ExclidrawFile
|
||||
* @param newExtension - extension of IMG file in ".extension" format
|
||||
* @returns
|
||||
*/
|
||||
/*export function getIMGPathFromExcalidrawFile(
|
||||
excalidrawPath: string,
|
||||
newExtension: string,
|
||||
): string {
|
||||
const isLegacyFile: boolean = excalidrawPath.endsWith(".excalidraw");
|
||||
const replaceExtension: string = isLegacyFile ? ".excalidraw" : ".md";
|
||||
return (
|
||||
excalidrawPath.substring(0, excalidrawPath.lastIndexOf(replaceExtension)) +
|
||||
newExtension
|
||||
);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Generates the image filename based on the excalidraw filename
|
||||
* @param path - path to the excalidraw file
|
||||
* @param extension - extension without the preceeding "."
|
||||
* @returns
|
||||
*/
|
||||
export function getIMGFilename(path: string, extension: string): string {
|
||||
return `${path.substring(0, path.lastIndexOf("."))}.${extension}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new file, if file already exists find first unique filename by adding a number to the end of the filename
|
||||
* @param filename
|
||||
* @param folderpath
|
||||
* @returns
|
||||
*/
|
||||
export function getNewUniqueFilepath(
|
||||
vault: Vault,
|
||||
filename: string,
|
||||
folderpath: string,
|
||||
): string {
|
||||
let fname = normalizePath(`${folderpath}/${filename}`);
|
||||
let file: TAbstractFile = vault.getAbstractFileByPath(fname);
|
||||
let i = 0;
|
||||
const extension = filename.endsWith(".xlsx.md")
|
||||
? ".xlsx.md"
|
||||
: filename.slice(filename.lastIndexOf("."));
|
||||
while (file) {
|
||||
fname = normalizePath(
|
||||
`${folderpath}/${filename.slice(
|
||||
0,
|
||||
filename.lastIndexOf(extension),
|
||||
)}_${i}${extension}`,
|
||||
);
|
||||
i++;
|
||||
file = vault.getAbstractFileByPath(fname);
|
||||
}
|
||||
return fname;
|
||||
}
|
||||
|
||||
export function getExcelFilename(settings: ExcelSettings): string {
|
||||
return (
|
||||
"Excel " +
|
||||
window.moment().format('YYYY-MM-DD HH.mm.ss') +
|
||||
".xlsx"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open or create a folderpath if it does not exist
|
||||
* @param folderpath
|
||||
*/
|
||||
export async function checkAndCreateFolder(folderpath: string) {
|
||||
const vault = app.vault;
|
||||
folderpath = normalizePath(folderpath);
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/658
|
||||
//@ts-ignore
|
||||
const folder = vault.getAbstractFileByPathInsensitive(folderpath);
|
||||
if (folder && folder instanceof TFolder) {
|
||||
return;
|
||||
}
|
||||
if (folder && folder instanceof TFile) {
|
||||
new Notice(`The folder cannot be created because it already exists as a file: ${folderpath}.`)
|
||||
}
|
||||
await vault.createFolder(folderpath);
|
||||
}
|
||||
53
src/utils/ModifierkeyHelper.ts
Normal file
53
src/utils/ModifierkeyHelper.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
export type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";
|
||||
export type ModifierKeys = {shiftKey:boolean, ctrlKey: boolean, metaKey: boolean, altKey: boolean};
|
||||
export type KeyEvent = PointerEvent | MouseEvent | KeyboardEvent | ModifierKeys;
|
||||
|
||||
export type DeviceType = {
|
||||
isDesktop: boolean,
|
||||
isPhone: boolean,
|
||||
isTablet: boolean,
|
||||
isMobile: boolean,
|
||||
isLinux: boolean,
|
||||
isMacOS: boolean,
|
||||
isWindows: boolean,
|
||||
isIOS: boolean,
|
||||
isAndroid: boolean
|
||||
};
|
||||
|
||||
export const DEVICE: DeviceType = {
|
||||
isDesktop: !document.body.hasClass("is-tablet") && !document.body.hasClass("is-mobile"),
|
||||
isPhone: document.body.hasClass("is-phone"),
|
||||
isTablet: document.body.hasClass("is-tablet"),
|
||||
isMobile: document.body.hasClass("is-mobile"), //running Obsidian Mobile, need to also check isTablet
|
||||
isLinux: document.body.hasClass("mod-linux") && ! document.body.hasClass("is-android"),
|
||||
isMacOS: document.body.hasClass("mod-macos") && ! document.body.hasClass("is-ios"),
|
||||
isWindows: document.body.hasClass("mod-windows"),
|
||||
isIOS: document.body.hasClass("is-ios"),
|
||||
isAndroid: document.body.hasClass("is-android")
|
||||
};
|
||||
|
||||
export const isCTRL = (e:KeyEvent) => DEVICE.isIOS || DEVICE.isMacOS ? e.metaKey : e.ctrlKey;
|
||||
export const isALT = (e:KeyEvent) => e.altKey;
|
||||
export const isMETA = (e:KeyEvent) => DEVICE.isIOS || DEVICE.isMacOS ? e.ctrlKey : e.metaKey;
|
||||
export const isSHIFT = (e:KeyEvent) => e.shiftKey;
|
||||
export const mdPropModifier = (ev: KeyEvent): boolean => !isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && isMETA(ev);
|
||||
|
||||
export const emulateCTRLClickForLinks = (e: KeyEvent) => {
|
||||
return {
|
||||
shiftKey: e.shiftKey,
|
||||
ctrlKey: e.ctrlKey || !(DEVICE.isIOS || DEVICE.isMacOS),
|
||||
metaKey: e.metaKey || (DEVICE.isIOS || DEVICE.isMacOS),
|
||||
altKey: e.altKey
|
||||
}
|
||||
}
|
||||
|
||||
export const linkClickModifierType = (ev: KeyEvent):PaneTarget => {
|
||||
if(isCTRL(ev) && !isALT(ev) && isSHIFT(ev) && !isMETA(ev)) return "active-pane";
|
||||
if(isCTRL(ev) && !isALT(ev) && !isSHIFT(ev) && !isMETA(ev)) return "new-tab";
|
||||
if(isCTRL(ev) && isALT(ev) && !isSHIFT(ev) && !isMETA(ev)) return "new-pane";
|
||||
if(DEVICE.isDesktop && isCTRL(ev) && isALT(ev) && isSHIFT(ev) && !isMETA(ev) ) return "popout-window";
|
||||
if(isCTRL(ev) && isALT(ev) && isSHIFT(ev) && !isMETA(ev)) return "new-tab";
|
||||
if(mdPropModifier(ev)) return "md-properties";
|
||||
return "active-pane";
|
||||
}
|
||||
126
src/utils/ObsidianUtils.ts
Normal file
126
src/utils/ObsidianUtils.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
import ExcelPlugin from "main";
|
||||
import { WorkspaceLeaf } from "obsidian";
|
||||
|
||||
const getLeafLoc = (
|
||||
leaf: WorkspaceLeaf
|
||||
): ["main" | "popout" | "left" | "right" | "hover", any] => {
|
||||
//@ts-ignore
|
||||
const leafId = leaf.id;
|
||||
const layout = app.workspace.getLayout();
|
||||
const getLeaves = (l: any) =>
|
||||
l.children
|
||||
.filter((c: any) => c.type !== "leaf")
|
||||
.map((c: any) => getLeaves(c))
|
||||
.flat()
|
||||
.concat(
|
||||
l.children
|
||||
.filter((c: any) => c.type === "leaf")
|
||||
.map((c: any) => c.id)
|
||||
);
|
||||
|
||||
const mainLeavesIds = getLeaves(layout.main);
|
||||
|
||||
return [
|
||||
layout.main && mainLeavesIds.contains(leafId)
|
||||
? "main"
|
||||
: layout.floating && getLeaves(layout.floating).contains(leafId)
|
||||
? "popout"
|
||||
: layout.left && getLeaves(layout.left).contains(leafId)
|
||||
? "left"
|
||||
: layout.right && getLeaves(layout.right).contains(leafId)
|
||||
? "right"
|
||||
: "hover",
|
||||
mainLeavesIds,
|
||||
];
|
||||
};
|
||||
|
||||
/*
|
||||
| Setting | Originating Leaf |
|
||||
| | Main Workspace | Hover Editor | Popout Window |
|
||||
| ----------------------- | -------------------------------- | -------------------------------------- | -------------------------------- |
|
||||
| InMain && InAdjacent | 1.1 Reuse Leaf in Main Workspace | 1.1 Reuse Leaf in Main Workspace | 1.1 Reuse Leaf in Main Workspace |
|
||||
| InMain && !InAdjacent | 1.2 New Leaf in Main Workspace | 1.2 New Leaf in Main Workspace | 1.2 New Leaf in Main Workspace |
|
||||
| !InMain && InAdjacent | 1.1 Reuse Leaf in Main Workspace | 3 Reuse Leaf in Current Hover Editor | 4 Reuse Leaf in Current Popout |
|
||||
| !InMain && !InAdjacent | 1.2 New Leaf in Main Workspace | 2 New Leaf in Current Hover Editor | 2 New Leaf in Current Popout |
|
||||
*/
|
||||
export const getNewOrAdjacentLeaf = (
|
||||
plugin: ExcelPlugin,
|
||||
leaf: WorkspaceLeaf
|
||||
): WorkspaceLeaf | null => {
|
||||
const [leafLoc, mainLeavesIds] = getLeafLoc(leaf);
|
||||
|
||||
const getMostRecentOrAvailableLeafInMainWorkspace = (
|
||||
inDifferentTabGroup?: boolean
|
||||
): WorkspaceLeaf => {
|
||||
let mainLeaf = app.workspace.getMostRecentLeaf();
|
||||
if (
|
||||
mainLeaf &&
|
||||
mainLeaf !== leaf &&
|
||||
mainLeaf.view?.containerEl.ownerDocument === document
|
||||
) {
|
||||
//Found a leaf in the main workspace that is not the originating leaf
|
||||
return mainLeaf;
|
||||
}
|
||||
//Iterate all leaves in the main workspace and find the first one that is not the originating leaf
|
||||
mainLeaf = null;
|
||||
mainLeavesIds.forEach((id: any) => {
|
||||
const l = app.workspace.getLeafById(id);
|
||||
if (
|
||||
mainLeaf ||
|
||||
!l.view?.navigation ||
|
||||
leaf === l ||
|
||||
//@ts-ignore
|
||||
(inDifferentTabGroup && l?.parent === leaf?.parent)
|
||||
)
|
||||
return;
|
||||
mainLeaf = l;
|
||||
});
|
||||
return mainLeaf;
|
||||
};
|
||||
|
||||
//1 - In Main Workspace
|
||||
if (["main", "left", "right"].contains(leafLoc)
|
||||
) {
|
||||
//1.2 - Reuse leaf if it is adjacent
|
||||
const ml = getMostRecentOrAvailableLeafInMainWorkspace(true);
|
||||
return ml ?? app.workspace.createLeafBySplit(leaf); //app.workspace.getLeaf(true);
|
||||
}
|
||||
|
||||
//3
|
||||
if (leafLoc === "hover") {
|
||||
const leaves = new Set<WorkspaceLeaf>();
|
||||
app.workspace.iterateAllLeaves((l) => {
|
||||
//@ts-ignore
|
||||
if (
|
||||
l !== leaf &&
|
||||
leaf.containerEl.parentElement === l.containerEl.parentElement
|
||||
)
|
||||
leaves.add(l);
|
||||
});
|
||||
if (leaves.size === 0) {
|
||||
return plugin.app.workspace.createLeafBySplit(leaf);
|
||||
}
|
||||
return Array.from(leaves)[0];
|
||||
}
|
||||
|
||||
//4
|
||||
if (leafLoc === "popout") {
|
||||
const popoutLeaves = new Set<WorkspaceLeaf>();
|
||||
app.workspace.iterateAllLeaves((l) => {
|
||||
if (
|
||||
l !== leaf &&
|
||||
l.view.navigation &&
|
||||
l.view.containerEl.ownerDocument ===
|
||||
leaf.view.containerEl.ownerDocument
|
||||
) {
|
||||
popoutLeaves.add(l);
|
||||
}
|
||||
});
|
||||
if (popoutLeaves.size === 0) {
|
||||
return app.workspace.createLeafBySplit(leaf);
|
||||
}
|
||||
return Array.from(popoutLeaves)[0];
|
||||
}
|
||||
|
||||
return plugin.app.workspace.createLeafBySplit(leaf);
|
||||
};
|
||||
15
src/utils/Settings.ts
Normal file
15
src/utils/Settings.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export interface ExcelSettings {
|
||||
folder: string;
|
||||
excelFilenamePrefix: String,
|
||||
excelEmbedPrefixWithFilename: true,
|
||||
excelFilnameEmbedPostfix: String,
|
||||
excelFilenameDateTime: String,
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: ExcelSettings = {
|
||||
folder: "Excel",
|
||||
excelFilenamePrefix: "Excel ",
|
||||
excelEmbedPrefixWithFilename: true,
|
||||
excelFilnameEmbedPostfix: " ",
|
||||
excelFilenameDateTime: "YYYY-MM-DD HH.mm.ss",
|
||||
};
|
||||
21
styles.css
21
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue