(ns frpong.helpers (:require [cljs.core.async :as async :refer [! chan put! close! sliding-buffer dropping-buffer timeout]] [domina :as dom :refer [log]] [domina.events :as ev]) (:require-macros [cljs.core.async.macros :as m :refer [go]] [frpong.core :refer (go-loop)])) (defn now [] (.valueOf (js/Date.))) (defn put-all! [cs x] (doseq [c cs] (put! c x))) (defn probe [ch probe-name] (let [c (chan)] (go (loop [] (if-let [v (! c v) (recur)) (close! c)))) c)) (defn multiplex [in cs-or-n] (let [cs (if (number? cs-or-n) (repeatedly cs-or-n chan) cs-or-n)] (go (loop [] (let [x (! c (f v)) (recur)) (close! c)))) c)) (defn filter-chan [f source] (let [c (chan)] (go (loop [] (if-let [v (! c v)) (recur)) (close! c)))) c)) (defn interval-chan ([msecs] (interval-chan msecs :leading)) ([msecs type] (let [c (chan (dropping-buffer 1))] (condp = type :leading (go-loop (>! c (now)) (! c (now)))) c))) (defn throttle [source control] (let [c (chan)] (go (loop [state ::init last nil] (let [[v sc] (alts! [source control])] (condp = sc source (condp = state ::init (do (>! c v) (recur ::throttling last)) ::throttling (recur state v)) control (if last (do (>! c last) (recur state nil)) (recur ::init last)))))) c)) (defn sustain [source control] (let [c (chan)] (go (loop [last nil] (let [[v ch] (alts! [source control] :priority true)] (if (nil? v) (close! c) (condp = ch source (do (>! c v) (recur v)) control (do (when last (>! c last)) (recur last))))))) c)) (defn debounce [source msecs] (let [c (chan)] (go (loop [state ::init cs [source]] (let [[_ threshold] cs] (let [[v sc] (alts! cs)] (condp = sc source (condp = state ::init (do (>! c v) (recur ::debouncing (conj cs (timeout msecs)))) ::debouncing (recur state (conj (pop cs) (timeout msecs)))) threshold (recur ::init (pop cs))))))) c)) (defn after-last [source msecs] (let [c (chan)] (go (loop [cs [source]] (let [[_ toc] cs] (let [[v sc] (alts! cs :priority true)] (recur (condp = sc source (conj (if toc (pop cs) cs) (timeout msecs)) toc (do (>! c (now)) (pop cs)))))))) c)) (defn fan-in [ins] (let [c (chan)] (go-loop (let [[x] (alts! ins)] (>! c x))) c)) (defn distinct-chan [source] (let [c (chan)] (go (loop [last ::init] (let [v (! c v)) (recur v)))) c)) (defn event-chan [event-type] (let [c (chan)] (ev/listen! event-type #(put! c %)) c)) (defn key-chan [keycodes] (let [source (event-chan :keydown) c (chan)] (go-loop (let [kc (:keyCode (! c (keycodes kc))))) c)) (defn frame-chan [] (let [fc (chan (sliding-buffer 1000)) rc (chan (sliding-buffer 10)) step (fn step [ts] (let [req-id (.requestAnimationFrame js/window step)] (put! fc ts) (put! rc req-id))) stop-fn (fn [] (go (loop [] (if-let [id (! c count) (recur (inc count))) (close! c)))) c)) (defn diff-chan [source] (let [c (chan)] (go (let [start (! c (- v start)) (recur v)) (close! c))))) c)) (defn dropping-chan [source n] (let [c (chan)] (go (loop [count 0] (if-let [v (! c v)) (recur (rem (inc count) n))) (close! c)))) c))