experiments(dui3): cleanup
This commit is contained in:
@@ -28,7 +28,6 @@ export interface IBaseBinding {
|
||||
export interface IBaseBindingHostEvents {
|
||||
displayToastNotification: (args: ToastInfo) => void
|
||||
documentChanged: () => void
|
||||
selectionChanged: (args: SelectionChangedInfo) => void
|
||||
}
|
||||
|
||||
export type Account = {
|
||||
|
||||
@@ -18,7 +18,7 @@ export class BaseBridge {
|
||||
|
||||
// NOTE: this could be private - as it should be only used by the host application.
|
||||
emit(eventName: string, payload: string) {
|
||||
const parsedPayload = JSON.parse(payload) as unknown
|
||||
const parsedPayload = payload ? (JSON.parse(payload) as unknown) : null
|
||||
this.emitter.emit(eventName, parsedPayload)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// import { IWebUiBinding } from '~/types'
|
||||
// import { BaseBridge } from '~/lib/bridge/base'
|
||||
|
||||
// export class CefSharpBridge extends BaseBridge {
|
||||
// constructor(bindingObject: IWebUiBinding) {
|
||||
// super()
|
||||
// const hoistTarget = this as unknown as Record<string, unknown>
|
||||
// const hoistSource = bindingObject as unknown as Record<string, unknown>
|
||||
|
||||
// for (const key in bindingObject) {
|
||||
// hoistTarget[key] = hoistSource[key]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Defines the expected contract of the host application bound object.
|
||||
*/
|
||||
export type IRawBridge = {
|
||||
GetBindingsMethodNames: () => Promise<string[]>
|
||||
RunMethod: (methodName: string, args: string) => Promise<string>
|
||||
ShowDevTools: () => Promise<void>
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
// github.com/johot/WebView2-better-bridge/blob/master/web-ui/src/betterBridge.ts
|
||||
import { BaseBridge } from '~/lib/bridge/base'
|
||||
|
||||
export type IRawBridge = {
|
||||
GetBindingsMethodNames: () => Promise<string[]>
|
||||
RunMethod: (methodName: string, args: string) => Promise<string>
|
||||
ShowDevTools: () => Promise<void>
|
||||
}
|
||||
|
||||
import { IRawBridge } from '~/lib/bridge/definitions'
|
||||
/**
|
||||
* A generic bridge class for Webivew2 or CefSharp.
|
||||
*/
|
||||
export class GenericBridge extends BaseBridge {
|
||||
private bridge: IRawBridge
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
// github.com/johot/WebView2-better-bridge/blob/master/web-ui/src/betterBridge.ts
|
||||
import { BaseBridge } from '~/lib/bridge/base'
|
||||
|
||||
type IWebView2 = {
|
||||
webview: {
|
||||
hostObjects: Record<string, IRawBridge> & {
|
||||
sync: Record<string, IRawBridge>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type IRawBridge = {
|
||||
GetBindingsMethodNames: () => string[]
|
||||
RunMethod: (methodName: string, args: string) => Promise<string>
|
||||
}
|
||||
|
||||
declare let chrome: IWebView2
|
||||
|
||||
export class WebView2Bridge extends BaseBridge {
|
||||
private webViewBridge: IRawBridge
|
||||
|
||||
constructor(bridgeName: string) {
|
||||
super()
|
||||
this.webViewBridge = chrome.webview.hostObjects[bridgeName]
|
||||
|
||||
// NOTE: GetMethods is a call to the .NET side.
|
||||
const availableMethodNames =
|
||||
chrome.webview.hostObjects.sync[bridgeName].GetBindingsMethodNames()
|
||||
|
||||
// NOTE: hoisting original calls as lowerCasedMethodNames, but using the UpperCasedName for the .NET call
|
||||
// This allows us to follow js convetions and keep .NET ones too (eg. bindings.sayHi('') => public string SayHi(string name) {}
|
||||
for (const methodName of availableMethodNames) {
|
||||
const lowercasedMethodName = lowercaseMethodName(methodName)
|
||||
const hoistTarget = this as unknown as Record<string, object>
|
||||
hoistTarget[lowercasedMethodName] = (...args: unknown[]) =>
|
||||
this.runMethod(methodName, args)
|
||||
}
|
||||
}
|
||||
|
||||
private async runMethod(methodName: string, args: unknown[]): Promise<unknown> {
|
||||
const preserializedArgs = args.map((a) => JSON.stringify(a))
|
||||
// NOTE: RunMethod is a call to the .NET side.
|
||||
const result = await this.webViewBridge.RunMethod(
|
||||
methodName,
|
||||
JSON.stringify(preserializedArgs)
|
||||
)
|
||||
|
||||
return JSON.parse(result) as unknown
|
||||
}
|
||||
}
|
||||
|
||||
const lowercaseMethodName = (name: string) =>
|
||||
name.charAt(0).toLowerCase() + name.slice(1)
|
||||
@@ -0,0 +1,25 @@
|
||||
import { DocumentInfo } from '~/lib/bindings/definitions/baseBindings'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const DocumentInfoInjectionKey = 'DUI_ACCOUNTS_STATE'
|
||||
|
||||
export async function useDocumentInfoSetup() {
|
||||
const app = useNuxtApp()
|
||||
const documentInfo = ref<DocumentInfo>()
|
||||
|
||||
app.$baseBinding.on('documentChanged', () => {
|
||||
setTimeout(async () => {
|
||||
const docInfo = await app.$baseBinding.getDocumentInfo()
|
||||
documentInfo.value = docInfo
|
||||
}, 500) // Don't ask
|
||||
})
|
||||
|
||||
documentInfo.value = await app.$baseBinding.getDocumentInfo()
|
||||
provide(DocumentInfoInjectionKey, documentInfo)
|
||||
return documentInfo
|
||||
}
|
||||
|
||||
export function useInjectedDocumentInfo() {
|
||||
const documentInfo = inject<Ref<DocumentInfo>>(DocumentInfoInjectionKey)
|
||||
return documentInfo
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
<div class="mx-2 py-1 px-2 rounded text-xs bg-primary text-white font-bold">
|
||||
for {{ appName }}
|
||||
</div>
|
||||
<!-- <HeaderNavLink :to="'/'" :name="'Home'"></HeaderNavLink> -->
|
||||
</Portal>
|
||||
<div class="space-y-2">
|
||||
<div>
|
||||
@@ -18,13 +17,17 @@
|
||||
{{ acc.accountInfo.serverInfo.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div>Your default account is {{ defaultAccount?.accountInfo }}</div>
|
||||
<div>
|
||||
Your default account is at {{ defaultAccount?.accountInfo.serverInfo.url }}
|
||||
</div>
|
||||
<div>
|
||||
<div v-for="(res, clientId) in queries" :key="clientId">
|
||||
<strong>{{ clientId }}:</strong>
|
||||
{{ res.result.value?.serverInfo.version || res.error }}
|
||||
</div>
|
||||
</div>
|
||||
<div>Doc info:</div>
|
||||
<div>{{ documentInfo }}</div>
|
||||
<div>
|
||||
<FormButton @click="refreshAccounts()">Refresh Accounts</FormButton>
|
||||
</div>
|
||||
@@ -36,11 +39,14 @@ import { UseQueryReturn, useQuery } from '@vue/apollo-composable'
|
||||
import { useAccountsSetup } from '~/lib/accounts/composables/setup'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import { ServerInfoTestQuery } from '~/lib/common/generated/gql/graphql'
|
||||
import { useDocumentInfoSetup } from '~/lib/document-info'
|
||||
|
||||
const { $baseBinding } = useNuxtApp()
|
||||
const appName = await $baseBinding.getSourceApplicationName()
|
||||
const { accounts, refreshAccounts, defaultAccount } = await useAccountsSetup()
|
||||
|
||||
const documentInfo = await useDocumentInfoSetup()
|
||||
|
||||
const versionQuery = graphql(`
|
||||
query ServerInfoTest {
|
||||
serverInfo {
|
||||
@@ -49,10 +55,6 @@ const versionQuery = graphql(`
|
||||
}
|
||||
`)
|
||||
|
||||
watch(accounts, () => {
|
||||
console.log('accounts were refreshed, shallow ref does its job')
|
||||
})
|
||||
|
||||
const clientIds = accounts.value.map((a) => a.accountInfo.id)
|
||||
|
||||
const queries: Record<
|
||||
|
||||
@@ -1,75 +1,64 @@
|
||||
// import { IWebUiBinding, MockedBindings } from '~/types'
|
||||
// import { WebView2Bridge } from '~/lib/bridge/webview'
|
||||
// import { CefSharpBridge } from '~/lib/bridge/cefSharp'
|
||||
// import { SketchupBridge } from '~/lib/bridge/sketchup'
|
||||
import { GenericBridge } from '~/lib/bridge/generic'
|
||||
import { IRawBridge } from '~/lib/bridge/definitions'
|
||||
|
||||
// interface ICefSharp {
|
||||
// BindObjectAsync: (arg: string) => Promise<void>
|
||||
// }
|
||||
import {
|
||||
IBaseBinding,
|
||||
IRhinoRandomBinding
|
||||
} from '~/lib/bindings/definitions/baseBindings'
|
||||
|
||||
// interface IWebView2 {
|
||||
// webview: unknown
|
||||
// }
|
||||
// Makes TS happy
|
||||
declare let globalThis: Record<string, unknown> & {
|
||||
CefSharp?: { BindObjectAsync: (name: string) => Promise<void> }
|
||||
chrome?: { webview: { hostObjects: Record<string, IRawBridge> } }
|
||||
sketchup?: Record<string, unknown>
|
||||
}
|
||||
|
||||
// declare let CefSharp: ICefSharp
|
||||
// declare let chrome: IWebView2
|
||||
// declare let sketchup: Record<string, unknown>
|
||||
|
||||
// declare let WebUIBinding: IWebUiBinding
|
||||
|
||||
// Tries to find the correct host application binding. The sequence is:
|
||||
// - CEFSharp (.NET)
|
||||
// - WebView2 (.NET)
|
||||
// - Sketchup (Ruby) - NOT IMPLEMENTED
|
||||
/**
|
||||
* Here we are loading any bindings that we expect to have from all
|
||||
* connectors. If some are not present, that's okay - we're going to
|
||||
* strip or customize functionality from the ui itself.
|
||||
*/
|
||||
export default defineNuxtPlugin(async () => {
|
||||
// let bindings: IWebUiBinding | undefined = undefined
|
||||
// try {
|
||||
// if (!CefSharp) throw new Error('No global CefSharp object found.')
|
||||
// await CefSharp.BindObjectAsync('WebUIBinding')
|
||||
// console.info('Bound WebUIBinding object for CefSharp.')
|
||||
// bindings = new CefSharpBridge(WebUIBinding) as unknown as IWebUiBinding
|
||||
// } catch (e) {
|
||||
// console.warn(
|
||||
// 'Failed to bind CefSharp. This can be totally normal if the host is different.'
|
||||
// )
|
||||
// console.warn(e)
|
||||
// }
|
||||
// try {
|
||||
// if (!chrome.webview) throw new Error('No global Webview2 object found.')
|
||||
// bindings = new WebView2Bridge('WebUIBinding') as unknown as IWebUiBinding
|
||||
// console.info('Bound WebUIBinding object for Webview2.')
|
||||
// } catch (e) {
|
||||
// console.warn(
|
||||
// 'Failed to bind Webview2. This can be totally normal if the host is different.'
|
||||
// )
|
||||
// console.warn(e)
|
||||
// }
|
||||
// // The sketchup ruby side is in flux. We know though that
|
||||
// // this part will work! Nevertheless, it will currently throw if loaded in sketchup.
|
||||
// try {
|
||||
// if (!sketchup) throw new Error('No global sketchup object found.')
|
||||
// console.info('Found Sketchup. Hi SketchUp! We have yet... a lot of work to do :) ')
|
||||
// const skpBindings = new SketchupBridge('default_bindings')
|
||||
// // Note, because of the way Sketchup bindings work, we need to wait here
|
||||
// // for them to be fully initialized.
|
||||
// await skpBindings.isInitalized
|
||||
// bindings = skpBindings as unknown as IWebUiBinding
|
||||
// } catch (e) {
|
||||
// console.warn(
|
||||
// 'Failed to bind sketchup. This can be totally normal if the host is different.'
|
||||
// )
|
||||
// console.warn(e)
|
||||
// }
|
||||
// if (!bindings) {
|
||||
// console.warn('No bindings found - falling back to mocked bindings.')
|
||||
// bindings = MockedBindings
|
||||
// }
|
||||
// // We need the bindings object in global scope to allow
|
||||
// // host applications to send messages back to it.
|
||||
// ;(globalThis as Record<string, unknown>).bindings = bindings
|
||||
// return {
|
||||
// provide: {
|
||||
// bindings
|
||||
// }
|
||||
// }
|
||||
const baseBinding = await tryHoistBinding<IBaseBinding>('baseBinding')
|
||||
|
||||
const rhinoRandomBinding = await tryHoistBinding<IRhinoRandomBinding>(
|
||||
'rhinoRandomBinding'
|
||||
)
|
||||
|
||||
return {
|
||||
provide: {
|
||||
baseBinding,
|
||||
rhinoRandomBinding
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Checks possible browser window targets for a given binding, and, if it finds it,
|
||||
* creates a bridge for it and registers it in the global scope.
|
||||
* @param name binding name
|
||||
* @returns null if the binding was not found, or the binding.
|
||||
*/
|
||||
const tryHoistBinding = async <T>(name: string) => {
|
||||
let bridge: GenericBridge | null = null
|
||||
|
||||
if (globalThis.CefSharp) {
|
||||
await globalThis.CefSharp.BindObjectAsync(name)
|
||||
bridge = new GenericBridge(globalThis[name] as unknown as IRawBridge)
|
||||
await bridge.create()
|
||||
}
|
||||
|
||||
if (globalThis.chrome && !bridge) {
|
||||
bridge = new GenericBridge(globalThis.chrome.webview.hostObjects[name])
|
||||
await bridge.create()
|
||||
}
|
||||
|
||||
if (globalThis.sketchup && !bridge) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (!bridge) console.warn(`Failed to bind ${name} binding.`)
|
||||
|
||||
globalThis[name] = bridge
|
||||
return bridge as unknown as T
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { GenericBridge, IRawBridge } from '~/lib/bridge/generic'
|
||||
import {
|
||||
IBaseBinding,
|
||||
IRhinoRandomBinding
|
||||
} from '~/lib/bindings/definitions/baseBindings'
|
||||
|
||||
// Makes TS happy
|
||||
declare let globalThis: Record<string, unknown> & {
|
||||
CefSharp?: { BindObjectAsync: (name: string) => Promise<void> }
|
||||
chrome?: { webview: { hostObjects: Record<string, IRawBridge> } }
|
||||
sketchup?: Record<string, unknown>
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
const tryHoistBinding = async <T>(name: string) => {
|
||||
let bridge: GenericBridge | null = null
|
||||
|
||||
if (globalThis.CefSharp) {
|
||||
await globalThis.CefSharp.BindObjectAsync(name)
|
||||
bridge = new GenericBridge(globalThis[name] as unknown as IRawBridge)
|
||||
await bridge.create()
|
||||
}
|
||||
|
||||
if (globalThis.chrome && !bridge) {
|
||||
bridge = new GenericBridge(globalThis.chrome.webview.hostObjects[name])
|
||||
await bridge.create()
|
||||
}
|
||||
|
||||
if (globalThis.sketchup && !bridge) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (!bridge) console.warn(`Failed to bind ${name} binding.`)
|
||||
|
||||
globalThis[name] = bridge
|
||||
return bridge as unknown as T
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin(async () => {
|
||||
const baseBinding = await tryHoistBinding<IBaseBinding>('baseBinding')
|
||||
const rhinoRandomBinding = await tryHoistBinding<IRhinoRandomBinding>(
|
||||
'rhinoRandomBinding'
|
||||
)
|
||||
|
||||
return {
|
||||
provide: {
|
||||
baseBinding,
|
||||
rhinoRandomBinding
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user