mirror of
https://github.com/busyogg/OneStepWikiLink.git
synced 2026-07-22 05:41:52 +00:00
完成核心功能
This commit is contained in:
commit
9a936e35f6
17 changed files with 3272 additions and 0 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
3
.eslintignore
Normal file
3
.eslintignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
|
||||
main.js
|
||||
23
.eslintrc
Normal file
23
.eslintrc
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# vscode
|
||||
.vscode
|
||||
|
||||
# Intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
# Don't include the compiled main.js file in the repo.
|
||||
# They should be uploaded to GitHub releases instead.
|
||||
main.js
|
||||
|
||||
# Exclude sourcemaps
|
||||
*.map
|
||||
|
||||
# obsidian
|
||||
data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
1
.npmrc
Normal file
1
.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
tag-version-prefix=""
|
||||
5
LICENSE
Normal file
5
LICENSE
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Copyright (C) 2020-2025 by Busyo.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
94
README.md
Normal file
94
README.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# Obsidian Sample Plugin
|
||||
|
||||
This is a sample 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.
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
|
||||
## First time developing plugins?
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
|
||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
|
||||
## Releasing new releases
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
|
||||
## Adding your plugin to the community plugin list
|
||||
|
||||
- Check the [plugin guidelines](https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines).
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
|
||||
## How to use
|
||||
|
||||
- Clone this repo.
|
||||
- Make sure your NodeJS is at least v16 (`node --version`).
|
||||
- `npm i` or `yarn` to install dependencies.
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
|
||||
## Manually installing the plugin
|
||||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
|
||||
## Improve code quality with eslint (optional)
|
||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
||||
- To use eslint with this project, make sure to install eslint from terminal:
|
||||
- `npm install -g eslint`
|
||||
- To use eslint to analyze this project use this command:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
|
||||
## Funding URL
|
||||
|
||||
You can include funding URLs where people who use your plugin can financially support it.
|
||||
|
||||
The simple way is to set the `fundingUrl` field to your link in your `manifest.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": "https://buymeacoffee.com"
|
||||
}
|
||||
```
|
||||
|
||||
If you have multiple URLs, you can also do:
|
||||
|
||||
```json
|
||||
{
|
||||
"fundingUrl": {
|
||||
"Buy Me a Coffee": "https://buymeacoffee.com",
|
||||
"GitHub Sponsor": "https://github.com/sponsors",
|
||||
"Patreon": "https://www.patreon.com/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
49
esbuild.config.mjs
Normal file
49
esbuild.config.mjs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === "production");
|
||||
|
||||
const context = await esbuild.context({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ["src/main.ts"],
|
||||
bundle: true,
|
||||
external: [
|
||||
"obsidian",
|
||||
"electron",
|
||||
"@codemirror/autocomplete",
|
||||
"@codemirror/collab",
|
||||
"@codemirror/commands",
|
||||
"@codemirror/language",
|
||||
"@codemirror/lint",
|
||||
"@codemirror/search",
|
||||
"@codemirror/state",
|
||||
"@codemirror/view",
|
||||
"@lezer/common",
|
||||
"@lezer/highlight",
|
||||
"@lezer/lr",
|
||||
...builtins],
|
||||
format: "cjs",
|
||||
target: "es2018",
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : "inline",
|
||||
treeShaking: true,
|
||||
outfile: "main.js",
|
||||
minify: prod,
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
await context.rebuild();
|
||||
process.exit(0);
|
||||
} else {
|
||||
await context.watch();
|
||||
}
|
||||
11
manifest.json
Normal file
11
manifest.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"id": "one-step-wiki-link",
|
||||
"name": "One Step Wiki Link",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "一步添加 wiki 链接",
|
||||
"author": "Obsidian",
|
||||
"authorUrl": "https://obsidian.md",
|
||||
"fundingUrl": "https://obsidian.md/pricing",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
2397
package-lock.json
generated
Normal file
2397
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
24
package.json
Normal file
24
package.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "one-step-wiki-link",
|
||||
"version": "1.0.0",
|
||||
"description": "一步添加 wiki 链接",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@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",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
351
src/main.ts
Normal file
351
src/main.ts
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
import { Editor, MarkdownFileInfo, MarkdownView, Plugin, TFile, View } from "obsidian";
|
||||
import { OneStepWikiLinkPluginSettingTab } from "./setting";
|
||||
|
||||
const path = require("path");
|
||||
|
||||
export enum Language {
|
||||
CN = "CN",
|
||||
EN = "EN"
|
||||
}
|
||||
|
||||
interface OneStepWikiLinkPluginSettings {
|
||||
showDetails: boolean;
|
||||
autoConvert: boolean;
|
||||
language: Language;
|
||||
NonBoundaryCheckers: string[];
|
||||
excludes: string[];
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: OneStepWikiLinkPluginSettings = {
|
||||
showDetails: true,
|
||||
autoConvert: false,
|
||||
language: Language.CN,
|
||||
NonBoundaryCheckers: ["Han", "Hiragana", "Katakana", "Hangul"],
|
||||
excludes: []
|
||||
}
|
||||
|
||||
export default class OneStepWikiLinkPlugin extends Plugin {
|
||||
|
||||
settings: OneStepWikiLinkPluginSettings;
|
||||
|
||||
// ----- 私有变量 -----
|
||||
|
||||
fileNameList: string[] = [];
|
||||
|
||||
currentFileName: string = "";
|
||||
|
||||
btnOneStep: HTMLDivElement | undefined;
|
||||
|
||||
divForDetails: HTMLDivElement | undefined;
|
||||
|
||||
openEditor: Editor | undefined;
|
||||
|
||||
matchingFiles: string[] = [];
|
||||
|
||||
labels = {
|
||||
btnOneStep: {
|
||||
[Language.CN]: "全部转换为维基链接",
|
||||
[Language.EN]: "Convert All to Wiki Links"
|
||||
}
|
||||
}
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
||||
this.addSettingTab(new OneStepWikiLinkPluginSettingTab(this.app, this));
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.init();
|
||||
});
|
||||
}
|
||||
|
||||
onunload() {
|
||||
this.btnOneStep?.remove();
|
||||
this.divForDetails?.remove();
|
||||
}
|
||||
|
||||
async init() {
|
||||
//初始化文件名列表
|
||||
this.getAllFileNames();
|
||||
|
||||
//获取当前编辑器
|
||||
this.openEditor = this.app.workspace.getActiveViewOfType(MarkdownView)?.editor;
|
||||
|
||||
//初始化按钮
|
||||
let outlinkPanel = this.app.workspace.getLeavesOfType("outgoing-link")[0];
|
||||
if (outlinkPanel && !this.btnOneStep) {
|
||||
this.createButton(outlinkPanel.view.containerEl);
|
||||
if (!this.openEditor) {
|
||||
this.btnOneStep && (this.btnOneStep as HTMLDivElement).addClass("hide");
|
||||
this.divForDetails && (this.divForDetails as HTMLDivElement).addClass("hide");
|
||||
}
|
||||
}
|
||||
|
||||
this.registerEvent(this.app.workspace.on("active-leaf-change", (leaf) => {
|
||||
|
||||
//监听页面变化,防止出链界面关闭后再打开按钮消失
|
||||
let outlinkPanel = this.app.workspace.getLeavesOfType("outgoing-link")[0];
|
||||
|
||||
if (outlinkPanel) {
|
||||
if (!this.btnOneStep) {
|
||||
this.createButton(outlinkPanel.view.containerEl);
|
||||
}
|
||||
} else {
|
||||
this.btnOneStep = undefined;
|
||||
}
|
||||
|
||||
let type = leaf?.view.getViewType();
|
||||
if (leaf) {
|
||||
//监听当前激活的编辑器
|
||||
if (type === "markdown") {
|
||||
this.openEditor = leaf.view.app.workspace.activeEditor?.editor;
|
||||
// console.log(this.openEditor);
|
||||
if (this.openEditor) {
|
||||
this.checkContent(this.openEditor.getValue());
|
||||
}
|
||||
} else if (type == "empty") {
|
||||
this.btnOneStep?.addClass("hide");
|
||||
this.divForDetails?.addClass("hide");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
let file = this.app.workspace.getActiveFile();
|
||||
this.openEditor = this.app.workspace.getActiveViewOfType(MarkdownView)?.editor;
|
||||
|
||||
if (file && this.openEditor) {
|
||||
this.currentFileName = (file as TFile).basename;
|
||||
|
||||
let content = await this.app.vault.read(file);
|
||||
this.checkContent(content);
|
||||
}
|
||||
|
||||
this.addCommand({
|
||||
id: "convert-all-matching-words-to-wiki-links",
|
||||
name: "Convert All Matching Words to Wiki Links",
|
||||
editorCallback: (editor) => {
|
||||
this.convert2WikiLink();
|
||||
}
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "convert-all-matching-words-to-wiki-links-cn",
|
||||
name: "转换所有匹配的单词为维基链接",
|
||||
editorCallback: (editor) => {
|
||||
this.convert2WikiLink();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//监听文本变化
|
||||
this.registerEvent(this.app.workspace.on("editor-change", async (file, data) => {
|
||||
// console.log(file, data);
|
||||
if (file) {
|
||||
this.currentFileName = (data.file as TFile).basename;
|
||||
// console.log(file.getValue());
|
||||
this.checkContent(file.getValue());
|
||||
}
|
||||
}));
|
||||
|
||||
this.registerEvent(this.app.vault.on("rename", (file, oldPath) => {
|
||||
this.updateFileNameList((file as TFile).basename, true, oldPath.replace(".md", ""));
|
||||
}));
|
||||
|
||||
this.registerEvent(this.app.vault.on("delete", (file) => {
|
||||
this.updateFileNameList((file as TFile).basename, false);
|
||||
}));
|
||||
|
||||
// this.registerEvent(this.app.workspace.on("file-open", async (file) => {
|
||||
// // console.log("file open", file);
|
||||
// this.openEditor = this.app.workspace.getActiveViewOfType(MarkdownView)?.editor;
|
||||
|
||||
// if (file) {
|
||||
// this.currentFileName = (file as TFile).basename;
|
||||
|
||||
// let content = await this.app.vault.read(file);
|
||||
// this.checkContent(content);
|
||||
// }
|
||||
// }));
|
||||
|
||||
console.log(this.fileNameList)
|
||||
|
||||
// this.checkContent();
|
||||
}
|
||||
|
||||
getAllFileNames() {
|
||||
this.fileNameList = [];
|
||||
|
||||
let files = this.app.vault.getMarkdownFiles();
|
||||
for (let file of files) {
|
||||
|
||||
let checkFileName = this.settings.excludes.includes(file.basename);
|
||||
let checkFilePath;
|
||||
for (let exclude of this.settings.excludes) {
|
||||
let filePath = path.dirname(file.path) + "/";
|
||||
if (exclude.endsWith("/") && filePath.startsWith(exclude)) {
|
||||
checkFilePath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkFileName || checkFilePath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.fileNameList.push(file.basename);
|
||||
}
|
||||
}
|
||||
|
||||
updateFileNameList(name: string, add: boolean, extra: string = "") {
|
||||
|
||||
if (add) {
|
||||
let index = this.fileNameList.indexOf(extra);
|
||||
if (index >= 0) {
|
||||
this.fileNameList[index] = name;
|
||||
} else {
|
||||
this.fileNameList.push(name);
|
||||
}
|
||||
} else {
|
||||
this.fileNameList.splice(this.fileNameList.indexOf(name), 1);
|
||||
}
|
||||
}
|
||||
|
||||
checkContent(data: string) {
|
||||
|
||||
this.matchingFiles = [];
|
||||
|
||||
if (this.divForDetails) {
|
||||
this.divForDetails.empty();
|
||||
}
|
||||
|
||||
const contentWithoutLinks = data.replace(/\[\[([^\[\]]+)\]\]/g, "");
|
||||
|
||||
this.fileNameList.forEach(fileName => {
|
||||
// 排除当前文件
|
||||
if (fileName !== this.currentFileName && contentWithoutLinks.includes(fileName)) {
|
||||
this.matchingFiles.push(fileName);
|
||||
|
||||
//添加详情
|
||||
if (this.divForDetails) {
|
||||
this.divForDetails.createDiv({
|
||||
cls: "one-step-wikilink-detail-busyo",
|
||||
text: fileName
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.matchingFiles.sort((a, b) => a.length > b.length ? -1 : 1);
|
||||
|
||||
if (this.matchingFiles.length > 0) {
|
||||
|
||||
if (this.settings.autoConvert) {
|
||||
this.btnOneStep?.addClass("hide");
|
||||
this.divForDetails?.addClass("hide");
|
||||
this.convert2WikiLink();
|
||||
} else {
|
||||
this.btnOneStep?.removeClass("hide");
|
||||
this.settings.showDetails && this.divForDetails?.removeClass("hide");
|
||||
}
|
||||
} else {
|
||||
this.btnOneStep?.addClass("hide");
|
||||
this.divForDetails?.addClass("hide");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** 转换所有匹配项为维基链接 */
|
||||
convert2WikiLink() {
|
||||
if (this.openEditor) {
|
||||
let data = this.openEditor.getValue();
|
||||
|
||||
let changes = [];
|
||||
|
||||
for (const match of this.matchingFiles) {
|
||||
let regex = new RegExp(`(?<!\\[\\[)${match}\\b(?!\\]\\])`, "g");
|
||||
//检测字符串最后一个字符是否为有边界的语言
|
||||
if (this.isNonBoundaryChar(match.charAt(match.length - 1))) {
|
||||
regex = new RegExp(`(?<!\\[\\[)${match}(?!\\]\\])`, "g");
|
||||
}
|
||||
|
||||
let res
|
||||
while ((res = regex.exec(data)) !== null) {
|
||||
|
||||
let pos = this.openEditor.offsetToPos(res.index);
|
||||
let endPos = { ch: pos.ch + match.length, line: pos.line };
|
||||
|
||||
changes.push({
|
||||
from: pos,
|
||||
to: endPos,
|
||||
text: `[[${match}]]`
|
||||
});
|
||||
|
||||
// data = data.replace(regex, `[[${match}]]`);
|
||||
}
|
||||
}
|
||||
|
||||
this.openEditor.transaction({ changes: changes });
|
||||
}
|
||||
}
|
||||
|
||||
// 判断字符是否属于有边界的语言(如英文、法文等)
|
||||
isNonBoundaryChar(char: string) {
|
||||
if (this.settings.NonBoundaryCheckers.length === 0) return false;
|
||||
|
||||
let checkers = this.settings.NonBoundaryCheckers
|
||||
.map(checker => `\\p{Script=${checker}}`) // 生成 Unicode Script 规则
|
||||
.join("|"); // 以 | 分隔
|
||||
|
||||
return new RegExp(checkers, "u").test(char);
|
||||
}
|
||||
|
||||
createButton(root: Element) {
|
||||
let container = root.querySelector(".outgoing-link-pane");
|
||||
if (container) {
|
||||
this.btnOneStep = container.createDiv({
|
||||
cls: "one-step-wikilink-container-busyo",
|
||||
text: this.labels.btnOneStep[this.settings.language]
|
||||
});
|
||||
container.insertBefore(this.btnOneStep, container.firstChild);
|
||||
|
||||
this.btnOneStep.onclick = () => {
|
||||
this.convert2WikiLink();
|
||||
};
|
||||
|
||||
this.divForDetails = container.createDiv({
|
||||
cls: "one-step-wikilink-detail-container-busyo"
|
||||
});
|
||||
|
||||
container.insertBefore(this.divForDetails, container.firstChild);
|
||||
|
||||
if (!this.settings.showDetails) {
|
||||
this.divForDetails.addClass("hide");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
|
||||
//保存配置的时候检测是否需要显示目标 Div
|
||||
if (this.matchingFiles.length > 0) {
|
||||
!this.settings.showDetails && this.divForDetails?.removeClass("hide");
|
||||
} else {
|
||||
this.divForDetails?.addClass("hide");
|
||||
}
|
||||
|
||||
//更改语言
|
||||
this.btnOneStep?.setText(this.labels.btnOneStep[this.settings.language]);
|
||||
|
||||
//更新文件列表
|
||||
this.getAllFileNames();
|
||||
if (this.openEditor) {
|
||||
this.checkContent(this.openEditor.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
167
src/setting.ts
Normal file
167
src/setting.ts
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
import OneStepWikiLinkPlugin from "src/main";
|
||||
import { App, PluginSettingTab, Setting, View, WorkspaceLeaf } from "obsidian";
|
||||
import { Language } from "src/main";
|
||||
|
||||
export class OneStepWikiLinkPluginSettingTab extends PluginSettingTab {
|
||||
plugin: OneStepWikiLinkPlugin;
|
||||
|
||||
labels = {
|
||||
details: {
|
||||
name: {
|
||||
[Language.CN]: "详情开关",
|
||||
[Language.EN]: "Details Switch"
|
||||
},
|
||||
desc: {
|
||||
[Language.CN]: "是否显示所有匹配的内容",
|
||||
[Language.EN]: "Whether to display all matching content"
|
||||
}
|
||||
},
|
||||
autoConvert: {
|
||||
name: {
|
||||
[Language.CN]: "自动转换开关",
|
||||
[Language.EN]: "Auto Convert Switch"
|
||||
},
|
||||
desc: {
|
||||
[Language.CN]: "是否自动转换所有匹配的内容",
|
||||
[Language.EN]: "Whether to automatically convert all matching content"
|
||||
}
|
||||
},
|
||||
NonBoundaryCheckers: {
|
||||
name: {
|
||||
[Language.CN]: "非边界字符",
|
||||
[Language.EN]: "Non-Boundary Characters"
|
||||
},
|
||||
desc: {
|
||||
[Language.CN]: "用于检测没有边界的字符,如汉字,以 `,` 或 `,` 分隔,值为正则表达式的 `Script=Han` 形式中的 Han 部分",
|
||||
[Language.EN]: "Used to detect characters without boundaries, such as Chinese characters, separated by `,` or `,` , and the `Script=Han` part of the regular expression"
|
||||
}
|
||||
},
|
||||
excludes: {
|
||||
name: {
|
||||
[Language.CN]: "排除列表",
|
||||
[Language.EN]: "Exclude List"
|
||||
},
|
||||
desc: {
|
||||
[Language.CN]: "不检测排除列表中的文件,以 `,` 或 `,` 分隔,不带后缀,排除文件夹需要输入文件夹的相对路径并以 `/` 结尾",
|
||||
[Language.EN]: "Do not check files in the exclude list, separated by `,` or `,`, without suffix, exclude folders need to enter the relative path of the folder and end with `/`"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
settings: {
|
||||
key: {
|
||||
name: {
|
||||
CN: string;
|
||||
EN: string;
|
||||
};
|
||||
desc: {
|
||||
CN: string;
|
||||
EN: string;
|
||||
};
|
||||
}; value: Setting;
|
||||
}[] = [];
|
||||
|
||||
constructor(app: App, plugin: OneStepWikiLinkPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
let { containerEl } = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("语言 Language")
|
||||
.setDesc("选择语言 Choose language")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOption("CN", "CN")
|
||||
.addOption("EN", "EN")
|
||||
.setValue(this.plugin.settings.language)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.language = value as Language;
|
||||
await this.plugin.saveSettings();
|
||||
|
||||
this.updateLanguage();
|
||||
})
|
||||
);
|
||||
|
||||
this.settings.push(
|
||||
{
|
||||
key: this.labels.details,
|
||||
value: new Setting(containerEl)
|
||||
.setName(this.labels.details.name[this.plugin.settings.language])
|
||||
.setDesc(this.labels.details.desc[this.plugin.settings.language])
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showDetails)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.showDetails = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
this.settings.push(
|
||||
{
|
||||
key: this.labels.autoConvert,
|
||||
value: new Setting(containerEl)
|
||||
.setName(this.labels.autoConvert.name[this.plugin.settings.language])
|
||||
.setDesc(this.labels.autoConvert.desc[this.plugin.settings.language])
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.autoConvert)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.autoConvert = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
this.settings.push(
|
||||
{
|
||||
key: this.labels.NonBoundaryCheckers,
|
||||
value: new Setting(containerEl)
|
||||
.setName(this.labels.NonBoundaryCheckers.name[this.plugin.settings.language])
|
||||
.setDesc(this.labels.NonBoundaryCheckers.desc[this.plugin.settings.language])
|
||||
}
|
||||
);
|
||||
|
||||
let boundaryInput = containerEl.createDiv({ cls: "one-step-wikilink-setting-exclude-busyo" });
|
||||
boundaryInput.contentEditable = "plaintext-only";
|
||||
boundaryInput.textContent = this.plugin.settings.NonBoundaryCheckers.join(",");
|
||||
|
||||
boundaryInput.addEventListener('input', async () => {
|
||||
this.plugin.settings.NonBoundaryCheckers = (boundaryInput.textContent as string).replace(",", ",").split(",").filter(keyword => keyword !== "");
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
this.settings.push(
|
||||
{
|
||||
key: this.labels.excludes,
|
||||
value: new Setting(containerEl)
|
||||
.setName(this.labels.excludes.name[this.plugin.settings.language])
|
||||
.setDesc(this.labels.excludes.desc[this.plugin.settings.language])
|
||||
}
|
||||
);
|
||||
|
||||
let excludeInput = containerEl.createDiv({ cls: "one-step-wikilink-setting-exclude-busyo" });
|
||||
excludeInput.contentEditable = "plaintext-only";
|
||||
excludeInput.textContent = this.plugin.settings.excludes.join(",");
|
||||
|
||||
excludeInput.addEventListener('input', async () => {
|
||||
this.plugin.settings.excludes = (excludeInput.textContent as string).replace(",", ",").split(",").filter(keyword => keyword !== "");
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
}
|
||||
|
||||
updateLanguage() {
|
||||
for (let setting of this.settings) {
|
||||
setting.value.setName(setting.key.name[this.plugin.settings.language]);
|
||||
setting.value.setDesc(setting.key.desc[this.plugin.settings.language]);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
styles.css
Normal file
74
styles.css
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
|
||||
One Step WikiLink Custome Css
|
||||
|
||||
*/
|
||||
|
||||
.one-step-wikilink-container-busyo {
|
||||
/* display: inline-flex; */
|
||||
text-align: center;
|
||||
background-color: var(--interactive-normal);
|
||||
border-radius: var(--radius-s);
|
||||
box-shadow: var(--input-shadow);
|
||||
color: var(--text-muted);
|
||||
padding: var(--size-2-2) var(--size-2-3);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.one-step-wikilink-container-busyo:hover {
|
||||
background-color: var(--interactive-hover);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.one-step-wikilink-container-busyo:active {
|
||||
background-color: var(--interactive-active);
|
||||
}
|
||||
|
||||
.one-step-wikilink-container-busyo.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.one-step-wikilink-detail-container-busyo {
|
||||
text-align: center;
|
||||
background-color: var(--interactive-active);
|
||||
border-radius: var(--radius-s);
|
||||
box-shadow: var(--input-shadow);
|
||||
color: var(--text-muted);
|
||||
padding: var(--size-2-2) var(--size-2-3);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.one-step-wikilink-detail-container-busyo.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.one-step-wikilink-detail-busyo {
|
||||
display: inline-flex;
|
||||
text-align: center;
|
||||
background-color: var(--interactive-normal);
|
||||
border-radius: var(--radius-s);
|
||||
box-shadow: var(--input-shadow);
|
||||
color: var(--text-muted);
|
||||
padding: var(--size-2-2) var(--size-2-3);
|
||||
margin: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/** setting style */
|
||||
.one-step-wikilink-setting-exclude-busyo {
|
||||
width: 100%;
|
||||
min-height: 2em;
|
||||
height: auto;
|
||||
overflow-wrap: break-word;
|
||||
white-space: normal;
|
||||
|
||||
-webkit-app-region: no-drag;
|
||||
background: var(--background-modifier-form-field);
|
||||
border: var(--input-border-width) solid var(--background-modifier-border);
|
||||
color: var(--text-normal);
|
||||
font-family: inherit;
|
||||
padding: var(--size-4-1) var(--size-4-2);
|
||||
font-size: var(--font-ui-small);
|
||||
border-radius: var(--input-radius);
|
||||
outline: none;
|
||||
}
|
||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"strictNullChecks": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
14
version-bump.mjs
Normal file
14
version-bump.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
3
versions.json
Normal file
3
versions.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
Loading…
Reference in a new issue