Warning, file /plasma/plasma-browser-integration/extension/extension-purpose.js was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 Copyright (C) 2019 Kai Uwe Broulik <kde@privat.broulik.de> 0003 0004 This program is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU General Public License as 0006 published by the Free Software Foundation; either version 3 of 0007 the License, or (at your option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 GNU General Public License for more details. 0013 0014 You should have received a copy of the GNU General Public License 0015 along with this program. If not, see <http://www.gnu.org/licenses/>. 0016 */ 0017 0018 const purposeShareMenuId = "purpose_share"; 0019 let hasPurposeMenu = false; 0020 0021 // Stores <notification id, share url> so that when you click the finished 0022 // notification it will open the URL 0023 let purposeNotificationUrls = {}; 0024 0025 function purposeShare(data) { 0026 return new Promise((resolve, reject) => { 0027 sendPortMessageWithReply("purpose", "share", {data}).then((reply) => { 0028 if (!reply.success) { 0029 if (!["BUSY", "CANCELED", "INVALID_ARGUMENT"].includes(reply.errorCode) 0030 && reply.errorCode !== 1 /*ERR_USER_CANCELED*/) { 0031 chrome.notifications.create(null, { 0032 type: "basic", 0033 title: chrome.i18n.getMessage("purpose_share_failed_title"), 0034 message: chrome.i18n.getMessage("purpose_share_failed_text", 0035 reply.errorMessage || chrome.i18n.getMessage("general_error_unknown")), 0036 iconUrl: "icons/document-share-failed.png" 0037 }); 0038 } 0039 0040 reject(); 0041 return; 0042 } 0043 0044 let url = reply.response.url; 0045 if (url) { 0046 chrome.notifications.create(null, { 0047 type: "basic", 0048 title: chrome.i18n.getMessage("purpose_share_finished_title"), 0049 message: chrome.i18n.getMessage("purpose_share_finished_text", url), 0050 iconUrl: "icons/document-share.png" 0051 }, (notificationId) => { 0052 if (chrome.runtime.lastError) { 0053 return; 0054 } 0055 0056 purposeNotificationUrls[notificationId] = url; 0057 }); 0058 } 0059 0060 resolve(); 0061 }); 0062 }); 0063 } 0064 0065 function checkPurposeEnabled() { 0066 return Promise.all([ 0067 sendPortMessageWithReply("settings", "getSubsystemStatus"), 0068 SettingsUtils.get() 0069 ]).then((result) => { 0070 0071 const subsystemStatus = result[0]; 0072 const settings = result[1]; 0073 0074 // HACK Unfortunately I removed the loaded/unloaded signals for plugins 0075 // so we can't reliably know on settings change whether a module is enabled 0076 // sending settings is also legacy done without a reply we could wait for. 0077 // Instead, check whether the module is known and enabled in settings, 0078 // which should be close enough, since purpose plugin also has no additional 0079 // dependencies that could make it fail to load. 0080 return subsystemStatus.hasOwnProperty("purpose") 0081 && settings.purpose && settings.purpose.enabled; 0082 }); 0083 } 0084 0085 function updatePurposeMenu() { 0086 checkPurposeEnabled().then((enabled) => { 0087 if (enabled && !hasPurposeMenu) { 0088 let props = { 0089 id: purposeShareMenuId, 0090 contexts: ["link", "page", "image", "audio", "video", "selection"], 0091 title: chrome.i18n.getMessage("purpose_share") 0092 }; 0093 0094 if (IS_FIREFOX) { 0095 props.icons = { 0096 "16": "icons/document-share-symbolic.svg" 0097 } 0098 } 0099 0100 chrome.contextMenus.create(props, () => { 0101 const error = chrome.runtime.lastError; 0102 if (error) { 0103 console.warn("Error creating purpose context menu", error.message); 0104 return; 0105 } 0106 hasPurposeMenu = true; 0107 }); 0108 } else if (!enabled && hasPurposeMenu) { 0109 chrome.contextMenus.remove(purposeShareMenuId, () => { 0110 const error = chrome.runtime.lastError; 0111 if (error) { 0112 console.warn("Error removing purpose context menu", error.message); 0113 return; 0114 } 0115 hasPurposeMenu = false; 0116 }); 0117 } 0118 }); 0119 } 0120 0121 chrome.contextMenus.onClicked.addListener((info) => { 0122 if (info.menuItemId !== purposeShareMenuId) { 0123 return; 0124 } 0125 0126 let url = info.linkUrl || info.srcUrl || info.pageUrl; 0127 let selection = info.selectionText; 0128 if (!url && !selection) { 0129 return; 0130 } 0131 0132 let shareData = {}; 0133 if (selection) { 0134 shareData.text = selection; 0135 } else if (url) { 0136 shareData.url = url; 0137 if (info.linkText && info.linkText != url) { 0138 shareData.title = info.linkText; 0139 } 0140 } 0141 0142 // We probably shared the current page, add its title to shareData 0143 new Promise((resolve, reject) => { 0144 if (!info.linkUrl && !info.srcUrl && info.pageUrl) { 0145 chrome.tabs.query({ 0146 // more correct would probably be currentWindow + activeTab 0147 url: info.pageUrl 0148 }, (tabs) => { 0149 if (tabs[0]) { 0150 return resolve(tabs[0].title); 0151 } 0152 resolve(""); 0153 }); 0154 return; 0155 } 0156 0157 resolve(""); 0158 }).then((title) => { 0159 if (title) { 0160 shareData.title = title; 0161 } 0162 0163 purposeShare(shareData); 0164 }); 0165 }); 0166 0167 SettingsUtils.onChanged().addListener((delta) => { 0168 if (delta.purpose) { 0169 updatePurposeMenu(); 0170 } 0171 }); 0172 0173 addRuntimeCallback("purpose", "share", (message, sender, action) => { 0174 return purposeShare(message); 0175 }); 0176 0177 chrome.notifications.onClicked.addListener((notificationId) => { 0178 const url = purposeNotificationUrls[notificationId]; 0179 if (url) { 0180 chrome.tabs.create({url}); 0181 } 0182 }); 0183 0184 chrome.notifications.onClosed.addListener((notificationId) => { 0185 delete purposeNotificationUrls[notificationId]; 0186 });