perf: 优化代码

This commit is contained in:
appleex 2024-10-13 09:55:12 +08:00
parent eb9d617e21
commit 23fcd59035
16 changed files with 621 additions and 471 deletions

1
.gitignore vendored
View file

@ -12,6 +12,7 @@ package-lock.json
# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js
dist
# Exclude sourcemaps
*.map

View file

@ -1,6 +1,6 @@
# Obsidian Sample Plugin
# Obsidian Upload Plugin
This is a sample plugin for Obsidian (https://obsidian.md).
This is a Upload plugin for Obsidian (https://obsidian.md).
This project uses TypeScript to provide type checking and documentation.
The repo depends on the latest plugin API (obsidian.d.ts) in TypeScript Definition format, which contains TSDoc comments describing what it does.
@ -94,3 +94,8 @@ If you have multiple URLs, you can also do:
## API Documentation
See https://github.com/obsidianmd/obsidian-api
## References
- [obsidian-image-upload-toolkit](https://github.com/addozhang/obsidian-image-upload-toolkit)
-

View file

@ -1,6 +1,7 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import copyStaticFiles from "esbuild-copy-static-files";
const banner =
`/*
@ -15,7 +16,7 @@ const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["main.ts"],
entryPoints: ["./src/main.ts"],
bundle: true,
external: [
"obsidian",
@ -33,12 +34,25 @@ const context = await esbuild.context({
"@lezer/lr",
...builtins],
format: "cjs",
// watch: !prod,
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
// outdir: './dist',
// outfile: "main.js",
outfile: prod ? './dist/main.js' : './main.js',
minify: prod,
plugins: [
prod && copyStaticFiles({
src: './manifest.json',
dest: './dist/manifest.json'
}),
prod && copyStaticFiles({
src: './styles.css',
dest: './dist/styles.css'
})
]
});
if (prod) {

460
main.ts
View file

@ -1,460 +0,0 @@
import {
App,
Editor,
MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting,
Menu,
MenuItem,
TFile,
FileSystemAdapter,
addIcon,
} from 'obsidian';
import { readFile } from "fs";
import axios from "axios";
import objectPath from 'object-path';
import { resolve, relative, join, parse, posix, basename, dirname } from "path";
import Helper from "./helper";
import { isAssetTypeAnImage, bufferToArrayBuffer } from "./utils";
// Remember to rename these classes and interfaces!
interface MyPluginSettings {
mySetting: string;
uploader: string;
mode: string;
apiURL: string;
apiReqHeader: string;
apiReqBody: string;
imgUrlPath: string;
imgUrlPrefix: string;
lskySetting: ILskySettings;
}
interface ILskySettings {
endpoint: string;
reqHeader: string;
reqBody: string;
imgUrlPath: string;
imgUrlPrefix: string;
}
interface IImage {
path: string;
name: string;
source: string;
}
// 默认设置
const DEFAULT_SETTINGS: MyPluginSettings = {
mySetting: 'default',
uploader: 'lsky',
mode: 'lsky',
apiURL: '',
apiReqHeader: '',
apiReqBody: "{\"image\": \"$FILE\"}",
imgUrlPath: '',
imgUrlPrefix: '',
lskySetting: {
endpoint: '',
reqHeader: '',
reqBody: '',
imgUrlPath: '',
imgUrlPrefix: '',
},
}
export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
// 自定义
helper: Helper;
editor: Editor;
async onload() {
await this.loadSettings();
// T
this.helper = new Helper(this.app);
// This creates an icon in the left ribbon.
const ribbonIconEl = this.addRibbonIcon('dice', 'Upload Plugin', (evt: MouseEvent) => {
// Called when the user clicks the icon.
new Notice('This is a notice!');
});
// Perform additional things with the ribbon
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');
// This adds a simple command that can be triggered anywhere
this.addCommand({
id: 'open-sample-modal-simple',
name: 'Open sample modal (simple)',
callback: () => {
new SampleModal(this.app).open();
}
});
// This adds an editor command that can perform some operation on the current editor instance
this.addCommand({
id: 'sample-editor-command',
name: 'Sample editor command',
editorCallback: (editor: Editor, view: MarkdownView) => {
console.log(editor.getSelection());
editor.replaceSelection('Sample Editor Command');
}
});
// This adds a complex command that can check whether the current state of the app allows execution of the command
this.addCommand({
id: 'open-sample-modal-complex',
name: 'Open sample modal (complex)',
checkCallback: (checking: boolean) => {
// Conditions to check
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (markdownView) {
// If checking is true, we're simply "checking" if the command can be run.
// If checking is false, then we want to actually perform the operation.
if (!checking) {
new SampleModal(this.app).open();
}
// This command will only show up in Command Palette when the check function returns true
return true;
}
}
});
// 注册事件,添加右键菜单项
this.registerFileMenu();
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SampleSettingTab(this.app, this));
// 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);
});
// 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));
}
onunload() {
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
// 自定义方法
// 上传操作
async uploadFile(image: File): Promise<string> {
return new Promise((resolve, reject) => {
const formData = new FormData();
const uploadBody = JSON.parse(this.settings.apiReqBody);
for (const key in uploadBody) {
if (uploadBody[key] == "$FILE") {
formData.append(key, image, image.name)
}
else {
formData.append(key, uploadBody[key])
}
}
axios.post(this.settings.apiURL, formData, {
"headers": JSON.parse(this.settings.apiReqHeader)
}).then(res => {
const url = [this.settings.imgUrlPrefix, objectPath.get(res.data, this.settings.imgUrlPath)].join('')
resolve(url)
}, err => {
reject(err)
})
})
}
async uploadMenuFile(file: TFile) {
let content = this.helper.getValue();
const basePath = (
this.app.vault.adapter as FileSystemAdapter
).getBasePath();
let imageList: IImage[] = [];
const fileArray = this.helper.getAllFiles();
for (const match of fileArray) {
const imageName = match.name;
const encodedUri = match.path;
const fileName = basename(decodeURI(encodedUri));
if (file && file.name === fileName) {
const abstractImageFile = join(basePath, file.path);
if (isAssetTypeAnImage(abstractImageFile)) {
imageList.push({
path: abstractImageFile,
name: imageName,
source: match.source,
});
}
}
}
if (imageList.length === 0) {
new Notice("没有找到文件");
return;
}
const fileList = imageList.map(item => item.path);
const files = [];
for (let i = 0; i < fileList.length; i++) {
const file = fileList[i];
const buffer: Buffer = await new Promise((resolve, reject) => {
readFile(file, (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
});
const arrayBuffer = bufferToArrayBuffer(buffer);
files.push(new File([arrayBuffer], file));
}
if (files.length === 0) {
new Notice("没有找到文件");
return;
}
// 上传
this.uploadFile(files[0])
.then(res => {
imageList.map(item => {
content = content.replaceAll(
item.source,
`![](${res})`
);
});
this.helper.setValue(content);
new Notice("上传成功");
})
.catch(err => {
new Notice(`上传失败: ${err}`);
});
}
// 添加右键菜单项
registerFileMenu() {
this.registerEvent(
this.app.workspace.on(
"file-menu",
(menu: Menu, file: TFile, source: string, leaf) => {
if (source === "canvas-menu") return false;
if (!isAssetTypeAnImage(file.path)) return false;
menu.addItem((item: MenuItem) => {
item
.setTitle("上传文件")
.setIcon("upload")
.onClick(() => {
if (!(file instanceof TFile)) {
return false;
}
new Notice('准备上传');
this.uploadMenuFile(file);
});
});
}
)
);
}
}
class SampleModal extends Modal {
constructor(app: App) {
super(app);
}
onOpen() {
const {contentEl} = this;
contentEl.setText('Woah!');
}
onClose() {
const {contentEl} = this;
contentEl.empty();
}
}
class SampleSettingTab extends PluginSettingTab {
plugin: MyPlugin;
constructor(app: App, plugin: MyPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
let defaultDiv: HTMLDivElement, modeDiv: HTMLDivElement, otherDiv: HTMLDivElement;
/*大标题*/
containerEl.createEl("h1", {text: "上传设置"});
/*默认配置*/
defaultDiv = containerEl.createDiv();
// 模式
new Setting(defaultDiv)
.setName('模式')
.setDesc('选择一种模式')
.addDropdown(e => {
e.addOption("lsky", "Lsky")
e.addOption("halo", "Halo")
e.setValue(this.plugin.settings.mode)
e.onChange(async value => {
this.plugin.settings.mode = value;
// await this.plugin.saveSettings();
await this.selectModeSettings(value, modeDiv);
})
})
/*模式配置*/
modeDiv = containerEl.createDiv()
this.plugin.settings.mode === 'lsky' && this.selectModeSettings(this.plugin.settings.mode, modeDiv);
/*其它配置*/
}
// 自定义方法
// 切换模式,不同的模式对应不同的配置
private async selectModeSettings(value: any, parentEl: HTMLDivElement) {
parentEl && parentEl.empty();
switch (value) {
case 'lsky':
this.drawLskySettings(parentEl);
break;
default:
break;
}
}
// Lskypro 设置
private drawLskySettings(parentEL: HTMLDivElement) {
// Api URL
new Setting(parentEL)
.setName("API 地址")
.setDesc("请求地址")
.addText(text => {
text
.setPlaceholder("")
.setValue(this.plugin.settings.apiURL)
.onChange(async (value) => {
try {
this.plugin.settings.apiURL = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
})
// Api request header
new Setting(parentEL)
.setName("POST Header")
.setDesc("请求头json 格式")
.addTextArea((text) => {
text.setPlaceholder("输入合法的请求头")
.setValue(this.plugin.settings.apiReqHeader)
.onChange(async (value) => {
try {
this.plugin.settings.apiReqHeader = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
text.inputEl.rows = 5
text.inputEl.cols = 40
})
// Api request body
new Setting(parentEL)
.setName("POST Body")
.setDesc("请求体json 格式")
.addTextArea((text) => {
text.setPlaceholder("输入合法的请求体")
.setValue(this.plugin.settings.apiReqBody)
.onChange(async (value) => {
try {
this.plugin.settings.apiReqBody = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
text.inputEl.rows = 5
text.inputEl.cols = 40
})
new Setting(parentEL)
.setName("图片 URL 路径")
.setDesc("返回json数据中的图片URL字段的路径data/pathname")
.addText(text => {
text
.setPlaceholder("")
.setValue(this.plugin.settings.imgUrlPath)
.onChange(async (value) => {
try {
this.plugin.settings.imgUrlPath = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
})
new Setting(parentEL)
.setName("图片 URL 前缀")
.setDesc("可选当填入时URL = 前缀 + 图片的路径值")
.addText(text => {
text
.setPlaceholder("")
.setValue(this.plugin.settings.imgUrlPrefix)
.onChange(async (value) => {
try {
this.plugin.settings.imgUrlPrefix = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
})
}
}

View file

@ -4,8 +4,8 @@
"version": "0.1.0",
"minAppVersion": "0.15.0",
"description": "Demonstrates some of the capabilities of the Obsidian API.",
"author": "Appleex",
"authorUrl": "https://obsidian.md",
"fundingUrl": "https://obsidian.md/pricing",
"author": "appleex",
"authorUrl": "https://github.com/Appleec/e-obsidian-upload-plugin",
"fundingUrl": "https://github.com/Appleec/e-obsidian-upload-plugin",
"isDesktopOnly": false
}

View file

@ -18,6 +18,7 @@
"@typescript-eslint/parser": "5.29.0",
"builtin-modules": "3.3.0",
"esbuild": "0.17.3",
"esbuild-copy-static-files": "^0.1.0",
"obsidian": "latest",
"tslib": "2.4.0",
"typescript": "4.7.4"

24
src/config.ts Normal file
View file

@ -0,0 +1,24 @@
const config = {
modes: [
{
text: 'Lskypro',
value: 'lsky',
},
{
text: 'Github',
value: 'github',
},
],
reqHeader: {
"Authorization": "Bearer Jq7mTKdjN7BxMjLoG8Jj8eaGGV2GuurwumOGFCBm",
"Accept": "application/json",
"Content-Type": "multipart/form-data"
},
reqBody: {
"file": "$FILE",
"strategy_id": 2
}
}
export const { modes } = config;
export default config;

45
src/lskyUpload.ts Normal file
View file

@ -0,0 +1,45 @@
// Defaults
import { IUploadPluginSettings } from "./type";
import axios from "axios";
import objectPath from "object-path";
class LskyUpload {
private readonly settings: IUploadPluginSettings;
constructor(settings: IUploadPluginSettings) {
this.settings = settings;
}
async upload(file: File, fullPath?: string): Promise<string> {
return new Promise((resolve, reject) => {
const formData = new FormData();
const uploadBody = JSON.parse(this.settings.lskySetting.apiReqBody);
for (const key in uploadBody) {
if (uploadBody[key] == "$FILE") {
formData.append(key, file, file.name)
}
else {
formData.append(key, uploadBody[key])
}
}
axios.post(this.settings.lskySetting.apiURL, formData, {
"headers": JSON.parse(this.settings.lskySetting.apiReqHeader)
}).then(res => {
const url = [this.settings.lskySetting.imgUrlPrefix, objectPath.get(res.data, this.settings.lskySetting.imgUrlPath)].join('')
resolve(url)
}, err => {
reject(err)
})
})
}
//
drawSettingsTab(parentEL: HTMLDivElement) {
}
}
export default LskyUpload;

253
src/main.ts Normal file
View file

@ -0,0 +1,253 @@
import {
App,
Editor,
MarkdownView,
Notice,
Plugin,
Menu,
MenuItem,
TFile,
FileSystemAdapter,
addIcon,
} from 'obsidian';
import { readFile } from 'fs';
import { join, basename } from 'path';
// Utils
import Helper from "./utils/helper";
import { isAssetTypeAnImage, bufferToArrayBuffer } from "./utils/utils";
import uploader from "./uploader";
// Class
import UploadSettingTab from './settings-tab';
import UploadModal from './modal';
// Types
import { IUploadPluginSettings, IImage, IUploader } from './type';
// Remember to rename these classes and interfaces!
// 默认选项
const DEFAULT_SETTINGS: IUploadPluginSettings = {
mode: 'lsky',
apiURL: '',
apiReqHeader: '',
apiReqBody: "{\"file\": \"$FILE\"}",
imgUrlPath: '',
imgUrlPrefix: '',
lskySetting: {
apiURL: "",
apiReqHeader: "",
apiReqBody: "{\"file\": \"$FILE\"}",
imgUrlPath: "",
imgUrlPrefix: "",
}
}
class UploadPlugin extends Plugin {
settings: IUploadPluginSettings;
// 自定义
helper: Helper;
editor: Editor;
// Uploader
uploader: IUploader;
async onload() {
// 加载设置
await this.loadSettings();
// 赋值
this.helper = new Helper(this.app);
this.uploader = uploader(this.settings);
// This creates an icon in the left ribbon.
const ribbonIconEl = this.addRibbonIcon('dice', 'Upload Plugin', (evt: MouseEvent) => {
// Called when the user clicks the icon.
new Notice('This is a notice!');
});
// Perform additional things with the ribbon
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');
// This adds a simple command that can be triggered anywhere
this.addCommand({
id: 'open-sample-modal-simple',
name: 'Open sample modal (simple)',
callback: () => {
new UploadModal(this.app).open();
}
});
// This adds an editor command that can perform some operation on the current editor instance
this.addCommand({
id: 'sample-editor-command',
name: 'Sample editor command',
editorCallback: (editor: Editor, view: MarkdownView) => {
console.log(editor.getSelection());
editor.replaceSelection('Sample Editor Command');
}
});
// This adds a complex command that can check whether the current state of the app allows execution of the command
this.addCommand({
id: 'open-sample-modal-complex',
name: 'Open sample modal (complex)',
checkCallback: (checking: boolean) => {
// Conditions to check
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (markdownView) {
// If checking is true, we're simply "checking" if the command can be run.
// If checking is false, then we want to actually perform the operation.
if (!checking) {
new UploadModal(this.app).open();
}
// This command will only show up in Command Palette when the check function returns true
return true;
}
}
});
// 注册事件,添加右键菜单项
this.registerMenuEvent();
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new UploadSettingTab(this.app, this));
// 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);
});
// 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));
}
onunload() {}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
// 自定义方法
// 右键菜单上传文件
async menuUploadFile(file: TFile) {
new Notice('准备上传');
let content = this.helper.getValue();
const basePath = (
this.app.vault.adapter as FileSystemAdapter
).getBasePath();
let imageList: IImage[] = [];
const fileArray = this.helper.getAllFiles();
for (const match of fileArray) {
const imageName = match.name;
const encodedUri = match.path;
const fileName = basename(decodeURI(encodedUri));
if (file && file.name === fileName) {
const abstractImageFile = join(basePath, file.path);
if (isAssetTypeAnImage(abstractImageFile)) {
imageList.push({
path: abstractImageFile,
name: imageName,
source: match.source,
});
}
}
}
if (imageList.length === 0) {
new Notice("没有找到文件");
return;
}
const fileList = imageList.map(item => item.path);
const files = [];
for (let i = 0; i < fileList.length; i++) {
const file = fileList[i];
const buffer: Buffer = await new Promise((resolve, reject) => {
readFile(file, (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
});
const arrayBuffer = bufferToArrayBuffer(buffer);
files.push(new File([arrayBuffer], file));
}
if (files.length === 0) {
new Notice("没有找到文件");
return;
}
if (!this.uploader) {
new Notice("上传配置加载失败,请检查设置");
return;
}
// 上传
this.uploader.upload(files[0])
.then(res => {
imageList.map(item => {
content = content.replaceAll(
item.source,
`![](${res})`
);
});
this.helper.setValue(content);
new Notice("上传成功");
})
.catch(err => {
new Notice(`上传失败: ${err}`);
});
}
// 注册右键菜单事件
registerMenuEvent() {
this.registerEvent(
this.app.workspace.on(
"file-menu",
(menu: Menu, file: TFile, source: string, leaf) => {
if (source === "canvas-menu") return false;
if (!isAssetTypeAnImage(file.path)) return false;
menu.addItem((item: MenuItem) => {
item
.setTitle("上传文件")
.setIcon("upload")
.onClick(() => {
if (!(file instanceof TFile)) {
return false;
}
this.menuUploadFile(file);
});
});
}
)
);
}
}
export default UploadPlugin;

23
src/modal.ts Normal file
View file

@ -0,0 +1,23 @@
import {
App,
Modal,
Notice,
} from 'obsidian';
class UploadModal extends Modal {
constructor(app: App) {
super(app);
}
onOpen() {
const {contentEl} = this;
contentEl.setText('Woah!');
}
onClose() {
const {contentEl} = this;
contentEl.empty();
}
}
export default UploadModal;

193
src/settings-tab.ts Normal file
View file

@ -0,0 +1,193 @@
// Default
import {
App,
PluginSettingTab,
Setting,
} from 'obsidian';
// Class
import UploadPlugin from './main';
// Utils
import { modes } from './config';
// Settings Tab
class UploadSettingsTab extends PluginSettingTab {
plugin: UploadPlugin;
// 定义三种 DIV 容器
defaultDiv: HTMLDivElement; // 默认容器,存放公共配置
modeDiv: HTMLDivElement; // 模式容器,存放不同模式下的配置
otherDiv: HTMLDivElement; // 其它容器,存放额外配置
constructor(app: App, plugin: UploadPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
// 设置大标题
containerEl.createEl("h1", { text: "上传设置" });
// 默认配置
this.defaultDiv = containerEl.createDiv();
this.drawDefaultSettings(this.defaultDiv);
// 模式配置
this.modeDiv = containerEl.createDiv();
this.drawModeSettings(this.modeDiv, this.plugin.settings.mode);
// 其它配置
this.otherDiv = containerEl.createDiv();
this.drawOtherSettings(this.otherDiv);
}
// 自定义方法
// 默认配置
private drawDefaultSettings(parentEl: HTMLDivElement) {
new Setting(parentEl)
.setName('模式')
.setDesc('选择一种模式')
.addDropdown(e => {
modes.forEach((m) => {
e.addOption(m.value, m.text);
})
e.setValue(this.plugin.settings.mode)
e.onChange(async value => {
this.plugin.settings.mode = value;
await this.plugin.saveSettings();
await this.drawModeSettings(this.modeDiv, value);
})
})
}
// 模式配置
// 切换模式,不同的模式对应不同的配置
private async drawModeSettings(parentEl: HTMLDivElement, args: any) {
parentEl && parentEl.empty();
switch (args) {
case 'lsky':
this.drawLskySettings(parentEl);
break;
case 'github':
this.drawGithubSettings(parentEl);
break;
default:
break;
}
}
// 其它配置
private drawOtherSettings(parentEl: HTMLDivElement) {
}
// Lskypro 设置
private drawLskySettings(parentEL: HTMLDivElement) {
// Api URL
new Setting(parentEL)
.setName("API 地址")
.setDesc("请求地址")
.addText(text => {
text
.setPlaceholder("")
.setValue(this.plugin.settings.lskySetting.apiURL)
.onChange(async (value) => {
try {
this.plugin.settings.lskySetting.apiURL = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
})
// Api request header
new Setting(parentEL)
.setName("POST Header")
.setDesc("请求头json 格式")
.addTextArea((text) => {
text.setPlaceholder("输入合法的请求头")
.setValue(this.plugin.settings.lskySetting.apiReqHeader)
.onChange(async (value) => {
try {
this.plugin.settings.lskySetting.apiReqHeader = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
text.inputEl.rows = 5
text.inputEl.cols = 40
})
// Api request body
new Setting(parentEL)
.setName("POST Body")
.setDesc("请求体json 格式")
.addTextArea((text) => {
text.setPlaceholder("输入合法的请求体")
.setValue(this.plugin.settings.lskySetting.apiReqBody)
.onChange(async (value) => {
try {
this.plugin.settings.lskySetting.apiReqBody = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
text.inputEl.rows = 5
text.inputEl.cols = 40
})
new Setting(parentEL)
.setName("图片 URL 路径")
.setDesc("返回json数据中的图片URL字段的路径data/pathname")
.addText(text => {
text
.setPlaceholder("")
.setValue(this.plugin.settings.lskySetting.imgUrlPath)
.onChange(async (value) => {
try {
this.plugin.settings.lskySetting.imgUrlPath = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
})
new Setting(parentEL)
.setName("图片 URL 前缀")
.setDesc("可选当填入时URL = 前缀 + 图片的路径值")
.addText(text => {
text
.setPlaceholder("")
.setValue(this.plugin.settings.lskySetting.imgUrlPrefix)
.onChange(async (value) => {
try {
this.plugin.settings.lskySetting.imgUrlPrefix = value;
await this.plugin.saveSettings();
}
catch (e) {
console.log(e)
}
})
})
}
// Github 设置
private drawGithubSettings(parentEL: HTMLDivElement) {}
}
export default UploadSettingsTab;

29
src/type.ts Normal file
View file

@ -0,0 +1,29 @@
export interface ILskySettings {
apiURL: string;
apiReqHeader: string;
apiReqBody: string;
imgUrlPath: string;
imgUrlPrefix: string;
}
export interface IImage {
path: string;
name: string;
source: string;
}
export interface IUploadPluginSettings {
mode: string;
apiURL: string;
apiReqHeader: string;
apiReqBody: string;
imgUrlPath: string;
imgUrlPrefix: string;
lskySetting: ILskySettings;
}
export interface IUploader {
upload(file: File, fullPath?: string): Promise<string>;
}

15
src/uploader.ts Normal file
View file

@ -0,0 +1,15 @@
import LskyUpload from "./lskyUpload";
// Types
import { IUploadPluginSettings, IUploader } from './type';
function Uploader(settings: IUploadPluginSettings): IUploader {
switch (settings.mode) {
case 'lsky':
return new LskyUpload(settings);
default:
throw new Error('should not reach here!')
}
}
export default Uploader;

View file

@ -42,11 +42,16 @@ export default class Helper {
}
getValue() {
const editor = this.getEditor();
return editor.getValue();
if (editor) {
return editor.getValue();
} else {
return "";
}
}
setValue(value: string) {
const editor = this.getEditor();
const editor: any = this.getEditor();
const { left, top } = editor.getScrollInfo();
const position = editor.getCursor();
@ -57,7 +62,8 @@ export default class Helper {
// get all file urls, include local and internet
getAllFiles(): Image[] {
const editor = this.getEditor();
const editor: any = this.getEditor();
let value = editor.getValue();
return this.getImageLink(value);
}

View file

@ -17,7 +17,8 @@
"ES6",
"ES2021",
"ES7"
]
],
"allowSyntheticDefaultImports": true
},
"include": [
"**/*.ts"