diff --git a/src/assets/icon-gray-128.png b/src/assets/icon-gray-128.png new file mode 100644 index 0000000..5b552be Binary files /dev/null and b/src/assets/icon-gray-128.png differ diff --git a/src/assets/icon-gray-16.png b/src/assets/icon-gray-16.png new file mode 100644 index 0000000..0bc88ac Binary files /dev/null and b/src/assets/icon-gray-16.png differ diff --git a/src/assets/icon-gray-48.png b/src/assets/icon-gray-48.png new file mode 100644 index 0000000..0546144 Binary files /dev/null and b/src/assets/icon-gray-48.png differ diff --git a/src/background.ts b/src/background.ts index 5312899..00821c3 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,69 +1,101 @@ -import browser from 'webextension-polyfill'; - -let awaitingResponse = false - -const onFeedDownloaded = (req: XMLHttpRequest) => { - return async () => { - awaitingResponse = false - if (req.status >= 400) { - console.error( - `Could not load URL feed: ${req.responseURL}: ` + - `${req.status}: ${req.statusText}` - ) - - return - } - - const [tab] = await browser.tabs.query({ - active: true, - currentWindow: true - }) - - if (!tab || tab.id === -1) - return - - await browser.tabs.sendMessage( - tab.id, { - type: 'renderFeed', - document: req.responseText - } - ) - } -} - -const renderFeed = (url: string) => { - awaitingResponse = true - const req = new XMLHttpRequest() - req.onload = onFeedDownloaded(req) - req.open('GET', url) - req.responseType = 'text' - req.send() -} - -browser.webNavigation.onCompleted.addListener( - async (event: {tabId: Number}) => { - const { tabId } = event - await browser.tabs.sendMessage(tabId, {type: 'renderFeed'}) - } -) - -browser.webRequest.onHeadersReceived.addListener( - async (event: { - url: string, - responseHeaders: Array<{name: string, value: string}> - }) => { - if (awaitingResponse) - return - - const {url, responseHeaders} = event - const contentType = responseHeaders.find( - h => h.name.toLowerCase() === 'content-type' - )?.value || '' - - if (contentType.startsWith('application/rss+xml')) - renderFeed(url) - }, - {urls: ['']}, - ['blocking', 'responseHeaders'] -) - +import browser from 'webextension-polyfill'; + +interface State { + awaitingResponse: boolean + feedUrl: string | null +} + +const state: State = { + awaitingResponse: false, + feedUrl: null, +} + +const getActiveTab = async () => { + const [tab] = await browser.tabs.query({ + active: true, + currentWindow: true + }) + + return tab +} + +const onFeedDownloaded = (req: XMLHttpRequest) => { + return async () => { + state.awaitingResponse = false + if (req.status >= 400) { + console.error( + `Could not load URL feed: ${req.responseURL}: ` + + `${req.status}: ${req.statusText}` + ) + + return + } + + const tab = await getActiveTab() + if (!tab || tab.id === -1) + return + + await browser.tabs.sendMessage( + tab.id, { + type: 'renderFeed', + document: req.responseText + } + ) + } +} + +const renderFeed = (url: string) => { + state.awaitingResponse = true + const req = new XMLHttpRequest() + req.onload = onFeedDownloaded(req) + req.open('GET', url) + req.responseType = 'text' + req.send() +} + +const updateFeedUrl = (tabId: number, feedUrl: string | null) => { + if (!feedUrl?.length) { + browser.pageAction.hide() + state.feedUrl = null + } else { + browser.pageAction.show(tabId) + state.feedUrl = feedUrl + } +} + +browser.pageAction.onClicked.addListener( + async () => { + if (state.feedUrl?.length) + renderFeed(state.feedUrl) + } +) + +browser.webNavigation.onCompleted.addListener( + async (event: {tabId: number}) => { + const { tabId } = event + const feedUrl = await browser.tabs.sendMessage(tabId, {type: 'extractFeedUrl'}) + updateFeedUrl(tabId, feedUrl) + await browser.tabs.sendMessage(tabId, {type: 'renderFeed'}) + } +) + +browser.webRequest.onHeadersReceived.addListener( + async (event: { + url: string, + responseHeaders: Array<{name: string, value: string}> + }) => { + if (state.awaitingResponse) + return + + const {url, responseHeaders} = event + const contentType = responseHeaders.find( + h => h.name.toLowerCase() === 'content-type' + )?.value || '' + + if (contentType.startsWith('application/rss+xml')) + renderFeed(url) + }, + {urls: ['']}, + ['blocking', 'responseHeaders'] +) + diff --git a/src/main.ts b/src/main.ts index cb9b641..cc11e53 100644 --- a/src/main.ts +++ b/src/main.ts @@ -177,7 +177,7 @@ const extractFeedUrl = () => { browser.runtime.onMessage.addListener( async ( message: { - type: Object, + type: string, url: string, document: string, } diff --git a/src/manifest_v2.json b/src/manifest_v2.json index aa2e0cd..827c1e9 100644 --- a/src/manifest_v2.json +++ b/src/manifest_v2.json @@ -3,9 +3,13 @@ "description": "An easy way to render RSS feeds directly in your browser", "version": "0.1.2", "manifest_version": 2, - "browser_action": { - "default_title": "Feed Viewer", - "default_popup": "popup/index.html" + "page_action": { + "default_icon": { + "16": "assets/icon-gray-16.png", + "48": "assets/icon-gray-48.png", + "128": "assets/icon-gray-128.png" + }, + "default_title": "Detected an RSS/Atom feed" }, "icons": { "16": "assets/icon16.png", diff --git a/src/manifest_v3.json b/src/manifest_v3.json index 45258e4..3577ddb 100644 --- a/src/manifest_v3.json +++ b/src/manifest_v3.json @@ -3,14 +3,13 @@ "description": "An easy way to render RSS feeds directly in your browser", "version": "0.1.2", "manifest_version": 3, - "action": { - "default_title": "Feed Viewer", - "default_popup": "popup/index.html", + "page_action": { "default_icon": { - "16": "assets/icon16.png", - "48": "assets/icon48.png", - "128": "assets/icon128.png" - } + "16": "assets/icon-gray-16.png", + "48": "assets/icon-gray-48.png", + "128": "assets/icon-gray-128.png" + }, + "default_title": "Detected an RSS/Atom feed" }, "background": { "service_worker": "background.ts", diff --git a/src/popup/Popup.vue b/src/popup/Popup.vue deleted file mode 100644 index ef20f02..0000000 --- a/src/popup/Popup.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - diff --git a/src/popup/index.html b/src/popup/index.html deleted file mode 100644 index 82e4e6b..0000000 --- a/src/popup/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - RSS Viewer Popup - - -
- - - diff --git a/src/popup/main.ts b/src/popup/main.ts deleted file mode 100644 index cf39580..0000000 --- a/src/popup/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createApp } from "vue"; -import App from "./Popup.vue"; - -const app = createApp(App) -app.mount('#app')