一、前情提要:
思源的 URL scheme 能够通过块超链接做到唤起思源并打开指定的块,然后还能。。。。。。。。。。
额,好像然后就不能做什么了。
所以这次我们就来尝试一下扩展一下思源的 URL Scheme
二、实现原理
1、ipcRenderer
可以先在代码片段里面测试一下这段代码:
const {ipcRenderer} = require('electron')
ipcRenderer.on('siyuan-openurl',(event,msg)=>{
console.log(event,msg)
})
随便在什么地方打开一个思源的块超链接,就可以看到在控制台的输出了:
啊,可以看到后面的 msg
参数就是块超链接的内容~~~。
这是为什么呢?
之前我们说过,思源的 main.js
里面是可以直接看到内容的,这里可以看一下第 771 到 799 行:
app.on('open-url', (event, url) => { // for macOS
if (url.startsWith('siyuan://')) {
siyuanOpenURL = url
if (mainWindow && !mainWindow.isDestroyed()) {
if (mainWindow.isMinimized()) {
mainWindow.restore()
}
if (!mainWindow.isVisible()) {
mainWindow.show()
}
mainWindow.focus()
mainWindow.webContents.send('siyuan-openurl', url)
}
}
})
app.on('second-instance', (event, commandLine) => {
if (mainWindow && !mainWindow.isDestroyed()) {
if (mainWindow.isMinimized()) {
mainWindow.restore()
}
if (!mainWindow.isVisible()) {
mainWindow.show()
}
mainWindow.focus()
mainWindow.webContents.send('siyuan-openurl',
commandLine.find((arg) => arg.startsWith('siyuan://')))
}
})
这两个地方就是通过进程间通信,把块超链接的内容发送给了思源的主界面。
所以我们可以通过监听这个 siyuan-openurl
信道来获取 url 的内容。
有关 ipcRenderer 之类的参考 electorn 的文档:
ipcRenderer | Electron (electronjs.org)
其实就是用来通信的嘛
2、URL 对象
这个其实就是冷饭了,之前在实现白板的时候不是用了一个解析 URL 参数的对象嘛,这次要使用的就是那个:
思源笔记折腾记录 - 做一个白板 - 保存数据和显示模式 - 链滴 (ld246.com)
之前是这样写的:
export function 获取地址参数(){
let 中间变量 = {}
new URL(window.location.href).searchParams.forEach(
(value,key)=>{中间变量[key]=value}
)
return 中间变量
}
那么很容易就想到,只要把这个函数跟上面的那个结合一下,就可以了:
const {ipcRenderer} = require('electron')
ipcRenderer.on('siyuan-openurl',(event,msg)=>{
执行URL(msg)
})
function 执行URL(url){
let url 对象 = new URL(url)
console.log(url对象)
}
可以看到 url 对象上有这么些属性:
这样我们就可以它进行进一步的操作了。
3、注册动作
首先我们假设,一个类似:
siyuan://<路径>/<下级路径>?<参数>
的 url。
它最开始的路径名就是要执行的动作,下级路径和 url 的 searchParams 都直接传递给对应的回调函数。
这样我们就能开始注册回调了:
const url动作注册表 = []
const { ipcRenderer } = require('electron')
ipcRenderer.on('siyuan-openurl', (event, msg) => {
执行URL(msg)
})
function 执行URL(url) {
let url对象 = new URL(url)
let 路径名 = url对象.pathname.replace('//', '').split('/')[0]
let 搜索参数 = {}
url对象.searchParams.forEach(
(value, key) => { 搜索参数[key] = value }
)
console.log(路径名, 搜索参数)
url动作注册表.forEach(
注册表项 => {
console.log(注册表项.动作 === 路径名)
if (注册表项.动作 === 路径名) {
try {
(async () => { 注册表项.回调函数(url对象.pathname.replace('//', ''), JSON.parse(JSON.stringify(搜索参数))) })()
} catch (e) {
console.warn(e)
}
}
}
)
}
function 注册url动作(动作, 回调函数) {
url动作注册表.push({ 动作: 动作, 回调函数: 回调函数 })
}
注册url动作('blocks', (路径名, 参数) => { console.log('你点击的是',路径名, 参数) })
啊,我就随便注册一个函数试试。。。。。
现在点击一个块超链接,啊不对,现在应该叫超级块超链接,因为它的战斗力已经超过 114514 了,看一下输出就可以看到:
OK,收工。
把它挂载到 noobApi 上方便以后调用:
const url动作注册表 = []
if (window.require) {
const { ipcRenderer } = require('electron')
ipcRenderer.on('siyuan-openurl', (event, msg) => {
执行URL(msg)
})
function 执行URL(url) {
let url对象 = new URL(url)
let 路径名 = url对象.pathname.replace('//', '').split('/')[0]
let 搜索参数 = {}
url对象.searchParams.forEach(
(value, key) => { 搜索参数[key] = value }
)
console.log(路径名, 搜索参数)
url动作注册表.forEach(
注册表项 => {
console.log(注册表项.动作 === 路径名)
if (注册表项.动作 === 路径名) {
try {
(async () => { 注册表项.回调函数(url对象.pathname.replace('//', ''), JSON.parse(JSON.stringify(搜索参数))) })()
} catch (e) {
console.warn(e)
}
}
}
)
}
}
export default function 注册url动作(动作, 回调函数) {
url动作注册表.push({ 动作: 动作, 回调函数: 回调函数 })
}
4、试一试
注册一个打开当天日记的函数试试:
noobApi.url动作.注册url动作('DailyNote', () => {
noobApi.核心api.创建日记({
notebook
:
"20210808180117-czj9bvb"
})
})
效果就像这样
这样这个 issue 就能够自己动手撸啦:
丰富 siyuan://
协议动作,如创建文档 · Issue #6875 · siyuan-note/siyuan (github.com)
所谓折腾就是有 bug 要上,没有 bug,创造 bug 也要上嘛~~~
思考题:issue 里面提到的创建文档咋整?(其实就是换个接口而已。。。。。。)
代码片段的仓库在这里
leolee9086/snippets (github.com)
viteWdigets 的仓库在这里
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于