2 Copyright (C) 2019 Kai Uwe Broulik <kde@privat.broulik.de>
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.
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.
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/>.
18 const purposeShareMenuId = "purpose_share";
19 let hasPurposeMenu = false;
21 // Stores <notification id, share url> so that when you click the finished
22 // notification it will open the URL
23 let purposeNotificationUrls = {};
25 function purposeShare(data) {
26 return new Promise((resolve, reject) => {
27 sendPortMessageWithReply("purpose", "share", {data}).then((reply) => {
29 if (!["BUSY", "CANCELED", "INVALID_ARGUMENT"].includes(reply.errorCode)
30 && reply.errorCode !== 1 /*ERR_USER_CANCELED*/) {
31 chrome.notifications.create(null, {
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"
44 let url = reply.response.url;
46 chrome.notifications.create(null, {
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) {
56 purposeNotificationUrls[notificationId] = url;
65 function checkPurposeEnabled() {
67 sendPortMessageWithReply("settings", "getSubsystemStatus"),
71 const subsystemStatus = result[0];
72 const settings = result[1];
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;
85 function updatePurposeMenu() {
86 checkPurposeEnabled().then((enabled) => {
87 if (enabled && !hasPurposeMenu) {
89 id: purposeShareMenuId,
90 contexts: ["link", "page", "image", "audio", "video", "selection"],
91 title: chrome.i18n.getMessage("purpose_share")
96 "16": "icons/document-share-symbolic.svg"
100 chrome.contextMenus.create(props, () => {
101 const error = chrome.runtime.lastError;
103 console.warn("Error creating purpose context menu", error.message);
106 hasPurposeMenu = true;
108 } else if (!enabled && hasPurposeMenu) {
109 chrome.contextMenus.remove(purposeShareMenuId, () => {
110 const error = chrome.runtime.lastError;
112 console.warn("Error removing purpose context menu", error.message);
115 hasPurposeMenu = false;
121 chrome.contextMenus.onClicked.addListener((info) => {
122 if (info.menuItemId !== purposeShareMenuId) {
126 let url = info.linkUrl || info.srcUrl || info.pageUrl;
127 let selection = info.selectionText;
128 if (!url && !selection) {
134 shareData.text = selection;
137 if (info.linkText && info.linkText != url) {
138 shareData.title = info.linkText;
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) {
146 // more correct would probably be currentWindow + activeTab
150 return resolve(tabs[0].title);
160 shareData.title = title;
163 purposeShare(shareData);
167 SettingsUtils.onChanged().addListener((delta) => {
173 addRuntimeCallback("purpose", "share", (message, sender, action) => {
174 return purposeShare(message);
177 chrome.notifications.onClicked.addListener((notificationId) => {
178 const url = purposeNotificationUrls[notificationId];
180 chrome.tabs.create({url});
184 chrome.notifications.onClosed.addListener((notificationId) => {
185 delete purposeNotificationUrls[notificationId];