mirror of
https://github.com/logseq/logseq.git
synced 2026-05-01 01:16:27 +00:00
Enhance/more ns plugin api (#4828)
* improve(plugin): WIP add settings schema * improve(plugin): add identity for settings modal * improve(plugin): WIP add settings input * fix(ui): scrollbar overlay of modal panel content * improve(plugin): WIP add more render types of setting item * improve(plugin): WIP polish settings items * improve(plugin): WIP settings list of plugins * improve(plugin): more settings types & polish releated ui * fix(plugin): sometimes disable plugin not work * improve(plugin): polish ui of plugin settings * fix(dev): warning of lint * improve(plugin): add api of settings changed * chore: build libs core * fix(ui): width of settings panel wrap * improve(plugin): separate layouts data from settings aio file * imporve(plugin): container size of single plugin settings * fix: add missing state * improve(plugin): add Git ns * improve(plugin): git related api * improve(api): type of git result * chore: build libs core * fix(dev): kondo lint * fix(plugin): use cdn sdk when js entry * chore: build libs core * fix(plugin): env condition * improve(plugin): add UI ns * fix(api): arguments of datascript query * enhance(api): manageable message instance of UI tools * enhance(api): WIP add experiments api * enhance(api): WIP add resources state of plugin * improve(plugin): add status of loading script resources * improve(plugin): more opts for script loader * improve(plugin): WIP add fenced code renderer hook * improve(plugin): fenced code renderer hook * fix(plugin): resource root path of plugin fs location * imporve(plugin): support local files for loading scripts * improve(plugin): types of expirements api * fix: typo of class * enhance(api): add namespace related apis * enhance(api): add linked refrences related apis * enhance(plugin): add sample links to related api comments * improve(plugin): add db changed hook & optimize strategy of caller for hooks * improve(plugin): compatible commands registration for old sdk * improve(plugin): collect user sdk version for plugin local * improve(plugin): add internal callable apis for user sdk * chore(plugin): missing files & bump libs version * improve(plugin): compatiable for old sdk about hook messaging optimization * improve(plugin): db hook optimization for old sdk * enhance(ux): auto focus searchbar when open plugins list * improve(plugin): api of a hook from specific block changed event * improve(plugin): api of db block change hook * improve(plugin): add show bracket user config of api * improve(plugin): api of db block change hook * fix(api): toggle collapsed of block * improve(api): try to init grpah with git before exec git commands * improve(plugin): attributes of sandbox container * improve(dev): support register command with keybinding * improve(plugin): add api of register shortcut command * fix(plugin): reubild slash commands when new command registration * fix(dev): lint * improve(dev): lint script of libs codebase * chore(dev): remove useless codes * improve(plugin):sanitize path string of plugin repo value * fix(plugin): rebuild commands list when unregister a plugin * fix(ui): overflow width of query result table * chore: rebuild libs core * improve(plugin): add assets related apis * chore: rebuild libs core * improve(plugin): support replace state of into block in page api * improve(plugin): prepend/append child block in page * improve(plugin): polished exceptions message of plugin update/install * fix(plugin): update settings within gui * improve(ux): debounce change event of input for plugin settings gui * chore: rebuild libs core * enhance(plugin): catch exception of hook plugin
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
import { deepMerge, mergeSettingsWithSchema, safetyPathJoin } from './helpers'
|
||||
import {
|
||||
deepMerge,
|
||||
mergeSettingsWithSchema,
|
||||
safeSnakeCase,
|
||||
safetyPathJoin,
|
||||
} from './helpers'
|
||||
import { LSPluginCaller } from './LSPlugin.caller'
|
||||
import {
|
||||
IAppProxy, IDBProxy,
|
||||
IAppProxy,
|
||||
IDBProxy,
|
||||
IEditorProxy,
|
||||
ILSPluginUser,
|
||||
LSPluginBaseInfo,
|
||||
@@ -10,19 +16,33 @@ import {
|
||||
BlockCommandCallback,
|
||||
StyleString,
|
||||
ThemeOptions,
|
||||
UIOptions, IHookEvent, BlockIdentity,
|
||||
UIOptions,
|
||||
IHookEvent,
|
||||
BlockIdentity,
|
||||
BlockPageName,
|
||||
UIContainerAttrs, SimpleCommandCallback, SimpleCommandKeybinding, SettingSchemaDesc, IUserOffHook
|
||||
UIContainerAttrs,
|
||||
SimpleCommandCallback,
|
||||
SimpleCommandKeybinding,
|
||||
SettingSchemaDesc,
|
||||
IUserOffHook,
|
||||
IGitProxy,
|
||||
IUIProxy,
|
||||
UserProxyTags,
|
||||
BlockUUID,
|
||||
BlockEntity,
|
||||
IDatom,
|
||||
IAssetsProxy,
|
||||
} from './LSPlugin'
|
||||
import Debug from 'debug'
|
||||
import * as CSS from 'csstype'
|
||||
import { snakeCase } from 'snake-case'
|
||||
import EventEmitter from 'eventemitter3'
|
||||
import { LSPluginFileStorage } from './modules/LSPlugin.Storage'
|
||||
import { LSPluginExperiments } from './modules/LSPlugin.Experiments'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__LSP__HOST__: boolean
|
||||
logseq: LSPluginUser
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,14 +54,14 @@ const debug = Debug('LSPlugin:user')
|
||||
* @param opts
|
||||
* @param action
|
||||
*/
|
||||
function registerSimpleCommand (
|
||||
function registerSimpleCommand(
|
||||
this: LSPluginUser,
|
||||
type: string,
|
||||
opts: {
|
||||
key: string,
|
||||
label: string,
|
||||
desc?: string,
|
||||
palette?: boolean,
|
||||
key: string
|
||||
label: string
|
||||
desc?: string
|
||||
palette?: boolean
|
||||
keybinding?: SimpleCommandKeybinding
|
||||
},
|
||||
action: SimpleCommandCallback
|
||||
@@ -57,40 +77,62 @@ function registerSimpleCommand (
|
||||
|
||||
this.caller?.call(`api:call`, {
|
||||
method: 'register-plugin-simple-command',
|
||||
args: [this.baseInfo.id, [{ key, label, type, desc, keybinding }, ['editor/hook', eventKey]], palette]
|
||||
args: [
|
||||
this.baseInfo.id,
|
||||
[{ key, label, type, desc, keybinding }, ['editor/hook', eventKey]],
|
||||
palette,
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
const app: Partial<IAppProxy> = {
|
||||
registerCommand: registerSimpleCommand,
|
||||
|
||||
registerCommandPalette (
|
||||
opts: { key: string; label: string, keybinding?: SimpleCommandKeybinding },
|
||||
action: SimpleCommandCallback) {
|
||||
|
||||
registerCommandPalette(
|
||||
opts: { key: string; label: string; keybinding?: SimpleCommandKeybinding },
|
||||
action: SimpleCommandCallback
|
||||
) {
|
||||
const { key, label, keybinding } = opts
|
||||
const group = 'global-palette-command'
|
||||
const group = '$palette$'
|
||||
|
||||
return registerSimpleCommand.call(
|
||||
this, group,
|
||||
this,
|
||||
group,
|
||||
{ key, label, palette: true, keybinding },
|
||||
action)
|
||||
action
|
||||
)
|
||||
},
|
||||
|
||||
registerUIItem (
|
||||
registerCommandShortcut(
|
||||
keybinding: SimpleCommandKeybinding,
|
||||
action: SimpleCommandCallback
|
||||
) {
|
||||
const { binding } = keybinding
|
||||
const group = '$shortcut$'
|
||||
const key = group + safeSnakeCase(binding)
|
||||
|
||||
return registerSimpleCommand.call(
|
||||
this,
|
||||
group,
|
||||
{ key, palette: false, keybinding },
|
||||
action
|
||||
)
|
||||
},
|
||||
|
||||
registerUIItem(
|
||||
type: 'toolbar' | 'pagebar',
|
||||
opts: { key: string, template: string }
|
||||
opts: { key: string; template: string }
|
||||
) {
|
||||
const pid = this.baseInfo.id
|
||||
// opts.key = `${pid}_${opts.key}`
|
||||
|
||||
this.caller?.call(`api:call`, {
|
||||
method: 'register-plugin-ui-item',
|
||||
args: [pid, type, opts]
|
||||
args: [pid, type, opts],
|
||||
})
|
||||
},
|
||||
|
||||
registerPageMenuItem (
|
||||
registerPageMenuItem(
|
||||
this: LSPluginUser,
|
||||
tag: string,
|
||||
action: (e: IHookEvent & { page: string }) => void
|
||||
@@ -103,29 +145,34 @@ const app: Partial<IAppProxy> = {
|
||||
const label = tag
|
||||
const type = 'page-menu-item'
|
||||
|
||||
registerSimpleCommand.call(this,
|
||||
type, {
|
||||
key, label
|
||||
}, action)
|
||||
registerSimpleCommand.call(
|
||||
this,
|
||||
type,
|
||||
{
|
||||
key,
|
||||
label,
|
||||
},
|
||||
action
|
||||
)
|
||||
},
|
||||
|
||||
setFullScreen (flag) {
|
||||
setFullScreen(flag) {
|
||||
const sf = (...args) => this._callWin('setFullScreen', ...args)
|
||||
|
||||
if (flag === 'toggle') {
|
||||
this._callWin('isFullScreen').then(r => {
|
||||
this._callWin('isFullScreen').then((r) => {
|
||||
r ? sf() : sf(true)
|
||||
})
|
||||
} else {
|
||||
flag ? sf(true) : sf()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let registeredCmdUid = 0
|
||||
|
||||
const editor: Partial<IEditorProxy> = {
|
||||
registerSlashCommand (
|
||||
registerSlashCommand(
|
||||
this: LSPluginUser,
|
||||
tag: string,
|
||||
actions: BlockCommandCallback | Array<SlashCommandAction>
|
||||
@@ -136,7 +183,7 @@ const editor: Partial<IEditorProxy> = {
|
||||
actions = [
|
||||
['editor/clear-current-slash', false],
|
||||
['editor/restore-saved-cursor'],
|
||||
['editor/hook', actions]
|
||||
['editor/hook', actions],
|
||||
]
|
||||
}
|
||||
|
||||
@@ -169,11 +216,11 @@ const editor: Partial<IEditorProxy> = {
|
||||
|
||||
this.caller?.call(`api:call`, {
|
||||
method: 'register-plugin-slash-command',
|
||||
args: [this.baseInfo.id, [tag, actions]]
|
||||
args: [this.baseInfo.id, [tag, actions]],
|
||||
})
|
||||
},
|
||||
|
||||
registerBlockContextMenuItem (
|
||||
registerBlockContextMenuItem(
|
||||
this: LSPluginUser,
|
||||
tag: string,
|
||||
action: BlockCommandCallback
|
||||
@@ -186,30 +233,68 @@ const editor: Partial<IEditorProxy> = {
|
||||
const label = tag
|
||||
const type = 'block-context-menu-item'
|
||||
|
||||
registerSimpleCommand.call(this,
|
||||
type, {
|
||||
key, label
|
||||
}, action)
|
||||
registerSimpleCommand.call(
|
||||
this,
|
||||
type,
|
||||
{
|
||||
key,
|
||||
label,
|
||||
},
|
||||
action
|
||||
)
|
||||
},
|
||||
|
||||
scrollToBlockInPage (
|
||||
scrollToBlockInPage(
|
||||
this: LSPluginUser,
|
||||
pageName: BlockPageName,
|
||||
blockId: BlockIdentity
|
||||
blockId: BlockIdentity,
|
||||
opts?: { replaceState: boolean }
|
||||
) {
|
||||
const anchor = `block-content-` + blockId
|
||||
this.App.pushState(
|
||||
'page',
|
||||
{ name: pageName },
|
||||
{ anchor }
|
||||
)
|
||||
}
|
||||
if (opts?.replaceState) {
|
||||
this.App.replaceState('page', { name: pageName }, { anchor })
|
||||
} else {
|
||||
this.App.pushState('page', { name: pageName }, { anchor })
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const db: Partial<IDBProxy> = {}
|
||||
const db: Partial<IDBProxy> = {
|
||||
onBlockChanged(
|
||||
this: LSPluginUser,
|
||||
uuid: BlockUUID,
|
||||
callback: (
|
||||
block: BlockEntity,
|
||||
txData: Array<IDatom>,
|
||||
txMeta?: { outlinerOp: string; [p: string]: any }
|
||||
) => void
|
||||
): IUserOffHook {
|
||||
const pid = this.baseInfo.id
|
||||
const hook = `hook:db:${safeSnakeCase(`block:${uuid}`)}`
|
||||
const aBlockChange = ({ block, txData, txMeta }) => {
|
||||
if (block.uuid !== uuid) {
|
||||
return
|
||||
}
|
||||
|
||||
callback(block, txData, txMeta)
|
||||
}
|
||||
|
||||
this.caller.on(hook, aBlockChange)
|
||||
this.App._installPluginHook(pid, hook)
|
||||
|
||||
return () => {
|
||||
this.caller.off(hook, aBlockChange)
|
||||
this.App._uninstallPluginHook(pid, hook)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const git: Partial<IGitProxy> = {}
|
||||
const ui: Partial<IUIProxy> = {}
|
||||
const assets: Partial<IAssetsProxy> = {}
|
||||
|
||||
type uiState = {
|
||||
key?: number,
|
||||
key?: number
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
@@ -219,7 +304,12 @@ const KEY_MAIN_UI = 0
|
||||
* User plugin instance
|
||||
* @public
|
||||
*/
|
||||
export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements ILSPluginUser {
|
||||
export class LSPluginUser
|
||||
extends EventEmitter<LSPluginUserEvents>
|
||||
implements ILSPluginUser {
|
||||
// @ts-ignore
|
||||
private _version: string = LIB_VERSION
|
||||
private _debugTag: string = ''
|
||||
private _settingsSchema?: Array<SettingSchemaDesc>
|
||||
private _connected: boolean = false
|
||||
|
||||
@@ -229,7 +319,8 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
*/
|
||||
private _ui = new Map<number, uiState>()
|
||||
|
||||
private readonly _fileStorage: LSPluginFileStorage
|
||||
private _mFileStorage: LSPluginFileStorage
|
||||
private _mExperiments: LSPluginExperiments
|
||||
|
||||
/**
|
||||
* handler of before unload plugin
|
||||
@@ -241,7 +332,7 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
* @param _baseInfo
|
||||
* @param _caller
|
||||
*/
|
||||
constructor (
|
||||
constructor(
|
||||
private _baseInfo: LSPluginBaseInfo,
|
||||
private _caller: LSPluginCaller
|
||||
) {
|
||||
@@ -264,22 +355,16 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
const cb = this._beforeunloadCallback
|
||||
|
||||
try {
|
||||
cb && await cb(rest)
|
||||
cb && (await cb(rest))
|
||||
actor?.resolve(null)
|
||||
} catch (e) {
|
||||
console.debug(`${_caller.debugTag} [beforeunload] `, e)
|
||||
actor?.reject(e)
|
||||
}
|
||||
})
|
||||
|
||||
// modules
|
||||
this._fileStorage = new LSPluginFileStorage(this)
|
||||
}
|
||||
|
||||
async ready (
|
||||
model?: any,
|
||||
callback?: any
|
||||
) {
|
||||
async ready(model?: any, callback?: any) {
|
||||
if (this._connected) return
|
||||
|
||||
try {
|
||||
@@ -296,7 +381,8 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
|
||||
if (this._settingsSchema) {
|
||||
baseInfo.settings = mergeSettingsWithSchema(
|
||||
baseInfo.settings, this._settingsSchema
|
||||
baseInfo.settings,
|
||||
this._settingsSchema
|
||||
)
|
||||
|
||||
// TODO: sync host settings schema
|
||||
@@ -304,50 +390,56 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
}
|
||||
|
||||
if (baseInfo?.id) {
|
||||
this._caller.debugTag = `#${baseInfo.id} [${baseInfo.name}]`
|
||||
this._debugTag =
|
||||
this._caller.debugTag = `#${baseInfo.id} [${baseInfo.name}]`
|
||||
}
|
||||
|
||||
await this._execCallableAPIAsync('setSDKMetadata', {
|
||||
version: this._version,
|
||||
})
|
||||
|
||||
callback && callback.call(this, baseInfo)
|
||||
} catch (e) {
|
||||
console.error('[LSPlugin Ready Error]', e)
|
||||
console.error(`${this._debugTag} [Ready Error]`, e)
|
||||
}
|
||||
}
|
||||
|
||||
ensureConnected () {
|
||||
ensureConnected() {
|
||||
if (!this._connected) {
|
||||
throw new Error('not connected')
|
||||
}
|
||||
}
|
||||
|
||||
beforeunload (callback: (e: any) => Promise<void>): void {
|
||||
beforeunload(callback: (e: any) => Promise<void>): void {
|
||||
if (typeof callback !== 'function') return
|
||||
this._beforeunloadCallback = callback
|
||||
}
|
||||
|
||||
provideModel (model: Record<string, any>) {
|
||||
provideModel(model: Record<string, any>) {
|
||||
this.caller._extendUserModel(model)
|
||||
return this
|
||||
}
|
||||
|
||||
provideTheme (theme: ThemeOptions) {
|
||||
provideTheme(theme: ThemeOptions) {
|
||||
this.caller.call('provider:theme', theme)
|
||||
return this
|
||||
}
|
||||
|
||||
provideStyle (style: StyleString) {
|
||||
provideStyle(style: StyleString) {
|
||||
this.caller.call('provider:style', style)
|
||||
return this
|
||||
}
|
||||
|
||||
provideUI (ui: UIOptions) {
|
||||
provideUI(ui: UIOptions) {
|
||||
this.caller.call('provider:ui', ui)
|
||||
return this
|
||||
}
|
||||
|
||||
useSettingsSchema (schema: Array<SettingSchemaDesc>) {
|
||||
useSettingsSchema(schema: Array<SettingSchemaDesc>) {
|
||||
if (this.connected) {
|
||||
this.caller.call('settings:schema', {
|
||||
schema, isSync: true
|
||||
schema,
|
||||
isSync: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -355,48 +447,56 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
return this
|
||||
}
|
||||
|
||||
updateSettings (attrs: Record<string, any>) {
|
||||
updateSettings(attrs: Record<string, any>) {
|
||||
this.caller.call('settings:update', attrs)
|
||||
// TODO: update associated baseInfo settings
|
||||
}
|
||||
|
||||
onSettingsChanged<T = any> (cb: (a: T, b: T) => void): IUserOffHook {
|
||||
onSettingsChanged<T = any>(cb: (a: T, b: T) => void): IUserOffHook {
|
||||
const type = 'settings:changed'
|
||||
this.on(type, cb)
|
||||
return () => this.off(type, cb)
|
||||
}
|
||||
|
||||
showSettingsUI () {
|
||||
showSettingsUI() {
|
||||
this.caller.call('settings:visible:changed', { visible: true })
|
||||
}
|
||||
|
||||
hideSettingsUI () {
|
||||
hideSettingsUI() {
|
||||
this.caller.call('settings:visible:changed', { visible: false })
|
||||
}
|
||||
|
||||
setMainUIAttrs (attrs: Partial<UIContainerAttrs>): void {
|
||||
setMainUIAttrs(attrs: Partial<UIContainerAttrs>): void {
|
||||
this.caller.call('main-ui:attrs', attrs)
|
||||
}
|
||||
|
||||
setMainUIInlineStyle (style: CSS.Properties): void {
|
||||
setMainUIInlineStyle(style: CSS.Properties): void {
|
||||
this.caller.call('main-ui:style', style)
|
||||
}
|
||||
|
||||
hideMainUI (opts?: { restoreEditingCursor: boolean }): void {
|
||||
const payload = { key: KEY_MAIN_UI, visible: false, cursor: opts?.restoreEditingCursor }
|
||||
hideMainUI(opts?: { restoreEditingCursor: boolean }): void {
|
||||
const payload = {
|
||||
key: KEY_MAIN_UI,
|
||||
visible: false,
|
||||
cursor: opts?.restoreEditingCursor,
|
||||
}
|
||||
this.caller.call('main-ui:visible', payload)
|
||||
this.emit('ui:visible:changed', payload)
|
||||
this._ui.set(payload.key, payload)
|
||||
}
|
||||
|
||||
showMainUI (opts?: { autoFocus: boolean }): void {
|
||||
const payload = { key: KEY_MAIN_UI, visible: true, autoFocus: opts?.autoFocus }
|
||||
showMainUI(opts?: { autoFocus: boolean }): void {
|
||||
const payload = {
|
||||
key: KEY_MAIN_UI,
|
||||
visible: true,
|
||||
autoFocus: opts?.autoFocus,
|
||||
}
|
||||
this.caller.call('main-ui:visible', payload)
|
||||
this.emit('ui:visible:changed', payload)
|
||||
this._ui.set(payload.key, payload)
|
||||
}
|
||||
|
||||
toggleMainUI (): void {
|
||||
toggleMainUI(): void {
|
||||
const payload = { key: KEY_MAIN_UI, toggle: true }
|
||||
const state = this._ui.get(payload.key)
|
||||
if (state && state.visible) {
|
||||
@@ -406,28 +506,32 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
}
|
||||
}
|
||||
|
||||
get isMainUIVisible (): boolean {
|
||||
get version(): string {
|
||||
return this._version
|
||||
}
|
||||
|
||||
get isMainUIVisible(): boolean {
|
||||
const state = this._ui.get(KEY_MAIN_UI)
|
||||
return Boolean(state && state.visible)
|
||||
}
|
||||
|
||||
get connected (): boolean {
|
||||
get connected(): boolean {
|
||||
return this._connected
|
||||
}
|
||||
|
||||
get baseInfo (): LSPluginBaseInfo {
|
||||
get baseInfo(): LSPluginBaseInfo {
|
||||
return this._baseInfo
|
||||
}
|
||||
|
||||
get settings () {
|
||||
get settings() {
|
||||
return this.baseInfo?.settings
|
||||
}
|
||||
|
||||
get caller (): LSPluginCaller {
|
||||
get caller(): LSPluginCaller {
|
||||
return this._caller
|
||||
}
|
||||
|
||||
resolveResourceFullUrl (filePath: string) {
|
||||
resolveResourceFullUrl(filePath: string) {
|
||||
this.ensureConnected()
|
||||
if (!filePath) return
|
||||
filePath = filePath.replace(/^[.\\/]+/, '')
|
||||
@@ -437,20 +541,17 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_makeUserProxy (
|
||||
target: any,
|
||||
tag?: 'app' | 'editor' | 'db'
|
||||
) {
|
||||
_makeUserProxy(target: any, tag?: UserProxyTags) {
|
||||
const that = this
|
||||
const caller = this.caller
|
||||
|
||||
return new Proxy(target, {
|
||||
get (target: any, propKey, receiver) {
|
||||
get(target: any, propKey, receiver) {
|
||||
const origMethod = target[propKey]
|
||||
|
||||
return function (this: any, ...args: any) {
|
||||
if (origMethod) {
|
||||
const ret = origMethod.apply(that, args)
|
||||
const ret = origMethod.apply(that, args.concat(tag))
|
||||
if (ret !== PROXY_CONTINUE) return
|
||||
}
|
||||
|
||||
@@ -462,50 +563,96 @@ export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements IL
|
||||
const f = hookMatcher[0].toLowerCase()
|
||||
const s = hookMatcher.input!
|
||||
const e = s.slice(f.length)
|
||||
const isOff = f === 'off'
|
||||
const pid = that.baseInfo.id
|
||||
|
||||
const type = `hook:${tag}:${snakeCase(e)}`
|
||||
const type = `hook:${tag}:${safeSnakeCase(e)}`
|
||||
const handler = args[0]
|
||||
caller[f](type, handler)
|
||||
return f !== 'off' ? () => (caller.off(type, handler)) : void 0
|
||||
|
||||
if (isOff) {
|
||||
return () => {
|
||||
caller.off(type, handler)
|
||||
that.App._uninstallPluginHook(pid, type)
|
||||
}
|
||||
} else {
|
||||
return that.App._installPluginHook(pid, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let method = propKey as string
|
||||
|
||||
if ((['git', 'ui', 'assets'] as UserProxyTags[]).includes(tag)) {
|
||||
method = tag + '_' + method
|
||||
}
|
||||
|
||||
// Call host
|
||||
return caller.callAsync(`api:call`, {
|
||||
tag, method: propKey, args: args
|
||||
tag,
|
||||
method,
|
||||
args: args,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
_callWin (...args) {
|
||||
_execCallableAPIAsync(method, ...args) {
|
||||
return this._caller.callAsync(`api:call`, {
|
||||
method: '_callMainWin',
|
||||
args: args
|
||||
method,
|
||||
args,
|
||||
})
|
||||
}
|
||||
|
||||
_execCallableAPI(method, ...args) {
|
||||
this._caller.call(`api:call`, {
|
||||
method,
|
||||
args,
|
||||
})
|
||||
}
|
||||
|
||||
_callWin(...args) {
|
||||
return this._execCallableAPIAsync(`_callMainWin`, ...args)
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface methods of {@link IAppProxy}
|
||||
*/
|
||||
get App (): IAppProxy {
|
||||
get App(): IAppProxy {
|
||||
return this._makeUserProxy(app, 'app')
|
||||
}
|
||||
|
||||
get Editor (): IEditorProxy {
|
||||
get Editor(): IEditorProxy {
|
||||
return this._makeUserProxy(editor, 'editor')
|
||||
}
|
||||
|
||||
get DB (): IDBProxy {
|
||||
return this._makeUserProxy(db)
|
||||
get DB(): IDBProxy {
|
||||
return this._makeUserProxy(db, 'db')
|
||||
}
|
||||
|
||||
get FileStorage (): LSPluginFileStorage {
|
||||
return this._fileStorage
|
||||
get Git(): IGitProxy {
|
||||
return this._makeUserProxy(git, 'git')
|
||||
}
|
||||
|
||||
get UI(): IUIProxy {
|
||||
return this._makeUserProxy(ui, 'ui')
|
||||
}
|
||||
|
||||
get Assets(): IAssetsProxy {
|
||||
return this._makeUserProxy(assets, 'assets')
|
||||
}
|
||||
|
||||
get FileStorage(): LSPluginFileStorage {
|
||||
let m = this._mFileStorage
|
||||
if (!m) m = this._mFileStorage = new LSPluginFileStorage(this)
|
||||
return m
|
||||
}
|
||||
|
||||
get Experiments(): LSPluginExperiments {
|
||||
let m = this._mExperiments
|
||||
if (!m) m = this._mExperiments = new LSPluginExperiments(this)
|
||||
return m
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,15 +661,15 @@ export * from './LSPlugin'
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function setupPluginUserInstance (
|
||||
export function setupPluginUserInstance(
|
||||
pluginBaseInfo: LSPluginBaseInfo,
|
||||
pluginCaller: LSPluginCaller
|
||||
) {
|
||||
return new LSPluginUser(pluginBaseInfo, pluginCaller)
|
||||
}
|
||||
|
||||
if (window.__LSP__HOST__ == null) { // Entry of iframe mode
|
||||
// entry of iframe mode
|
||||
if (window.__LSP__HOST__ == null) {
|
||||
const caller = new LSPluginCaller(null)
|
||||
// @ts-ignore
|
||||
window.logseq = setupPluginUserInstance({} as any, caller)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user