aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/@types/stores.types.ts4
-rw-r--r--src/config.ts1
-rw-r--r--src/webview/find.ts4
-rw-r--r--src/webview/lib/RecipeWebview.ts2
-rw-r--r--src/webview/recipe.ts (renamed from src/webview/recipe.js)72
5 files changed, 45 insertions, 38 deletions
diff --git a/src/@types/stores.types.ts b/src/@types/stores.types.ts
index bf2dc8bd2..bbb37cff9 100644
--- a/src/@types/stores.types.ts
+++ b/src/@types/stores.types.ts
@@ -78,7 +78,7 @@ interface TypedStore {
78 resetStatus: () => void; 78 resetStatus: () => void;
79} 79}
80 80
81interface AppStore extends TypedStore { 81export interface AppStore extends TypedStore {
82 accentColor: string; 82 accentColor: string;
83 adaptableDarkMode: boolean; 83 adaptableDarkMode: boolean;
84 progressbarAccentColor: string; 84 progressbarAccentColor: string;
@@ -102,7 +102,7 @@ interface AppStore extends TypedStore {
102 isOnline: boolean; 102 isOnline: boolean;
103 isSystemDarkModeEnabled: () => void; 103 isSystemDarkModeEnabled: () => void;
104 isSystemMuteOverridden: () => void; 104 isSystemMuteOverridden: () => void;
105 locale: () => void; 105 locale: string;
106 lockedPassword: string; 106 lockedPassword: string;
107 reloadAfterResume: boolean; 107 reloadAfterResume: boolean;
108 reloadAfterResumeTime: number; 108 reloadAfterResumeTime: number;
diff --git a/src/config.ts b/src/config.ts
index 4bd1ca155..e4baf27c5 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -456,4 +456,5 @@ export const DEFAULT_SERVICE_SETTINGS = {
456 hasHostedOption: false, 456 hasHostedOption: false,
457 allowFavoritesDelineationInUnreadCount: false, 457 allowFavoritesDelineationInUnreadCount: false,
458 disablewebsecurity: false, 458 disablewebsecurity: false,
459 spellcheckerLanguage: false,
459}; 460};
diff --git a/src/webview/find.ts b/src/webview/find.ts
index 0665d9670..ead818b07 100644
--- a/src/webview/find.ts
+++ b/src/webview/find.ts
@@ -24,4 +24,8 @@ export default class FindInPage extends ElectronFindInPage {
24 constructor(options = {}) { 24 constructor(options = {}) {
25 super(webContentsShim, options); 25 super(webContentsShim, options);
26 } 26 }
27
28 openFindWindow() {
29 super.openFindWindow();
30 }
27} 31}
diff --git a/src/webview/lib/RecipeWebview.ts b/src/webview/lib/RecipeWebview.ts
index a896f1b6e..20be3f866 100644
--- a/src/webview/lib/RecipeWebview.ts
+++ b/src/webview/lib/RecipeWebview.ts
@@ -39,7 +39,7 @@ class RecipeWebview {
39 39
40 loopFunc = () => null; 40 loopFunc = () => null;
41 41
42 darkModeHandler = false; 42 darkModeHandler: ((darkMode: boolean, config: any) => void) | null = null;
43 43
44 // TODO Remove this once we implement a proper wrapper. 44 // TODO Remove this once we implement a proper wrapper.
45 get ipcRenderer() { 45 get ipcRenderer() {
diff --git a/src/webview/recipe.js b/src/webview/recipe.ts
index acf4f9f31..887d9c367 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.ts
@@ -1,19 +1,14 @@
1/* eslint-disable global-require */ 1/* eslint-disable global-require */
2/* eslint-disable import/no-dynamic-require */
2/* eslint-disable import/first */ 3/* eslint-disable import/first */
3import { contextBridge, ipcRenderer } from 'electron'; 4import { contextBridge, ipcRenderer } from 'electron';
4import { join } from 'path'; 5import { join } from 'path';
5import { autorun, computed, makeObservable, observable } from 'mobx'; 6import { autorun, computed, makeObservable, observable } from 'mobx';
6import { pathExistsSync, readFileSync } from 'fs-extra'; 7import { pathExistsSync, readFileSync } from 'fs-extra';
7import { debounce } from 'lodash'; 8import { debounce } from 'lodash';
8
9// For some services darkreader tries to use the chrome extension message API
10// This will cause the service to fail loading
11// As the message API is not actually needed, we'll add this shim sendMessage
12// function in order for darkreader to continue working
13window.chrome.runtime.sendMessage = () => {};
14import { 9import {
15 enable as enableDarkMode,
16 disable as disableDarkMode, 10 disable as disableDarkMode,
11 enable as enableDarkMode,
17} from 'darkreader'; 12} from 'darkreader';
18 13
19import { existsSync } from 'fs'; 14import { existsSync } from 'fs';
@@ -35,8 +30,8 @@ import {
35} from './darkmode'; 30} from './darkmode';
36import FindInPage from './find'; 31import FindInPage from './find';
37import { 32import {
38 NotificationsHandler,
39 notificationsClassDefinition, 33 notificationsClassDefinition,
34 NotificationsHandler,
40} from './notifications'; 35} from './notifications';
41import { 36import {
42 getDisplayMediaSelector, 37 getDisplayMediaSelector,
@@ -44,12 +39,20 @@ import {
44 screenShareJs, 39 screenShareJs,
45} from './screenshare'; 40} from './screenshare';
46import { 41import {
47 switchDict,
48 getSpellcheckerLocaleByFuzzyIdentifier, 42 getSpellcheckerLocaleByFuzzyIdentifier,
43 switchDict,
49} from './spellchecker'; 44} from './spellchecker';
50 45
51import { DEFAULT_APP_SETTINGS } from '../config';
52import { ifUndefinedString } from '../jsUtils'; 46import { ifUndefinedString } from '../jsUtils';
47import { AppStore } from '../@types/stores.types';
48import Service from '../models/Service';
49
50// For some services darkreader tries to use the chrome extension message API
51// This will cause the service to fail loading
52// As the message API is not actually needed, we'll add this shim sendMessage
53// function in order for darkreader to continue working
54// @ts-ignore
55window.chrome.runtime.sendMessage = () => {};
53 56
54const debug = require('../preload-safe-debug')('Ferdium:Plugin'); 57const debug = require('../preload-safe-debug')('Ferdium:Plugin');
55 58
@@ -64,7 +67,7 @@ const notificationsHandler = new NotificationsHandler();
64// Patching window.open 67// Patching window.open
65const originalWindowOpen = window.open; 68const originalWindowOpen = window.open;
66 69
67window.open = (url, frameName, features) => { 70window.open = (url, frameName, features): WindowProxy | null => {
68 debug('window.open', url, frameName, features); 71 debug('window.open', url, frameName, features);
69 if (!url) { 72 if (!url) {
70 // The service hasn't yet supplied a URL (as used in Skype). 73 // The service hasn't yet supplied a URL (as used in Skype).
@@ -93,17 +96,19 @@ window.open = (url, frameName, features) => {
93 clearInterval(checkInterval); 96 clearInterval(checkInterval);
94 }, 1000); 97 }, 1000);
95 98
96 return newWindow; 99 return newWindow as Window;
97 } 100 }
98 101
99 // We need to differentiate if the link should be opened in a popup or in the systems default browser 102 // We need to differentiate if the link should be opened in a popup or in the systems default browser
100 if (!frameName && !features && typeof features !== 'string') { 103 if (!frameName && !features && typeof features !== 'string') {
101 return ipcRenderer.sendToHost('new-window', url); 104 ipcRenderer.sendToHost('new-window', url);
105 return null;
102 } 106 }
103 107
104 if (url) { 108 if (url) {
105 return originalWindowOpen(url, frameName, features); 109 return originalWindowOpen(url, frameName, features);
106 } 110 }
111 return null;
107}; 112};
108 113
109// We can't override APIs here, so we first expose functions via 'window.ferdium', 114// We can't override APIs here, so we first expose functions via 'window.ferdium',
@@ -126,17 +131,15 @@ ipcRenderer.sendToHost(
126); 131);
127 132
128class RecipeController { 133class RecipeController {
129 @observable settings = { 134 // @ts-ignore
135 @observable settings: {
136 overrideSpellcheckerLanguage: boolean;
137 app: AppStore;
138 service: Service;
139 } = {
130 overrideSpellcheckerLanguage: false, 140 overrideSpellcheckerLanguage: false,
131 app: DEFAULT_APP_SETTINGS,
132 service: {
133 isDarkModeEnabled: false,
134 spellcheckerLanguage: '',
135 },
136 }; 141 };
137 142
138 spellcheckProvider = null;
139
140 ipcEvents = { 143 ipcEvents = {
141 'initialize-recipe': 'loadRecipeModule', 144 'initialize-recipe': 'loadRecipeModule',
142 'settings-update': 'updateAppSettings', 145 'settings-update': 'updateAppSettings',
@@ -147,9 +150,9 @@ class RecipeController {
147 150
148 universalDarkModeInjected = false; 151 universalDarkModeInjected = false;
149 152
150 recipe = null; 153 recipe: RecipeWebview | null = null;
151 154
152 userscript = null; 155 userscript: Userscript | null = null;
153 156
154 hasUpdatedBeforeRecipeLoaded = false; 157 hasUpdatedBeforeRecipeLoaded = false;
155 158
@@ -166,9 +169,7 @@ class RecipeController {
166 ); 169 );
167 } 170 }
168 171
169 cldIdentifier = null; 172 findInPage: FindInPage | null = null;
170
171 findInPage = null;
172 173
173 async initialize() { 174 async initialize() {
174 for (const channel of Object.keys(this.ipcEvents)) { 175 for (const channel of Object.keys(this.ipcEvents)) {
@@ -181,7 +182,6 @@ class RecipeController {
181 debug('Send "hello" to host'); 182 debug('Send "hello" to host');
182 setTimeout(() => ipcRenderer.sendToHost('hello'), 100); 183 setTimeout(() => ipcRenderer.sendToHost('hello'), 100);
183 184
184 this.spellcheckingProvider = null;
185 contextMenu( 185 contextMenu(
186 () => this.settings.app.enableSpellchecking, 186 () => this.settings.app.enableSpellchecking,
187 () => this.settings.app.spellcheckerLanguage, 187 () => this.settings.app.spellcheckerLanguage,
@@ -216,7 +216,7 @@ class RecipeController {
216 }); 216 });
217 } 217 }
218 218
219 loadRecipeModule(event, config, recipe) { 219 loadRecipeModule(_event, config, recipe) {
220 debug('loadRecipeModule'); 220 debug('loadRecipeModule');
221 const modulePath = join(recipe.path, 'webview.js'); 221 const modulePath = join(recipe.path, 'webview.js');
222 debug('module path', modulePath); 222 debug('module path', modulePath);
@@ -230,7 +230,6 @@ class RecipeController {
230 sessionHandler, 230 sessionHandler,
231 ); 231 );
232 if (existsSync(modulePath)) { 232 if (existsSync(modulePath)) {
233 // eslint-disable-next-line import/no-dynamic-require
234 require(modulePath)(this.recipe, { ...config, recipe }); 233 require(modulePath)(this.recipe, { ...config, recipe });
235 debug('Initialize Recipe', config, recipe); 234 debug('Initialize Recipe', config, recipe);
236 } 235 }
@@ -255,12 +254,11 @@ class RecipeController {
255 const data = readFileSync(userCss); 254 const data = readFileSync(userCss);
256 styles.innerHTML += data.toString(); 255 styles.innerHTML += data.toString();
257 } 256 }
258 document.querySelector('head').append(styles); 257 document.querySelector('head')?.append(styles);
259 258
260 const userJs = join(recipe.path, 'user.js'); 259 const userJs = join(recipe.path, 'user.js');
261 if (pathExistsSync(userJs)) { 260 if (pathExistsSync(userJs)) {
262 const loadUserJs = () => { 261 const loadUserJs = () => {
263 // eslint-disable-next-line import/no-dynamic-require
264 const userJsModule = require(userJs); 262 const userJsModule = require(userJs);
265 263
266 if (typeof userJsModule === 'function') { 264 if (typeof userJsModule === 'function') {
@@ -280,7 +278,7 @@ class RecipeController {
280 } 278 }
281 279
282 openFindInPage() { 280 openFindInPage() {
283 this.findInPage.openFindWindow(); 281 this.findInPage?.openFindWindow();
284 } 282 }
285 283
286 update() { 284 update() {
@@ -328,6 +326,7 @@ class RecipeController {
328 'Darkmode enabled?', 326 'Darkmode enabled?',
329 this.settings.service.isDarkModeEnabled, 327 this.settings.service.isDarkModeEnabled,
330 'Dark theme active?', 328 'Dark theme active?',
329 // @ts-ignore
331 this.settings.app.isDarkThemeActive, 330 this.settings.app.isDarkThemeActive,
332 ); 331 );
333 332
@@ -375,6 +374,10 @@ class RecipeController {
375 { brightness, contrast, sepia }, 374 { brightness, contrast, sepia },
376 { 375 {
377 css: customDarkModeCss[window.location.host] || '', 376 css: customDarkModeCss[window.location.host] || '',
377 invert: [],
378 ignoreImageAnalysis: [],
379 ignoreInlineStyle: [],
380 disableStyleSheetsProxy: false,
378 }, 381 },
379 ); 382 );
380 this.universalDarkModeInjected = true; 383 this.universalDarkModeInjected = true;
@@ -415,11 +418,11 @@ class RecipeController {
415 } 418 }
416 } 419 }
417 420
418 updateAppSettings(event, data) { 421 updateAppSettings(_event, data) {
419 this.settings.app = Object.assign(this.settings.app, data); 422 this.settings.app = Object.assign(this.settings.app, data);
420 } 423 }
421 424
422 updateServiceSettings(event, data) { 425 updateServiceSettings(_event, data) {
423 this.settings.service = Object.assign(this.settings.service, data); 426 this.settings.service = Object.assign(this.settings.service, data);
424 } 427 }
425 428
@@ -470,4 +473,3 @@ class RecipeController {
470 473
471/* eslint-disable no-new */ 474/* eslint-disable no-new */
472new RecipeController(); 475new RecipeController();
473/* eslint-enable no-new */