diff options
Diffstat (limited to 'src/webview')
-rw-r--r-- | src/webview/contextMenuBuilder.ts | 117 | ||||
-rw-r--r-- | src/webview/notifications.ts | 75 | ||||
-rw-r--r-- | src/webview/recipe.ts | 2 |
3 files changed, 95 insertions, 99 deletions
diff --git a/src/webview/contextMenuBuilder.ts b/src/webview/contextMenuBuilder.ts index 0a8b9c57b..d68605963 100644 --- a/src/webview/contextMenuBuilder.ts +++ b/src/webview/contextMenuBuilder.ts | |||
@@ -130,8 +130,8 @@ interface ContextMenuStringTable { | |||
130 | translatorLanguage: string; | 130 | translatorLanguage: string; |
131 | }) => string; | 131 | }) => string; |
132 | openLinkUrl: () => string; | 132 | openLinkUrl: () => string; |
133 | openLinkInFerdiumUrl: () => string; | ||
134 | openInBrowser: () => string; | 133 | openInBrowser: () => string; |
134 | openInFerdium: () => string; | ||
135 | copyLinkUrl: () => string; | 135 | copyLinkUrl: () => string; |
136 | copyImageUrl: () => string; | 136 | copyImageUrl: () => string; |
137 | copyImage: () => string; | 137 | copyImage: () => string; |
@@ -158,8 +158,8 @@ const contextMenuStringTable: ContextMenuStringTable = { | |||
158 | `Translate to ${translatorLanguage}`, | 158 | `Translate to ${translatorLanguage}`, |
159 | translateLanguage: ({ translatorLanguage }) => `${translatorLanguage}`, | 159 | translateLanguage: ({ translatorLanguage }) => `${translatorLanguage}`, |
160 | openLinkUrl: () => 'Open Link', | 160 | openLinkUrl: () => 'Open Link', |
161 | openLinkInFerdiumUrl: () => 'Open Link in Ferdium', | ||
162 | openInBrowser: () => 'Open in Browser', | 161 | openInBrowser: () => 'Open in Browser', |
162 | openInFerdium: () => 'Open in Ferdium', | ||
163 | copyLinkUrl: () => 'Copy Link', | 163 | copyLinkUrl: () => 'Copy Link', |
164 | copyImageUrl: () => 'Copy Image Address', | 164 | copyImageUrl: () => 'Copy Image Address', |
165 | copyImage: () => 'Copy Image', | 165 | copyImage: () => 'Copy Image', |
@@ -299,10 +299,13 @@ export class ContextMenuBuilder { | |||
299 | this.addPastePlain(menu, menuInfo); | 299 | this.addPastePlain(menu, menuInfo); |
300 | this.addInspectElement(menu, menuInfo); | 300 | this.addInspectElement(menu, menuInfo); |
301 | this.processMenu(menu); | 301 | this.processMenu(menu); |
302 | 302 | this.addSeparator(menu); | |
303 | this.copyPageUrl(menu, menuInfo); | 303 | this.copyPageUrl(menu, menuInfo); |
304 | this.goToHomePage(menu, menuInfo); | 304 | this.addSeparator(menu); |
305 | this.openInBrowser(menu, menuInfo); | 305 | this.openInBrowser(menu, menuInfo); |
306 | this.openInFerdium(menu, menuInfo); | ||
307 | this.addSeparator(menu); | ||
308 | this.goToHomePage(menu, menuInfo); | ||
306 | 309 | ||
307 | return menu; | 310 | return menu; |
308 | } | 311 | } |
@@ -340,16 +343,8 @@ export class ContextMenuBuilder { | |||
340 | }, | 343 | }, |
341 | }); | 344 | }); |
342 | 345 | ||
343 | const openInFerdiumLink = new MenuItem({ | ||
344 | label: this.stringTable.openLinkInFerdiumUrl(), | ||
345 | click: () => { | ||
346 | window.location.href = menuInfo.linkURL; | ||
347 | }, | ||
348 | }); | ||
349 | |||
350 | menu.append(copyLink); | 346 | menu.append(copyLink); |
351 | menu.append(openLink); | 347 | menu.append(openLink); |
352 | menu.append(openInFerdiumLink); | ||
353 | 348 | ||
354 | if (this.isSrcUrlValid(menuInfo)) { | 349 | if (this.isSrcUrlValid(menuInfo)) { |
355 | this.addSeparator(menu); | 350 | this.addSeparator(menu); |
@@ -358,13 +353,15 @@ export class ContextMenuBuilder { | |||
358 | 353 | ||
359 | this.addInspectElement(menu, menuInfo); | 354 | this.addInspectElement(menu, menuInfo); |
360 | this.processMenu(menu); | 355 | this.processMenu(menu); |
361 | |||
362 | this.addSeparator(menu); | 356 | this.addSeparator(menu); |
363 | this.goBack(menu); | 357 | this.goBack(menu); |
364 | this.goForward(menu); | 358 | this.goForward(menu); |
365 | this.copyPageUrl(menu, menuInfo); | 359 | this.copyPageUrl(menu, menuInfo); |
366 | this.goToHomePage(menu, menuInfo); | 360 | this.addSeparator(menu); |
367 | this.openInBrowser(menu, menuInfo); | 361 | this.openInBrowser(menu, menuInfo); |
362 | this.openInFerdium(menu, menuInfo); | ||
363 | this.addSeparator(menu); | ||
364 | this.goToHomePage(menu, menuInfo); | ||
368 | 365 | ||
369 | return menu; | 366 | return menu; |
370 | } | 367 | } |
@@ -384,16 +381,19 @@ export class ContextMenuBuilder { | |||
384 | this.addTranslateItems(menu, menuInfo); | 381 | this.addTranslateItems(menu, menuInfo); |
385 | } | 382 | } |
386 | this.addCopy(menu, menuInfo); | 383 | this.addCopy(menu, menuInfo); |
387 | this.addInspectElement(menu, menuInfo); | ||
388 | // @ts-expect-error Expected 1 arguments, but got 2. | ||
389 | this.processMenu(menu, menuInfo); | ||
390 | 384 | ||
385 | this.addInspectElement(menu, menuInfo); | ||
386 | this.processMenu(menu); | ||
391 | this.addSeparator(menu); | 387 | this.addSeparator(menu); |
392 | this.goBack(menu); | 388 | this.goBack(menu); |
393 | this.goForward(menu); | 389 | this.goForward(menu); |
390 | this.addSeparator(menu); | ||
394 | this.copyPageUrl(menu, menuInfo); | 391 | this.copyPageUrl(menu, menuInfo); |
395 | this.goToHomePage(menu, menuInfo); | 392 | this.addSeparator(menu); |
396 | this.openInBrowser(menu, menuInfo); | 393 | this.openInBrowser(menu, menuInfo); |
394 | this.openInFerdium(menu, menuInfo); | ||
395 | this.addSeparator(menu); | ||
396 | this.goToHomePage(menu, menuInfo); | ||
397 | 397 | ||
398 | return menu; | 398 | return menu; |
399 | } | 399 | } |
@@ -412,8 +412,7 @@ export class ContextMenuBuilder { | |||
412 | this.addImageItems(menu, menuInfo); | 412 | this.addImageItems(menu, menuInfo); |
413 | } | 413 | } |
414 | this.addInspectElement(menu, menuInfo); | 414 | this.addInspectElement(menu, menuInfo); |
415 | // @ts-expect-error Expected 1 arguments, but got 2. | 415 | this.processMenu(menu); |
416 | this.processMenu(menu, menuInfo); | ||
417 | 416 | ||
418 | return menu; | 417 | return menu; |
419 | } | 418 | } |
@@ -644,7 +643,7 @@ export class ContextMenuBuilder { | |||
644 | addImageItems( | 643 | addImageItems( |
645 | menu: Electron.CrossProcessExports.Menu, | 644 | menu: Electron.CrossProcessExports.Menu, |
646 | menuInfo: IContextMenuParams, | 645 | menuInfo: IContextMenuParams, |
647 | ) { | 646 | ): void { |
648 | const copyImage = new MenuItem({ | 647 | const copyImage = new MenuItem({ |
649 | label: this.stringTable.copyImage(), | 648 | label: this.stringTable.copyImage(), |
650 | click: () => { | 649 | click: () => { |
@@ -719,8 +718,6 @@ export class ContextMenuBuilder { | |||
719 | 718 | ||
720 | menu.append(downloadImage); | 719 | menu.append(downloadImage); |
721 | } | 720 | } |
722 | |||
723 | return menu; | ||
724 | } | 721 | } |
725 | 722 | ||
726 | /** | 723 | /** |
@@ -729,7 +726,7 @@ export class ContextMenuBuilder { | |||
729 | addCut( | 726 | addCut( |
730 | menu: Electron.CrossProcessExports.Menu, | 727 | menu: Electron.CrossProcessExports.Menu, |
731 | menuInfo: IContextMenuParams, | 728 | menuInfo: IContextMenuParams, |
732 | ) { | 729 | ): void { |
733 | const webContents = this.getWebContents(); | 730 | const webContents = this.getWebContents(); |
734 | menu.append( | 731 | menu.append( |
735 | new MenuItem({ | 732 | new MenuItem({ |
@@ -739,8 +736,6 @@ export class ContextMenuBuilder { | |||
739 | click: () => webContents.cut(), | 736 | click: () => webContents.cut(), |
740 | }), | 737 | }), |
741 | ); | 738 | ); |
742 | |||
743 | return menu; | ||
744 | } | 739 | } |
745 | 740 | ||
746 | /** | 741 | /** |
@@ -749,7 +744,7 @@ export class ContextMenuBuilder { | |||
749 | addCopy( | 744 | addCopy( |
750 | menu: Electron.CrossProcessExports.Menu, | 745 | menu: Electron.CrossProcessExports.Menu, |
751 | menuInfo: IContextMenuParams, | 746 | menuInfo: IContextMenuParams, |
752 | ) { | 747 | ): void { |
753 | const webContents = this.getWebContents(); | 748 | const webContents = this.getWebContents(); |
754 | menu.append( | 749 | menu.append( |
755 | new MenuItem({ | 750 | new MenuItem({ |
@@ -759,8 +754,6 @@ export class ContextMenuBuilder { | |||
759 | click: () => webContents.copy(), | 754 | click: () => webContents.copy(), |
760 | }), | 755 | }), |
761 | ); | 756 | ); |
762 | |||
763 | return menu; | ||
764 | } | 757 | } |
765 | 758 | ||
766 | /** | 759 | /** |
@@ -769,7 +762,7 @@ export class ContextMenuBuilder { | |||
769 | addPaste( | 762 | addPaste( |
770 | menu: Electron.CrossProcessExports.Menu, | 763 | menu: Electron.CrossProcessExports.Menu, |
771 | menuInfo: IContextMenuParams, | 764 | menuInfo: IContextMenuParams, |
772 | ) { | 765 | ): void { |
773 | const webContents = this.getWebContents(); | 766 | const webContents = this.getWebContents(); |
774 | menu.append( | 767 | menu.append( |
775 | new MenuItem({ | 768 | new MenuItem({ |
@@ -779,14 +772,12 @@ export class ContextMenuBuilder { | |||
779 | click: () => webContents.paste(), | 772 | click: () => webContents.paste(), |
780 | }), | 773 | }), |
781 | ); | 774 | ); |
782 | |||
783 | return menu; | ||
784 | } | 775 | } |
785 | 776 | ||
786 | addPastePlain( | 777 | addPastePlain( |
787 | menu: Electron.CrossProcessExports.Menu, | 778 | menu: Electron.CrossProcessExports.Menu, |
788 | menuInfo: IContextMenuParams, | 779 | menuInfo: IContextMenuParams, |
789 | ) { | 780 | ): void { |
790 | if ( | 781 | if ( |
791 | menuInfo.editFlags.canPaste && | 782 | menuInfo.editFlags.canPaste && |
792 | !menuInfo.linkText && | 783 | !menuInfo.linkText && |
@@ -806,9 +797,8 @@ export class ContextMenuBuilder { | |||
806 | /** | 797 | /** |
807 | * Adds a separator item. | 798 | * Adds a separator item. |
808 | */ | 799 | */ |
809 | addSeparator(menu: Electron.CrossProcessExports.Menu) { | 800 | addSeparator(menu: Electron.CrossProcessExports.Menu): void { |
810 | menu.append(new MenuItem({ type: 'separator' })); | 801 | menu.append(new MenuItem({ type: 'separator' })); |
811 | return menu; | ||
812 | } | 802 | } |
813 | 803 | ||
814 | /** | 804 | /** |
@@ -818,18 +808,17 @@ export class ContextMenuBuilder { | |||
818 | menu: Electron.CrossProcessExports.Menu, | 808 | menu: Electron.CrossProcessExports.Menu, |
819 | menuInfo: IContextMenuParams, | 809 | menuInfo: IContextMenuParams, |
820 | needsSeparator = true, | 810 | needsSeparator = true, |
821 | ) { | 811 | ): void { |
822 | const webContents = this.getWebContents(); | 812 | const webContents = this.getWebContents(); |
823 | if (!this.debugMode) return menu; | 813 | if (!this.debugMode) return; |
824 | if (needsSeparator) this.addSeparator(menu); | 814 | if (needsSeparator) this.addSeparator(menu); |
825 | 815 | ||
826 | const inspect = new MenuItem({ | 816 | menu.append( |
827 | label: this.stringTable.inspectElement(), | 817 | new MenuItem({ |
828 | click: () => webContents.inspectElement(menuInfo.x, menuInfo.y), | 818 | label: this.stringTable.inspectElement(), |
829 | }); | 819 | click: () => webContents.inspectElement(menuInfo.x, menuInfo.y), |
830 | 820 | }), | |
831 | menu.append(inspect); | 821 | ); |
832 | return menu; | ||
833 | } | 822 | } |
834 | 823 | ||
835 | /** | 824 | /** |
@@ -847,7 +836,7 @@ export class ContextMenuBuilder { | |||
847 | (arg0: string): void; | 836 | (arg0: string): void; |
848 | }, | 837 | }, |
849 | outputFormat: string = 'image/png', | 838 | outputFormat: string = 'image/png', |
850 | ) { | 839 | ): void { |
851 | let canvas: HTMLCanvasElement | null = document.createElement('canvas'); | 840 | let canvas: HTMLCanvasElement | null = document.createElement('canvas'); |
852 | const ctx = canvas.getContext('2d'); | 841 | const ctx = canvas.getContext('2d'); |
853 | const img = new Image(); | 842 | const img = new Image(); |
@@ -871,7 +860,7 @@ export class ContextMenuBuilder { | |||
871 | /** | 860 | /** |
872 | * Adds the 'go back' menu item | 861 | * Adds the 'go back' menu item |
873 | */ | 862 | */ |
874 | goBack(menu: Electron.CrossProcessExports.Menu) { | 863 | goBack(menu: Electron.CrossProcessExports.Menu): void { |
875 | const webContents = this.getWebContents(); | 864 | const webContents = this.getWebContents(); |
876 | 865 | ||
877 | menu.append( | 866 | menu.append( |
@@ -882,14 +871,12 @@ export class ContextMenuBuilder { | |||
882 | click: () => webContents.goBack(), | 871 | click: () => webContents.goBack(), |
883 | }), | 872 | }), |
884 | ); | 873 | ); |
885 | |||
886 | return menu; | ||
887 | } | 874 | } |
888 | 875 | ||
889 | /** | 876 | /** |
890 | * Adds the 'go forward' menu item | 877 | * Adds the 'go forward' menu item |
891 | */ | 878 | */ |
892 | goForward(menu: Electron.CrossProcessExports.Menu) { | 879 | goForward(menu: Electron.CrossProcessExports.Menu): void { |
893 | const webContents = this.getWebContents(); | 880 | const webContents = this.getWebContents(); |
894 | menu.append( | 881 | menu.append( |
895 | new MenuItem({ | 882 | new MenuItem({ |
@@ -899,8 +886,6 @@ export class ContextMenuBuilder { | |||
899 | click: () => webContents.goForward(), | 886 | click: () => webContents.goForward(), |
900 | }), | 887 | }), |
901 | ); | 888 | ); |
902 | |||
903 | return menu; | ||
904 | } | 889 | } |
905 | 890 | ||
906 | /** | 891 | /** |
@@ -909,7 +894,7 @@ export class ContextMenuBuilder { | |||
909 | copyPageUrl( | 894 | copyPageUrl( |
910 | menu: Electron.CrossProcessExports.Menu, | 895 | menu: Electron.CrossProcessExports.Menu, |
911 | menuInfo: IContextMenuParams, | 896 | menuInfo: IContextMenuParams, |
912 | ) { | 897 | ): void { |
913 | menu.append( | 898 | menu.append( |
914 | new MenuItem({ | 899 | new MenuItem({ |
915 | label: this.stringTable.copyPageUrl(), | 900 | label: this.stringTable.copyPageUrl(), |
@@ -923,8 +908,6 @@ export class ContextMenuBuilder { | |||
923 | }, | 908 | }, |
924 | }), | 909 | }), |
925 | ); | 910 | ); |
926 | |||
927 | return menu; | ||
928 | } | 911 | } |
929 | 912 | ||
930 | /** | 913 | /** |
@@ -933,7 +916,7 @@ export class ContextMenuBuilder { | |||
933 | goToHomePage( | 916 | goToHomePage( |
934 | menu: Electron.CrossProcessExports.Menu, | 917 | menu: Electron.CrossProcessExports.Menu, |
935 | menuInfo: IContextMenuParams, | 918 | menuInfo: IContextMenuParams, |
936 | ) { | 919 | ): void { |
937 | const baseURL = new window.URL(menuInfo.pageURL); | 920 | const baseURL = new window.URL(menuInfo.pageURL); |
938 | menu.append( | 921 | menu.append( |
939 | new MenuItem({ | 922 | new MenuItem({ |
@@ -946,8 +929,6 @@ export class ContextMenuBuilder { | |||
946 | }, | 929 | }, |
947 | }), | 930 | }), |
948 | ); | 931 | ); |
949 | |||
950 | return menu; | ||
951 | } | 932 | } |
952 | 933 | ||
953 | /** | 934 | /** |
@@ -956,7 +937,7 @@ export class ContextMenuBuilder { | |||
956 | openInBrowser( | 937 | openInBrowser( |
957 | menu: Electron.CrossProcessExports.Menu, | 938 | menu: Electron.CrossProcessExports.Menu, |
958 | menuInfo: IContextMenuParams, | 939 | menuInfo: IContextMenuParams, |
959 | ) { | 940 | ): void { |
960 | menu.append( | 941 | menu.append( |
961 | new MenuItem({ | 942 | new MenuItem({ |
962 | label: this.stringTable.openInBrowser(), | 943 | label: this.stringTable.openInBrowser(), |
@@ -966,14 +947,30 @@ export class ContextMenuBuilder { | |||
966 | }, | 947 | }, |
967 | }), | 948 | }), |
968 | ); | 949 | ); |
950 | } | ||
969 | 951 | ||
970 | return menu; | 952 | /** |
953 | * Adds the 'open in ferdium' menu item. | ||
954 | */ | ||
955 | openInFerdium( | ||
956 | menu: Electron.CrossProcessExports.Menu, | ||
957 | menuInfo: IContextMenuParams, | ||
958 | ): void { | ||
959 | menu.append( | ||
960 | new MenuItem({ | ||
961 | label: this.stringTable.openInFerdium(), | ||
962 | enabled: true, | ||
963 | click: () => { | ||
964 | window.location.href = menuInfo.linkURL; | ||
965 | }, | ||
966 | }), | ||
967 | ); | ||
971 | } | 968 | } |
972 | 969 | ||
973 | _sendNotificationOnClipboardEvent( | 970 | _sendNotificationOnClipboardEvent( |
974 | isDisabled: boolean, | 971 | isDisabled: boolean, |
975 | notificationText: () => string, | 972 | notificationText: () => string, |
976 | ) { | 973 | ): void { |
977 | if (isDisabled) { | 974 | if (isDisabled) { |
978 | return; | 975 | return; |
979 | } | 976 | } |
diff --git a/src/webview/notifications.ts b/src/webview/notifications.ts index e4401ab6e..0da86fbba 100644 --- a/src/webview/notifications.ts +++ b/src/webview/notifications.ts | |||
@@ -31,52 +31,51 @@ export class NotificationsHandler { | |||
31 | } | 31 | } |
32 | 32 | ||
33 | export const notificationsClassDefinition = `(() => { | 33 | export const notificationsClassDefinition = `(() => { |
34 | class Notification { | 34 | class Notification { |
35 | static permission = 'granted'; | 35 | static permission = 'granted'; |
36 | |||
37 | constructor(title = '', options = {}) { | ||
38 | this.title = title; | ||
39 | this.options = options; | ||
40 | try { | ||
41 | window.ferdium.displayNotification(title, options) | ||
42 | .then(() => { | ||
43 | if (typeof (this.onClick) === 'function') { | ||
44 | this.onClick(); | ||
45 | } | ||
46 | }); | ||
47 | } catch(error) { | ||
48 | this.options.onClick = null; | ||
49 | window.ferdium.displayNotification(title, options) | ||
50 | .then(() => { | ||
51 | if (typeof (this.onClick) === 'function') { | ||
52 | this.onClick(); | ||
53 | } | ||
54 | }); | ||
55 | } | ||
56 | } | ||
57 | 36 | ||
58 | static requestPermission(cb = null) { | 37 | static _notification; |
59 | if (!cb) { | ||
60 | return new Promise((resolve) => { | ||
61 | resolve(Notification.permission); | ||
62 | }); | ||
63 | } | ||
64 | 38 | ||
65 | if (typeof (cb) === 'function') { | 39 | constructor(title = '', options = {}) { |
66 | return cb(Notification.permission); | 40 | Notification._displayNotification(title, options); |
67 | } | 41 | } |
68 | 42 | ||
69 | return Notification.permission; | 43 | static _displayNotification(title, options) { |
70 | } | 44 | Notification._notification = window.ferdium |
45 | .displayNotification(title, options) | ||
46 | .then(() => { | ||
47 | // TODO: After several tries, we couldn't find a way to trigger the native notification onclick event. | ||
48 | // This was needed so that user could go to the specific context when clicking on the notification (it only goes to the service now). | ||
49 | // For now, we don't do anything here | ||
50 | }); | ||
51 | } | ||
71 | 52 | ||
72 | onNotify(data) { | 53 | static requestPermission(cb) { |
73 | return data; | 54 | if (typeof cb === 'function') { |
55 | cb(Notification.permission); | ||
74 | } | 56 | } |
75 | 57 | ||
76 | onClick() {} | 58 | return Promise.resolve(Notification.permission); |
59 | } | ||
60 | |||
61 | onNotify(data) { | ||
62 | return data; | ||
63 | } | ||
77 | 64 | ||
78 | close() {} | 65 | close() { |
66 | if (Notification._notification) { | ||
67 | Notification._notification = null; | ||
68 | } | ||
79 | } | 69 | } |
80 | 70 | ||
71 | onclick() {} | ||
72 | |||
73 | onclose() {} | ||
74 | |||
75 | onerror() {} | ||
76 | |||
77 | onshow() {} | ||
78 | } | ||
79 | |||
81 | window.Notification = Notification; | 80 | window.Notification = Notification; |
82 | })();`; | 81 | })();`; |
diff --git a/src/webview/recipe.ts b/src/webview/recipe.ts index a35a99699..ad2215ffd 100644 --- a/src/webview/recipe.ts +++ b/src/webview/recipe.ts | |||
@@ -121,7 +121,7 @@ contextBridge.exposeInMainWorld('ferdium', { | |||
121 | setDialogTitle: (title: string | null | undefined) => | 121 | setDialogTitle: (title: string | null | undefined) => |
122 | dialogTitleHandler.setDialogTitle(title), | 122 | dialogTitleHandler.setDialogTitle(title), |
123 | displayNotification: (title: string, options: any) => { | 123 | displayNotification: (title: string, options: any) => { |
124 | notificationsHandler.displayNotification( | 124 | return notificationsHandler.displayNotification( |
125 | title, | 125 | title, |
126 | // The following line is needed so that a proper clone of the "options" object is made. | 126 | // The following line is needed so that a proper clone of the "options" object is made. |
127 | // This line was causing issues with some services. | 127 | // This line was causing issues with some services. |