aboutsummaryrefslogtreecommitdiffstats
path: root/src/webview/recipe.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/webview/recipe.js')
-rw-r--r--src/webview/recipe.js132
1 files changed, 73 insertions, 59 deletions
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index 8da45864b..d143675dc 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -1,11 +1,9 @@
1/* eslint-disable import/first */ 1/* eslint-disable import/first */
2import { ipcRenderer } from 'electron'; 2import { contextBridge, ipcRenderer } from 'electron';
3import { getCurrentWebContents } from '@electron/remote';
4import path from 'path'; 3import path from 'path';
5import { autorun, computed, observable } from 'mobx'; 4import { autorun, computed, observable } from 'mobx';
6import fs from 'fs-extra'; 5import fs from 'fs-extra';
7import { debounce } from 'lodash'; 6import { debounce } from 'lodash';
8import { FindInPage } from 'electron-find';
9 7
10// For some services darkreader tries to use the chrome extension message API 8// For some services darkreader tries to use the chrome extension message API
11// This will cause the service to fail loading 9// This will cause the service to fail loading
@@ -23,16 +21,81 @@ import customDarkModeCss from './darkmode/custom';
23import RecipeWebview from './lib/RecipeWebview'; 21import RecipeWebview from './lib/RecipeWebview';
24import Userscript from './lib/Userscript'; 22import Userscript from './lib/Userscript';
25 23
26import { switchDict, getSpellcheckerLocaleByFuzzyIdentifier } from './spellchecker'; 24import { BadgeHandler } from './badge';
27import { injectDarkModeStyle, isDarkModeStyleInjected, removeDarkModeStyle } from './darkmode';
28import contextMenu from './contextMenu'; 25import contextMenu from './contextMenu';
29import './notifications'; 26import { injectDarkModeStyle, isDarkModeStyleInjected, removeDarkModeStyle } from './darkmode';
30import { screenShareCss } from './screenshare'; 27import FindInPage from './find';
28import { NotificationsHandler, notificationsClassDefinition } from './notifications';
29import { getDisplayMediaSelector, screenShareCss, screenShareJs } from './screenshare';
30import { switchDict, getSpellcheckerLocaleByFuzzyIdentifier } from './spellchecker';
31 31
32import { DEFAULT_APP_SETTINGS, isDevMode } from '../environment'; 32import { DEFAULT_APP_SETTINGS } from '../environment';
33 33
34const debug = require('debug')('Ferdi:Plugin'); 34const debug = require('debug')('Ferdi:Plugin');
35 35
36const badgeHandler = new BadgeHandler();
37
38const notificationsHandler = new NotificationsHandler();
39
40// Patching window.open
41const originalWindowOpen = window.open;
42
43window.open = (url, frameName, features) => {
44 debug('window.open', url, frameName, features);
45 if (!url) {
46 // The service hasn't yet supplied a URL (as used in Skype).
47 // Return a new dummy window object and wait for the service to change the properties
48 const newWindow = {
49 location: {
50 href: '',
51 },
52 };
53
54 const checkInterval = setInterval(() => {
55 // Has the service changed the URL yet?
56 if (newWindow.location.href !== '') {
57 if (features) {
58 originalWindowOpen(newWindow.location.href, frameName, features);
59 } else {
60 // Open the new URL
61 ipcRenderer.sendToHost('new-window', newWindow.location.href);
62 }
63 clearInterval(checkInterval);
64 }
65 }, 0);
66
67 setTimeout(() => {
68 // Stop checking for location changes after 1 second
69 clearInterval(checkInterval);
70 }, 1000);
71
72 return newWindow;
73 }
74
75 // We need to differentiate if the link should be opened in a popup or in the systems default browser
76 if (!frameName && !features && typeof features !== 'string') {
77 return ipcRenderer.sendToHost('new-window', url);
78 }
79
80 if (url) {
81 return originalWindowOpen(url, frameName, features);
82 }
83};
84
85// We can't override APIs here, so we first expose functions via window.ferdi,
86// then overwrite the corresponding field of the window object by injected JS.
87contextBridge.exposeInMainWorld('ferdi', {
88 open: window.open,
89 setBadge: (direct, indirect) => badgeHandler.setBadge(direct || 0, indirect || 0),
90 displayNotification: (title, options) => notificationsHandler.displayNotification(title, options),
91 getDisplayMediaSelector,
92});
93
94ipcRenderer.sendToHost('inject-js-unsafe',
95 'window.open = window.ferdi.open;',
96 notificationsClassDefinition,
97 screenShareJs);
98
36class RecipeController { 99class RecipeController {
37 @observable settings = { 100 @observable settings = {
38 overrideSpellcheckerLanguage: false, 101 overrideSpellcheckerLanguage: false,
@@ -97,7 +160,7 @@ class RecipeController {
97 autorun(() => this.update()); 160 autorun(() => this.update());
98 161
99 document.addEventListener('DOMContentLoaded', () => { 162 document.addEventListener('DOMContentLoaded', () => {
100 this.findInPage = new FindInPage(getCurrentWebContents(), { 163 this.findInPage = new FindInPage({
101 inputFocusColor: '#CE9FFC', 164 inputFocusColor: '#CE9FFC',
102 textColor: '#212121', 165 textColor: '#212121',
103 }); 166 });
@@ -111,7 +174,7 @@ class RecipeController {
111 // Delete module from cache 174 // Delete module from cache
112 delete require.cache[require.resolve(modulePath)]; 175 delete require.cache[require.resolve(modulePath)];
113 try { 176 try {
114 this.recipe = new RecipeWebview(); 177 this.recipe = new RecipeWebview(badgeHandler, notificationsHandler);
115 // eslint-disable-next-line 178 // eslint-disable-next-line
116 require(modulePath)(this.recipe, {...config, recipe,}); 179 require(modulePath)(this.recipe, {...config, recipe,});
117 debug('Initialize Recipe', config, recipe); 180 debug('Initialize Recipe', config, recipe);
@@ -327,52 +390,3 @@ class RecipeController {
327/* eslint-disable no-new */ 390/* eslint-disable no-new */
328new RecipeController(); 391new RecipeController();
329/* eslint-enable no-new */ 392/* eslint-enable no-new */
330
331// Patching window.open
332const originalWindowOpen = window.open;
333
334window.open = (url, frameName, features) => {
335 debug('window.open', url, frameName, features);
336 if (!url) {
337 // The service hasn't yet supplied a URL (as used in Skype).
338 // Return a new dummy window object and wait for the service to change the properties
339 const newWindow = {
340 location: {
341 href: '',
342 },
343 };
344
345 const checkInterval = setInterval(() => {
346 // Has the service changed the URL yet?
347 if (newWindow.location.href !== '') {
348 if (features) {
349 originalWindowOpen(newWindow.location.href, frameName, features);
350 } else {
351 // Open the new URL
352 ipcRenderer.sendToHost('new-window', newWindow.location.href);
353 }
354 clearInterval(checkInterval);
355 }
356 }, 0);
357
358 setTimeout(() => {
359 // Stop checking for location changes after 1 second
360 clearInterval(checkInterval);
361 }, 1000);
362
363 return newWindow;
364 }
365
366 // We need to differentiate if the link should be opened in a popup or in the systems default browser
367 if (!frameName && !features && typeof features !== 'string') {
368 return ipcRenderer.sendToHost('new-window', url);
369 }
370
371 if (url) {
372 return originalWindowOpen(url, frameName, features);
373 }
374};
375
376if (isDevMode) {
377 window.log = console.log;
378}