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.js164
1 files changed, 108 insertions, 56 deletions
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index d143675dc..598c3eb9a 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -23,11 +23,25 @@ import Userscript from './lib/Userscript';
23 23
24import { BadgeHandler } from './badge'; 24import { BadgeHandler } from './badge';
25import contextMenu from './contextMenu'; 25import contextMenu from './contextMenu';
26import { injectDarkModeStyle, isDarkModeStyleInjected, removeDarkModeStyle } from './darkmode'; 26import {
27 injectDarkModeStyle,
28 isDarkModeStyleInjected,
29 removeDarkModeStyle,
30} from './darkmode';
27import FindInPage from './find'; 31import FindInPage from './find';
28import { NotificationsHandler, notificationsClassDefinition } from './notifications'; 32import {
29import { getDisplayMediaSelector, screenShareCss, screenShareJs } from './screenshare'; 33 NotificationsHandler,
30import { switchDict, getSpellcheckerLocaleByFuzzyIdentifier } from './spellchecker'; 34 notificationsClassDefinition,
35} from './notifications';
36import {
37 getDisplayMediaSelector,
38 screenShareCss,
39 screenShareJs,
40} from './screenshare';
41import {
42 switchDict,
43 getSpellcheckerLocaleByFuzzyIdentifier,
44} from './spellchecker';
31 45
32import { DEFAULT_APP_SETTINGS } from '../environment'; 46import { DEFAULT_APP_SETTINGS } from '../environment';
33 47
@@ -86,15 +100,19 @@ window.open = (url, frameName, features) => {
86// then overwrite the corresponding field of the window object by injected JS. 100// then overwrite the corresponding field of the window object by injected JS.
87contextBridge.exposeInMainWorld('ferdi', { 101contextBridge.exposeInMainWorld('ferdi', {
88 open: window.open, 102 open: window.open,
89 setBadge: (direct, indirect) => badgeHandler.setBadge(direct || 0, indirect || 0), 103 setBadge: (direct, indirect) =>
90 displayNotification: (title, options) => notificationsHandler.displayNotification(title, options), 104 badgeHandler.setBadge(direct || 0, indirect || 0),
105 displayNotification: (title, options) =>
106 notificationsHandler.displayNotification(title, options),
91 getDisplayMediaSelector, 107 getDisplayMediaSelector,
92}); 108});
93 109
94ipcRenderer.sendToHost('inject-js-unsafe', 110ipcRenderer.sendToHost(
111 'inject-js-unsafe',
95 'window.open = window.ferdi.open;', 112 'window.open = window.ferdi.open;',
96 notificationsClassDefinition, 113 notificationsClassDefinition,
97 screenShareJs); 114 screenShareJs,
115);
98 116
99class RecipeController { 117class RecipeController {
100 @observable settings = { 118 @observable settings = {
@@ -129,7 +147,9 @@ class RecipeController {
129 } 147 }
130 148
131 @computed get spellcheckerLanguage() { 149 @computed get spellcheckerLanguage() {
132 const selected = this.settings.service.spellcheckerLanguage || this.settings.app.spellcheckerLanguage; 150 const selected =
151 this.settings.service.spellcheckerLanguage ||
152 this.settings.app.spellcheckerLanguage;
133 return selected; 153 return selected;
134 } 154 }
135 155
@@ -138,7 +158,7 @@ class RecipeController {
138 findInPage = null; 158 findInPage = null;
139 159
140 async initialize() { 160 async initialize() {
141 Object.keys(this.ipcEvents).forEach((channel) => { 161 Object.keys(this.ipcEvents).forEach(channel => {
142 ipcRenderer.on(channel, (...args) => { 162 ipcRenderer.on(channel, (...args) => {
143 debug('Received IPC event for channel', channel, 'with', ...args); 163 debug('Received IPC event for channel', channel, 'with', ...args);
144 this[this.ipcEvents[channel]](...args); 164 this[this.ipcEvents[channel]](...args);
@@ -176,7 +196,7 @@ class RecipeController {
176 try { 196 try {
177 this.recipe = new RecipeWebview(badgeHandler, notificationsHandler); 197 this.recipe = new RecipeWebview(badgeHandler, notificationsHandler);
178 // eslint-disable-next-line 198 // eslint-disable-next-line
179 require(modulePath)(this.recipe, {...config, recipe,}); 199 require(modulePath)(this.recipe, { ...config, recipe });
180 debug('Initialize Recipe', config, recipe); 200 debug('Initialize Recipe', config, recipe);
181 201
182 this.settings.service = Object.assign(config, { recipe }); 202 this.settings.service = Object.assign(config, { recipe });
@@ -195,14 +215,14 @@ class RecipeController {
195 styles.innerHTML = screenShareCss; 215 styles.innerHTML = screenShareCss;
196 216
197 const userCss = path.join(recipe.path, 'user.css'); 217 const userCss = path.join(recipe.path, 'user.css');
198 if (await fs.exists(userCss)) { 218 if (fs.existsSync(userCss)) {
199 const data = await fs.readFile(userCss); 219 const data = await fs.readFile(userCss);
200 styles.innerHTML += data.toString(); 220 styles.innerHTML += data.toString();
201 } 221 }
202 document.querySelector('head').appendChild(styles); 222 document.querySelector('head').appendChild(styles);
203 223
204 const userJs = path.join(recipe.path, 'user.js'); 224 const userJs = path.join(recipe.path, 'user.js');
205 if (await fs.exists(userJs)) { 225 if (fs.existsSync(userJs)) {
206 const loadUserJs = () => { 226 const loadUserJs = () => {
207 // eslint-disable-next-line 227 // eslint-disable-next-line
208 const userJsModule = require(userJs); 228 const userJsModule = require(userJs);
@@ -230,8 +250,14 @@ class RecipeController {
230 update() { 250 update() {
231 debug('enableSpellchecking', this.settings.app.enableSpellchecking); 251 debug('enableSpellchecking', this.settings.app.enableSpellchecking);
232 debug('isDarkModeEnabled', this.settings.service.isDarkModeEnabled); 252 debug('isDarkModeEnabled', this.settings.service.isDarkModeEnabled);
233 debug('System spellcheckerLanguage', this.settings.app.spellcheckerLanguage); 253 debug(
234 debug('Service spellcheckerLanguage', this.settings.service.spellcheckerLanguage); 254 'System spellcheckerLanguage',
255 this.settings.app.spellcheckerLanguage,
256 );
257 debug(
258 'Service spellcheckerLanguage',
259 this.settings.service.spellcheckerLanguage,
260 );
235 debug('darkReaderSettigs', this.settings.service.darkReaderSettings); 261 debug('darkReaderSettigs', this.settings.service.darkReaderSettings);
236 debug('searchEngine', this.settings.app.searchEngine); 262 debug('searchEngine', this.settings.app.searchEngine);
237 263
@@ -244,7 +270,10 @@ class RecipeController {
244 let { spellcheckerLanguage } = this; 270 let { spellcheckerLanguage } = this;
245 if (spellcheckerLanguage.includes('automatic')) { 271 if (spellcheckerLanguage.includes('automatic')) {
246 this.automaticLanguageDetection(); 272 this.automaticLanguageDetection();
247 debug('Found `automatic` locale, falling back to user locale until detected', this.settings.app.locale); 273 debug(
274 'Found `automatic` locale, falling back to user locale until detected',
275 this.settings.app.locale,
276 );
248 spellcheckerLanguage = this.settings.app.locale; 277 spellcheckerLanguage = this.settings.app.locale;
249 } 278 }
250 switchDict(spellcheckerLanguage); 279 switchDict(spellcheckerLanguage);
@@ -256,7 +285,7 @@ class RecipeController {
256 this.hasUpdatedBeforeRecipeLoaded = true; 285 this.hasUpdatedBeforeRecipeLoaded = true;
257 } 286 }
258 287
259 console.log( 288 debug(
260 'Darkmode enabled?', 289 'Darkmode enabled?',
261 this.settings.service.isDarkModeEnabled, 290 this.settings.service.isDarkModeEnabled,
262 'Dark theme active?', 291 'Dark theme active?',
@@ -267,22 +296,29 @@ class RecipeController {
267 removeDarkModeStyle, 296 removeDarkModeStyle,
268 disableDarkMode, 297 disableDarkMode,
269 enableDarkMode, 298 enableDarkMode,
270 injectDarkModeStyle: () => injectDarkModeStyle(this.settings.service.recipe.path), 299 injectDarkModeStyle: () =>
300 injectDarkModeStyle(this.settings.service.recipe.path),
271 isDarkModeStyleInjected, 301 isDarkModeStyleInjected,
272 }; 302 };
273 303
274 if (this.settings.service.isDarkModeEnabled && this.settings.app.isDarkThemeActive !== false) { 304 if (
305 this.settings.service.isDarkModeEnabled &&
306 this.settings.app.isDarkThemeActive !== false
307 ) {
275 debug('Enable dark mode'); 308 debug('Enable dark mode');
276 309
277 // Check if recipe has a darkmode.css 310 // Check if recipe has a darkmode.css
278 const darkModeStyle = path.join(this.settings.service.recipe.path, 'darkmode.css'); 311 const darkModeStyle = path.join(
312 this.settings.service.recipe.path,
313 'darkmode.css',
314 );
279 const darkModeExists = fs.pathExistsSync(darkModeStyle); 315 const darkModeExists = fs.pathExistsSync(darkModeStyle);
280 316
281 console.log('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No'); 317 debug('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No');
282 318
283 // Check if recipe has a custom dark mode handler 319 // Check if recipe has a custom dark mode handler
284 if (this.recipe && this.recipe.darkModeHandler) { 320 if (this.recipe && this.recipe.darkModeHandler) {
285 console.log('Using custom dark mode handler'); 321 debug('Using custom dark mode handler');
286 322
287 // Remove other dark mode styles if they were already loaded 323 // Remove other dark mode styles if they were already loaded
288 if (this.hasUpdatedBeforeRecipeLoaded) { 324 if (this.hasUpdatedBeforeRecipeLoaded) {
@@ -293,25 +329,32 @@ class RecipeController {
293 329
294 this.recipe.darkModeHandler(true, handlerConfig); 330 this.recipe.darkModeHandler(true, handlerConfig);
295 } else if (darkModeExists) { 331 } else if (darkModeExists) {
296 console.log('Injecting darkmode.css'); 332 debug('Injecting darkmode.css');
297 injectDarkModeStyle(this.settings.service.recipe.path); 333 injectDarkModeStyle(this.settings.service.recipe.path);
298 334
299 // Make sure universal dark mode is disabled 335 // Make sure universal dark mode is disabled
300 disableDarkMode(); 336 disableDarkMode();
301 this.universalDarkModeInjected = false; 337 this.universalDarkModeInjected = false;
302 } else if (this.settings.app.universalDarkMode && !ignoreList.includes(window.location.host)) { 338 } else if (
303 console.log('Injecting Dark Reader'); 339 this.settings.app.universalDarkMode &&
340 !ignoreList.includes(window.location.host)
341 ) {
342 debug('Injecting Dark Reader');
304 343
305 // Use Dark Reader instead 344 // Use Dark Reader instead
306 const { brightness, contrast, sepia } = this.settings.service.darkReaderSettings; 345 const { brightness, contrast, sepia } =
307 enableDarkMode({ brightness, contrast, sepia }, { 346 this.settings.service.darkReaderSettings;
308 css: customDarkModeCss[window.location.host] || '', 347 enableDarkMode(
309 }); 348 { brightness, contrast, sepia },
349 {
350 css: customDarkModeCss[window.location.host] || '',
351 },
352 );
310 this.universalDarkModeInjected = true; 353 this.universalDarkModeInjected = true;
311 } 354 }
312 } else { 355 } else {
313 debug('Remove dark mode'); 356 debug('Remove dark mode');
314 console.log('DarkMode disabled - removing remaining styles'); 357 debug('DarkMode disabled - removing remaining styles');
315 358
316 if (this.recipe && this.recipe.darkModeHandler) { 359 if (this.recipe && this.recipe.darkModeHandler) {
317 // Remove other dark mode styles if they were already loaded 360 // Remove other dark mode styles if they were already loaded
@@ -323,10 +366,10 @@ class RecipeController {
323 366
324 this.recipe.darkModeHandler(false, handlerConfig); 367 this.recipe.darkModeHandler(false, handlerConfig);
325 } else if (isDarkModeStyleInjected()) { 368 } else if (isDarkModeStyleInjected()) {
326 console.log('Removing injected darkmode.css'); 369 debug('Removing injected darkmode.css');
327 removeDarkModeStyle(); 370 removeDarkModeStyle();
328 } else { 371 } else {
329 console.log('Removing Dark Reader'); 372 debug('Removing Dark Reader');
330 373
331 disableDarkMode(); 374 disableDarkMode();
332 this.universalDarkModeInjected = false; 375 this.universalDarkModeInjected = false;
@@ -336,9 +379,9 @@ class RecipeController {
336 // Remove dark reader if (universal) dark mode was just disabled 379 // Remove dark reader if (universal) dark mode was just disabled
337 if (this.universalDarkModeInjected) { 380 if (this.universalDarkModeInjected) {
338 if ( 381 if (
339 !this.settings.app.darkMode 382 !this.settings.app.darkMode ||
340 || !this.settings.service.isDarkModeEnabled 383 !this.settings.service.isDarkModeEnabled ||
341 || !this.settings.app.universalDarkMode 384 !this.settings.app.universalDarkMode
342 ) { 385 ) {
343 disableDarkMode(); 386 disableDarkMode();
344 this.universalDarkModeInjected = false; 387 this.universalDarkModeInjected = false;
@@ -360,30 +403,39 @@ class RecipeController {
360 } 403 }
361 404
362 async automaticLanguageDetection() { 405 async automaticLanguageDetection() {
363 window.addEventListener('keyup', debounce(async (e) => { 406 window.addEventListener(
364 const element = e.target; 407 'keyup',
365 408 debounce(async e => {
366 if (!element) return; 409 const element = e.target;
367 410
368 let value = ''; 411 if (!element) return;
369 if (element.isContentEditable) { 412
370 value = element.textContent; 413 let value = '';
371 } else if (element.value) { 414 if (element.isContentEditable) {
372 value = element.value; 415 value = element.textContent;
373 } 416 } else if (element.value) {
417 value = element.value;
418 }
374 419
375 // Force a minimum length to get better detection results 420 // Force a minimum length to get better detection results
376 if (value.length < 25) return; 421 if (value.length < 25) return;
377 422
378 debug('Detecting language for', value); 423 debug('Detecting language for', value);
379 const locale = await ipcRenderer.invoke('detect-language', { sample: value }); 424 const locale = await ipcRenderer.invoke('detect-language', {
425 sample: value,
426 });
380 427
381 const spellcheckerLocale = getSpellcheckerLocaleByFuzzyIdentifier(locale); 428 const spellcheckerLocale =
382 debug('Language detected reliably, setting spellchecker language to', spellcheckerLocale); 429 getSpellcheckerLocaleByFuzzyIdentifier(locale);
383 if (spellcheckerLocale) { 430 debug(
384 switchDict(spellcheckerLocale); 431 'Language detected reliably, setting spellchecker language to',
385 } 432 spellcheckerLocale,
386 }, 225)); 433 );
434 if (spellcheckerLocale) {
435 switchDict(spellcheckerLocale);
436 }
437 }, 225),
438 );
387 } 439 }
388} 440}
389 441