-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.ts
107 lines (98 loc) · 3.13 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* eslint-disable no-console */
import Vue from 'vue'
import QWebChannel from './qwebchannel'
import { assert, isQtClient, log } from '@/shared/utils'
import {
dispatch,
createPusher,
createProp,
registerSignalListener
} from './helper'
import { QObjectMap, QObjectJSKeys, PusherJSKeys } from '@/config/bridge'
declare global {
interface Window {
qt: {
webChannelTransport: {
send: (payload: any) => void
onmessage: (payload: any) => void
}
}
}
}
/**
* @description Declaration Merging
* @doc https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
*/
declare module 'vue/types/vue' {
interface Vue {
prototype: {
$$pushers: QtPushersMap
$$props: QtPropsMap
}
}
}
// https://stackoverflow.com/questions/47181789/limit-object-properties-to-keyof-interface
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types
type QtPushersMap = {
[name in QObjectJSKeys]: ReturnType<typeof createPusher>
}
type QtPropsMap = Record<QObjectJSKeys, any>
export default {
install(Vue: Vue) {
if (!__DEV__) {
assert(
window && window.qt && window.qt.webChannelTransport,
"'qt' or 'qt.webChannelTransport' should be initialized(injected) by QtWebEngine"
)
}
if (__DEV__ && !isQtClient) {
window.qt = {
webChannelTransport: {
send() {
log('QWebChannel simulator activated !')
},
onmessage() {}
}
}
}
new QWebChannel(window.qt.webChannelTransport, function(channel) {
// NOTICE: all communication is under scope(QObject) mapping from Qt side
// You can also create your own single or multiple scope(QObject) which is similar with following logic.
const pushersMap = {} as QtPushersMap
const propsMap = {} as QtPropsMap
;(Object.keys(QObjectMap) as QObjectJSKeys[]).forEach(QObjectJSKey => {
const currentScope = channel.objects[QObjectMap[QObjectJSKey]]
pushersMap[QObjectJSKey] = createPusher(currentScope)
propsMap[QObjectJSKey] = createProp(currentScope)
registerSignalListener(currentScope)
})
/**
* @usage
* Call Cpp method in Vue instance:
* this.$$pusher.QObjectJSKey({
* action: 'JS_METHOD_NAME_MAPPING_QT_METHOD_NAME',
* payload: 'REQUEST_PAYLOAD'
* })
*
* get Cpp properties in Vue instance:
* this.$$prop.QObjectJSKey.propNameSameAsQtSideProperty
*/
Vue.prototype.$$pushers = pushersMap
Vue.prototype.$$props = propsMap
// First frontend navigation
// Why not use signal listener directly?
// 1. Qt side never known when frontend router is available until JS side
// push `loaded` message to Qt side positively.
// 2. This callback alway be called after router initialization
pushersMap
.jsSideQObjectMappingKey({
action: PusherJSKeys.jsSideMappingMethodName,
payload: 'PASS_PAYLOAD_TO_QT_SIDE'
})
.then(res => {
dispatch(res as string)
log('[PUSHER]: Bridge load!')
})
})
}
}