diff options
Diffstat (limited to 'src/webview/lib/RecipeWebview.ts')
-rw-r--r-- | src/webview/lib/RecipeWebview.ts | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/webview/lib/RecipeWebview.ts b/src/webview/lib/RecipeWebview.ts new file mode 100644 index 000000000..09dc462ed --- /dev/null +++ b/src/webview/lib/RecipeWebview.ts | |||
@@ -0,0 +1,177 @@ | |||
1 | import { ipcRenderer } from 'electron'; | ||
2 | import { BrowserWindow } from '@electron/remote'; | ||
3 | import { pathExistsSync, readFileSync, existsSync } from 'fs-extra'; | ||
4 | |||
5 | const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); | ||
6 | |||
7 | class RecipeWebview { | ||
8 | badgeHandler: any; | ||
9 | |||
10 | dialogTitleHandler: any; | ||
11 | |||
12 | notificationsHandler: any; | ||
13 | |||
14 | sessionHandler: any; | ||
15 | |||
16 | constructor( | ||
17 | badgeHandler, | ||
18 | dialogTitleHandler, | ||
19 | notificationsHandler, | ||
20 | sessionHandler, | ||
21 | ) { | ||
22 | this.badgeHandler = badgeHandler; | ||
23 | this.dialogTitleHandler = dialogTitleHandler; | ||
24 | this.notificationsHandler = notificationsHandler; | ||
25 | this.sessionHandler = sessionHandler; | ||
26 | |||
27 | ipcRenderer.on('poll', () => { | ||
28 | this.loopFunc(); | ||
29 | |||
30 | debug('Poll event'); | ||
31 | |||
32 | // This event is for checking if the service recipe is still actively | ||
33 | // communicating with the client | ||
34 | ipcRenderer.sendToHost('alive'); | ||
35 | }); | ||
36 | } | ||
37 | |||
38 | loopFunc = () => null; | ||
39 | |||
40 | darkModeHandler = false; | ||
41 | |||
42 | // TODO Remove this once we implement a proper wrapper. | ||
43 | get ipcRenderer() { | ||
44 | return ipcRenderer; | ||
45 | } | ||
46 | |||
47 | // TODO Remove this once we implement a proper wrapper. | ||
48 | get BrowserWindow() { | ||
49 | return BrowserWindow; | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * Initialize the loop | ||
54 | * | ||
55 | * @param {Function} Function that will be executed | ||
56 | */ | ||
57 | loop(fn) { | ||
58 | this.loopFunc = fn; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * Set the unread message badge | ||
63 | * | ||
64 | * @param {string | number | undefined | null} direct Set the count of direct messages | ||
65 | * eg. Slack direct mentions, or a | ||
66 | * message to @channel | ||
67 | * @param {string | number | undefined | null} indirect Set a badge that defines there are | ||
68 | * new messages but they do not involve | ||
69 | * me directly to me eg. in a channel | ||
70 | */ | ||
71 | setBadge(direct = 0, indirect = 0) { | ||
72 | this.badgeHandler.setBadge(direct, indirect); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * Set the active dialog title to the app title | ||
77 | * | ||
78 | * @param {string | undefined | null} title Set the active dialog title | ||
79 | * to the app title | ||
80 | * eg. WhatsApp contact name | ||
81 | */ | ||
82 | setDialogTitle(title) { | ||
83 | this.dialogTitleHandler.setDialogTitle(title); | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * Safely parse the given text into an integer | ||
88 | * | ||
89 | * @param {string | number | undefined | null} text to be parsed | ||
90 | */ | ||
91 | safeParseInt(text) { | ||
92 | return this.badgeHandler.safeParseInt(text); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * Injects the contents of a CSS file into the current webview | ||
97 | * | ||
98 | * @param {Array} files CSS files that should be injected. This must | ||
99 | * be an absolute path to the file | ||
100 | */ | ||
101 | injectCSS(...files) { | ||
102 | // eslint-disable-next-line unicorn/no-array-for-each | ||
103 | files.forEach(file => { | ||
104 | if (pathExistsSync(file)) { | ||
105 | const styles = document.createElement('style'); | ||
106 | styles.innerHTML = readFileSync(file, 'utf8'); | ||
107 | |||
108 | const head = document.querySelector('head'); | ||
109 | |||
110 | if (head) { | ||
111 | head.append(styles); | ||
112 | debug('Append styles', styles); | ||
113 | } | ||
114 | } | ||
115 | }); | ||
116 | } | ||
117 | |||
118 | injectJSUnsafe(...files) { | ||
119 | Promise.all( | ||
120 | files.map(file => { | ||
121 | if (existsSync(file)) { | ||
122 | return readFileSync(file, 'utf8'); | ||
123 | } | ||
124 | debug('Script not found', file); | ||
125 | return null; | ||
126 | }), | ||
127 | ).then(scripts => { | ||
128 | const scriptsFound = scripts.filter(script => script !== null); | ||
129 | if (scriptsFound.length > 0) { | ||
130 | debug('Inject scripts to main world', scriptsFound); | ||
131 | ipcRenderer.sendToHost('inject-js-unsafe', ...scriptsFound); | ||
132 | } | ||
133 | }); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * Set a custom handler for turning on and off dark mode | ||
138 | * | ||
139 | * @param {function} handler | ||
140 | */ | ||
141 | handleDarkMode(handler) { | ||
142 | this.darkModeHandler = handler; | ||
143 | } | ||
144 | |||
145 | onNotify(fn) { | ||
146 | if (typeof fn === 'function') { | ||
147 | this.notificationsHandler.onNotify = fn; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | initialize(fn) { | ||
152 | if (typeof fn === 'function') { | ||
153 | fn(); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | clearStorageData(serviceId, targetsToClear) { | ||
158 | ipcRenderer.send('clear-storage-data', { | ||
159 | serviceId, | ||
160 | targetsToClear, | ||
161 | }); | ||
162 | } | ||
163 | |||
164 | releaseServiceWorkers() { | ||
165 | this.sessionHandler.releaseServiceWorkers(); | ||
166 | } | ||
167 | |||
168 | setAvatarImage(avatarUrl) { | ||
169 | ipcRenderer.sendToHost('avatar', avatarUrl); | ||
170 | } | ||
171 | |||
172 | openNewWindow(url) { | ||
173 | ipcRenderer.sendToHost('new-window', url); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | export default RecipeWebview; | ||