aboutsummaryrefslogtreecommitdiffstats
path: root/src/webview/contextMenuBuilder.ts
diff options
context:
space:
mode:
authorLibravatar André Oliveira <37463445+SpecialAro@users.noreply.github.com>2022-08-17 22:54:41 +0100
committerLibravatar GitHub <noreply@github.com>2022-08-17 22:54:41 +0100
commitfb0cc81d1db0d88c90bb112a0caec66095fcc0f0 (patch)
treeaaa5d0f92f55ccf3984af2cbf2ebbcb1da5fd7c6 /src/webview/contextMenuBuilder.ts
parent6.0.1-nightly.16 [skip ci] (diff)
downloadferdium-app-fb0cc81d1db0d88c90bb112a0caec66095fcc0f0.tar.gz
ferdium-app-fb0cc81d1db0d88c90bb112a0caec66095fcc0f0.tar.zst
ferdium-app-fb0cc81d1db0d88c90bb112a0caec66095fcc0f0.zip
Feature: Add Ferdium Translator (#548)
Add feature to translate text natively using https://github.com/shikar/NODE_GOOGLE_TRANSLATE package and a LibreTranslate self-hosted option (already running on our server on https://translator.ferdium.org).
Diffstat (limited to 'src/webview/contextMenuBuilder.ts')
-rw-r--r--src/webview/contextMenuBuilder.ts255
1 files changed, 229 insertions, 26 deletions
diff --git a/src/webview/contextMenuBuilder.ts b/src/webview/contextMenuBuilder.ts
index 7bd86556e..2e64977c1 100644
--- a/src/webview/contextMenuBuilder.ts
+++ b/src/webview/contextMenuBuilder.ts
@@ -11,8 +11,16 @@ import { clipboard, ipcRenderer, nativeImage, WebContents } from 'electron';
11import { Menu, MenuItem } from '@electron/remote'; 11import { Menu, MenuItem } from '@electron/remote';
12import { cmdOrCtrlShortcutKey, isMac } from '../environment'; 12import { cmdOrCtrlShortcutKey, isMac } from '../environment';
13 13
14import { SEARCH_ENGINE_NAMES, SEARCH_ENGINE_URLS } from '../config'; 14import {
15 SEARCH_ENGINE_NAMES,
16 SEARCH_ENGINE_URLS,
17 GOOGLE_TRANSLATOR_LANGUAGES,
18 TRANSLATOR_ENGINE_GOOGLE,
19 TRANSLATOR_ENGINE_LIBRETRANSLATE,
20 LIBRETRANSLATE_TRANSLATOR_LANGUAGES,
21} from '../config';
15import { openExternalUrl } from '../helpers/url-helpers'; 22import { openExternalUrl } from '../helpers/url-helpers';
23import IContextMenuParams from '../models/IContextMenuParams';
16 24
17function matchesWord(string: string) { 25function matchesWord(string: string) {
18 const regex = 26 const regex =
@@ -21,6 +29,83 @@ function matchesWord(string: string) {
21 return string.match(regex); 29 return string.match(regex);
22} 30}
23 31
32function childOf(node, ancestor) {
33 let child = node;
34 while (child !== null) {
35 if (child === ancestor) return true;
36 child = child.parentNode;
37 }
38 return false;
39}
40
41function translatePopup(res, isError: boolean = false) {
42 const elementExists = document.querySelector('#container-ferdium-translator');
43 if (elementExists) {
44 elementExists.remove();
45 }
46
47 const style = document.createElement('style');
48 style.innerHTML = `
49 .container-ferdium-translator {
50 position: fixed;
51 opacity: 0.9;
52 z-index: 999999;
53 ${
54 isError
55 ? `background: rgb(255 37 37);`
56 : `background: rgb(131 131 131);`
57 }
58 border-radius: 8px;
59 top: 5%;
60 left: 50%;
61 transform: translate(-50%, -5%);
62 display: flex;
63 flex-direction: row;
64 -webkit-box-shadow: 0px 10px 13px -7px #000000, 5px 5px 13px 9px rgba(0,0,0,0);
65 overflow: auto;
66 max-height: 95%;
67 max-width: 90%;
68 width: max-content;
69 height: max-content;
70 -webkit-animation: scale-up-center 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
71 }
72 .container-ferdium-translator > p {
73 color: white;
74 margin: 10px;
75 text-align: justify;
76 }
77
78 @-webkit-keyframes scale-up-center {
79 0% {
80 -webkit-transform: translate(-50%, -50%) scale(0.5);
81 }
82 100% {
83 -webkit-transform: translate(-50%, -50%) scale(1);
84 }
85 }
86 `;
87 document.head.append(style);
88
89 const para = document.createElement('p');
90
91 const node = document.createTextNode(res);
92 para.append(node);
93
94 const div = document.createElement('div');
95 div.setAttribute('id', 'container-ferdium-translator');
96 div.setAttribute('class', 'container-ferdium-translator');
97
98 div.append(para);
99
100 document.body.insertBefore(div, document.body.firstChild);
101
102 document.addEventListener('click', e => {
103 if (div !== e.target && !childOf(e.target, div)) {
104 div?.remove();
105 }
106 });
107}
108
24interface ContextMenuStringTable { 109interface ContextMenuStringTable {
25 lookUpDefinition: ({ word }: { word: string }) => string; 110 lookUpDefinition: ({ word }: { word: string }) => string;
26 cut: () => string; 111 cut: () => string;
@@ -28,6 +113,17 @@ interface ContextMenuStringTable {
28 paste: () => string; 113 paste: () => string;
29 pasteAndMatchStyle: () => string; 114 pasteAndMatchStyle: () => string;
30 searchWith: ({ searchEngine }: { searchEngine: string }) => string; 115 searchWith: ({ searchEngine }: { searchEngine: string }) => string;
116 translate: () => string;
117 quickTranslate: ({
118 translatorLanguage,
119 }: {
120 translatorLanguage: string;
121 }) => string;
122 translateLanguage: ({
123 translatorLanguage,
124 }: {
125 translatorLanguage: string;
126 }) => string;
31 openLinkUrl: () => string; 127 openLinkUrl: () => string;
32 openLinkInFerdiumUrl: () => string; 128 openLinkInFerdiumUrl: () => string;
33 openInBrowser: () => string; 129 openInBrowser: () => string;
@@ -52,6 +148,10 @@ const contextMenuStringTable: ContextMenuStringTable = {
52 paste: () => 'Paste', 148 paste: () => 'Paste',
53 pasteAndMatchStyle: () => 'Paste and match style', 149 pasteAndMatchStyle: () => 'Paste and match style',
54 searchWith: ({ searchEngine }) => `Search with ${searchEngine}`, 150 searchWith: ({ searchEngine }) => `Search with ${searchEngine}`,
151 translate: () => `Translate to ...`,
152 quickTranslate: ({ translatorLanguage }) =>
153 `Translate to ${translatorLanguage}`,
154 translateLanguage: ({ translatorLanguage }) => `${translatorLanguage}`,
55 openLinkUrl: () => 'Open Link', 155 openLinkUrl: () => 'Open Link',
56 openLinkInFerdiumUrl: () => 'Open Link in Ferdium', 156 openLinkInFerdiumUrl: () => 'Open Link in Ferdium',
57 openInBrowser: () => 'Open in Browser', 157 openInBrowser: () => 'Open in Browser',
@@ -127,7 +227,7 @@ export class ContextMenuBuilder {
127 * 227 *
128 * @param contextInfo The object returned from the 'context-menu' Electron event. 228 * @param contextInfo The object returned from the 'context-menu' Electron event.
129 */ 229 */
130 async showPopupMenu(contextInfo: Electron.ContextMenuParams): Promise<void> { 230 async showPopupMenu(contextInfo: IContextMenuParams): Promise<void> {
131 const menu = await this.buildMenuForElement(contextInfo); 231 const menu = await this.buildMenuForElement(contextInfo);
132 if (!menu) return; 232 if (!menu) return;
133 menu.popup(); 233 menu.popup();
@@ -139,7 +239,7 @@ export class ContextMenuBuilder {
139 * the list but use most of the default behavior. 239 * the list but use most of the default behavior.
140 */ 240 */
141 async buildMenuForElement( 241 async buildMenuForElement(
142 info: Electron.ContextMenuParams, 242 info: IContextMenuParams,
143 ): Promise<Electron.CrossProcessExports.Menu> { 243 ): Promise<Electron.CrossProcessExports.Menu> {
144 if (info.linkURL && info.linkURL.length > 0) { 244 if (info.linkURL && info.linkURL.length > 0) {
145 return this.buildMenuForLink(info); 245 return this.buildMenuForLink(info);
@@ -165,12 +265,17 @@ export class ContextMenuBuilder {
165 * @return {Menu} The `Menu` 265 * @return {Menu} The `Menu`
166 */ 266 */
167 buildMenuForTextInput( 267 buildMenuForTextInput(
168 menuInfo: Electron.ContextMenuParams, 268 menuInfo: IContextMenuParams,
169 ): Electron.CrossProcessExports.Menu { 269 ): Electron.CrossProcessExports.Menu {
170 const menu = new Menu(); 270 const menu = new Menu();
171 271
272 const { enableTranslator } = menuInfo;
273
172 this.addSpellingItems(menu, menuInfo); 274 this.addSpellingItems(menu, menuInfo);
173 this.addSearchItems(menu, menuInfo); 275 this.addSearchItems(menu, menuInfo);
276 if (enableTranslator) {
277 this.addTranslateItems(menu, menuInfo);
278 }
174 279
175 this.addCut(menu, menuInfo); 280 this.addCut(menu, menuInfo);
176 this.addCopy(menu, menuInfo); 281 this.addCopy(menu, menuInfo);
@@ -194,7 +299,7 @@ export class ContextMenuBuilder {
194 * @return {Menu} The `Menu` 299 * @return {Menu} The `Menu`
195 */ 300 */
196 buildMenuForLink( 301 buildMenuForLink(
197 menuInfo: Electron.ContextMenuParams, 302 menuInfo: IContextMenuParams,
198 ): Electron.CrossProcessExports.Menu { 303 ): Electron.CrossProcessExports.Menu {
199 const menu = new Menu(); 304 const menu = new Menu();
200 const isEmailAddress = menuInfo.linkURL.startsWith('mailto:'); 305 const isEmailAddress = menuInfo.linkURL.startsWith('mailto:');
@@ -208,7 +313,6 @@ export class ContextMenuBuilder {
208 const url = isEmailAddress ? menuInfo.linkText : menuInfo.linkURL; 313 const url = isEmailAddress ? menuInfo.linkText : menuInfo.linkURL;
209 clipboard.writeText(url); 314 clipboard.writeText(url);
210 this._sendNotificationOnClipboardEvent( 315 this._sendNotificationOnClipboardEvent(
211 // @ts-expect-error Property 'clipboardNotifications' does not exist on type 'ContextMenuParams'.
212 menuInfo.clipboardNotifications, 316 menuInfo.clipboardNotifications,
213 () => `Link URL copied: ${url}`, 317 () => `Link URL copied: ${url}`,
214 ); 318 );
@@ -257,11 +361,16 @@ export class ContextMenuBuilder {
257 * Builds a menu applicable to a text field. 361 * Builds a menu applicable to a text field.
258 */ 362 */
259 buildMenuForText( 363 buildMenuForText(
260 menuInfo: Electron.ContextMenuParams, 364 menuInfo: IContextMenuParams,
261 ): Electron.CrossProcessExports.Menu { 365 ): Electron.CrossProcessExports.Menu {
262 const menu = new Menu(); 366 const menu = new Menu();
263 367
368 const { enableTranslator } = menuInfo;
369
264 this.addSearchItems(menu, menuInfo); 370 this.addSearchItems(menu, menuInfo);
371 if (enableTranslator) {
372 this.addTranslateItems(menu, menuInfo);
373 }
265 this.addCopy(menu, menuInfo); 374 this.addCopy(menu, menuInfo);
266 this.addInspectElement(menu, menuInfo); 375 this.addInspectElement(menu, menuInfo);
267 // @ts-expect-error Expected 1 arguments, but got 2. 376 // @ts-expect-error Expected 1 arguments, but got 2.
@@ -283,7 +392,7 @@ export class ContextMenuBuilder {
283 * @return {Menu} The `Menu` 392 * @return {Menu} The `Menu`
284 */ 393 */
285 buildMenuForImage( 394 buildMenuForImage(
286 menuInfo: Electron.ContextMenuParams, 395 menuInfo: IContextMenuParams,
287 ): Electron.CrossProcessExports.Menu { 396 ): Electron.CrossProcessExports.Menu {
288 const menu = new Menu(); 397 const menu = new Menu();
289 398
@@ -303,7 +412,7 @@ export class ContextMenuBuilder {
303 */ 412 */
304 addSpellingItems( 413 addSpellingItems(
305 menu: Electron.CrossProcessExports.Menu, 414 menu: Electron.CrossProcessExports.Menu,
306 menuInfo: Electron.ContextMenuParams, 415 menuInfo: IContextMenuParams,
307 ) { 416 ) {
308 const webContents = this.getWebContents(); 417 const webContents = this.getWebContents();
309 // Add each spelling suggestion 418 // Add each spelling suggestion
@@ -338,7 +447,7 @@ export class ContextMenuBuilder {
338 */ 447 */
339 addSearchItems( 448 addSearchItems(
340 menu: Electron.CrossProcessExports.Menu, 449 menu: Electron.CrossProcessExports.Menu,
341 menuInfo: Electron.ContextMenuParams, 450 menuInfo: IContextMenuParams,
342 ) { 451 ) {
343 if (!menuInfo.selectionText || menuInfo.selectionText.length === 0) { 452 if (!menuInfo.selectionText || menuInfo.selectionText.length === 0) {
344 return menu; 453 return menu;
@@ -364,11 +473,9 @@ export class ContextMenuBuilder {
364 473
365 const search = new MenuItem({ 474 const search = new MenuItem({
366 label: this.stringTable.searchWith({ 475 label: this.stringTable.searchWith({
367 // @ts-expect-error Property 'searchEngine' does not exist on type 'ContextMenuParams'.
368 searchEngine: SEARCH_ENGINE_NAMES[menuInfo.searchEngine], 476 searchEngine: SEARCH_ENGINE_NAMES[menuInfo.searchEngine],
369 }), 477 }),
370 click: () => { 478 click: () => {
371 // @ts-expect-error Property 'searchEngine' does not exist on type 'ContextMenuParams'.
372 const url = SEARCH_ENGINE_URLS[menuInfo.searchEngine]({ 479 const url = SEARCH_ENGINE_URLS[menuInfo.searchEngine]({
373 searchTerm: encodeURIComponent(menuInfo.selectionText), 480 searchTerm: encodeURIComponent(menuInfo.selectionText),
374 }); 481 });
@@ -382,7 +489,106 @@ export class ContextMenuBuilder {
382 return menu; 489 return menu;
383 } 490 }
384 491
385 isSrcUrlValid(menuInfo: Electron.ContextMenuParams) { 492 /**
493 * Adds translate-related menu items.
494 */
495 addTranslateItems(
496 menu: Electron.CrossProcessExports.Menu,
497 menuInfo: IContextMenuParams,
498 ) {
499 const { translatorEngine } = menuInfo;
500
501 if (!menuInfo.selectionText || menuInfo.selectionText.length === 0) {
502 return menu;
503 }
504
505 const match = matchesWord(menuInfo.selectionText);
506 if (!match || match.length === 0) {
507 return menu;
508 }
509
510 const generateTranslationItems = async (
511 translateToLanguage: string,
512 translatorEngine: string,
513 ) => {
514 // TODO: Need to support i18n
515 translatePopup('Loading...', false);
516
517 const translatedText = await ipcRenderer.invoke('translate', {
518 text: menuInfo.selectionText,
519 translateToLanguage,
520 translatorEngine,
521 });
522
523 translatePopup(translatedText.text, translatedText.error);
524 };
525
526 let arrayLanguagesAfterEngine;
527 if (translatorEngine === TRANSLATOR_ENGINE_LIBRETRANSLATE) {
528 arrayLanguagesAfterEngine = LIBRETRANSLATE_TRANSLATOR_LANGUAGES;
529 } else if (translatorEngine === TRANSLATOR_ENGINE_GOOGLE) {
530 arrayLanguagesAfterEngine = GOOGLE_TRANSLATOR_LANGUAGES;
531 }
532
533 const arrayLanguages = Object.keys(arrayLanguagesAfterEngine).map(
534 code => arrayLanguagesAfterEngine[code],
535 );
536
537 const menuLanguages = new Menu();
538
539 const getLanguageCode = (obj, val): string =>
540 Object.keys(obj).find(key => obj[key] === val)!;
541
542 for (const language in arrayLanguages) {
543 if (arrayLanguages[language]) {
544 const languageItem = new MenuItem({
545 label: this.stringTable.translateLanguage({
546 translatorLanguage: arrayLanguages[language],
547 }),
548 click: () => {
549 const translateToLanguageCode = getLanguageCode(
550 arrayLanguagesAfterEngine,
551 arrayLanguages[language],
552 );
553 generateTranslationItems(translateToLanguageCode, translatorEngine);
554 },
555 });
556 menuLanguages.append(languageItem);
557 }
558 }
559
560 const translateToLanguage =
561 arrayLanguagesAfterEngine[menuInfo.translatorLanguage];
562
563 const translateToLanguageCode = getLanguageCode(
564 arrayLanguagesAfterEngine,
565 translateToLanguage,
566 );
567 const quickTranslateItem = new MenuItem({
568 label: this.stringTable.quickTranslate({
569 translatorLanguage: translateToLanguage,
570 }),
571 click: () => {
572 generateTranslationItems(translateToLanguageCode, translatorEngine);
573 },
574 });
575
576 const translateItem = new MenuItem({
577 label: this.stringTable.translate(),
578 submenu: menuLanguages,
579 click: () => {
580 generateTranslationItems(translateToLanguageCode, translatorEngine);
581 },
582 });
583
584 menu.append(translateItem);
585 menu.append(quickTranslateItem);
586 this.addSeparator(menu);
587
588 return menu;
589 }
590
591 isSrcUrlValid(menuInfo: IContextMenuParams) {
386 return menuInfo.srcURL && menuInfo.srcURL.length > 0; 592 return menuInfo.srcURL && menuInfo.srcURL.length > 0;
387 } 593 }
388 594
@@ -391,7 +597,7 @@ export class ContextMenuBuilder {
391 */ 597 */
392 addImageItems( 598 addImageItems(
393 menu: Electron.CrossProcessExports.Menu, 599 menu: Electron.CrossProcessExports.Menu,
394 menuInfo: Electron.ContextMenuParams, 600 menuInfo: IContextMenuParams,
395 ) { 601 ) {
396 const copyImage = new MenuItem({ 602 const copyImage = new MenuItem({
397 label: this.stringTable.copyImage(), 603 label: this.stringTable.copyImage(),
@@ -403,7 +609,6 @@ export class ContextMenuBuilder {
403 ); 609 );
404 610
405 this._sendNotificationOnClipboardEvent( 611 this._sendNotificationOnClipboardEvent(
406 // @ts-expect-error Property 'clipboardNotifications' does not exist on type 'ContextMenuParams'.
407 menuInfo.clipboardNotifications, 612 menuInfo.clipboardNotifications,
408 () => `Image copied from URL: ${menuInfo.srcURL}`, 613 () => `Image copied from URL: ${menuInfo.srcURL}`,
409 ); 614 );
@@ -418,7 +623,6 @@ export class ContextMenuBuilder {
418 click: () => { 623 click: () => {
419 const result = clipboard.writeText(menuInfo.srcURL); 624 const result = clipboard.writeText(menuInfo.srcURL);
420 this._sendNotificationOnClipboardEvent( 625 this._sendNotificationOnClipboardEvent(
421 // @ts-expect-error Property 'clipboardNotifications' does not exist on type 'ContextMenuParams'.
422 menuInfo.clipboardNotifications, 626 menuInfo.clipboardNotifications,
423 () => `Image URL copied: ${menuInfo.srcURL}`, 627 () => `Image URL copied: ${menuInfo.srcURL}`,
424 ); 628 );
@@ -446,7 +650,6 @@ export class ContextMenuBuilder {
446 }); 650 });
447 }); 651 });
448 this._sendNotificationOnClipboardEvent( 652 this._sendNotificationOnClipboardEvent(
449 // @ts-expect-error Property 'clipboardNotifications' does not exist on type 'ContextMenuParams'.
450 menuInfo.clipboardNotifications, 653 menuInfo.clipboardNotifications,
451 () => `Image downloaded: ${urlWithoutBlob}`, 654 () => `Image downloaded: ${urlWithoutBlob}`,
452 ); 655 );
@@ -464,7 +667,7 @@ export class ContextMenuBuilder {
464 */ 667 */
465 addCut( 668 addCut(
466 menu: Electron.CrossProcessExports.Menu, 669 menu: Electron.CrossProcessExports.Menu,
467 menuInfo: Electron.ContextMenuParams, 670 menuInfo: IContextMenuParams,
468 ) { 671 ) {
469 const webContents = this.getWebContents(); 672 const webContents = this.getWebContents();
470 menu.append( 673 menu.append(
@@ -484,7 +687,7 @@ export class ContextMenuBuilder {
484 */ 687 */
485 addCopy( 688 addCopy(
486 menu: Electron.CrossProcessExports.Menu, 689 menu: Electron.CrossProcessExports.Menu,
487 menuInfo: Electron.ContextMenuParams, 690 menuInfo: IContextMenuParams,
488 ) { 691 ) {
489 const webContents = this.getWebContents(); 692 const webContents = this.getWebContents();
490 menu.append( 693 menu.append(
@@ -504,7 +707,7 @@ export class ContextMenuBuilder {
504 */ 707 */
505 addPaste( 708 addPaste(
506 menu: Electron.CrossProcessExports.Menu, 709 menu: Electron.CrossProcessExports.Menu,
507 menuInfo: Electron.ContextMenuParams, 710 menuInfo: IContextMenuParams,
508 ) { 711 ) {
509 const webContents = this.getWebContents(); 712 const webContents = this.getWebContents();
510 menu.append( 713 menu.append(
@@ -521,7 +724,7 @@ export class ContextMenuBuilder {
521 724
522 addPastePlain( 725 addPastePlain(
523 menu: Electron.CrossProcessExports.Menu, 726 menu: Electron.CrossProcessExports.Menu,
524 menuInfo: Electron.ContextMenuParams, 727 menuInfo: IContextMenuParams,
525 ) { 728 ) {
526 if ( 729 if (
527 menuInfo.editFlags.canPaste && 730 menuInfo.editFlags.canPaste &&
@@ -552,7 +755,7 @@ export class ContextMenuBuilder {
552 */ 755 */
553 addInspectElement( 756 addInspectElement(
554 menu: Electron.CrossProcessExports.Menu, 757 menu: Electron.CrossProcessExports.Menu,
555 menuInfo: Electron.ContextMenuParams, 758 menuInfo: IContextMenuParams,
556 needsSeparator = true, 759 needsSeparator = true,
557 ) { 760 ) {
558 const webContents = this.getWebContents(); 761 const webContents = this.getWebContents();
@@ -609,6 +812,7 @@ export class ContextMenuBuilder {
609 */ 812 */
610 goBack(menu: Electron.CrossProcessExports.Menu) { 813 goBack(menu: Electron.CrossProcessExports.Menu) {
611 const webContents = this.getWebContents(); 814 const webContents = this.getWebContents();
815
612 menu.append( 816 menu.append(
613 new MenuItem({ 817 new MenuItem({
614 label: this.stringTable.goBack(), 818 label: this.stringTable.goBack(),
@@ -643,7 +847,7 @@ export class ContextMenuBuilder {
643 */ 847 */
644 copyPageUrl( 848 copyPageUrl(
645 menu: Electron.CrossProcessExports.Menu, 849 menu: Electron.CrossProcessExports.Menu,
646 menuInfo: Electron.ContextMenuParams, 850 menuInfo: IContextMenuParams,
647 ) { 851 ) {
648 menu.append( 852 menu.append(
649 new MenuItem({ 853 new MenuItem({
@@ -652,7 +856,6 @@ export class ContextMenuBuilder {
652 click: () => { 856 click: () => {
653 clipboard.writeText(window.location.href); 857 clipboard.writeText(window.location.href);
654 this._sendNotificationOnClipboardEvent( 858 this._sendNotificationOnClipboardEvent(
655 // @ts-expect-error Property 'clipboardNotifications' does not exist on type 'ContextMenuParams'.
656 menuInfo?.clipboardNotifications, 859 menuInfo?.clipboardNotifications,
657 () => `Page URL copied: ${window.location.href}`, 860 () => `Page URL copied: ${window.location.href}`,
658 ); 861 );
@@ -668,7 +871,7 @@ export class ContextMenuBuilder {
668 */ 871 */
669 goToHomePage( 872 goToHomePage(
670 menu: Electron.CrossProcessExports.Menu, 873 menu: Electron.CrossProcessExports.Menu,
671 menuInfo: Electron.ContextMenuParams, 874 menuInfo: IContextMenuParams,
672 ) { 875 ) {
673 const baseURL = new window.URL(menuInfo.pageURL); 876 const baseURL = new window.URL(menuInfo.pageURL);
674 menu.append( 877 menu.append(
@@ -691,7 +894,7 @@ export class ContextMenuBuilder {
691 */ 894 */
692 openInBrowser( 895 openInBrowser(
693 menu: Electron.CrossProcessExports.Menu, 896 menu: Electron.CrossProcessExports.Menu,
694 menuInfo: Electron.ContextMenuParams, 897 menuInfo: IContextMenuParams,
695 ) { 898 ) {
696 menu.append( 899 menu.append(
697 new MenuItem({ 900 new MenuItem({