From 12e9d50a4584a4084a957af116e821f654ca89f1 Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Thu, 11 Jan 2018 07:37:18 -0500 Subject: [PATCH] Move all logic to background script --- ext/manifest.json | 13 +----- project.clj | 10 ++--- src/looped_in/background.cljs | 40 ------------------ src/looped_in/content.cljs | 50 ---------------------- src/looped_in/logging.cljs | 8 ++-- src/looped_in/main.cljs | 79 +++++++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 112 deletions(-) delete mode 100644 src/looped_in/background.cljs delete mode 100644 src/looped_in/content.cljs create mode 100644 src/looped_in/main.cljs diff --git a/ext/manifest.json b/ext/manifest.json index 859b3e2..4a68575 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -9,25 +9,16 @@ "96": "icons/icon96.png", "128": "icons/icon128.png" }, - "content_scripts": [ - { - "matches": [""], - "js": [ - "js/browser-polyfill.min.js", - "js/generated/out/cljs_base.js", - "js/generated/content.js" - ] - } - ], "background": { "scripts": ["js/browser-polyfill.min.js", "js/generated/out/cljs_base.js", - "js/generated/background.js"] + "js/generated/main.js"] }, "browser_action": { "default_icon": "icons/icon48.png", "default_title": "Looped In" }, + "permissions": ["tabs"], "content_security_policy": "script-src 'self'; object-src 'self'; connect-src 'self' https://hn.algolia.com", "web_accessible_resources": ["js/*.map", "js/generated/*.map"] } diff --git a/project.clj b/project.clj index c660f29..4db89b8 100644 --- a/project.clj +++ b/project.clj @@ -14,11 +14,7 @@ :source-map true :pretty-print true :output-dir "ext/js/generated/out" - :language-in :es6 :modules - {:content - {:output-to "ext/js/generated/content.js" - :entries #{"looped-in.content"}} - :background - {:output-to "ext/js/generated/background.js" - :entries #{"looped-in.background"}}}}}]}) + {:background + {:output-to "ext/js/generated/main.js" + :entries #{"looped-in.main"}}}}}]}) diff --git a/src/looped_in/background.cljs b/src/looped_in/background.cljs deleted file mode 100644 index 9325ccb..0000000 --- a/src/looped_in/background.cljs +++ /dev/null @@ -1,40 +0,0 @@ -(ns looped-in.background - (:require [clojure.core.match :refer [match]] - [cljs.core.async :refer [go chan >! promise]])) - -(enable-console-print!) - -(def browser-action (.-browserAction js/browser)) - -(defn fetch-submission - "Fetches submissions from Hacker News by `url`" - [url] - (let [response-chan (chan)] - (GET "https://hn.algolia.com/api/v1/search" - {:params {"query" url - "hitsPerPage" 1000 - "restrictSearchableAttributes" "url"} - :handler (fn [res] (go (>! response-chan res))) - :error-handler (fn [err] (log/error "Error fetching HN stories:" - (clj->js err)))}) - response-chan)) - -(defn handle-message - "Handles messages from the content script" - [msg] - (match (.-type msg) - "urlVisited" (channel->promise (fetch-submission (.-url msg))) - x (log/warn "Ignoring unknown message type" x))) - -(-> js/browser - (.-runtime) - (.-onMessage) - (.addListener handle-message - #_(fn [msg] - (prn msg) - (.setBadgeBackgroundColor browser-action #js {:color "#232323"}) - (.setBadgeText browser-action - #js {:text (str (.-numComments msg))})))) diff --git a/src/looped_in/content.cljs b/src/looped_in/content.cljs deleted file mode 100644 index 2584df0..0000000 --- a/src/looped_in/content.cljs +++ /dev/null @@ -1,50 +0,0 @@ -(ns looped-in.content - (:require-macros [cljs.core.async.macros :refer [go]]) - (:require [ajax.core :refer [GET]] - [cljs.core.async :as async :refer [go channel]])) - -(enable-console-print!) - -(defn filter-response - "Filters a response from hn.algolia.com to give just the relevant results" - ;; TODO implement a cache by URL and timestamp that caches the results of the - ;; request and this method for 5 minutes using localStorage - [url response] - (let [{:strs [hits]} response] - (log/debug "response" response) - (filter #(= (get % "url") url) hits))) - -(defn sort-hits - "Sorts hits from hn.algolia.com by post date descending" - [hits] - (sort-by #(get % "created_at_i") #(compare %2 %1) hits)) - -(defn total-num-comments - "Returns the total number of comments from some hits" - [hits] - (reduce (fn [acc {:strs [num_comments]}] (+ acc num_comments)) 0 hits)) - -(defn handle-hits - "Handles a filtered response" - [hits] - (log/debug (clj->js hits)) - (let [num-comments (total-num-comments hits)] - (-> js/browser - (.-runtime) - (.sendMessage #js {:numComments num-comments})))) - -#_(let [current-url (-> js/window (.-location) (.-href)) - sub-chan (fetch-submission current-url)] - (go (->> ( js/window (.-location) (.-href)) - results-chan (-> js/browser - (.-runtime) - (.sendMessage #js {:type "urlVisited" :url current-url}) - (promise->channel))] - (go (log/debug "results:" (js args))) (defn error [& args] - (apply js/console.error "[Looped In]" args)) + (apply js/console.error "[Looped In]" (map clj->js args))) (defn debug [& args] - (apply js/console.debug "[Looped In]" args)) + (apply js/console.debug "[Looped In]" (map clj->js args))) (defn warn [& args] - (apply js/console.warn "[Looped In]" args)) + (apply js/console.warn "[Looped In]" (map clj->js args))) diff --git a/src/looped_in/main.cljs b/src/looped_in/main.cljs new file mode 100644 index 0000000..37458bf --- /dev/null +++ b/src/looped_in/main.cljs @@ -0,0 +1,79 @@ +(ns looped-in.main + (:require [clojure.core.match :refer [match]] + [cljs.core.async :refer [go chan >! promise promise->channel]])) + +(enable-console-print!) + +(defn fetch-submission + "Fetches submissions from Hacker News by `url`" + [url] + (let [response-chan (chan)] + (GET "https://hn.algolia.com/api/v1/search" + {:params {"query" url + "hitsPerPage" 1000 + "restrictSearchableAttributes" "url"} + :handler (fn [res] (go (>! response-chan res))) + :error-handler (fn [err] (log/error "Error fetching HN stories:" + (clj->js err)))}) + response-chan)) + +(defn url-path [url] + (when (not (nil? url)) + (second (re-matches #"http.*://(.*)" url)))) + +(defn filter-response + "Filters a response from hn.algolia.com to give just the relevant results" + [url response] + (let [{:strs [hits]} response] + (filter #(= (url-path (get % "url")) (url-path url)) hits))) + +(defn sort-hits + "Sorts hits from hn.algolia.com by post date descending" + [hits] + (sort-by #(get % "created_at_i") #(compare %2 %1) hits)) + +(defn total-num-comments + "Returns the total number of comments from some hits" + [hits] + (reduce (fn [acc {:strs [num_comments]}] (+ acc num_comments)) 0 hits)) + +(defn set-badge-text! [text] + (.setBadgeBackgroundColor (.-browserAction js/browser) #js {:color "#232323"}) + (.setBadgeText (.-browserAction js/browser) #js {:text text})) + +;; TODO implement a cache on the result of the urlVisited message + +(defn handle-update [tab-id] + (go (let [query-p (-> js/browser (.-tabs) (.query #js {:active true + :currentWindow true})) + query-chan (promise->channel query-p) + tab (first (> response + (filter-response url) + (sort-hits)) + num-comments (total-num-comments hits)] + (set-badge-text! (str num-comments))))) + +(-> js/browser + (.-tabs) + (.-onActivated) + (.addListener handle-update)) + +(-> js/browser + (.-tabs) + (.-onUpdated) + (.addListener handle-update)) + +;; Application logic: +;; 1. Event comes in (new url) +;; 2. Fetch HN hits +;; 3. Filter and sort hits +;; 4. Count comments, update badge +;; 5. Fetch item details +;; 6. Construct popup (or sidebar?) html