update readme
[dotfiles/.git] / .config / BraveSoftware / Brave-Browser / Default / Extensions / cimiefiiaegbelhefglklhhakcgmhkai / 1.7.6_0 / extension-purpose.js
1 /*
2     Copyright (C) 2019 Kai Uwe Broulik <kde@privat.broulik.de>
3
4     This program is free software; you can redistribute it and/or
5     modify it under the terms of the GNU General Public License as
6     published by the Free Software Foundation; either version 3 of
7     the License, or (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 const purposeShareMenuId = "purpose_share";
19 let hasPurposeMenu = false;
20
21 // Stores <notification id, share url> so that when you click the finished
22 // notification it will open the URL
23 let purposeNotificationUrls = {};
24
25 function purposeShare(data) {
26     return new Promise((resolve, reject) => {
27         sendPortMessageWithReply("purpose", "share", {data}).then((reply) => {
28             if (!reply.success) {
29                 if (!["BUSY", "CANCELED", "INVALID_ARGUMENT"].includes(reply.errorCode)
30                     && reply.errorCode !== 1 /*ERR_USER_CANCELED*/) {
31                     chrome.notifications.create(null, {
32                         type: "basic",
33                         title: chrome.i18n.getMessage("purpose_share_failed_title"),
34                         message: chrome.i18n.getMessage("purpose_share_failed_text",
35                                                         reply.errorMessage || chrome.i18n.getMessage("general_error_unknown")),
36                         iconUrl: "icons/document-share-failed.png"
37                     });
38                 }
39
40                 reject();
41                 return;
42             }
43
44             let url = reply.response.url;
45             if (url) {
46                 chrome.notifications.create(null, {
47                     type: "basic",
48                     title: chrome.i18n.getMessage("purpose_share_finished_title"),
49                     message: chrome.i18n.getMessage("purpose_share_finished_text", url),
50                     iconUrl: "icons/document-share.png"
51                 }, (notificationId) => {
52                     if (chrome.runtime.lastError) {
53                         return;
54                     }
55
56                     purposeNotificationUrls[notificationId] = url;
57                 });
58             }
59
60             resolve();
61         });
62     });
63 }
64
65 function checkPurposeEnabled() {
66     return Promise.all([
67         sendPortMessageWithReply("settings", "getSubsystemStatus"),
68         SettingsUtils.get()
69     ]).then((result) => {
70
71         const subsystemStatus = result[0];
72         const settings = result[1];
73
74         // HACK Unfortunately I removed the loaded/unloaded signals for plugins
75         // so we can't reliably know on settings change whether a module is enabled
76         // sending settings is also legacy done without a reply we could wait for.
77         // Instead, check whether the module is known and enabled in settings,
78         // which should be close enough, since purpose plugin also has no additional
79         // dependencies that could make it fail to load.
80         return subsystemStatus.hasOwnProperty("purpose")
81             && settings.purpose && settings.purpose.enabled;
82     });
83 }
84
85 function updatePurposeMenu() {
86     checkPurposeEnabled().then((enabled) => {
87         if (enabled && !hasPurposeMenu) {
88             let props = {
89                 id: purposeShareMenuId,
90                 contexts: ["link", "page", "image", "audio", "video", "selection"],
91                 title: chrome.i18n.getMessage("purpose_share")
92             };
93
94             if (IS_FIREFOX) {
95                 props.icons = {
96                     "16": "icons/document-share-symbolic.svg"
97                 }
98             }
99
100             chrome.contextMenus.create(props, () => {
101                 const error = chrome.runtime.lastError;
102                 if (error) {
103                     console.warn("Error creating purpose context menu", error.message);
104                     return;
105                 }
106                 hasPurposeMenu = true;
107             });
108         } else if (!enabled && hasPurposeMenu) {
109             chrome.contextMenus.remove(purposeShareMenuId, () => {
110                 const error = chrome.runtime.lastError;
111                 if (error) {
112                     console.warn("Error removing purpose context menu", error.message);
113                     return;
114                 }
115                 hasPurposeMenu = false;
116             });
117         }
118     });
119 }
120
121 chrome.contextMenus.onClicked.addListener((info) => {
122     if (info.menuItemId !== purposeShareMenuId) {
123         return;
124     }
125
126     let url = info.linkUrl || info.srcUrl || info.pageUrl;
127     let selection = info.selectionText;
128     if (!url && !selection) {
129         return;
130     }
131
132     let shareData = {};
133     if (selection) {
134         shareData.text = selection;
135     } else if (url) {
136         shareData.url = url;
137         if (info.linkText && info.linkText != url) {
138             shareData.title = info.linkText;
139         }
140     }
141
142     // We probably shared the current page, add its title to shareData
143     new Promise((resolve, reject) => {
144         if (!info.linkUrl && !info.srcUrl && info.pageUrl) {
145             chrome.tabs.query({
146                 // more correct would probably be currentWindow + activeTab
147                 url: info.pageUrl
148             }, (tabs) => {
149                 if (tabs[0]) {
150                     return resolve(tabs[0].title);
151                 }
152                 resolve("");
153             });
154             return;
155         }
156
157         resolve("");
158     }).then((title) => {
159         if (title) {
160             shareData.title = title;
161         }
162
163         purposeShare(shareData);
164     });
165 });
166
167 SettingsUtils.onChanged().addListener((delta) => {
168     if (delta.purpose) {
169         updatePurposeMenu();
170     }
171 });
172
173 addRuntimeCallback("purpose", "share", (message, sender, action) => {
174     return purposeShare(message);
175 });
176
177 chrome.notifications.onClicked.addListener((notificationId) => {
178     const url = purposeNotificationUrls[notificationId];
179     if (url) {
180         chrome.tabs.create({url});
181     }
182 });
183
184 chrome.notifications.onClosed.addListener((notificationId) => {
185     delete purposeNotificationUrls[notificationId];
186 });