From 0d2241de06f0dba962be12d209abb2f9547309a2 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 12 Jul 2022 14:18:05 -0700 Subject: [PATCH] Extension: support right click saveurl and shortcut key to save current tab --- pkg/extension/src/manifest.json | 11 +- pkg/extension/src/scripts/background.js | 221 +++++++++++------- .../content/content-listener-script.js | 1 - 3 files changed, 153 insertions(+), 80 deletions(-) diff --git a/pkg/extension/src/manifest.json b/pkg/extension/src/manifest.json index 17ff70de7..ced972368 100644 --- a/pkg/extension/src/manifest.json +++ b/pkg/extension/src/manifest.json @@ -22,7 +22,7 @@ "256": "/images/extension/icon-256.png" }, - "permissions": ["activeTab", "storage", "https://*/**", "http://*/**"], + "permissions": ["activeTab", "storage", "contextMenus", "https://*/**", "http://*/**"], "background": { "page": "/views/background.html", @@ -72,5 +72,14 @@ "default_title": "Omnivore Save Article" }, + "commands": { + "_execute_browser_action": { + "suggested_key": { + "default": "Alt + O" + }, + "description": "Save the current tab to Omnivore" + } + }, + "web_accessible_resources": ["views/cta-popup.html"] } diff --git a/pkg/extension/src/scripts/background.js b/pkg/extension/src/scripts/background.js index 0e9099bef..600c17c13 100644 --- a/pkg/extension/src/scripts/background.js +++ b/pkg/extension/src/scripts/background.js @@ -47,6 +47,17 @@ function removeStorage (itemsToRemove) { }); } +function getCurrentTab () { + return new Promise((resolve) => { + browserApi.tabs.query({ + active: true, + currentWindow: true + }, function (tabs) { + resolve(tabs[0] || null); + }); + }); +} + function setupConnection(xhr) { xhr.setRequestHeader('Content-Type', 'application/json'); if (authToken) { @@ -164,6 +175,119 @@ function clearClickCompleteState () { }); } +function handleSaveResponse (tab, xhr) { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + const { data } = JSON.parse(xhr.response); + if ('createArticle' in data) { + if ('errorCodes' in data.createArticle) { + const messagePayload = { + text: descriptions[data.createArticle.errorCodes[0]] || 'Unable to save page', + type: 'error' + }; + + if (data.createArticle.errorCodes[0] === 'UNAUTHORIZED') { + messagePayload.errorCode = 401; + messagePayload.url = omnivoreURL; + + clearClickCompleteState(); + } + + browserApi.tabs.sendMessage(tab.id, { + action: ACTIONS.ShowMessage, + payload: messagePayload + }); + } else { + const article = data.createArticle.createdArticle; + const user = data.createArticle.user; + const link = omnivoreURL + (article.hasContent ? (`/${user.profile.username}/` + article.slug) : '/home'); + browserApi.tabs.sendMessage(tab.id, { + action: ACTIONS.ShowMessage, + payload: { + text: 'Saved to Omnivore', + link: link, + linkText: 'View', + type: 'success' + } + }); + } + } else { + if ('errorCodes' in data.createArticleSavingRequest) { + browserApi.tabs.sendMessage(tab.id, { + action: ACTIONS.ShowMessage, + payload: { + text: descriptions[data.createArticleSavingRequest.errorCodes[0]] || 'Unable to save page', + type: 'error' + } + }); + } else { + const articleSavingRequest = data.createArticleSavingRequest.articleSavingRequest; + const link = omnivoreURL + '/article/sr/' + articleSavingRequest.id; + browserApi.tabs.sendMessage(tab.id, { + action: ACTIONS.ShowMessage, + payload: { + text: 'Saved to Omnivore', + link: link, + linkText: 'View', + type: 'success' + } + }); + } + } + } else if (xhr.status === 400) { + browserApi.tabs.sendMessage(tab.id, { + action: ACTIONS.ShowMessage, + payload: { + text: 'Unable to save page', + type: 'error' + } + }); + } + } +} + +async function saveUrl (currentTab, url) { + browserApi.tabs.sendMessage(currentTab.id, { + action: ACTIONS.ShowMessage, + payload: { + type: 'loading', + text: 'Saving...' + } + }); + + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open('POST', omnivoreGraphqlURL + 'graphql', true); + setupConnection(xhr); + xhr.onerror = (err) => { + resolve(null); + }; + xhr.onload = (res) => { + try { + handleSaveResponse(currentTab, xhr) + } catch (err) { + console.log('response error', err) + } + resolve({}); + }; + + const data = JSON.stringify({ + query: CREATE_ARTICLE_SAVING_REQUEST_QUERY, + variables: { + input: { + url + } + } + }); + + xhr.send(data); + }) + .catch((err) => { + console.error('error saving url', err) + return undefined + }); +} + function saveArticle (tab) { browserApi.tabs.sendMessage(tab.id, { action: ACTIONS.ShowMessage, @@ -183,72 +307,7 @@ function saveArticle (tab) { }; xhr.onreadystatechange = function () { if (xhr.readyState === 4) { - if (xhr.status === 200) { - const { data } = JSON.parse(xhr.response); - if ('createArticle' in data) { - if ('errorCodes' in data.createArticle) { - const messagePayload = { - text: descriptions[data.createArticle.errorCodes[0]] || 'Unable to save page', - type: 'error' - }; - - if (data.createArticle.errorCodes[0] === 'UNAUTHORIZED') { - messagePayload.errorCode = 401; - messagePayload.url = omnivoreURL; - - clearClickCompleteState(); - } - - browserApi.tabs.sendMessage(tab.id, { - action: ACTIONS.ShowMessage, - payload: messagePayload - }); - } else { - const article = data.createArticle.createdArticle; - const user = data.createArticle.user; - const link = omnivoreURL + (article.hasContent ? (`/${user.profile.username}/` + article.slug) : '/home'); - browserApi.tabs.sendMessage(tab.id, { - action: ACTIONS.ShowMessage, - payload: { - text: 'Saved to Omnivore', - link: link, - linkText: 'View', - type: 'success' - } - }); - } - } else { - if ('errorCodes' in data.createArticleSavingRequest) { - browserApi.tabs.sendMessage(tab.id, { - action: ACTIONS.ShowMessage, - payload: { - text: descriptions[data.createArticleSavingRequest.errorCodes[0]] || 'Unable to save page', - type: 'error' - } - }); - } else { - const articleSavingRequest = data.createArticleSavingRequest.articleSavingRequest; - const link = omnivoreURL + '/article/sr/' + articleSavingRequest.id; - browserApi.tabs.sendMessage(tab.id, { - action: ACTIONS.ShowMessage, - payload: { - text: 'Saved to Omnivore', - link: link, - linkText: 'View', - type: 'success' - } - }); - } - } - } else if (xhr.status === 400) { - browserApi.tabs.sendMessage(tab.id, { - action: ACTIONS.ShowMessage, - payload: { - text: 'Unable to save page', - type: 'error' - } - }); - } + handleSaveResponse(tab, xhr) } }; @@ -484,18 +543,13 @@ function checkAuthOnFirstClickPostInstall (tabId) { }); } -function getCurrentTab () { - return new Promise((resolve) => { - browserApi.tabs.query({ - active: true, - currentWindow: true - }, function (tabs) { - resolve(tabs[0] || null); - }); - }); +function handleActionClick () { + executeAction(function (currentTab) { + onExtensionClick(currentTab.id); + }) } -function handleActionClick () { +function executeAction(action) { getCurrentTab().then((currentTab) => { browserApi.tabs.sendMessage(currentTab.id, { action: ACTIONS.Ping @@ -504,7 +558,7 @@ function handleActionClick () { // Content script ready const isSignedUp = await checkAuthOnFirstClickPostInstall(currentTab.id); if (isSignedUp) { - onExtensionClick(currentTab.id); + action(currentTab); } } else { const extensionManifest = browserApi.runtime.getManifest(); @@ -518,7 +572,7 @@ function handleActionClick () { executeScripts(currentTab.id, scriptFiles, async function () { const isSignedUp = await checkAuthOnFirstClickPostInstall(currentTab.id); if (isSignedUp) { - onExtensionClick(currentTab.id); + action(currentTab); } }); } @@ -644,6 +698,17 @@ function init () { browserActionApi.setIcon({ path: getIconPath(true) }); + + browserApi.contextMenus.create({ + id: "log-selection", + title: "Save to Omnivore", + contexts: ["link"], + onclick: async function(obj) { + executeAction(async function (currentTab) { + await saveUrl(currentTab, obj.linkUrl) + }) + }, + }); } init(); diff --git a/pkg/extension/src/scripts/content/content-listener-script.js b/pkg/extension/src/scripts/content/content-listener-script.js index 523f4d239..8fc3f0b73 100644 --- a/pkg/extension/src/scripts/content/content-listener-script.js +++ b/pkg/extension/src/scripts/content/content-listener-script.js @@ -22,7 +22,6 @@ } browserApi.runtime.onMessage.addListener(({ action, payload }, sender, sendResponse) => { - /* async actions */ if (action === ACTIONS.GetContent) { prepareContent().then((pageContent) => { sendResponse({