获取和修改文件的配置
this.app.vault.getConfig("option")
// 这里的option怎么获取
// 1 用devtools查看选项字段,在app.js中搜索
// 2 打开devtools,修改设置选项,然后用下面的代码查看具体选项
// this.app.vault.config
// 修改文件配置
app.vault.setConfig("vimMode", false)
通过命令 id 执行命令
this.app.commands.executeCommandById('app:open-settings');
//查看命令列表
// app.commands.listCommands().filter(f=>[f.id, f.name].some(i=>i.contains('runjs')))
//app.commands.listCommands().filter(f=>f.id.contains('runjs'))
//app.commands.listCommands().filter(f=>f.name.contains('runjs'))
command 命令的动态添加、修改、删除和查找
// 添加命令
app.commands.addCommand({
"id": "runjs:command-test3",
"name": "RunJS: runjs test3",
mobileOnly: false, //是否仅手机显示
showOnMobileToolbar: false, //是否在手机工具栏显示
icon: "lucide-bold", //图标
//快捷键 see https://www.electronjs.org/zh/docs/latest/api/accelerator
hotkeys: [{ modifiers: ["Mod", "Shift"], key: "N" }],
//hotkeys: [{ modifiers: ["Mod", "Alt"], key: "ArrowLeft" }]
repeatable: false, //是否可重复执行
allowPreview: false, //是否允许预览模式执行
allowProperties: true, //是否允许文档属性中执行
callback: () => {console.log('333');alert(333);}
})
// 修改命令
app.commands.commands['runjs:command-2'].name = 'RunJS: runjs test2';
//app.commands.commands['runjs:command-2']和app.commands.findCommand('runjs:command-2')等价
app.commands.findCommand('runjs:command-2').callback = ()=>{console.log('111');alert(111);}
app.commands.commands['xxxx'].checkCallback = (checking)=>{}
app.commands.commands['xxxx'].editorCallback = (editor, view)=>{}
app.commands.commands['xxxx'].editorCheckCallback = (checking, editor, view)=>{}
// 删除命令
app.commands.removeCommand('runjs:command-2');
// 查找命令
app.commands.findCommand('runjs:command-2')
app.commands.listCommands().filter(f=>[f.id, f.name].some(i=>i.contains('runjs')))
// 执行命令
app.commands.executeCommandById('app:open-settings');
快捷键管理
// 添加快捷键
// see https://www.electronjs.org/zh/docs/latest/api/accelerator
app.hotkeyManager.addDefaultHotkeys(commandId, [{ modifiers: ["Mod", "Alt"], key: "ArrowLeft" }])
//获取默认快捷键
app.hotkeyManager.getDefaultHotkeys(commandId)
// 删除快捷键
app.hotkeyManager.removeDefaultHotkeys(commandId);
// 获取快捷键
app.hotkeyManager.getHotkeys(commandId);
// 修改快捷键
app.hotkeyManager.setHotkeys(commandId)
// 打印快捷键
app.hotkeyManager.printHotkeyForCommand(commandId)
// 重新加载快捷键
app.hotkeyManager.load()
// 保存快捷键
app.hotkeyManager.save();
添加,修改,删除 frontmatter
const file = this.app.vault.getFileByPath("demo.md");
if(file) {
//see https://forum.obsidian.md/t/how-to-use-app-filemanager-processfrontmatter/73467
this.app.fileManager.processFrontMatter(file, (frontmatter: any) => {
frontmatter['a'] = "aaaa";
frontmatter['b'] = "bbbb";
frontmatter['c'] = "cccc";
})
}
//清空当前文件frontmatter
// 如果当前文件可用 app.workspace.getActiveFile()
const file = app.vault.getFileByPath("你的文件名.md");
app.fileManager.processFrontMatter(file, (frontmatter) => { for(i in frontmatter){delete frontmatter[i]} });
//清空所有文件frontmatter
// 郑重声明:如果你不知道这段代码在干什么,请不要测试!!!
// 危险!危险!危险!请在沙盒中测试无误后使用,后果自负!!!
app.vault.getFiles().forEach(p=>{
// 只对markdown文件操作
if(p.extension==="md"){
const file = app.vault.getFileByPath(p.path);
app.fileManager.processFrontMatter(file, (frontmatter) => { for(i in frontmatter){delete frontmatter[i]} });
}
});
读取 frontmatter
// 从缓存读取
let fm = this.app.metadataCache.getFileCache(file)?.frontmatter
console.log(fm)
// 从文件解析
import { getFrontMatterInfo, parseYaml } from 'obsidian';
const content = await this.app.vault.read(file)
const yaml = getFrontMatterInfo(content).frontmatter
const yamlObj = parseYaml(yaml)
console.log(yamlObj)
激活叶子
this.app.workspace.setActiveLeaf(leaf, { focus: true });
复制到剪切板
navigator.clipboard.writeText('');
记录叶子的光标和滚动条位置
onst state = leaf.getEphemeralState()
setTimeout(() => {
leaf.setEphemeralState(state);
}, 42);
关闭重复标签
this.app.workspace.onLayoutReady(() => {
this.registerEvent(
this.app.workspace.on("active-leaf-change", (activeLeaf) => {
const filePath = activeLeaf?.view.getState().file;
if (!filePath) return;
const viewType = activeLeaf?.view.getViewType();
// 获取已存在的其他叶子
let repeatLeaves = this.app.workspace.getLeavesOfType(viewType).filter((leaf) =>
// 不包含新打开的叶子
leaf !== activeLeaf &&
// 限制同一个分割窗口下的叶子
//leaf.parent.id === activeLeaf.parent.id &&
// 筛选文件路径相同的叶子
leaf.view?.getState().file === filePath
)
if(repeatLeaves.length > 0) {
repeatLeaves.push(activeLeaf)
// 排序规则,pinned优先,相同条件下,最先打开的优先
repeatLeaves = repeatLeaves.sort((leaf1, leaf2) => {
// 如果 leaf1 被固定但 leaf2 没有,leaf1 在前
if (leaf1.pinned && !leaf2.pinned) return -1;
// 如果 leaf2 被固定但 leaf1 没有,leaf2 在前
if (!leaf1.pinned && leaf2.pinned) return 1;
// 当两者都 pinned 或者都没有 pinned 的情况,根据 activeTime 排序
const leaf2ActiveTime =leaf2.activeTime || Date.now()
if (leaf1.activeTime !== leaf2ActiveTime) {
// 时间早的在前
return leaf1.activeTime - leaf2ActiveTime;
}
// activeTime 相同的情况下,保持原顺序
return 0;
});
// 激活排序后的第一个叶子
const newActiveLeaf = repeatLeaves.shift();
this.app.workspace.setActiveLeaf(newActiveLeaf, { focus: true });
// 关闭排序后的其他叶子
repeatLeaves.forEach((leaf) => {
leaf?.detach()
});
}
// 如果设置为默认锁定体验更佳,但锁定的叶子关闭需要点击两次或者右键关闭
// 这样相当于每次都新标签打开
// setTimeout(() => {
// const currActiveLeaf = this.app.workspace.getActiveViewOfType(ItemView)?.leaf;
// if(!currActiveLeaf?.pinned) currActiveLeaf?.setPinned(true);
// }, 42);
})
)
})
用默认应用打开文件(也可以打开文件夹)
this.app.openWithDefaultApp(FolderOrFile)
获取 .obsidian
目录
const vault = this.app.vault
const adapter = vault.adapter
const obConfigDir = adapter.path.join(adapter.basePath, vault.configDir)
console.log(obConfigDir)
获取当前激活 view 的类型
this.app.workspace.activeLeaf.view.getViewType()
或
获取 rootSplit
@ts-ignore
this.app.workspace.rootSplit.containerEl
当未开启番茄工作法且鼠标不在状态栏焦点时自动隐藏状态栏
/* 当未开启番茄工作法且鼠标不在状态栏焦点时隐藏状态栏 */
.status-bar:not(:hover):has(.plugin-obsidian-statusbar-pomo:empty) {
opacity: 0;
}
notice 倒计时
let count = 10
const a=new Notice("hello "+count, 0);
while (count > 0) {
count--;
await new Promise((resolve) => setTimeout(resolve, 1000)).then(() => {a.setMessage("hello "+count);});
}
a.hide()
在当前叶子打开文件
await app.workspace.activeLeaf.openFile(app.vault.getAbstractFileByPath("demo.md"))
在左侧面板打开文件
app.workspace.getLeftLeaf().openFile(app.vault.getAbstractFileByPath("demo.md"))
新窗口打开文件
await app.workspace.getLeaf('tab').openFile(app.vault.getAbstractFileByPath('demo.md'))
obsidian 插件外 require(‘obsidian’)
-
先去github安装这个插件obsidian-fix-require-modules并开启插件。
-
如下方法调用
const ob = require('obsidian');
const markdown = ob.htmlToMarkdown(htmlContent);
htmlToMarkdown 在非 obsidian 环境可以用 turndown,貌似 obsidian 中就用的这个项目。
但在 runjs 中科院直接导入 obsidian,比如:
//在runjs中可以这样导入
import * as obsidian from 'obsidian';
obsidian.setIcon(document.querySelector(".side-dock-settings > .side-dock-ribbon-action:nth-child(3) > svg").parentElement, 'document');
写文档
app.vault.adapter.write("demo.md", 'demo')
在新窗口打开一个当前文档
新窗口打开,原窗口还在,打开的是副本
app.commands.executeCommandById(“workspace:open-in-new-window”);
新窗口打开,原窗口光标,替换方式打开
app.commands.executeCommandById(“workspace:move-to-new-window”);
以置顶方式打开新窗口
感谢 @熊猫别熬夜 噗~ 提供
const openFilePath = "todo.md"; // 设置打开的文件路径
const activeWindowWidth = 380; // 设置新窗口的宽度
const activeWindowHeight = 500; // 设置新窗口的高度
// 获取屏幕大小
const screenWidth = activeWindow.screen.width;
const screenHeight = activeWindow.screen.height;
// 计算新窗口的位置和大小
const activeWindowLeft = (screenWidth - activeWindowWidth) / 2;
const activeWindowTop = (screenHeight - activeWindowHeight) / 2;
//打开文档
app.workspace.getLeaf('window').openFile(app.vault.getAbstractFileByPath(openFilePath));
// 暂停5ms
await sleep(5)
//await new Promise(resolve => setTimeout(resolve, 5));
// 将激活窗口置顶
activeWindow.electronWindow.setAlwaysOnTop(true);
// 调整窗口大小为宽度,高度
activeWindow.resizeTo(activeWindowWidth, activeWindowHeight);
// 设置窗口的位置和大小
activeWindow.moveTo(activeWindowLeft, activeWindowTop);
参考:我开发了一个可以把某笔记屏幕置顶的小工具 - 经验分享 - Obsidian 中文论坛
也可以参考:Float on Top for Mac? - Basement - Obsidian Forum
let getWindow = require('electron').remote.getCurrentWindow();
getWindow.setOpacity(0.88);
getWindow.setAlwaysOnTop(true);
外部执行命令
// mac
open --background "obsidian://advanced-uri?vault=vault_name&commandid=runjs%253Acommand-0"
//linux
xdg-open "obsidian://advanced-uri?vault=vault_name&commandid=runjs%253Acommand-0"
//windows
start /b "obsidian://advanced-uri?vault=vault_name&commandid=runjs%253Acommand-0"
// 判断当前主题
// 方法1
let theme = app.getTheme();
if(theme == 'moonstone'){
theme = 'light'
} else if(theme == 'obsidian') {
theme = 'dark'
} else {
const isLight = window.matchMedia("(prefers-color-scheme: light)");
if (isLight.matches) {
theme = 'light'
} else {
theme = 'dark'
}
}
// 方法2
const theme = document.body.classList.contains("theme-light") ? 'light' : 'dark';
获取系统插件
this.app.internalPlugins.getEnabledPluginById("bookmarks")
判断插件已启用
const metaeditEnabled = app.plugins.enabledPlugins.has("metaedit");
获取已安装插件信息
app.plugins.manifests
插件管理
//判断是否安装
if (!app.plugins.plugins[pluginId]) {
console.log(`插件 ${pluginId} 未安装`);
}
//禁用插件
await app.plugins.disablePlugin(pluginId);
// 等待一段时间以确保插件完全禁用
await new Promise(r => setTimeout(r, 1000));
console.log(`插件 ${pluginId} 已禁用`);
// 启用插件
await app.plugins.enablePlugin(pluginId);
console.log(`插件 ${pluginId} 已启用`);
// 重新加载插件
// 先禁用再启用
//卸载插件
//先禁用插件,再删除插件目录
//重置插件
//先禁用,删除插件data.json配置,再启用插件
删除文件
const trashOption = this.app.vault.getConfig("trashOption");
if(trashOption === 'system') {
// 移动到系统回收站
await app.vault.trash(app.vault.getAbstractFileByPath(path), true);
} else if(trashOption === 'local') {
// 移动到obsidian的.trash目录
await app.vault.trash(app.vault.getAbstractFileByPath(path), false);
} else {
// 永久删除
await app.vault.adapter.remove(path);
// 也可以用app.vault.delete
//await app.vault.delete(app.vault.getAbstractFileByPath(path))
}
添加,删除,修改书签
//查看
// 按分组和未分组分开展示
app.internalPlugins.plugins.bookmarks.instance.items
// 全部展示
app.internalPlugins.getEnabledPluginById("bookmarks").getBookmarks()
//添加
// type类型,file,folder,search,group
// 添加文件书签
app.internalPlugins.plugins.bookmarks.instance.addItem({
"type": "file",
"ctime": 1716495589884,
"path": "未命名 2.md"
})
// 添加分组书签
app.internalPlugins.plugins.bookmarks.instance.addItem({
"type": "group",
"ctime": 1715068875125,
"items": [
{
"type": "file",
"ctime": 1715068911064,
"path": "linux/Linux find 模拟 tree 命令.md"
}
],
"title": "分组2"
})
// 删除
app.internalPlugins.plugins.bookmarks.instance.removeItem(app.internalPlugins.plugins.bookmarks.instance.items[0])
// 修改
// 先更新app.internalPlugins.plugins.bookmarks.instance.items的值,
// 再执行app.internalPlugins.plugins.bookmarks.instance.editItem(),比如
app.internalPlugins.plugins.bookmarks.instance.items[1]['title']='分组22'
app.internalPlugins.plugins.bookmarks.instance.editItem();
//也可以直接修改.obsidian/bookmarks.json
//打开书签面板
app.workspace.ensureSideLeaf('bookmarks', "left", { active: true})
//判断是否已添加到书签
app.internalPlugins.plugins.bookmarks.bookmarkLookup.hasOwnProperty(path)
在资源管理器中显示文件
// 在资源管理器中显示文件
app.showInFolder('demo.md');
// 在资源管理器中显示文件夹
app.showInFolder('tools');
取消注册事件
app.workspace.off("editor-menu", menuCallback);
不安装 nodejs 开发插件
// 放到main.js中
const ob = require('obsidian')
module.exports = class extends ob.Plugin {
constructor(app, manifest) {
super(app, manifest)
}
onload() {
// 这里注册一个命令以展示其中一个 modal
this.addCommand({
id: 'test-my-demo', name: 'Test my Demo',
callback: async ()=> {
alert('Test my Demo')
}
})
}
onunload() {}
}
通过接口打开 custom frames 的窗口
// 删除文心一言叶子
app.workspace.detachLeavesOfType('custom-frames-文心一言')
//重新打开文心一言叶子,right显示右侧,left显示左侧,active:false仅打开不激活叶子
// ensureSideLeaf函数会检查是否已打开,如果已打开不再打开
app.workspace.ensureSideLeaf('custom-frames-文心一言', "right", { active: true})
//也可以通过custom frames提供的接口打开
// 该接口有三个参数:第一个参数同上是视图类型,第二个参数true中间视图打开,false右侧面板打开,第三个参数,'split分割窗口打开,'tab'新标签打开,'window'新窗口打开
app.plugins.plugins['obsidian-custom-frames'].openLeaf('custom-frames-文心一言, false)
注意:这里的”文心一言“是你在custom frames里输入的名字,根据自己需要修改,但必须有”custom-frames-“前缀,即”custom-frames-你填写的名字“
遍历叶子的方法
//遍历所有叶子
app.workspace.iterateAllLeaves((leaf)=>{console.log(leaf)});
//遍历指定视图类型的叶子
app.workspace.getLeavesOfType('markdown');
//遍历左侧面板的叶子
app.workspace.iterateLeaves(app.workspace.leftSplit, (leaf)=>{console.log(leaf)})
//遍历右侧面板的叶子
app.workspace.iterateLeaves(app.workspace.rightSplit, (leaf)=>{console.log(leaf)})
//遍历中间面板的叶子
app.workspace.iterateLeaves(app.workspace.rootSplit, (leaf)=>{console.log(leaf)})
app.workspace.iterateRootLeaves((leaf)=>{console.log(leaf)})
//遍历floatingSplit叶子(虽然还不知道floating分割窗口是啥)
app.workspace.iterateLeaves(app.workspace.floatingSplit, (leaf)=>{console.log(leaf)})
// 把叶子从隐藏状态显示出来(即获取焦点,但不是激活)
leaf = this.app.workspace.getLeavesOfType('bookmarks')[0];
this.app.workspace.revealLeaf(leaf);
获取叶子
源码:
const getLeaf = function(type, tabData) {
if (type === "split") {
return this.splitActiveLeaf(tabData);
} else if (type === "tab" || type === true) {
return this.createLeafInTabGroup();
} else if (type === "window") {
return this.openPopoutLeaf();
} else {
return this.getUnpinnedLeaf();
}
}
由源码可知
app.workspace.getLeaf() // 当前标签
app.workspace.getLeaf('tab') // 新标签
app.workspace.getLeaf('split', 'vertical') // 垂直拆分
app.workspace.getLeaf('split', 'horizontal') // 水平拆分
app.workspace.getLeaf('window') // 新窗口
app.workspace.getLeftLeaf(); // 新建左侧边栏
app.workspace.getLeftLeaf(false); // 新建左边栏水平拆分
app.workspace.getLeftLeaf(); // 新建右侧边栏
app.workspace.getLeftLeaf(false); // 新建右栏水平拆分
app.workspace.getMostRecentLeaf(); // 最近的叶子
app.workspace.ensureSideLeaf(); // 显示或创建面板
app.workspace.revealLeaf(); // 显示面板
获取平台类型
window.process.platform
//或
require('obsidian').Platform
获取文档编辑器
const editor = app.workspace.getActiveFileView()?.editor
//或
//const editor = app.workspace.activeEditor?.editor
//插入文本到最后
editor.insertText("\naaaaa")
//插入文本到某行
editor.replaceRange("| 22 | 33 | 66 |\n", { line: 13, ch: 0 })
// 获取文本块行
const file = app.metadataCache.getFileCache(app.vault.getAbstractFileByPath("demo.md"))
const tables = file.sections.filter(s=>s.type === 'table')
//或
// const table = file.blocks["block-name"]
// 光标移动事件
this.app.workspace.on("editor-selection-change", (t,n,i)=>{console.log(t,n, i)})
// 获取光标处的元素
document.querySelectorAll(".workspace-split.mod-root .cm-active.cm-line")
// html,表格渲染时执行
this.registerMarkdownPostProcessor((element, context) => {});
获取激活文档的元素
activeDocument.activeElement
常用方法、函数
// 后退
app.workspace.activeLeaf.history.back()
// 前进
app.workspace.activeLeaf.history.forward()
// 切换主题
app.changeTheme("obsidian") //暗色主题
app.changeTheme("moonstone") //亮色主题
// 打开设置
app.setting.open()
// 打开更新内容
app.showReleaseNotes()
//触发预览和编辑模式
app.workspace.activeEditor.toggleMode()
//调用添加文档属性
app.workspace.activeLeaf.view.metadataEditor.addProperty()
//关闭当前标签页
app.workspace.activeLeaf.detach()
// 触发左侧边栏
app.workspace.leftSplit.toggle()
// 触发右侧边栏
app.workspace.rightSplit.toggle()
// 触发robbion
var e=app, n = e.vault.getConfig("showRibbon");
e.vault.setConfig("showRibbon", !n),
e.updateRibbonDisplay(),
e.workspace.updateFrameless()
// 放大
var e = electron.webFrame.getZoomLevel();
e < 3 && electron.webFrame.setZoomLevel(e + .5)
// 缩小
var e = electron.webFrame.getZoomLevel();
e > -2.5 && electron.webFrame.setZoomLevel(e - .5)
// 复原
electron.webFrame.setZoomLevel(0)
// 新标签新建笔记
app.fileManager.createAndOpenMarkdownFile("", "tab")
//当前标签新建笔记
app.fileManager.createAndOpenMarkdownFile("", false)
模拟获取文件潜在链接
// 获取编辑器内容
let fileContent = app.workspace.activeLeaf.view.editor.getValue();
// 获取潜在链接,并过滤代码块和已是链接的文本(仅简单对`[[]]`形式的链接过滤)
const mentions = app.vault.getFiles().map(item=>item.basename).filter(item=>fileContent.replace(/`+.*?`+/gs, '').replace(/\[\[.*?\]\]/gs, '').includes(item));
// 替换潜在链接
mentions.forEach(m=>fileContent=fileContent.replace(new RegExp(m, 'g'), `[[${m}]]`));
// 替换当前编辑器内容,需谨慎操作
app.workspace.activeLeaf.view.editor.setValue(fileContent)
触发系统菜单
navFileTitle.addEventListener('contextmenu', (event: MouseEvent) => {
if (!currentFile?.path) return;
const menu = new Menu();
menu.addItem((item) =>
item
.setSection('action')
.setTitle('Open in new tab')
.setIcon('file-plus')
.onClick(() => {
this.focusFile(currentFile, 'tab');
})
);
const file = this.app.vault.getAbstractFileByPath(currentFile?.path);
this.app.workspace.trigger(
'file-menu',
menu,
file,
'link-context-menu',
);
menu.showAtPosition({ x: event.clientX, y: event.clientY });
});
触发自定义事件
//定义事件
const myEvent = new Events();
//注册事件
const myEventHander = () => {console.log('MY_EVENT run')};
this.registerEvent(
myEvent?.on("MY_EVENT", myEventHander)
);
// 取消注册事件
myEvent?.off("MY_EVENT", myEventHander)
// 触发自定义事件
myEvent?.trigger("MY_EVENT");
最简单的插件开发模板
// main.js
// 在根目录添加 .hotreload文件可支持热加载
const { Plugin } = require('obsidian')
module.exports = class extends Plugin {
onload() {
console.log('myplugin onload')
// this.registerObsidianProtocolHandler('open-tab', (url)=> {
// if (url.action != 'open-tab' || !url.file) return
// this.app.workspace.getLeaf('tab').openFile(this.app.metadataCache.getFirstLinkpathDest(url.file, url.file))
// });
}
onunload() {}
}
// manifest.json 文件
{
"id": "my-plugin",
"name": "My Plugin",
"version": "0.0.1",
"minAppVersion": "1.5.3",
"description": "Plugin for daily use",
"isDesktopOnly": false
}
监控文件打开函数
```dataviewjs
// 开始监控文件打开
onSomeFileOpened("all", (leaf, file) => {
// 打开的文件是dataviewjs脚本所在文件时跳过
if(dv.current().file.path === file) return;
// dataview内容区输出
dv.container.empty();
dv.paragraph("你刚才打开了 " + file);
//控制台打印打开的文件
console.log(file, "opened @", new Date().toLocaleString());
// 通知显示打开的文件路径
new Notice(file + " opened.");
});
// 监控文件打开函数
// watches 待监控的文件,支持数组,watches有3种情况
// 当watches==all或空值(即!watches)时,代表监控所有文件
// 当为文件路径或数组时,代表只监控watches中的文件
// 当watches=["exclude", []]时,代表监控所有的文件,但排除watches[1]中的文件
// 注意:当watches内容被修改时,这时候应该重启obsidian,不然相当于开启了两个监控,因为是通过watches的内容来区分是否同一个监控的
// callback 第一个参数打开文件所在的leaf,第二个参数打开的文件路径
function onSomeFileOpened(watches, callback) {
const timerKey = encodeURIComponent(watches.toString());
if(!global[timerKey]) global[timerKey] = {};
const onActiveLeafChange = async (activeLeaf) => {
// 定时防止无效触发,只取最后一个触发
if(global[timerKey]?.lastOpenedLeafTimer) clearTimeout(global[timerKey].lastOpenedLeafTimer)
global[timerKey].lastOpenedLeafTimer = setTimeout(async () => {
// 获取文件路径
let filePath = activeLeaf?.view.getState()?.file
// 所有文件
if(watches === "all" || !watches) {
callback(activeLeaf, filePath);
}
// 排除文件
else if(watches[0] && watches[0] === "exclude" && watches[1] && watches[1].length > 0) {
if(!watches[1].includes(filePath)) {
callback(activeLeaf, filePath);
}
}
// 允许文件
else if(watches.includes(filePath)) {
callback(activeLeaf, filePath);
}
}, 42);
};
app.workspace.off("active-leaf-change", onActiveLeafChange);
app.workspace.on('active-leaf-change', onActiveLeafChange);
onActiveLeafChange(app.workspace.activeLeaf);
}
```
获取多语言文字和字段
// 获取语言类型,输出 'zh', 'en', 'zh-TW'等
i18next.language;
// 获取某种语言下的文字配置
i18next.getDataByLanguage(i18next.language);
// 比如,获取官方同步插件的"注册"按钮的文字
i18next.getDataByLanguage(i18next.language).default.plugins.sync["button-sign-up"];
// ribbon设置按钮文字
i18next.getDataByLanguage(i18next.language).default.interface.settings
//或通过下面方式获取
const Translate = i18next.t.bind(i18next);
Translate("plugins.file-explorer.action-change-sort")
选择文件对话框(仅支持桌面版)
const { dialog } = require('electron').remote;
// 设置只允许选择文件,'openDirectory' 用于选择目录,'multiSelections' 允许多选
const result = dialog.showOpenDialog({ properties: ['openFile'] })
//用户是否取消了选择(`canceled`)以及选择的文件路径数组(`filePaths`)
console.log(result.filePaths);
渲染 Markdown 到 HTML
感谢 @PlayerMiller 大佬提供
const string = `## demo\n**aaaaa**`;
const el = createDiv()
//path 可省略,通常用于处理文档中的相对路径
const path = app.workspace.getActiveFile().path
// ExcalidrawAutomate.obsidian在支持obsidian的插件中可以去掉ExcalidrawAutomate前缀
await ExcalidrawAutomate.obsidian.MarkdownRenderer.render(app, str, el, path)
console.log(el.innerHTML);
渲染 HTML 到 Markdown
obsidian.htmlToMarkdown(htmlContent)
Excalidraw 弹窗
//添加dropdown
let gridFrequency = 20;
const customControls = (container) => {
new ea.obsidian.Setting(container)
.setName(`Major grid frequency`)
.addDropdown(dropdown => {
[2,3,4,5,6,7,8,9,10].forEach(grid=>dropdown.addOption(grid,grid));
dropdown
.setValue(gridFrequency)
.onChange(value => {
gridFrequency = value;
})
})
}
// 弹窗输入框
const result = await utils.inputPrompt(
"Grid size?",
null,
"20",
null,
1,
false,
customControls
);
console.log(result);
advance-uri 获取 URI 参数
app.plugins.plugins["obsidian-advanced-uri"].lastParameters
版本 version
// 返回安装版本
require("electron").remote.app.getVersion()
// 返回obsidian版本
require("electron").ipcRenderer.sendSync("version")
// 更新
require("electron").ipcRenderer.sendSync("update")
// 检查更新
require("electron").ipcRenderer.sendSync("check-update")
// 禁止更新
require("electron").ipcRenderer.sendSync("disable-update")
// 重启
require("electron").ipcRenderer.sendSync("relaunch")
//获取用户目录
window.electron.ipcRenderer.sendSync("documents-dir")
//获取用户桌面目录
window.electron.ipcRenderer.sendSync("desktop-dir")
//打开沙盒仓库
electron.ipcRenderer.sendSync("sandbox")
//查看沙盒仓库路径
electron.ipcRenderer.sendSync("get-sandbox-vault-path")
// 执行js代码,第二个参数userGesture为true则可以将触发视为用户的操作
electron.webFrame.executeJavaScript('alert(1)')
//缩放网页,放大
var e = electron.webFrame.getZoomLevel();
< 3 && electron.webFrame.setZoomLevel(e + .5)
//缩小
e > -2.5 && electron.webFrame.setZoomLevel(e - .5)
//恢复缩放
electron.webFrame.setZoomLevel(0)
//打开搜索
e.workspace.activeEditor.showSearch(false)
//打开替换
e.workspace.activeEditor.showSearch(true)
//查看仓库列表
electron.ipcRenderer.sendSync("vault-list")
//打开仓库
window.electron.ipcRenderer.sendSync("vault-open", t.path, !1)
// 导出pdf
app.workspace.activeLeaf.view.printToPdf()
// 打开文件恢复窗口
app.internalPlugins.plugins['file-recovery'].instance.openModal()
打开悬浮搜索
// 打开悬浮搜索
// query查询字符串,isInHover是否是用hover editor
async function openFloatSearch(query, isInHover=true) {
const selected = app.workspace.activeLeaf.view.editor?.getSelection();
//const leaf = app.workspace.getLeaf('tab');
// 这种createLeafInParent方式可能有时会不成功
const leaf = app.workspace.createLeafInParent(app.workspace.floatingSplit);
await leaf.setViewState({
type: 'search',
active: false,
state: {
query: query || selected || ""
}
});
if(isInHover) app.plugins.plugins['obsidian-hover-editor'].convertLeafToPopover(leaf);
}
// 加上path:前缀仅搜索当前激活文件
openFloatSearch(`path:${app.workspace.getActiveFile()?.path} ${app.workspace.activeEditor?.getSelection()||""}`);
调用 ob 自带的 Markdown 编辑器,实时渲染 Markdown 示例(官方不推荐)
感谢 @PlayerMiller 大佬提供
//main.js
const createEditor = (app)=> {
const md = app.embedRegistry.embedByExtension.md({app, containerEl: createDiv()})
md.load(); md.editable = !0; md.showEditor()
const mEditor = Object.getPrototypeOf(Object.getPrototypeOf(md.editMode)).constructor
md.unload()
return e = new mEditor(app, createDiv(), {
app, scroll: 0, editMode: null,
get editor() { return e.editor },
showSearch() {},
toggleMode() {},
onMarkdownScroll() {},
getMode: ()=> 'source',
// get file() { return view.file },
// get path() { return view.file.path },
})
}
const test = (app, ob)=> new class extends ob.Modal {
constructor(app) { super(app); this.open() }
onOpen() {
const e = createEditor(app); e.set('**test**'); e.load()
e.containerEl.setCssProps({
width: '200px', height: '100px',
background: 'var(--background-secondary)',
})
this.containerEl.append(e.containerEl)
this.modalEl.style.display = 'none'
const value = myEditor.editor.getValue();
window.myEditor = e;
console.log(e, value)
}
}(app, ob)
const ob = require('obsidian')
module.exports = class extends ob.Plugin {
onload() {
this.addCommand({
id: 'new-editor-modal', name: 'New editor modal',
callback: async ()=> test(this.app, ob),
})
}
onunload() {}
}
以上仅供参考。
有知道更多api的大佬可继续补充。