diff --git a/src/main/computersandblues/lodestone/app.cljs b/src/main/computersandblues/lodestone/app.cljs index 12cdfaf..8fba95c 100644 --- a/src/main/computersandblues/lodestone/app.cljs +++ b/src/main/computersandblues/lodestone/app.cljs @@ -234,32 +234,36 @@ on-response on-response on-error on-error}}] ((fn fetch-favorites' [url] - (println :calling url) - (swap! state assoc :api/state :loading) - (-> (mastodon-request! {:url url :bearer-token bearer-token}) - (.then (fn [response] - (on-response response) - (if (continue? response) - (js/setTimeout #(fetch-favorites' (link-header "next" (:raw response))) 500) - (swap! state dissoc :api/state :loading)))) - (.catch (fn [response] - (swap! state dissoc :api/state) - (on-error response))))) - (favorites-url {:instance-url instance-url :max-id max-id}))) + (let [req-id (js/Date.now)] + (println :calling url) + (swap! state assoc-in [:section/posts :loading] req-id) + (-> (mastodon-request! {:url url :bearer-token bearer-token}) + (.then (fn [response] + (on-response response) + (if (continue? response) + (js/setTimeout #(fetch-favorites' (link-header "next" (:raw response))) 500) + (when (= req-id (-> @state :section/posts :loading)) + (swap! state update :section/posts dissoc :loading)))) + (.catch (fn [response] + (when (= req-id (-> @state :section/posts :loading)) + (swap! state update :section/posts dissoc :loading)) + (on-error response)))))) + (favorites-url {:instance-url instance-url :max-id max-id})))) ;;; views (defn debounce [ms f] - (let [timeout (volatile! nil)] + (let [prev (volatile! (js/Date.now)) + trail (volatile! (js/setTimeout (fn dummy []) ms))] (fn debounced-fn [& args] - (when @timeout - (js/clearTimeout @timeout)) - (js/console.log "debounced-fn called" (js/Date.now)) - (vreset! timeout - (js/setTimeout (fn scheduled-fn [] - (js/console.log "scheduled-fn called" (js/Date.now)) - (vreset! timeout nil) - (apply f args)) ms))))) + (let [now (js/Date.now)] + (if (> (- now @prev) ms) + (do (vreset! prev now) + (apply f args)) + (do (js/clearTimeout @trail) + (vreset! trail (js/setTimeout (fn [] + (vreset! prev (js/Date.now)) + (apply f args)))))))))) (defn search [] [:input {:placeholder "Start typing to search…" @@ -341,15 +345,20 @@ (matches? (j/get-in post [:account :acct])) ; search for url + username of poster (some #(matches? (j/get % :username)) (j/get post :mentions))))) ; search only for username of mentions (take per-page) - (map #(js->clj % :keywordize-keys true)))] + (map #(js->clj % :keywordize-keys true))) + refresh-id (js/Date.now)] + (swap! state assoc-in [:section/posts :loading] refresh-id) (-> (js/Promise.all #js [(db/count! ::db/posts) (-> (db/open-cursor! ::db/posts db/all "prev") (db/transduce-cursor xform))]) (.then (fn [[total displayed-posts]] - (swap! state update :section/posts #(-> (assoc % :total total) - (assoc :displayed-posts displayed-posts)))))))) + (swap! state update :section/posts #(let [v (-> (assoc % :total total) + (assoc :displayed-posts displayed-posts))] + (if (= refresh-id (:loading %)) + (dissoc v :loading) + v)))))))) -(def debounced-refresh! (debounce 100 (partial refresh-displayed-posts!))) +(def debounced-refresh! (debounce 20 (partial refresh-displayed-posts!))) (defn- fetch-posts! [opts] (let [defaults {:max-id nil @@ -360,7 +369,7 @@ (fetch-favorites! (merge defaults opts)))) (defn posts-section [{:keys [posts]}] - (let [{:keys [per-page query total displayed-posts]} posts] + (let [{:keys [per-page query total displayed-posts loading]} posts] [:section.favorites [:h2 "Favorites"] [:header.controls @@ -370,6 +379,7 @@ (str ", displaying " (count displayed-posts) (when query " matches"))))] [:div.search-form [search] + (when loading " …") #_(cond (= api-state :loading) " …" (= api-state :error) " API Error!")]] [:ul.results (map-indexed (fn [idx favorite]