Files
logseq/libs/src/LSPlugin.shadow.ts
Charlie 79bc33e1e3 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
2022-04-21 18:43:16 +08:00

113 lines
2.5 KiB
TypeScript

import EventEmitter from 'eventemitter3'
import { PluginLocal } from './LSPlugin.core'
import { LSPluginUser } from './LSPlugin.user'
// @ts-ignore
const { importHTML, createSandboxContainer } = window.QSandbox || {}
function userFetch(url, opts) {
if (!url.startsWith('http')) {
url = url.replace('file://', '')
return new Promise(async (resolve, reject) => {
try {
const content = await window.apis.doAction(['readFile', url])
resolve({
text() {
return content
},
})
} catch (e) {
console.error(e)
reject(e)
}
})
}
return fetch(url, opts)
}
class LSPluginShadowFrame extends EventEmitter<'mounted' | 'unmounted'> {
private _frame?: HTMLElement
private _root?: ShadowRoot
private _loaded = false
private _unmountFns: Array<() => Promise<void>> = []
constructor(private _pluginLocal: PluginLocal) {
super()
_pluginLocal._dispose(() => {
this._unmount()
})
}
async load() {
const { name, entry } = this._pluginLocal.options
if (this.loaded || !entry) return
const { template, execScripts } = await importHTML(entry, {
fetch: userFetch,
})
this._mount(template, document.body)
const sandbox = createSandboxContainer(name, {
elementGetter: () => this._root?.firstChild,
})
const global = sandbox.instance.proxy as any
global.__shadow_mode__ = true
global.LSPluginLocal = this._pluginLocal
global.LSPluginShadow = this
global.LSPluginUser = global.logseq = new LSPluginUser(
this._pluginLocal.toJSON() as any,
this._pluginLocal.caller!
)
// TODO: {mount, unmount}
const execResult: any = await execScripts(global, true)
this._unmountFns.push(execResult.unmount)
this._loaded = true
}
_mount(content: string, container: HTMLElement) {
const frame = (this._frame = document.createElement('div'))
frame.classList.add('lsp-shadow-sandbox')
frame.id = this._pluginLocal.id
this._root = frame.attachShadow({ mode: 'open' })
this._root.innerHTML = `<div>${content}</div>`
container.appendChild(frame)
this.emit('mounted')
}
_unmount() {
for (const fn of this._unmountFns) {
fn && fn.call(null)
}
}
destroy() {
this.frame?.parentNode?.removeChild(this.frame)
}
get loaded(): boolean {
return this._loaded
}
get document() {
return this._root?.firstChild as HTMLElement
}
get frame(): HTMLElement {
return this._frame!
}
}
export { LSPluginShadowFrame }